tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

install-ds.c (47681B)


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