summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/modutil/install-ds.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/modutil/install-ds.c')
-rw-r--r--security/nss/cmd/modutil/install-ds.c1525
1 files changed, 1525 insertions, 0 deletions
diff --git a/security/nss/cmd/modutil/install-ds.c b/security/nss/cmd/modutil/install-ds.c
new file mode 100644
index 000000000..c8fef7897
--- /dev/null
+++ b/security/nss/cmd/modutil/install-ds.c
@@ -0,0 +1,1525 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "install-ds.h"
+#include <prmem.h>
+#include <plstr.h>
+#include <prprf.h>
+#include <string.h>
+
+#define PORT_Strcasecmp PL_strcasecmp
+
+#define MODULE_FILE_STRING "ModuleFile"
+#define MODULE_NAME_STRING "ModuleName"
+#define MECH_FLAGS_STRING "DefaultMechanismFlags"
+#define CIPHER_FLAGS_STRING "DefaultCipherFlags"
+#define FILES_STRING "Files"
+#define FORWARD_COMPATIBLE_STRING "ForwardCompatible"
+#define PLATFORMS_STRING "Platforms"
+#define RELATIVE_DIR_STRING "RelativePath"
+#define ABSOLUTE_DIR_STRING "AbsolutePath"
+#define FILE_PERMISSIONS_STRING "FilePermissions"
+#define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform"
+#define EXECUTABLE_STRING "Executable"
+
+#define DEFAULT_PERMISSIONS 0777
+
+#define PLATFORM_SEPARATOR_CHAR ':'
+
+/* Error codes */
+enum {
+ BOGUS_RELATIVE_DIR = 0,
+ BOGUS_ABSOLUTE_DIR,
+ BOGUS_FILE_PERMISSIONS,
+ NO_RELATIVE_DIR,
+ NO_ABSOLUTE_DIR,
+ EMPTY_PLATFORM_STRING,
+ BOGUS_PLATFORM_STRING,
+ REPEAT_MODULE_FILE,
+ REPEAT_MODULE_NAME,
+ BOGUS_MODULE_FILE,
+ BOGUS_MODULE_NAME,
+ REPEAT_MECH,
+ BOGUS_MECH_FLAGS,
+ REPEAT_CIPHER,
+ BOGUS_CIPHER_FLAGS,
+ REPEAT_FILES,
+ REPEAT_EQUIV,
+ BOGUS_EQUIV,
+ EQUIV_TOO_MUCH_INFO,
+ NO_FILES,
+ NO_MODULE_FILE,
+ NO_MODULE_NAME,
+ NO_PLATFORMS,
+ EQUIV_LOOP,
+ UNKNOWN_MODULE_FILE
+};
+
+/* Indexed by the above error codes */
+static const char* errString[] = {
+ "%s: Invalid relative directory",
+ "%s: Invalid absolute directory",
+ "%s: Invalid file permissions",
+ "%s: No relative directory specified",
+ "%s: No absolute directory specified",
+ "Empty string given for platform name",
+ "%s: invalid platform string",
+ "More than one ModuleFile entry given for platform %s",
+ "More than one ModuleName entry given for platform %s",
+ "Invalid ModuleFile specification for platform %s",
+ "Invalid ModuleName specification for platform %s",
+ "More than one DefaultMechanismFlags entry given for platform %s",
+ "Invalid DefaultMechanismFlags specification for platform %s",
+ "More than one DefaultCipherFlags entry given for platform %s",
+ "Invalid DefaultCipherFlags entry given for platform %s",
+ "More than one Files entry given for platform %s",
+ "More than one EquivalentPlatform entry given for platform %s",
+ "Invalid EquivalentPlatform specification for platform %s",
+ "Module %s uses an EquivalentPlatform but also specifies its own"
+ " information",
+ "No Files specification in module %s",
+ "No ModuleFile specification in module %s",
+ "No ModuleName specification in module %s",
+ "No Platforms specification in installer script",
+ "Platform %s has an equivalency loop",
+ "Module file \"%s\" in platform \"%s\" does not exist"
+};
+
+static char* PR_Strdup(const char* str);
+
+#define PAD(x) \
+ { \
+ int i; \
+ for (i = 0; i < x; i++) \
+ printf(" "); \
+ }
+#define PADINC 4
+
+Pk11Install_File*
+Pk11Install_File_new()
+{
+ Pk11Install_File* new_this;
+ new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File));
+ Pk11Install_File_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_File_init(Pk11Install_File* _this)
+{
+ _this->jarPath = NULL;
+ _this->relativePath = NULL;
+ _this->absolutePath = NULL;
+ _this->executable = PR_FALSE;
+ _this->permissions = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_File
+// Class: Pk11Install_File
+// Notes: Destructor.
+*/
+void
+Pk11Install_File_delete(Pk11Install_File* _this)
+{
+ Pk11Install_File_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_File
+*/
+void
+Pk11Install_File_Cleanup(Pk11Install_File* _this)
+{
+ if (_this->jarPath) {
+ PR_Free(_this->jarPath);
+ _this->jarPath = NULL;
+ }
+ if (_this->relativePath) {
+ PR_Free(_this->relativePath);
+ _this->relativePath = NULL;
+ }
+ if (_this->absolutePath) {
+ PR_Free(_this->absolutePath);
+ _this->absolutePath = NULL;
+ }
+
+ _this->permissions = 0;
+ _this->executable = PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_File
+// Notes: Creates a file data structure from a syntax tree.
+// Returns: NULL for success, otherwise an error message.
+*/
+char*
+Pk11Install_File_Generate(Pk11Install_File* _this,
+ const Pk11Install_Pair* pair)
+{
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Pair* subpair;
+ Pk11Install_ListIter* subiter;
+ Pk11Install_Value* subval;
+ char* errStr;
+ char* endp;
+ PRBool gotPerms;
+
+ iter = NULL;
+ subiter = NULL;
+ errStr = NULL;
+ gotPerms = PR_FALSE;
+
+ /* Clear out old values */
+ Pk11Install_File_Cleanup(_this);
+
+ _this->jarPath = PR_Strdup(pair->key);
+
+ /* Go through all the pairs under this file heading */
+ iter = Pk11Install_ListIter_new(pair->list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ subpair = val->pair;
+
+ /* Relative directory */
+ if (!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->relativePath = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+
+ /* Absolute directory */
+ } else if (!PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->absolutePath = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+
+ /* file permissions */
+ } else if (!PORT_Strcasecmp(subpair->key,
+ FILE_PERMISSIONS_STRING)) {
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE) ||
+ !subval->string || !subval->string[0]) {
+ errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
+ _this->jarPath);
+ goto loser;
+ }
+ _this->permissions = (int)strtol(subval->string, &endp, 8);
+ if (*endp != '\0') {
+ errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
+ _this->jarPath);
+ goto loser;
+ }
+ gotPerms = PR_TRUE;
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ } else {
+ if (!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) {
+ _this->executable = PR_TRUE;
+ }
+ }
+ }
+
+ /* Default permission value */
+ if (!gotPerms) {
+ _this->permissions = DEFAULT_PERMISSIONS;
+ }
+
+ /* Make sure we got all the information */
+ if (!_this->relativePath && !_this->absolutePath) {
+ errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
+ goto loser;
+ }
+#if 0
+ if(!_this->relativePath ) {
+ errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath);
+ goto loser;
+ }
+ if(!_this->absolutePath) {
+ errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
+ goto loser;
+ }
+#endif
+
+loser:
+ if (iter) {
+ Pk11Install_ListIter_delete(&iter);
+ }
+ if (subiter) {
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_File
+*/
+void
+Pk11Install_File_Print(Pk11Install_File* _this, int pad)
+{
+ PAD(pad);
+ printf("jarPath: %s\n",
+ _this->jarPath ? _this->jarPath : "<NULL>");
+ PAD(pad);
+ printf("relativePath: %s\n",
+ _this->relativePath ? _this->relativePath : "<NULL>");
+ PAD(pad);
+ printf("absolutePath: %s\n",
+ _this->absolutePath ? _this->absolutePath : "<NULL>");
+ PAD(pad);
+ printf("permissions: %o\n", _this->permissions);
+}
+
+Pk11Install_PlatformName*
+Pk11Install_PlatformName_new()
+{
+ Pk11Install_PlatformName* new_this;
+ new_this = (Pk11Install_PlatformName*)
+ PR_Malloc(sizeof(Pk11Install_PlatformName));
+ Pk11Install_PlatformName_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this)
+{
+ _this->OS = NULL;
+ _this->verString = NULL;
+ _this->numDigits = 0;
+ _this->arch = NULL;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_PlatformName
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this)
+{
+ Pk11Install_PlatformName_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this)
+{
+ if (_this->OS) {
+ PR_Free(_this->OS);
+ _this->OS = NULL;
+ }
+ if (_this->verString) {
+ int i;
+ for (i = 0; i < _this->numDigits; i++) {
+ PR_Free(_this->verString[i]);
+ }
+ PR_Free(_this->verString);
+ _this->verString = NULL;
+ }
+ if (_this->arch) {
+ PR_Free(_this->arch);
+ _this->arch = NULL;
+ }
+ _this->numDigits = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_PlatformName
+// Notes: Extracts the information from a platform string.
+*/
+char*
+Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
+ const char* str)
+{
+ char* errStr;
+ char* copy;
+ char *end, *start; /* start and end of a section (OS, version, arch)*/
+ char *pend, *pstart; /* start and end of one portion of version*/
+ char* endp; /* used by strtol*/
+ int periods, i;
+
+ errStr = NULL;
+ copy = NULL;
+
+ if (!str) {
+ errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]);
+ goto loser;
+ }
+ copy = PR_Strdup(str);
+
+ /*
+ // Get the OS
+ */
+ end = strchr(copy, PLATFORM_SEPARATOR_CHAR);
+ if (!end || end == copy) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *end = '\0';
+
+ _this->OS = PR_Strdup(copy);
+
+ /*
+ // Get the digits of the version of form: x.x.x (arbitrary number of digits)
+ */
+
+ start = end + 1;
+ end = strchr(start, PLATFORM_SEPARATOR_CHAR);
+ if (!end) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *end = '\0';
+
+ if (end != start) {
+ /* Find out how many periods*/
+ periods = 0;
+ pstart = start;
+ while ((pend = strchr(pstart, '.'))) {
+ periods++;
+ pstart = pend + 1;
+ }
+ _this->numDigits = 1 + periods;
+ _this->verString = (char**)PR_Malloc(sizeof(char*) * _this->numDigits);
+
+ pstart = start;
+ i = 0;
+ /* Get the digits before each period*/
+ while ((pend = strchr(pstart, '.'))) {
+ if (pend == pstart) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ *pend = '\0';
+ _this->verString[i] = PR_Strdup(pstart);
+ endp = pend;
+ if (endp == pstart || (*endp != '\0')) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ pstart = pend + 1;
+ i++;
+ }
+ /* Last digit comes after the last period*/
+ if (*pstart == '\0') {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ _this->verString[i] = PR_Strdup(pstart);
+ /*
+ if(endp==pstart || (*endp != '\0')) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ */
+ } else {
+ _this->verString = NULL;
+ _this->numDigits = 0;
+ }
+
+ /*
+ // Get the architecture
+ */
+ start = end + 1;
+ if (strchr(start, PLATFORM_SEPARATOR_CHAR)) {
+ errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
+ goto loser;
+ }
+ _this->arch = PR_Strdup(start);
+
+ if (copy) {
+ PR_Free(copy);
+ }
+ return NULL;
+loser:
+ if (_this->OS) {
+ PR_Free(_this->OS);
+ _this->OS = NULL;
+ }
+ if (_this->verString) {
+ for (i = 0; i < _this->numDigits; i++) {
+ PR_Free(_this->verString[i]);
+ }
+ PR_Free(_this->verString);
+ _this->verString = NULL;
+ }
+ _this->numDigits = 0;
+ if (_this->arch) {
+ PR_Free(_this->arch);
+ _this->arch = NULL;
+ }
+ if (copy) {
+ PR_Free(copy);
+ }
+
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator ==
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS, arch, and version
+*/
+PRBool
+Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ int i;
+
+ if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
+ return PR_FALSE;
+ }
+
+ if (PORT_Strcasecmp(_this->OS, cmp->OS) ||
+ PORT_Strcasecmp(_this->arch, cmp->arch) ||
+ _this->numDigits != cmp->numDigits) {
+ return PR_FALSE;
+ }
+
+ for (i = 0; i < _this->numDigits; i++) {
+ if (PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) {
+ return PR_FALSE;
+ }
+ }
+ return PR_TRUE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator <=
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS and arch and a lower
+// or equal release.
+*/
+PRBool
+Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ return (Pk11Install_PlatformName_equal(_this, cmp) ||
+ Pk11Install_PlatformName_lt(_this, cmp))
+ ? PR_TRUE
+ : PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: operator <
+// Class: Pk11Install_PlatformName
+// Returns: PR_TRUE if the platform have the same OS and arch and a greater
+// release.
+*/
+PRBool
+Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
+ Pk11Install_PlatformName* cmp)
+{
+ int i, scmp;
+
+ if (!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
+ return PR_FALSE;
+ }
+
+ if (PORT_Strcasecmp(_this->OS, cmp->OS)) {
+ return PR_FALSE;
+ }
+ if (PORT_Strcasecmp(_this->arch, cmp->arch)) {
+ return PR_FALSE;
+ }
+
+ for (i = 0; (i < _this->numDigits) && (i < cmp->numDigits); i++) {
+ scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]);
+ if (scmp > 0) {
+ return PR_FALSE;
+ } else if (scmp < 0) {
+ return PR_TRUE;
+ }
+ }
+ /* All the digits they have in common are the same. */
+ if (_this->numDigits < cmp->numDigits) {
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetString
+// Class: Pk11Install_PlatformName
+// Returns: String composed of OS, release, and architecture separated
+// by the separator char. Memory is allocated by this function
+// but is the responsibility of the caller to de-allocate.
+*/
+char*
+Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this)
+{
+ char* ret;
+ char* ver;
+ char* OS_;
+ char* arch_;
+
+ OS_ = NULL;
+ arch_ = NULL;
+
+ OS_ = _this->OS ? _this->OS : "";
+ arch_ = _this->arch ? _this->arch : "";
+
+ ver = Pk11Install_PlatformName_GetVerString(_this);
+ ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver,
+ PLATFORM_SEPARATOR_CHAR, arch_);
+
+ PR_Free(ver);
+
+ return ret;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetVerString
+// Class: Pk11Install_PlatformName
+// Returns: The version string for this platform, in the form x.x.x with an
+// arbitrary number of digits. Memory allocated by function,
+// must be de-allocated by caller.
+*/
+char*
+Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this)
+{
+ char* tmp;
+ char* ret;
+ int i;
+ char buf[80];
+
+ tmp = (char*)PR_Malloc(80 * _this->numDigits + 1);
+ tmp[0] = '\0';
+
+ for (i = 0; i < _this->numDigits - 1; i++) {
+ sprintf(buf, "%s.", _this->verString[i]);
+ strcat(tmp, buf);
+ }
+ if (i < _this->numDigits) {
+ sprintf(buf, "%s", _this->verString[i]);
+ strcat(tmp, buf);
+ }
+
+ ret = PR_Strdup(tmp);
+ free(tmp);
+
+ return ret;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_PlatformName
+*/
+void
+Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad)
+{
+ char* str = NULL;
+ PAD(pad);
+ printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>");
+ PAD(pad);
+ printf("Digits: ");
+ if (_this->numDigits == 0) {
+ printf("None\n");
+ } else {
+ str = Pk11Install_PlatformName_GetVerString(_this);
+ printf("%s\n", str);
+ PR_Free(str);
+ }
+ PAD(pad);
+ printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>");
+}
+
+Pk11Install_Platform*
+Pk11Install_Platform_new()
+{
+ Pk11Install_Platform* new_this;
+ new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform));
+ Pk11Install_Platform_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_Platform_init(Pk11Install_Platform* _this)
+{
+ Pk11Install_PlatformName_init(&_this->name);
+ Pk11Install_PlatformName_init(&_this->equivName);
+ _this->equiv = NULL;
+ _this->usesEquiv = PR_FALSE;
+ _this->moduleFile = NULL;
+ _this->moduleName = NULL;
+ _this->modFile = -1;
+ _this->mechFlags = 0;
+ _this->cipherFlags = 0;
+ _this->files = NULL;
+ _this->numFiles = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_Platform
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_delete(Pk11Install_Platform* _this)
+{
+ Pk11Install_Platform_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this)
+{
+ int i;
+ if (_this->moduleFile) {
+ PR_Free(_this->moduleFile);
+ _this->moduleFile = NULL;
+ }
+ if (_this->moduleName) {
+ PR_Free(_this->moduleName);
+ _this->moduleName = NULL;
+ }
+ if (_this->files) {
+ for (i = 0; i < _this->numFiles; i++) {
+ Pk11Install_File_delete(&_this->files[i]);
+ }
+ PR_Free(_this->files);
+ _this->files = NULL;
+ }
+ _this->equiv = NULL;
+ _this->usesEquiv = PR_FALSE;
+ _this->modFile = -1;
+ _this->numFiles = 0;
+ _this->mechFlags = _this->cipherFlags = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_Platform
+// Notes: Creates a platform data structure from a syntax tree.
+// Returns: NULL for success, otherwise an error message.
+*/
+char*
+Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
+ const Pk11Install_Pair* pair)
+{
+ char* errStr;
+ char* endptr;
+ char* tmp;
+ int i;
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Value* subval;
+ Pk11Install_Pair* subpair;
+ Pk11Install_ListIter* subiter;
+ PRBool gotModuleFile, gotModuleName, gotMech,
+ gotCipher, gotFiles, gotEquiv;
+
+ errStr = NULL;
+ iter = subiter = NULL;
+ val = subval = NULL;
+ subpair = NULL;
+ gotModuleFile = gotModuleName = gotMech = gotCipher = gotFiles = gotEquiv = PR_FALSE;
+ Pk11Install_Platform_Cleanup(_this);
+
+ errStr = Pk11Install_PlatformName_Generate(&_this->name, pair->key);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s", pair->key, errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+
+ iter = Pk11Install_ListIter_new(pair->list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ subpair = val->pair;
+
+ if (!PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) {
+ if (gotModuleFile) {
+ errStr = PR_smprintf(errString[REPEAT_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->moduleFile = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+ gotModuleFile = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)) {
+ if (gotModuleName) {
+ errStr = PR_smprintf(errString[REPEAT_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->moduleName = PR_Strdup(subval->string);
+ Pk11Install_ListIter_delete(&subiter);
+ gotModuleName = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) {
+ endptr = NULL;
+
+ if (gotMech) {
+ errStr = PR_smprintf(errString[REPEAT_MECH],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->mechFlags = strtol(subval->string, &endptr, 0);
+ if (*endptr != '\0' || (endptr == subval->string)) {
+ errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ gotMech = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, CIPHER_FLAGS_STRING)) {
+ endptr = NULL;
+
+ if (gotCipher) {
+ errStr = PR_smprintf(errString[REPEAT_CIPHER],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ _this->cipherFlags = strtol(subval->string, &endptr, 0);
+ if (*endptr != '\0' || (endptr == subval->string)) {
+ errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ gotCipher = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key, FILES_STRING)) {
+ if (gotFiles) {
+ errStr = PR_smprintf(errString[REPEAT_FILES],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ _this->numFiles = subpair->list->numPairs;
+ _this->files = (Pk11Install_File*)
+ PR_Malloc(sizeof(Pk11Install_File) * _this->numFiles);
+ for (i = 0; i < _this->numFiles; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ Pk11Install_File_init(&_this->files[i]);
+ val = subiter->current;
+ if (val && (val->type == PAIR_VALUE)) {
+ errStr = Pk11Install_File_Generate(&_this->files[i], val->pair);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+ }
+ }
+ gotFiles = PR_TRUE;
+ } else if (!PORT_Strcasecmp(subpair->key,
+ EQUIVALENT_PLATFORM_STRING)) {
+ if (gotEquiv) {
+ errStr = PR_smprintf(errString[REPEAT_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ subiter = Pk11Install_ListIter_new(subpair->list);
+ subval = subiter->current;
+ if (!subval || (subval->type != STRING_VALUE)) {
+ errStr = PR_smprintf(errString[BOGUS_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ errStr = Pk11Install_PlatformName_Generate(&_this->equivName,
+ subval->string);
+ if (errStr) {
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ tmp = PR_smprintf("%s: %s",
+ Pk11Install_PlatformName_GetString(&_this->name), errStr);
+ PR_smprintf_free(errStr);
+ errStr = tmp;
+ goto loser;
+ }
+ _this->usesEquiv = PR_TRUE;
+ }
+ }
+ }
+
+ /* Make sure we either have an EquivalentPlatform or all the other info */
+ if (_this->usesEquiv &&
+ (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) {
+ errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotFiles && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_FILES],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotModuleFile && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_MODULE_FILE],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ if (!gotModuleName && !_this->usesEquiv) {
+ errStr = PR_smprintf(errString[NO_MODULE_NAME],
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+
+ /* Point the modFile pointer to the correct file */
+ if (gotModuleFile) {
+ for (i = 0; i < _this->numFiles; i++) {
+ if (!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath)) {
+ _this->modFile = i;
+ break;
+ }
+ }
+ if (_this->modFile == -1) {
+ errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE],
+ _this->moduleFile,
+ Pk11Install_PlatformName_GetString(&_this->name));
+ goto loser;
+ }
+ }
+
+loser:
+ if (iter) {
+ PR_Free(iter);
+ }
+ if (subiter) {
+ PR_Free(subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_Platform
+*/
+void
+Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad)
+{
+ int i;
+
+ PAD(pad);
+ printf("Name:\n");
+ Pk11Install_PlatformName_Print(&_this->name, pad + PADINC);
+ PAD(pad);
+ printf("equivName:\n");
+ Pk11Install_PlatformName_Print(&_this->equivName, pad + PADINC);
+ PAD(pad);
+ if (_this->usesEquiv) {
+ printf("Uses equiv, which points to:\n");
+ Pk11Install_Platform_Print(_this->equiv, pad + PADINC);
+ } else {
+ printf("Doesn't use equiv\n");
+ }
+ PAD(pad);
+ printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile
+ : "<NULL>");
+ PAD(pad);
+ printf("mechFlags: %lx\n", _this->mechFlags);
+ PAD(pad);
+ printf("cipherFlags: %lx\n", _this->cipherFlags);
+ PAD(pad);
+ printf("Files:\n");
+ for (i = 0; i < _this->numFiles; i++) {
+ Pk11Install_File_Print(&_this->files[i], pad + PADINC);
+ PAD(pad);
+ printf("--------------------\n");
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Pk11Install_Info
+// Class: Pk11Install_Info
+*/
+Pk11Install_Info*
+Pk11Install_Info_new()
+{
+ Pk11Install_Info* new_this;
+ new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info));
+ Pk11Install_Info_init(new_this);
+ return new_this;
+}
+
+void
+Pk11Install_Info_init(Pk11Install_Info* _this)
+{
+ _this->platforms = NULL;
+ _this->numPlatforms = 0;
+ _this->forwardCompatible = NULL;
+ _this->numForwardCompatible = 0;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: ~Pk11Install_Info
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_delete(Pk11Install_Info* _this)
+{
+ Pk11Install_Info_Cleanup(_this);
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Cleanup
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_Cleanup(Pk11Install_Info* _this)
+{
+ int i;
+ if (_this->platforms) {
+ for (i = 0; i < _this->numPlatforms; i++) {
+ Pk11Install_Platform_delete(&_this->platforms[i]);
+ }
+ PR_Free(&_this->platforms);
+ _this->platforms = NULL;
+ _this->numPlatforms = 0;
+ }
+
+ if (_this->forwardCompatible) {
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]);
+ }
+ PR_Free(&_this->forwardCompatible);
+ _this->numForwardCompatible = 0;
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Generate
+// Class: Pk11Install_Info
+// Takes: Pk11Install_ValueList *list, the top-level list
+// resulting from parsing an installer file.
+// Returns: char*, NULL if successful, otherwise an error string.
+// Caller is responsible for freeing memory.
+*/
+char*
+Pk11Install_Info_Generate(Pk11Install_Info* _this,
+ const Pk11Install_ValueList* list)
+{
+ char* errStr;
+ Pk11Install_ListIter* iter;
+ Pk11Install_Value* val;
+ Pk11Install_Pair* pair;
+ Pk11Install_ListIter* subiter;
+ Pk11Install_Value* subval;
+ Pk11Install_Platform *first, *second;
+ int i, j;
+
+ errStr = NULL;
+ iter = subiter = NULL;
+ Pk11Install_Info_Cleanup(_this);
+
+ iter = Pk11Install_ListIter_new(list);
+ for (; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
+ if (val->type == PAIR_VALUE) {
+ pair = val->pair;
+
+ if (!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) {
+ subiter = Pk11Install_ListIter_new(pair->list);
+ _this->numForwardCompatible = pair->list->numStrings;
+ _this->forwardCompatible = (Pk11Install_PlatformName*)
+ PR_Malloc(sizeof(Pk11Install_PlatformName) *
+ _this->numForwardCompatible);
+ for (i = 0; i < _this->numForwardCompatible; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ subval = subiter->current;
+ if (subval->type == STRING_VALUE) {
+ errStr = Pk11Install_PlatformName_Generate(
+ &_this->forwardCompatible[i], subval->string);
+ if (errStr) {
+ goto loser;
+ }
+ }
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ } else if (!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) {
+ subiter = Pk11Install_ListIter_new(pair->list);
+ _this->numPlatforms = pair->list->numPairs;
+ _this->platforms = (Pk11Install_Platform*)
+ PR_Malloc(sizeof(Pk11Install_Platform) *
+ _this->numPlatforms);
+ for (i = 0; i < _this->numPlatforms; i++,
+ Pk11Install_ListIter_nextItem(subiter)) {
+ Pk11Install_Platform_init(&_this->platforms[i]);
+ subval = subiter->current;
+ if (subval->type == PAIR_VALUE) {
+ errStr = Pk11Install_Platform_Generate(&_this->platforms[i], subval->pair);
+ if (errStr) {
+ goto loser;
+ }
+ }
+ }
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ }
+ }
+
+ if (_this->numPlatforms == 0) {
+ errStr = PR_smprintf(errString[NO_PLATFORMS]);
+ goto loser;
+ }
+
+ /*
+ //
+ // Now process equivalent platforms
+ //
+
+ // First the naive pass
+ */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (_this->platforms[i].usesEquiv) {
+ _this->platforms[i].equiv = NULL;
+ for (j = 0; j < _this->numPlatforms; j++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName,
+ &_this->platforms[j].name)) {
+ if (i == j) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ _this->platforms[i].equiv = &_this->platforms[j];
+ break;
+ }
+ }
+ if (_this->platforms[i].equiv == NULL) {
+ errStr = PR_smprintf(errString[BOGUS_EQUIV],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ }
+ }
+
+ /*
+ // Now the intelligent pass, which will also detect loops.
+ // We will send two pointers through the linked list of equivalent
+ // platforms. Both start with the current node. "first" traverses
+ // two nodes for each iteration. "second" lags behind, only traversing
+ // one node per iteration. Eventually one of two things will happen:
+ // first will hit the end of the list (a platform that doesn't use
+ // an equivalency), or first will equal second if there is a loop.
+ */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (_this->platforms[i].usesEquiv) {
+ second = _this->platforms[i].equiv;
+ if (!second->usesEquiv) {
+ /* The first link is the terminal node */
+ continue;
+ }
+ first = second->equiv;
+ while (first->usesEquiv) {
+ if (first == second) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ first = first->equiv;
+ if (!first->usesEquiv) {
+ break;
+ }
+ if (first == second) {
+ errStr = PR_smprintf(errString[EQUIV_LOOP],
+ Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
+ goto loser;
+ }
+ second = second->equiv;
+ first = first->equiv;
+ }
+ _this->platforms[i].equiv = first;
+ }
+ }
+
+loser:
+ if (iter) {
+ Pk11Install_ListIter_delete(&iter);
+ }
+ if (subiter) {
+ Pk11Install_ListIter_delete(&subiter);
+ }
+ return errStr;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: GetBestPlatform
+// Class: Pk11Install_Info
+// Takes: char *myPlatform, the platform we are currently running
+// on.
+*/
+Pk11Install_Platform*
+Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char* myPlatform)
+{
+ Pk11Install_PlatformName plat;
+ char* errStr;
+ int i, j;
+
+ errStr = NULL;
+
+ Pk11Install_PlatformName_init(&plat);
+ if ((errStr = Pk11Install_PlatformName_Generate(&plat, myPlatform))) {
+ PR_smprintf_free(errStr);
+ return NULL;
+ }
+
+ /* First try real platforms */
+ for (i = 0; i < _this->numPlatforms; i++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[i].name, &plat)) {
+ if (_this->platforms[i].equiv) {
+ return _this->platforms[i].equiv;
+ } else {
+ return &_this->platforms[i];
+ }
+ }
+ }
+
+ /* Now try forward compatible platforms */
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ if (Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i], &plat)) {
+ break;
+ }
+ }
+ if (i == _this->numForwardCompatible) {
+ return NULL;
+ }
+
+ /* Got a forward compatible name, find the actual platform. */
+ for (j = 0; j < _this->numPlatforms; j++) {
+ if (Pk11Install_PlatformName_equal(&_this->platforms[j].name,
+ &_this->forwardCompatible[i])) {
+ if (_this->platforms[j].equiv) {
+ return _this->platforms[j].equiv;
+ } else {
+ return &_this->platforms[j];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+// Method: Print
+// Class: Pk11Install_Info
+*/
+void
+Pk11Install_Info_Print(Pk11Install_Info* _this, int pad)
+{
+ int i;
+
+ PAD(pad);
+ printf("Forward Compatible:\n");
+ for (i = 0; i < _this->numForwardCompatible; i++) {
+ Pk11Install_PlatformName_Print(&_this->forwardCompatible[i], pad + PADINC);
+ PAD(pad);
+ printf("-------------------\n");
+ }
+ PAD(pad);
+ printf("Platforms:\n");
+ for (i = 0; i < _this->numPlatforms; i++) {
+ Pk11Install_Platform_Print(&_this->platforms[i], pad + PADINC);
+ PAD(pad);
+ printf("-------------------\n");
+ }
+}
+
+/*
+//////////////////////////////////////////////////////////////////////////
+*/
+static char*
+PR_Strdup(const char* str)
+{
+ char* tmp;
+ tmp = (char*)PR_Malloc((unsigned int)(strlen(str) + 1));
+ strcpy(tmp, str);
+ return tmp;
+}
+
+/* The global value list, the top of the tree */
+Pk11Install_ValueList* Pk11Install_valueList = NULL;
+
+/****************************************************************************/
+void
+Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
+ Pk11Install_Value* item)
+{
+ _this->numItems++;
+ if (item->type == STRING_VALUE) {
+ _this->numStrings++;
+ } else {
+ _this->numPairs++;
+ }
+ item->next = _this->head;
+ _this->head = item;
+}
+
+/****************************************************************************/
+Pk11Install_ListIter*
+Pk11Install_ListIter_new_default()
+{
+ Pk11Install_ListIter* new_this;
+ new_this = (Pk11Install_ListIter*)
+ PR_Malloc(sizeof(Pk11Install_ListIter));
+ Pk11Install_ListIter_init(new_this);
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_init(Pk11Install_ListIter* _this)
+{
+ _this->list = NULL;
+ _this->current = NULL;
+}
+
+/****************************************************************************/
+Pk11Install_ListIter*
+Pk11Install_ListIter_new(const Pk11Install_ValueList* _list)
+{
+ Pk11Install_ListIter* new_this;
+ new_this = (Pk11Install_ListIter*)
+ PR_Malloc(sizeof(Pk11Install_ListIter));
+ new_this->list = _list;
+ new_this->current = _list->head;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_delete(Pk11Install_ListIter** _this)
+{
+ (*_this)->list = NULL;
+ (*_this)->current = NULL;
+ PR_Free(*_this);
+ *_this = NULL;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ListIter_reset(Pk11Install_ListIter* _this)
+{
+ if (_this->list) {
+ _this->current = _this->list->head;
+ }
+}
+
+/*************************************************************************/
+Pk11Install_Value*
+Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this)
+{
+ if (_this->current) {
+ _this->current = _this->current->next;
+ }
+
+ return _this->current;
+}
+
+/****************************************************************************/
+Pk11Install_ValueList*
+Pk11Install_ValueList_new()
+{
+ Pk11Install_ValueList* new_this;
+ new_this = (Pk11Install_ValueList*)
+ PR_Malloc(sizeof(Pk11Install_ValueList));
+ new_this->numItems = 0;
+ new_this->numPairs = 0;
+ new_this->numStrings = 0;
+ new_this->head = NULL;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_ValueList_delete(Pk11Install_ValueList* _this)
+{
+
+ Pk11Install_Value* tmp;
+ Pk11Install_Value* list;
+ list = _this->head;
+
+ while (list != NULL) {
+ tmp = list;
+ list = list->next;
+ PR_Free(tmp);
+ }
+ PR_Free(_this);
+}
+
+/****************************************************************************/
+Pk11Install_Value*
+Pk11Install_Value_new_default()
+{
+ Pk11Install_Value* new_this;
+ new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value));
+ new_this->type = STRING_VALUE;
+ new_this->string = NULL;
+ new_this->pair = NULL;
+ new_this->next = NULL;
+ return new_this;
+}
+
+/****************************************************************************/
+Pk11Install_Value*
+Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr)
+{
+ Pk11Install_Value* new_this;
+ new_this = Pk11Install_Value_new_default();
+ new_this->type = _type;
+ if (_type == STRING_VALUE) {
+ new_this->pair = NULL;
+ new_this->string = ptr.string;
+ } else {
+ new_this->string = NULL;
+ new_this->pair = ptr.pair;
+ }
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_Value_delete(Pk11Install_Value* _this)
+{
+ if (_this->type == STRING_VALUE) {
+ PR_Free(_this->string);
+ } else {
+ PR_Free(_this->pair);
+ }
+}
+
+/****************************************************************************/
+Pk11Install_Pair*
+Pk11Install_Pair_new_default()
+{
+ return Pk11Install_Pair_new(NULL, NULL);
+}
+
+/****************************************************************************/
+Pk11Install_Pair*
+Pk11Install_Pair_new(char* _key, Pk11Install_ValueList* _list)
+{
+ Pk11Install_Pair* new_this;
+ new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair));
+ new_this->key = _key;
+ new_this->list = _list;
+ return new_this;
+}
+
+/****************************************************************************/
+void
+Pk11Install_Pair_delete(Pk11Install_Pair* _this)
+{
+ PR_Free(_this->key);
+ Pk11Install_ValueList_delete(_this->list);
+}
+
+/*************************************************************************/
+void
+Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad)
+{
+ while (_this) {
+ /*PAD(pad); printf("**Pair\n");
+ PAD(pad); printf("***Key====\n");*/
+ PAD(pad);
+ printf("%s {\n", _this->key);
+ /*PAD(pad); printf("====\n");*/
+ /*PAD(pad); printf("***ValueList\n");*/
+ Pk11Install_ValueList_Print(_this->list, pad + PADINC);
+ PAD(pad);
+ printf("}\n");
+ }
+}
+
+/*************************************************************************/
+void
+Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad)
+{
+ Pk11Install_Value* v;
+
+ /*PAD(pad);printf("**Value List**\n");*/
+ for (v = _this->head; v != NULL; v = v->next) {
+ Pk11Install_Value_Print(v, pad);
+ }
+}
+
+/*************************************************************************/
+void
+Pk11Install_Value_Print(Pk11Install_Value* _this, int pad)
+{
+ /*PAD(pad); printf("**Value, type=%s\n",
+ type==STRING_VALUE ? "string" : "pair");*/
+ if (_this->type == STRING_VALUE) {
+ /*PAD(pad+PADINC); printf("====\n");*/
+ PAD(pad);
+ printf("%s\n", _this->string);
+ /*PAD(pad+PADINC); printf("====\n");*/
+ } else {
+ Pk11Install_Pair_Print(_this->pair, pad + PADINC);
+ }
+}