Imported Upstream version 3.15.4
[platform/upstream/nss.git] / nss / cmd / modutil / install-ds.c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "install-ds.h"
6 #include <prmem.h>
7 #include <plstr.h>
8 #include <prprf.h>
9 #include <string.h>
10
11 #define PORT_Strcasecmp PL_strcasecmp
12
13 #define MODULE_FILE_STRING "ModuleFile"
14 #define MODULE_NAME_STRING "ModuleName"
15 #define MECH_FLAGS_STRING "DefaultMechanismFlags"
16 #define CIPHER_FLAGS_STRING "DefaultCipherFlags"
17 #define FILES_STRING "Files"
18 #define FORWARD_COMPATIBLE_STRING "ForwardCompatible"
19 #define PLATFORMS_STRING "Platforms"
20 #define RELATIVE_DIR_STRING "RelativePath"
21 #define ABSOLUTE_DIR_STRING "AbsolutePath"
22 #define FILE_PERMISSIONS_STRING "FilePermissions"
23 #define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform"
24 #define EXECUTABLE_STRING "Executable"
25
26 #define DEFAULT_PERMISSIONS 0777
27
28 #define PLATFORM_SEPARATOR_CHAR ':'
29
30 /* Error codes */
31 enum {
32         BOGUS_RELATIVE_DIR=0,
33         BOGUS_ABSOLUTE_DIR,
34         BOGUS_FILE_PERMISSIONS,
35         NO_RELATIVE_DIR,
36         NO_ABSOLUTE_DIR,
37         EMPTY_PLATFORM_STRING,
38         BOGUS_PLATFORM_STRING,
39         REPEAT_MODULE_FILE,
40         REPEAT_MODULE_NAME,
41         BOGUS_MODULE_FILE,
42         BOGUS_MODULE_NAME,
43         REPEAT_MECH,
44         BOGUS_MECH_FLAGS,
45         REPEAT_CIPHER,
46         BOGUS_CIPHER_FLAGS,
47         REPEAT_FILES,
48         REPEAT_EQUIV,
49         BOGUS_EQUIV,
50         EQUIV_TOO_MUCH_INFO,
51         NO_FILES,
52         NO_MODULE_FILE,
53         NO_MODULE_NAME,
54         NO_PLATFORMS,
55         EQUIV_LOOP,
56         UNKNOWN_MODULE_FILE
57 };
58
59 /* Indexed by the above error codes */
60 static const char *errString[] = {
61         "%s: Invalid relative directory",
62         "%s: Invalid absolute directory",
63         "%s: Invalid file permissions",
64         "%s: No relative directory specified",
65         "%s: No absolute directory specified",
66         "Empty string given for platform name",
67         "%s: invalid platform string",
68         "More than one ModuleFile entry given for platform %s",
69         "More than one ModuleName entry given for platform %s",
70         "Invalid ModuleFile specification for platform %s",
71         "Invalid ModuleName specification for platform %s",
72         "More than one DefaultMechanismFlags entry given for platform %s",
73         "Invalid DefaultMechanismFlags specification for platform %s",
74         "More than one DefaultCipherFlags entry given for platform %s",
75         "Invalid DefaultCipherFlags entry given for platform %s",
76         "More than one Files entry given for platform %s",
77         "More than one EquivalentPlatform entry given for platform %s",
78         "Invalid EquivalentPlatform specification for platform %s",
79         "Module %s uses an EquivalentPlatform but also specifies its own"
80                 " information",
81         "No Files specification in module %s",
82         "No ModuleFile specification in module %s",
83         "No ModuleName specification in module %s",
84         "No Platforms specification in installer script",
85         "Platform %s has an equivalency loop",
86         "Module file \"%s\" in platform \"%s\" does not exist"
87 };
88
89 static char* PR_Strdup(const char* str);
90
91 #define PAD(x)  {int i; for(i=0;i<x;i++) printf(" ");}
92 #define PADINC 4
93
94 Pk11Install_File*
95 Pk11Install_File_new()
96 {
97         Pk11Install_File* new_this;
98         new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File));
99         Pk11Install_File_init(new_this);
100         return new_this;
101 }
102
103 void
104 Pk11Install_File_init(Pk11Install_File* _this)
105 {
106         _this->jarPath=NULL;
107         _this->relativePath=NULL;
108         _this->absolutePath=NULL;
109         _this->executable=PR_FALSE;
110         _this->permissions=0;
111 }
112
113 /*
114 //////////////////////////////////////////////////////////////////////////
115 // Method:      ~Pk11Install_File
116 // Class:       Pk11Install_File
117 // Notes:       Destructor.
118 */
119 void
120 Pk11Install_File_delete(Pk11Install_File* _this)
121 {
122         Pk11Install_File_Cleanup(_this);
123 }
124
125 /*
126 //////////////////////////////////////////////////////////////////////////
127 // Method:      Cleanup
128 // Class:       Pk11Install_File
129 */
130 void
131 Pk11Install_File_Cleanup(Pk11Install_File* _this)
132 {
133         if(_this->jarPath) {
134                 PR_Free(_this->jarPath);
135                 _this->jarPath = NULL;
136         }
137         if(_this->relativePath) {
138                 PR_Free(_this->relativePath);
139                 _this->relativePath = NULL;
140         }
141         if(_this->absolutePath) {
142                 PR_Free(_this->absolutePath);
143                 _this->absolutePath = NULL;
144         }
145
146         _this->permissions = 0;
147         _this->executable = PR_FALSE;
148 }
149
150 /*
151 //////////////////////////////////////////////////////////////////////////
152 // Method:      Generate
153 // Class:       Pk11Install_File
154 // Notes:       Creates a file data structure from a syntax tree.
155 // Returns:     NULL for success, otherwise an error message.
156 */
157 char*
158 Pk11Install_File_Generate(Pk11Install_File* _this,
159                           const Pk11Install_Pair *pair)
160 {
161         Pk11Install_ListIter *iter;
162         Pk11Install_Value *val;
163         Pk11Install_Pair *subpair;
164         Pk11Install_ListIter *subiter;
165         Pk11Install_Value *subval;
166         char* errStr;
167         char *endp;
168         PRBool gotPerms;
169
170         iter=NULL;
171         subiter=NULL;
172         errStr=NULL;
173         gotPerms=PR_FALSE;
174
175         /* Clear out old values */
176         Pk11Install_File_Cleanup(_this);
177
178         _this->jarPath = PR_Strdup(pair->key);
179
180         /* Go through all the pairs under this file heading */
181         iter = Pk11Install_ListIter_new(pair->list);
182         for( ; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
183                 if(val->type == PAIR_VALUE) {
184                         subpair = val->pair;
185
186                         /* Relative directory */
187                         if(!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) {
188                                 subiter = Pk11Install_ListIter_new(subpair->list);
189                                 subval = subiter->current;
190                                 if(!subval || (subval->type != STRING_VALUE)){
191                                         errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR], 
192                                     _this->jarPath);
193                                         goto loser;
194                                 }
195                                 _this->relativePath = PR_Strdup(subval->string);
196                                 Pk11Install_ListIter_delete(subiter);
197                                 subiter = NULL;
198
199                                 /* Absolute directory */
200                         } else if( !PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) {
201                                 subiter = Pk11Install_ListIter_new(subpair->list);
202                                 subval = subiter->current;
203                                 if(!subval || (subval->type != STRING_VALUE)){
204                                         errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR], 
205                                     _this->jarPath);
206                                         goto loser;
207                                 }
208                                 _this->absolutePath = PR_Strdup(subval->string);
209                                 Pk11Install_ListIter_delete(subiter);
210                                 subiter = NULL;
211
212                         /* file permissions */
213                         } else if( !PORT_Strcasecmp(subpair->key,
214                                      FILE_PERMISSIONS_STRING)) {
215                                 subiter = Pk11Install_ListIter_new(subpair->list);
216                                 subval = subiter->current;
217                                 if(!subval || (subval->type != STRING_VALUE) ||
218                                    !subval->string || !subval->string[0]){
219                                         errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
220                                     _this->jarPath);
221                                         goto loser;
222                                 }
223                                 _this->permissions = (int) strtol(subval->string, &endp, 8);
224                                 if(*endp != '\0') {
225                                         errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
226                                     _this->jarPath);
227                                         goto loser;
228                                 }
229                                 gotPerms = PR_TRUE;
230                                 Pk11Install_ListIter_delete(subiter);
231                                 subiter = NULL;
232                         }
233                 } else {
234                         if(!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) {
235                                 _this->executable = PR_TRUE;
236                         }
237                 }
238         }
239
240         /* Default permission value */
241         if(!gotPerms) {
242                 _this->permissions = DEFAULT_PERMISSIONS;
243         }
244
245         /* Make sure we got all the information */
246         if(!_this->relativePath && !_this->absolutePath) {
247                 errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
248                 goto loser;
249         }
250 #if 0
251         if(!_this->relativePath ) {
252                 errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath);
253                 goto loser;
254         }
255         if(!_this->absolutePath) {
256                 errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
257                 goto loser;
258         }
259 #endif
260
261 loser:
262         if(iter) {
263                 Pk11Install_ListIter_delete(iter);
264                 PR_Free(iter);
265         }
266         if(subiter) {
267                 Pk11Install_ListIter_delete(subiter);
268                 PR_Free(subiter);
269         }
270         return errStr;
271 }
272
273 /*
274 //////////////////////////////////////////////////////////////////////////
275 // Method:      Print
276 // Class:       Pk11Install_File
277 */
278 void
279 Pk11Install_File_Print(Pk11Install_File* _this, int pad)
280 {
281         PAD(pad); printf("jarPath: %s\n", 
282                     _this->jarPath ? _this->jarPath : "<NULL>");
283         PAD(pad); printf("relativePath: %s\n",
284                                 _this->relativePath ? _this->relativePath: "<NULL>");
285         PAD(pad); printf("absolutePath: %s\n",
286                                 _this->absolutePath ? _this->absolutePath: "<NULL>");
287         PAD(pad); printf("permissions: %o\n", _this->permissions);
288 }
289
290 Pk11Install_PlatformName*
291 Pk11Install_PlatformName_new()
292 {
293         Pk11Install_PlatformName* new_this;
294         new_this = (Pk11Install_PlatformName*)
295                PR_Malloc(sizeof(Pk11Install_PlatformName));
296         Pk11Install_PlatformName_init(new_this);
297         return new_this;
298 }
299
300 void
301 Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this)
302 {
303         _this->OS = NULL;
304         _this->verString = NULL;
305         _this->numDigits = 0;
306         _this->arch = NULL;
307 }
308
309 /*
310 //////////////////////////////////////////////////////////////////////////
311 // Method:      ~Pk11Install_PlatformName
312 // Class:       Pk11Install_PlatformName
313 */
314 void
315 Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this)
316 {
317         Pk11Install_PlatformName_Cleanup(_this);
318 }
319
320 /*
321 //////////////////////////////////////////////////////////////////////////
322 // Method:      Cleanup
323 // Class:       Pk11Install_PlatformName
324 */
325 void
326 Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this)
327 {
328         if(_this->OS) {
329                 PR_Free(_this->OS);
330                 _this->OS = NULL;
331         }
332         if(_this->verString) {
333                 int i;
334                 for (i=0; i<_this->numDigits; i++) {
335                         PR_Free(_this->verString[i]);
336                 }
337                 PR_Free(_this->verString);
338                 _this->verString = NULL;
339         }
340         if(_this->arch) {
341                 PR_Free(_this->arch);
342                 _this->arch = NULL;
343         }
344         _this->numDigits = 0;
345 }
346
347 /*
348 //////////////////////////////////////////////////////////////////////////
349 // Method:      Generate
350 // Class:       Pk11Install_PlatformName
351 // Notes:       Extracts the information from a platform string.
352 */
353 char*
354 Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
355                                   const char *str)
356 {
357         char *errStr;
358         char *copy;
359         char *end, *start; /* start and end of a section (OS, version, arch)*/
360         char *pend, *pstart; /* start and end of one portion of version*/
361         char *endp; /* used by strtol*/
362         int periods, i;
363
364         errStr=NULL;
365         copy=NULL;
366
367         if(!str) {
368                 errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]);
369                 goto loser;
370         }
371         copy = PR_Strdup(str);
372
373         /*
374         // Get the OS
375         */
376         end = strchr(copy, PLATFORM_SEPARATOR_CHAR);
377         if(!end || end==copy) {
378                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
379                 goto loser;
380         }
381         *end = '\0';
382
383         _this->OS = PR_Strdup(copy);
384
385         /*
386         // Get the digits of the version of form: x.x.x (arbitrary number of digits)
387         */
388
389         start = end+1;
390         end = strchr(start, PLATFORM_SEPARATOR_CHAR);
391         if(!end) {
392                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
393                 goto loser;
394         }
395         *end = '\0';
396
397         if(end!=start) { 
398                 /* Find out how many periods*/
399                 periods = 0;
400                 pstart = start;
401                 while( (pend=strchr(pstart, '.')) ) {
402                         periods++;
403                         pstart = pend+1;
404                 }
405                 _this->numDigits= 1+ periods;
406                 _this->verString = (char**)PR_Malloc(sizeof(char*)*_this->numDigits);
407
408                 pstart = start;
409                 i = 0;
410                 /* Get the digits before each period*/
411                 while( (pend=strchr(pstart, '.')) ) {
412                         if(pend == pstart) {
413                                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
414                                 goto loser;
415                         }
416                         *pend = '\0';
417                         _this->verString[i] = PR_Strdup(pstart);
418                         endp = pend;
419                 if(endp==pstart || (*endp != '\0')) {
420                                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
421                                 goto loser;
422                         }
423                         pstart = pend+1;
424                         i++;
425                 }
426                 /* Last digit comes after the last period*/
427                 if(*pstart == '\0') {
428                         errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
429                         goto loser;
430                 }
431                 _this->verString[i] = PR_Strdup(pstart);
432                 /*
433                 if(endp==pstart || (*endp != '\0')) {
434                         errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
435                         goto loser;
436                 }
437                 */
438         } else {
439                 _this->verString = NULL;
440                 _this->numDigits = 0;
441         }
442
443         /*
444         // Get the architecture
445         */
446         start = end+1;
447         if( strchr(start, PLATFORM_SEPARATOR_CHAR) ) {
448                 errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
449                 goto loser;
450         }
451         _this->arch = PR_Strdup(start);
452
453         if(copy) {
454                 PR_Free(copy);
455         }
456         return NULL;
457 loser:
458         if(_this->OS) {
459                 PR_Free(_this->OS);
460                 _this->OS = NULL;
461         }
462         if(_this->verString) {
463                 for (i=0; i<_this->numDigits; i++) {
464                         PR_Free(_this->verString[i]);
465                 }
466                 PR_Free(_this->verString);
467                 _this->verString = NULL;
468         }
469         _this->numDigits = 0;
470         if(_this->arch) {
471                 PR_Free(_this->arch);
472                 _this->arch = NULL;
473         }
474
475         return errStr;
476 }
477
478 /*
479 //////////////////////////////////////////////////////////////////////////
480 // Method:      operator ==
481 // Class:       Pk11Install_PlatformName
482 // Returns:     PR_TRUE if the platform have the same OS, arch, and version
483 */
484 PRBool
485 Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
486                                Pk11Install_PlatformName* cmp) 
487 {
488         int i;
489
490         if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
491                 return PR_FALSE;
492         }
493
494         if(     PORT_Strcasecmp(_this->OS, cmp->OS) ||
495                 PORT_Strcasecmp(_this->arch, cmp->arch) ||
496                 _this->numDigits != cmp->numDigits ) {
497                         return PR_FALSE;
498         }
499
500         for(i=0; i < _this->numDigits; i++) {
501                 if(PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) {
502                         return PR_FALSE;
503                 }
504         }
505         return PR_TRUE;
506 }
507
508 /*
509 //////////////////////////////////////////////////////////////////////////
510 // Method:      operator <=
511 // Class:       Pk11Install_PlatformName
512 // Returns:     PR_TRUE if the platform have the same OS and arch and a lower
513 //                      or equal release.
514 */
515 PRBool
516 Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
517                               Pk11Install_PlatformName* cmp)
518 {
519         return (Pk11Install_PlatformName_equal(_this,cmp) ||
520           Pk11Install_PlatformName_lt(_this,cmp)) ? PR_TRUE : PR_FALSE;
521 }
522
523 /*
524 //////////////////////////////////////////////////////////////////////////
525 // Method:      operator <
526 // Class:       Pk11Install_PlatformName
527 // Returns:     PR_TRUE if the platform have the same OS and arch and a greater
528 //                      release.
529 */
530 PRBool
531 Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
532                             Pk11Install_PlatformName* cmp)
533 {
534         int i, scmp;
535
536         if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
537                 return PR_FALSE;
538         }
539
540         if( PORT_Strcasecmp(_this->OS, cmp->OS) ) {
541                 return PR_FALSE;
542         }
543         if( PORT_Strcasecmp(_this->arch, cmp->arch) ) {
544                 return PR_FALSE;
545         }
546
547         for(i=0; (i < _this->numDigits) && (i < cmp->numDigits); i++) {
548                 scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]);
549                 if (scmp > 0) {
550                         return PR_FALSE;
551                 } else if (scmp < 0) {
552                         return PR_TRUE;
553                 }
554         }
555         /* All the digits they have in common are the same. */
556         if(_this->numDigits < cmp->numDigits) {
557                 return  PR_TRUE;
558         } 
559
560         return PR_FALSE;
561 }
562
563 /*
564 //////////////////////////////////////////////////////////////////////////
565 // Method:      GetString
566 // Class:       Pk11Install_PlatformName
567 // Returns:     String composed of OS, release, and architecture separated
568 //                      by the separator char.  Memory is allocated by this function
569 //                      but is the responsibility of the caller to de-allocate.
570 */
571 char*
572 Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this) 
573 {
574         char *ret;
575         char *ver;
576         char *OS_;
577         char *arch_;
578
579         OS_=NULL;
580         arch_=NULL;
581
582         OS_ = _this->OS ? _this->OS : "";
583         arch_ = _this->arch ? _this->arch : "";
584
585         ver = Pk11Install_PlatformName_GetVerString(_this);
586         ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver,
587                                         PLATFORM_SEPARATOR_CHAR, arch_);
588
589         PR_Free(ver);
590
591         return ret;
592 }
593
594 /*
595 //////////////////////////////////////////////////////////////////////////
596 // Method:      GetVerString
597 // Class:       Pk11Install_PlatformName
598 // Returns:     The version string for this platform, in the form x.x.x with an
599 //                      arbitrary number of digits.  Memory allocated by function,
600 //                      must be de-allocated by caller.
601 */
602 char*
603 Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this) 
604 {
605         char *tmp;
606         char *ret;
607         int i;
608         char buf[80];
609
610         tmp = (char*)PR_Malloc(80*_this->numDigits+1);
611         tmp[0] = '\0';
612
613         for(i=0; i < _this->numDigits-1; i++) {
614                 sprintf(buf, "%s.", _this->verString[i]);
615                 strcat(tmp, buf);
616         }
617         if(i < _this->numDigits) {
618                 sprintf(buf, "%s", _this->verString[i]);
619                 strcat(tmp, buf);
620         }
621
622         ret = PR_Strdup(tmp);
623         free(tmp);
624
625         return ret;
626 }
627
628 /*
629 //////////////////////////////////////////////////////////////////////////
630 // Method:      Print
631 // Class:       Pk11Install_PlatformName
632 */
633 void
634 Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad)
635 {
636         PAD(pad); printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>");
637         PAD(pad); printf("Digits: ");
638         if(_this->numDigits == 0) {
639                 printf("None\n");
640         } else {
641                 printf("%s\n", Pk11Install_PlatformName_GetVerString(_this));
642         }
643         PAD(pad); printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>");
644 }
645
646 Pk11Install_Platform*
647 Pk11Install_Platform_new()
648 {
649         Pk11Install_Platform* new_this;
650         new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform));
651         Pk11Install_Platform_init(new_this);
652         return new_this;
653 }
654
655 void
656 Pk11Install_Platform_init(Pk11Install_Platform* _this)
657 {
658         Pk11Install_PlatformName_init(&_this->name);
659         Pk11Install_PlatformName_init(&_this->equivName);
660         _this->equiv = NULL;
661         _this->usesEquiv = PR_FALSE;
662         _this->moduleFile = NULL;
663         _this->moduleName = NULL;
664         _this->modFile = -1;
665         _this->mechFlags = 0;
666         _this->cipherFlags = 0;
667         _this->files = NULL;
668         _this->numFiles = 0;
669 }
670
671 /*
672 //////////////////////////////////////////////////////////////////////////
673 // Method:      ~Pk11Install_Platform
674 // Class:       Pk11Install_Platform
675 */
676 void
677 Pk11Install_Platform_delete(Pk11Install_Platform* _this)
678 {
679         Pk11Install_Platform_Cleanup(_this);
680 }
681
682 /*
683 //////////////////////////////////////////////////////////////////////////
684 // Method:      Cleanup
685 // Class:       Pk11Install_Platform
686 */
687 void
688 Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this)
689 {
690         int i;
691         if(_this->moduleFile) {
692                 PR_Free(_this->moduleFile);
693                 _this->moduleFile = NULL;
694         }
695         if(_this->moduleName) {
696                 PR_Free(_this->moduleName);
697                 _this->moduleName = NULL;
698         }
699         if(_this->files) {
700                 for (i=0;i<_this->numFiles;i++) {
701                         Pk11Install_File_delete(&_this->files[i]);
702                 }
703                 PR_Free(_this->files);
704                 _this->files = NULL;
705         }
706         _this->equiv = NULL;
707         _this->usesEquiv = PR_FALSE;
708         _this->modFile = -1;
709         _this->numFiles = 0;
710         _this->mechFlags = _this->cipherFlags = 0;
711 }
712
713 /*
714 //////////////////////////////////////////////////////////////////////////
715 // Method:      Generate
716 // Class:       Pk11Install_Platform
717 // Notes:       Creates a platform data structure from a syntax tree.
718 // Returns:     NULL for success, otherwise an error message.
719 */
720 char*
721 Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
722                               const Pk11Install_Pair *pair)
723 {
724         char* errStr;
725         char* endptr;
726         char* tmp;
727         int i;
728         Pk11Install_ListIter *iter;
729         Pk11Install_Value *val;
730         Pk11Install_Value *subval;
731         Pk11Install_Pair *subpair;
732         Pk11Install_ListIter *subiter;
733         PRBool gotModuleFile, gotModuleName, gotMech, 
734           gotCipher, gotFiles, gotEquiv;
735
736         errStr=NULL;
737         iter=subiter=NULL;
738         val=subval=NULL;
739         subpair=NULL;
740         gotModuleFile=gotModuleName=gotMech=gotCipher=gotFiles=gotEquiv=PR_FALSE;
741         Pk11Install_Platform_Cleanup(_this);
742
743         errStr = Pk11Install_PlatformName_Generate(&_this->name,pair->key);
744         if(errStr) {
745                 tmp = PR_smprintf("%s: %s", pair->key, errStr);
746                 PR_smprintf_free(errStr);
747                 errStr = tmp;
748                 goto loser;
749         }
750
751         iter = Pk11Install_ListIter_new(pair->list);
752         for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
753                 if(val->type==PAIR_VALUE) {
754                         subpair = val->pair;
755
756                         if( !PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) {
757                                 if(gotModuleFile) {
758                                         errStr = PR_smprintf(errString[REPEAT_MODULE_FILE],
759                                     Pk11Install_PlatformName_GetString(&_this->name));
760                                         goto loser;
761                                 }
762                                 subiter = Pk11Install_ListIter_new(subpair->list);
763                                 subval = subiter->current;
764                                 if(!subval || (subval->type != STRING_VALUE)) {
765                                         errStr = PR_smprintf(errString[BOGUS_MODULE_FILE],
766                                     Pk11Install_PlatformName_GetString(&_this->name));
767                                         goto loser;
768                                 }
769                                 _this->moduleFile = PR_Strdup(subval->string);
770                                 Pk11Install_ListIter_delete(subiter);
771                                 PR_Free(subiter);
772                                 subiter = NULL;
773                                 gotModuleFile = PR_TRUE;
774                         } else if(!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)){
775                                 if(gotModuleName) {
776                                         errStr = PR_smprintf(errString[REPEAT_MODULE_NAME],
777                                     Pk11Install_PlatformName_GetString(&_this->name));
778                                         goto loser;
779                                 }
780                                 subiter = Pk11Install_ListIter_new(subpair->list);
781                                 subval = subiter->current;
782                                 if(!subval || (subval->type != STRING_VALUE)) {
783                                         errStr = PR_smprintf(errString[BOGUS_MODULE_NAME],
784                                     Pk11Install_PlatformName_GetString(&_this->name));
785                                         goto loser;
786                                 }
787                                 _this->moduleName = PR_Strdup(subval->string);
788                                 Pk11Install_ListIter_delete(subiter);
789                                 PR_Free(subiter);
790                                 subiter = NULL;
791                                 gotModuleName = PR_TRUE;
792                         } else if(!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) {
793                                 endptr=NULL;
794
795                                 if(gotMech) {
796                                         errStr = PR_smprintf(errString[REPEAT_MECH],
797                                     Pk11Install_PlatformName_GetString(&_this->name));
798                                         goto loser;
799                                 }
800                                 subiter = Pk11Install_ListIter_new(subpair->list);
801                                 subval = subiter->current;
802                                 if(!subval || (subval->type != STRING_VALUE)) {
803                                         errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
804                                     Pk11Install_PlatformName_GetString(&_this->name));
805                                         goto loser;
806                                 }
807                                 _this->mechFlags = strtol(subval->string, &endptr, 0);
808                                 if(*endptr!='\0' || (endptr==subval->string) ) {
809                                         errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
810                                     Pk11Install_PlatformName_GetString(&_this->name));
811                                         goto loser;
812                                 }
813                                 Pk11Install_ListIter_delete(subiter);
814                                 PR_Free(subiter);
815                                 subiter=NULL;
816                                 gotMech = PR_TRUE;
817                         } else if(!PORT_Strcasecmp(subpair->key,CIPHER_FLAGS_STRING)) {
818                                 endptr=NULL;
819
820                                 if(gotCipher) {
821                                         errStr = PR_smprintf(errString[REPEAT_CIPHER],
822                                     Pk11Install_PlatformName_GetString(&_this->name));
823                                         goto loser;
824                                 }
825                                 subiter = Pk11Install_ListIter_new(subpair->list);
826                                 subval = subiter->current;
827                                 if(!subval || (subval->type != STRING_VALUE)) {
828                                         errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
829                                     Pk11Install_PlatformName_GetString(&_this->name));
830                                         goto loser;
831                                 }
832                                 _this->cipherFlags = strtol(subval->string, &endptr, 0);
833                                 if(*endptr!='\0' || (endptr==subval->string) ) {
834                                         errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
835                                     Pk11Install_PlatformName_GetString(&_this->name));
836                                         goto loser;
837                                 }
838                                 Pk11Install_ListIter_delete(subiter);
839                                 PR_Free(subiter);
840                                 subiter=NULL;
841                                 gotCipher = PR_TRUE;
842                         } else if(!PORT_Strcasecmp(subpair->key, FILES_STRING)) {
843                                 if(gotFiles) {
844                                         errStr = PR_smprintf(errString[REPEAT_FILES],
845                                     Pk11Install_PlatformName_GetString(&_this->name));
846                                         goto loser;
847                                 }
848                                 subiter = Pk11Install_ListIter_new(subpair->list);
849                                 _this->numFiles = subpair->list->numPairs;
850                                 _this->files = (Pk11Install_File*)
851                             PR_Malloc(sizeof(Pk11Install_File)*_this->numFiles);
852                                 for(i=0; i < _this->numFiles; i++, 
853                                    Pk11Install_ListIter_nextItem(subiter)) {
854                                         Pk11Install_File_init(&_this->files[i]);
855                                         val = subiter->current;
856                                         if(val && (val->type==PAIR_VALUE)) {
857                                                 errStr = Pk11Install_File_Generate(&_this->files[i],val->pair);
858                                                 if(errStr) {
859                                                         tmp = PR_smprintf("%s: %s", 
860                                        Pk11Install_PlatformName_GetString(&_this->name),errStr);
861                                                         PR_smprintf_free(errStr);
862                                                         errStr = tmp;
863                                                         goto loser;
864                                                 }
865                                         }
866                                 }
867                                 gotFiles = PR_TRUE;
868                         } else if(!PORT_Strcasecmp(subpair->key,
869                                     EQUIVALENT_PLATFORM_STRING)) {
870                                 if(gotEquiv) {
871                                         errStr = PR_smprintf(errString[REPEAT_EQUIV],
872                                     Pk11Install_PlatformName_GetString(&_this->name));
873                                         goto loser;
874                                 }
875                                 subiter = Pk11Install_ListIter_new(subpair->list);
876                                 subval = subiter->current;
877                                 if(!subval || (subval->type != STRING_VALUE) ) {
878                                         errStr = PR_smprintf(errString[BOGUS_EQUIV],
879                                Pk11Install_PlatformName_GetString(&_this->name));
880                                         goto loser;
881                                 }
882                                 errStr = Pk11Install_PlatformName_Generate(&_this->equivName,
883                                                        subval->string);
884                                 if(errStr) {
885                                         tmp = PR_smprintf("%s: %s", 
886                             Pk11Install_PlatformName_GetString(&_this->name), errStr);
887                                         tmp = PR_smprintf("%s: %s", 
888                             Pk11Install_PlatformName_GetString(&_this->name), errStr);
889                                         PR_smprintf_free(errStr);
890                                         errStr = tmp;
891                                         goto loser;
892                                 }
893                                 _this->usesEquiv = PR_TRUE;
894                         }
895                 }
896         }
897
898         /* Make sure we either have an EquivalentPlatform or all the other info */
899         if(_this->usesEquiv &&
900                 (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) {
901                 errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO], 
902                            Pk11Install_PlatformName_GetString(&_this->name));
903                 goto loser;
904         }
905         if(!gotFiles && !_this->usesEquiv) {
906                 errStr = PR_smprintf(errString[NO_FILES], 
907                            Pk11Install_PlatformName_GetString(&_this->name));
908                 goto loser;
909         }
910         if(!gotModuleFile && !_this->usesEquiv) {
911                 errStr= PR_smprintf(errString[NO_MODULE_FILE], 
912                           Pk11Install_PlatformName_GetString(&_this->name));
913                 goto loser;
914         }
915         if(!gotModuleName && !_this->usesEquiv) {
916                 errStr = PR_smprintf(errString[NO_MODULE_NAME], 
917                           Pk11Install_PlatformName_GetString(&_this->name));
918                 goto loser;
919         }
920
921         /* Point the modFile pointer to the correct file */
922         if(gotModuleFile) {
923                 for(i=0; i < _this->numFiles; i++) {
924                         if(!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath) ) {
925                                 _this->modFile = i;
926                                 break;
927                         }
928                 }
929                 if(_this->modFile==-1) {
930                         errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE], 
931                               _this->moduleFile,
932                               Pk11Install_PlatformName_GetString(&_this->name));
933                         goto loser;
934                 }
935         }
936         
937 loser:
938         if(iter) {
939                 PR_Free(iter);
940         }
941         if(subiter) {
942                 PR_Free(subiter);
943         }
944         return errStr;
945 }
946
947 /*
948 //////////////////////////////////////////////////////////////////////////
949 // Method:              Print
950 // Class:               Pk11Install_Platform
951 */
952 void
953 Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad)
954 {
955         int i;
956
957         PAD(pad); printf("Name:\n"); 
958         Pk11Install_PlatformName_Print(&_this->name,pad+PADINC);
959         PAD(pad); printf("equivName:\n"); 
960         Pk11Install_PlatformName_Print(&_this->equivName,pad+PADINC);
961         PAD(pad);
962         if(_this->usesEquiv) {
963                 printf("Uses equiv, which points to:\n");
964                 Pk11Install_Platform_Print(_this->equiv,pad+PADINC);
965         } else {
966                 printf("Doesn't use equiv\n");
967         }
968         PAD(pad); 
969         printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile 
970                                                  : "<NULL>");
971         PAD(pad); printf("mechFlags: %lx\n", _this->mechFlags);
972         PAD(pad); printf("cipherFlags: %lx\n", _this->cipherFlags);
973         PAD(pad); printf("Files:\n");
974         for(i=0; i < _this->numFiles; i++) {
975                 Pk11Install_File_Print(&_this->files[i],pad+PADINC);
976                 PAD(pad); printf("--------------------\n");
977         }
978 }
979
980 /*
981 //////////////////////////////////////////////////////////////////////////
982 // Method:              Pk11Install_Info
983 // Class:               Pk11Install_Info
984 */
985 Pk11Install_Info*
986 Pk11Install_Info_new()
987 {
988         Pk11Install_Info* new_this;
989         new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info));
990         Pk11Install_Info_init(new_this);
991         return new_this;
992 }
993
994 void
995 Pk11Install_Info_init(Pk11Install_Info* _this)
996 {
997         _this->platforms = NULL;
998         _this->numPlatforms = 0;
999         _this->forwardCompatible = NULL;
1000         _this->numForwardCompatible = 0;
1001 }
1002
1003 /*
1004 //////////////////////////////////////////////////////////////////////////
1005 // Method:              ~Pk11Install_Info
1006 // Class:               Pk11Install_Info
1007 */
1008 void
1009 Pk11Install_Info_delete(Pk11Install_Info* _this)
1010 {
1011         Pk11Install_Info_Cleanup(_this);
1012 }
1013
1014 /*
1015 //////////////////////////////////////////////////////////////////////////
1016 // Method:              Cleanup
1017 // Class:               Pk11Install_Info
1018 */
1019 void
1020 Pk11Install_Info_Cleanup(Pk11Install_Info* _this)
1021 {
1022         int i;
1023         if(_this->platforms) {
1024                 for (i=0;i<_this->numPlatforms;i++) {
1025                         Pk11Install_Platform_delete(&_this->platforms[i]);
1026                 }
1027                 PR_Free(&_this->platforms);
1028                 _this->platforms = NULL;
1029                 _this->numPlatforms = 0;
1030         }
1031
1032         if(_this->forwardCompatible) {
1033                 for (i=0;i<_this->numForwardCompatible;i++) {
1034                         Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]);
1035                 }
1036                 PR_Free(&_this->forwardCompatible);
1037                 _this->numForwardCompatible = 0;
1038         }
1039 }
1040
1041 /*
1042 //////////////////////////////////////////////////////////////////////////
1043 // Method:              Generate
1044 // Class:               Pk11Install_Info
1045 // Takes:               Pk11Install_ValueList *list, the top-level list
1046 //                              resulting from parsing an installer file.
1047 // Returns:             char*, NULL if successful, otherwise an error string.
1048 //                              Caller is responsible for freeing memory.
1049 */
1050 char*
1051 Pk11Install_Info_Generate(Pk11Install_Info* _this,
1052                           const Pk11Install_ValueList *list)
1053 {
1054         char *errStr;
1055         Pk11Install_ListIter *iter;
1056         Pk11Install_Value *val;
1057         Pk11Install_Pair *pair;
1058         Pk11Install_ListIter *subiter;
1059         Pk11Install_Value *subval;
1060         Pk11Install_Platform *first, *second;
1061         int i, j;
1062
1063         errStr=NULL;
1064         iter=subiter=NULL;
1065         Pk11Install_Info_Cleanup(_this);
1066
1067         iter = Pk11Install_ListIter_new(list);
1068         for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
1069                 if(val->type == PAIR_VALUE) {
1070                         pair = val->pair;
1071
1072                         if(!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) {
1073                                 subiter = Pk11Install_ListIter_new(pair->list);
1074                                 _this->numForwardCompatible = pair->list->numStrings;
1075                                 _this->forwardCompatible = (Pk11Install_PlatformName*)
1076                                         PR_Malloc(sizeof(Pk11Install_PlatformName)*
1077                                                _this->numForwardCompatible);
1078                                 for(i=0; i < _this->numForwardCompatible; i++, 
1079                        Pk11Install_ListIter_nextItem(subiter)) {
1080                                         subval = subiter->current;
1081                                         if(subval->type == STRING_VALUE) {
1082                                                 errStr = Pk11Install_PlatformName_Generate(
1083                               &_this->forwardCompatible[i], subval->string);
1084                                                 if(errStr) {
1085                                                         goto loser;
1086                                                 }
1087                                         }
1088                                 }
1089                                 Pk11Install_ListIter_delete(subiter);
1090                                 PR_Free(subiter);
1091                                 subiter = NULL;
1092                         } else if(!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) {
1093                                 subiter = Pk11Install_ListIter_new(pair->list);
1094                                 _this->numPlatforms = pair->list->numPairs;
1095                                 _this->platforms = (Pk11Install_Platform*)
1096                             PR_Malloc(sizeof(Pk11Install_Platform)*
1097                             _this->numPlatforms);
1098                                 for(i=0; i < _this->numPlatforms; i++, 
1099                        Pk11Install_ListIter_nextItem(subiter)) {
1100                                          Pk11Install_Platform_init(&_this->platforms[i]);
1101                                         subval = subiter->current;
1102                                         if(subval->type == PAIR_VALUE) {
1103                                                 errStr = Pk11Install_Platform_Generate(&_this->platforms[i],subval->pair);
1104                                                 if(errStr) {
1105                                                         goto loser;
1106                                                 }
1107                                         }
1108                                 }
1109                                 Pk11Install_ListIter_delete(subiter);
1110                                 PR_Free(subiter);
1111                                 subiter = NULL;
1112                         }
1113                 }
1114         }
1115
1116         if(_this->numPlatforms == 0) {
1117                 errStr = PR_smprintf(errString[NO_PLATFORMS]);
1118                 goto loser;
1119         }
1120
1121 /*
1122         //
1123         // Now process equivalent platforms
1124         //
1125
1126         // First the naive pass
1127 */
1128         for(i=0; i < _this->numPlatforms; i++) {
1129                 if(_this->platforms[i].usesEquiv) {
1130                         _this->platforms[i].equiv = NULL;
1131                         for(j=0; j < _this->numPlatforms; j++) {
1132                                 if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName,
1133                                            &_this->platforms[j].name)) {
1134                                         if(i==j) {
1135                                                 errStr = PR_smprintf(errString[EQUIV_LOOP],
1136                               Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1137                                                 goto loser;
1138                                         }
1139                                         _this->platforms[i].equiv = &_this->platforms[j];
1140                                         break;
1141                                 }
1142                         }
1143                         if(_this->platforms[i].equiv == NULL) {
1144                                 errStr = PR_smprintf(errString[BOGUS_EQUIV],
1145                        Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1146                                 goto loser;
1147                         }
1148                 }
1149         }
1150
1151 /*
1152         // Now the intelligent pass, which will also detect loops.
1153         // We will send two pointers through the linked list of equivalent
1154         // platforms. Both start with the current node.  "first" traverses
1155         // two nodes for each iteration.  "second" lags behind, only traversing
1156         // one node per iteration.  Eventually one of two things will happen:
1157         // first will hit the end of the list (a platform that doesn't use
1158         // an equivalency), or first will equal second if there is a loop.
1159 */
1160         for(i=0; i < _this->numPlatforms; i++) {
1161                 if(_this->platforms[i].usesEquiv) {
1162                         second = _this->platforms[i].equiv;
1163                         if(!second->usesEquiv) {
1164                                 /* The first link is the terminal node */
1165                                 continue;
1166                         }
1167                         first = second->equiv;
1168                         while(first->usesEquiv) {
1169                                 if(first == second) {
1170                                         errStr = PR_smprintf(errString[EQUIV_LOOP],
1171                          Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1172                                         goto loser;
1173                                 }
1174                                 first = first->equiv;
1175                                 if(!first->usesEquiv) {
1176                                         break;
1177                                 }
1178                                 if(first == second) {
1179                                         errStr = PR_smprintf(errString[EQUIV_LOOP],
1180                        Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
1181                                         goto loser;
1182                                 }
1183                                 second = second->equiv;
1184                                 first = first->equiv;
1185                         }
1186                         _this->platforms[i].equiv = first;
1187                 }
1188         }
1189
1190 loser:
1191         if(iter) {
1192                 Pk11Install_ListIter_delete(iter);
1193                 PR_Free(iter);
1194                 iter = NULL;
1195         }
1196         if(subiter) {
1197                 Pk11Install_ListIter_delete(subiter);
1198                 PR_Free(subiter);
1199                 subiter = NULL;
1200         }
1201         return errStr;
1202 }
1203
1204 /*
1205 //////////////////////////////////////////////////////////////////////////
1206 // Method:              GetBestPlatform
1207 // Class:               Pk11Install_Info
1208 // Takes:               char *myPlatform, the platform we are currently running
1209 //                              on.
1210 */
1211 Pk11Install_Platform*
1212 Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char *myPlatform)
1213 {
1214         Pk11Install_PlatformName plat;
1215         char *errStr;
1216         int i, j;
1217
1218         errStr=NULL;
1219
1220         Pk11Install_PlatformName_init(&plat);
1221         if( (errStr=Pk11Install_PlatformName_Generate(&plat, myPlatform)) ) {
1222                 PR_smprintf_free(errStr);
1223                 return NULL;
1224         }
1225
1226         /* First try real platforms */
1227         for(i=0; i < _this->numPlatforms; i++) {
1228                 if(Pk11Install_PlatformName_equal(&_this->platforms[i].name,&plat)) {
1229                         if(_this->platforms[i].equiv) {
1230                                 return _this->platforms[i].equiv;
1231                         }
1232                         else {
1233                                 return &_this->platforms[i];
1234                         }
1235                 }
1236         }
1237
1238         /* Now try forward compatible platforms */
1239         for(i=0; i < _this->numForwardCompatible; i++) {
1240                 if(Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i],&plat)) {
1241                         break;
1242                 }
1243         }
1244         if(i == _this->numForwardCompatible) {
1245                 return NULL;
1246         }
1247
1248         /* Got a forward compatible name, find the actual platform. */
1249         for(j=0; j < _this->numPlatforms; j++) {
1250                 if(Pk11Install_PlatformName_equal(&_this->platforms[j].name,
1251          &_this->forwardCompatible[i])) {
1252                         if(_this->platforms[j].equiv) {
1253                                 return _this->platforms[j].equiv;
1254                         } else {
1255                                 return &_this->platforms[j];
1256                         }
1257                 }
1258         }
1259
1260         return NULL;
1261 }
1262
1263 /*
1264 //////////////////////////////////////////////////////////////////////////
1265 // Method:              Print
1266 // Class:               Pk11Install_Info
1267 */
1268 void
1269 Pk11Install_Info_Print(Pk11Install_Info* _this, int pad)
1270 {
1271         int i;
1272
1273         PAD(pad); printf("Forward Compatible:\n");
1274         for(i = 0; i < _this->numForwardCompatible; i++) {
1275                 Pk11Install_PlatformName_Print(&_this->forwardCompatible[i],pad+PADINC);
1276                 PAD(pad); printf("-------------------\n");
1277         }
1278         PAD(pad); printf("Platforms:\n");
1279         for( i = 0; i < _this->numPlatforms; i++) {
1280                 Pk11Install_Platform_Print(&_this->platforms[i],pad+PADINC);
1281                 PAD(pad); printf("-------------------\n");
1282         }
1283 }
1284
1285 /*
1286 //////////////////////////////////////////////////////////////////////////
1287 */
1288 static char*
1289 PR_Strdup(const char* str)
1290 {
1291         char *tmp;
1292         tmp = (char*) PR_Malloc((unsigned int)(strlen(str)+1));
1293         strcpy(tmp, str);
1294         return tmp;
1295 }
1296
1297 /* The global value list, the top of the tree */
1298 Pk11Install_ValueList* Pk11Install_valueList=NULL;
1299
1300 /****************************************************************************/
1301 void
1302 Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
1303                               Pk11Install_Value *item)
1304 {
1305         _this->numItems++;
1306         if (item->type == STRING_VALUE) {
1307                 _this->numStrings++;
1308         } else {
1309                 _this->numPairs++;
1310         }
1311         item->next = _this->head;
1312         _this->head = item;
1313 }
1314
1315 /****************************************************************************/
1316 Pk11Install_ListIter*
1317 Pk11Install_ListIter_new_default()
1318 {
1319         Pk11Install_ListIter* new_this;
1320         new_this = (Pk11Install_ListIter*)
1321                     PR_Malloc(sizeof(Pk11Install_ListIter));
1322         Pk11Install_ListIter_init(new_this);
1323         return new_this;
1324 }
1325
1326 /****************************************************************************/
1327 void
1328 Pk11Install_ListIter_init(Pk11Install_ListIter* _this)
1329 {
1330         _this->list = NULL;
1331         _this->current = NULL;
1332 }
1333
1334 /****************************************************************************/
1335 Pk11Install_ListIter*
1336 Pk11Install_ListIter_new(const Pk11Install_ValueList *_list)
1337 {
1338         Pk11Install_ListIter* new_this;
1339         new_this = (Pk11Install_ListIter*)
1340                     PR_Malloc(sizeof(Pk11Install_ListIter));
1341         new_this->list = _list;
1342         new_this->current = _list->head;
1343         return new_this;
1344 }
1345
1346 /****************************************************************************/
1347 void
1348 Pk11Install_ListIter_delete(Pk11Install_ListIter* _this)
1349 {
1350         _this->list=NULL;
1351         _this->current=NULL;
1352 }
1353
1354 /****************************************************************************/
1355 void
1356 Pk11Install_ListIter_reset(Pk11Install_ListIter* _this)
1357 {
1358         if(_this->list) {
1359                 _this->current = _this->list->head;
1360         }
1361 }
1362
1363 /*************************************************************************/
1364 Pk11Install_Value*
1365 Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this)
1366 {
1367         if(_this->current) {
1368                 _this->current = _this->current->next;
1369         }
1370
1371         return _this->current;
1372 }
1373
1374 /****************************************************************************/
1375 Pk11Install_ValueList*
1376 Pk11Install_ValueList_new()
1377 {
1378         Pk11Install_ValueList* new_this;
1379         new_this = (Pk11Install_ValueList*)
1380                     PR_Malloc(sizeof(Pk11Install_ValueList));
1381         new_this->numItems = 0;
1382         new_this->numPairs = 0;
1383         new_this->numStrings = 0;
1384         new_this->head = NULL;
1385         return new_this;
1386 }
1387
1388 /****************************************************************************/
1389 void
1390 Pk11Install_ValueList_delete(Pk11Install_ValueList* _this)
1391 {
1392
1393         Pk11Install_Value *tmp;
1394         Pk11Install_Value *list;
1395         list = _this->head;
1396         
1397         while(list != NULL) {
1398                 tmp = list;
1399                 list = list->next;
1400                 PR_Free(tmp);
1401         }
1402         PR_Free(_this);
1403 }
1404
1405 /****************************************************************************/
1406 Pk11Install_Value*
1407 Pk11Install_Value_new_default()
1408 {
1409         Pk11Install_Value* new_this;
1410         new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value));
1411         new_this->type = STRING_VALUE;
1412         new_this->string = NULL;
1413         new_this->pair = NULL;
1414         new_this->next = NULL;
1415         return new_this;
1416 }
1417
1418 /****************************************************************************/
1419 Pk11Install_Value*
1420 Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr)
1421 {
1422         Pk11Install_Value* new_this;
1423         new_this = Pk11Install_Value_new_default();
1424         new_this->type = _type;
1425         if(_type == STRING_VALUE) {
1426                 new_this->pair = NULL;
1427                 new_this->string = ptr.string;
1428         } else {
1429                 new_this->string = NULL;
1430                 new_this->pair = ptr.pair;
1431         }
1432         return new_this;
1433 }
1434
1435 /****************************************************************************/
1436 void
1437 Pk11Install_Value_delete(Pk11Install_Value* _this)
1438 {
1439         if(_this->type == STRING_VALUE) {
1440                 PR_Free(_this->string);
1441         } else {
1442                 PR_Free(_this->pair);
1443         }
1444 }
1445
1446 /****************************************************************************/
1447 Pk11Install_Pair*
1448 Pk11Install_Pair_new_default()
1449 {
1450         return Pk11Install_Pair_new(NULL,NULL);
1451 }
1452
1453 /****************************************************************************/
1454 Pk11Install_Pair*
1455 Pk11Install_Pair_new(char *_key, Pk11Install_ValueList *_list)
1456 {
1457         Pk11Install_Pair* new_this;
1458         new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair));
1459         new_this->key = _key;
1460         new_this->list = _list;
1461         return new_this;
1462 }
1463
1464 /****************************************************************************/
1465 void
1466 Pk11Install_Pair_delete(Pk11Install_Pair* _this)
1467 {
1468         PR_Free(_this->key);
1469         Pk11Install_ValueList_delete(_this->list);
1470         PR_Free(_this->list);
1471 }
1472
1473 /*************************************************************************/
1474 void
1475 Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad)
1476 {
1477         while (_this) {
1478                 /*PAD(pad); printf("**Pair\n");
1479                 PAD(pad); printf("***Key====\n");*/
1480                 PAD(pad); printf("%s {\n", _this->key);
1481                 /*PAD(pad); printf("====\n");*/
1482                 /*PAD(pad); printf("***ValueList\n");*/
1483                 Pk11Install_ValueList_Print(_this->list,pad+PADINC);
1484                 PAD(pad); printf("}\n");
1485         }
1486 }
1487
1488 /*************************************************************************/
1489 void
1490 Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad)
1491 {
1492         Pk11Install_Value *v;
1493
1494         /*PAD(pad);printf("**Value List**\n");*/
1495         for(v = _this->head; v != NULL; v=v->next) {
1496                 Pk11Install_Value_Print(v,pad);
1497         }
1498 }
1499
1500 /*************************************************************************/
1501 void
1502 Pk11Install_Value_Print(Pk11Install_Value* _this, int pad)
1503 {
1504         /*PAD(pad); printf("**Value, type=%s\n",
1505                 type==STRING_VALUE ? "string" : "pair");*/
1506         if(_this->type==STRING_VALUE) {
1507                 /*PAD(pad+PADINC); printf("====\n");*/
1508                 PAD(pad); printf("%s\n", _this->string);
1509                 /*PAD(pad+PADINC); printf("====\n");*/
1510         } else {
1511                 Pk11Install_Pair_Print(_this->pair,pad+PADINC);
1512         }
1513 }