summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c883
1 files changed, 883 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c
new file mode 100644
index 00000000..872b96fd
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c
@@ -0,0 +1,883 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * A utility for linking multiple typelib files.
+ */
+
+#include "xpt_xdr.h"
+#include <stdio.h>
+#ifdef XP_MAC
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include "prlong.h"
+
+#ifndef NULL
+#define NULL (void *) 0
+#endif
+
+/* Forward declarations. */
+typedef struct fixElement fixElement;
+static int compare_IDEs_by_IID(const void *ap, const void *bp);
+static int compare_IDE_with_zero(const void *ap);
+static int compare_IDEs_by_name(const void *ap, const void *bp);
+static int compare_IDEs_by_name_space(const void *ap, const void *bp);
+static int compare_strings(const void *ap, const void *bp);
+static int compare_pointers(const void *ap, const void *bp);
+static int compare_fixElements_by_IID(const void *ap, const void *bp);
+static int compare_fixElements_by_name(const void *ap, const void *bp);
+static int compare_IIDs(const void *ap, const void *bp);
+PRBool shrink_IDE_array(XPTInterfaceDirectoryEntry *ide,
+ int element_to_delete, int num_interfaces);
+PRBool update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete,
+ int num_interfaces, int replacement);
+static int get_new_index(const fixElement *fix, int num_elements,
+ int target_file, int target_interface);
+PRBool copy_IDE(XPTInterfaceDirectoryEntry *from,
+ XPTInterfaceDirectoryEntry *to);
+PRBool copy_fixElement(fixElement *from, fixElement *to);
+static void print_IID(struct nsID *iid, FILE *file);
+static void xpt_link_usage(char *argv[]);
+
+struct fixElement {
+ nsID iid;
+ char* name;
+ int file_num;
+ int interface_num;
+ PRBool is_deleted;
+ /* These next two variables will point you to the substitute interface
+ * if this one has been deleted.
+ */
+ int maps_to_file_num;
+ int maps_to_interface_num;
+};
+
+/* Global variables. */
+PRUint16 trueNumberOfInterfaces = 0;
+PRUint16 totalNumberOfInterfaces = 0;
+PRUint16 oldTotalNumberOfInterfaces = 0;
+
+/* The following globals are explained in xpt_struct.h */
+PRUint8 major_version = XPT_MAJOR_VERSION;
+PRUint8 minor_version = XPT_MINOR_VERSION;
+
+#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
+
+#define main xptlink_main
+int xptlink_main(int argc, char *argv[]);
+extern size_t mac_get_file_length(const char* filename);
+#define get_file_length mac_get_file_length
+
+#else
+
+static size_t get_file_length(const char* filename)
+{
+ struct stat file_stat;
+ if (stat(filename, &file_stat) != 0) {
+ perror("FAILED: get_file_length");
+ exit(1);
+ }
+ return file_stat.st_size;
+}
+
+#endif /* XP_MAC && XPIDL_PLUGIN */
+
+int
+main(int argc, char **argv)
+{
+ XPTArena *arena;
+ XPTState *state;
+ XPTCursor curs, *cursor = &curs;
+ XPTHeader *header;
+ XPTInterfaceDirectoryEntry *IDE_array = NULL;
+ XPTInterfaceDescriptor *id;
+ XPTTypeDescriptor *td;
+ XPTAnnotation *ann, *first_ann;
+ PRUint32 header_sz, len;
+ PRUint32 oldOffset;
+ PRUint32 newOffset;
+ size_t flen = 0;
+ char *head, *data, *whole;
+ const char *outFileName;
+ FILE *in, *out;
+ fixElement *fix_array = NULL;
+ int i,j;
+ int k = 0;
+
+ if (argc < 3) {
+ xpt_link_usage(argv);
+ return 1;
+ }
+
+ arena = XPT_NewArena(1024 * 10, sizeof(double), "main xpt_link arena");
+ if (!arena) {
+ perror("FAILED: XPT_NewArena");
+ return 1;
+ }
+
+ first_ann = XPT_NewAnnotation(arena, XPT_ANN_LAST, NULL, NULL);
+
+ /* Check if the "-t version numnber" cmd line arg is present */
+ i = 1;
+ if (argv[i][0] == '-' && argv[i][1] == 't') {
+ /* Parse for "-t version number" */
+
+ /* If -t is the last argument on the command line, we have a problem */
+ if (i + 1 == argc) {
+ fprintf(stderr, "ERROR: missing version number after -t\n");
+ xpt_link_usage(argv);
+ return 1;
+ }
+
+ /*
+ * Assume that the argument after "-t" is the version number string
+ * and search for it in our internal list of acceptable version
+ * numbers.
+ */
+
+ switch (XPT_ParseVersionString(argv[++i], &major_version,
+ &minor_version)) {
+ case XPT_VERSION_CURRENT:
+ case XPT_VERSION_OLD:
+ break;
+ case XPT_VERSION_UNSUPPORTED:
+ fprintf(stderr, "ERROR: version \"%s\" not supported.\n",
+ argv[i]);
+ xpt_link_usage(argv);
+ return 1;
+ case XPT_VERSION_UNKNOWN:
+ default:
+ fprintf(stderr, "ERROR: version \"%s\" not recognised.\n",
+ argv[i]);
+ xpt_link_usage(argv);
+ return 1;
+ }
+
+ /* Hang onto the output file name. It's needed later. */
+ outFileName = argv[++i];
+
+ /* Increment i to the cmd line arg after outFileName */
+ i++;
+ }
+ else {
+ outFileName = argv[1];
+ i = 2;
+ }
+
+ for ( /* use i from earlier */ ; i < argc; i++) {
+ char *name = argv[i];
+
+ flen = get_file_length(name);
+ if (!flen) {
+ fprintf(stderr, "ERROR: file %s is zero length\n", name);
+ return 1;
+ }
+
+ in = fopen(name, "rb");
+ if (!in) {
+ perror("FAILED: fopen");
+ return 1;
+ }
+
+ whole = XPT_MALLOC(arena, flen);
+ if (!whole) {
+ perror("FAILED: XPT_MALLOC for whole");
+ return 1;
+ }
+
+ if (flen > 0) {
+ size_t rv = fread(whole, 1, flen, in);
+ if (rv < flen) {
+ fprintf(stderr, "short read (%zd vs %zd)! ouch!\n", rv, flen);
+ return 1;
+ }
+ if (ferror(in) != 0 || fclose(in) != 0) {
+ perror("FAILED: Unable to read typelib file.\n");
+ return 1;
+ }
+
+ state = XPT_NewXDRState(XPT_DECODE, whole, flen);
+ if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) {
+ fprintf(stdout, "XPT_MakeCursor failed for %s\n", name);
+ return 1;
+ }
+ if (!XPT_DoHeader(arena, cursor, &header)) {
+ fprintf(stdout,
+ "DoHeader failed for %s. Is %s a valid .xpt file?\n",
+ name, name);
+ return 1;
+ }
+
+ /*
+ * Make sure that the version of the typelib file is less than or
+ * equal to the version specified in the -t cmd line arg.
+ */
+
+ if (header &&
+ (header->major_version > major_version ||
+ (header->major_version == major_version &&
+ header->minor_version > minor_version))) {
+ fprintf(stderr, "FAILED: %s's version, %d.%d, is newer than "
+ "the version (%d.%d) specified in the -t "
+ "command line argument.\n",
+ name, header->major_version, header->minor_version,
+ major_version, minor_version);
+ return 1;
+ }
+
+ oldTotalNumberOfInterfaces = totalNumberOfInterfaces;
+ totalNumberOfInterfaces += header->num_interfaces;
+ if (header->num_interfaces > 0) {
+ XPTInterfaceDirectoryEntry *newIDE;
+ fixElement *newFix;
+
+ newIDE = (XPTInterfaceDirectoryEntry *)
+ XPT_MALLOC(arena, totalNumberOfInterfaces *
+ sizeof(XPTInterfaceDirectoryEntry));
+ if (!newIDE) {
+ perror("FAILED: XPT_MALLOC of IDE_array");
+ return 1;
+ }
+
+ if (IDE_array) {
+ if (oldTotalNumberOfInterfaces)
+ memcpy(newIDE, IDE_array,
+ oldTotalNumberOfInterfaces *
+ sizeof(XPTInterfaceDirectoryEntry));
+ XPT_FREE(arena, IDE_array);
+ }
+ IDE_array = newIDE;
+
+
+ newFix = (fixElement *)
+ XPT_MALLOC(arena,
+ totalNumberOfInterfaces * sizeof(fixElement));
+ if (!newFix) {
+ perror("FAILED: XPT_MALLOC of fix_array");
+ return 1;
+ }
+
+ if (fix_array) {
+ if (oldTotalNumberOfInterfaces)
+ memcpy(newFix, fix_array,
+ oldTotalNumberOfInterfaces *
+ sizeof(fixElement));
+ XPT_FREE(arena, fix_array);
+ }
+ fix_array = newFix;
+
+ for (j=0; j<header->num_interfaces; j++) {
+ if (!copy_IDE(&header->interface_directory[j],
+ &IDE_array[k])) {
+ perror("FAILED: 1st copying of IDE");
+ return 1;
+ }
+ fix_array[k].iid = IDE_array[k].iid;
+ fix_array[k].name = IDE_array[k].name;
+ fix_array[k].file_num = i-2;
+ fix_array[k].interface_num = j+1;
+ fix_array[k].is_deleted = PR_FALSE;
+ fix_array[k].maps_to_file_num = i-2;
+ fix_array[k].maps_to_interface_num = j+1;
+
+ k++;
+ }
+ }
+
+ /* Copy the annotations if they are not 'empty'
+ */
+ if (header->annotations != NULL &&
+ header->annotations->flags != XPT_ANN_LAST) {
+ ann = first_ann;
+ while (ann->next != NULL) {
+ ann = ann->next;
+ }
+ ann->next = header->annotations;
+ }
+
+ XPT_FREEIF(arena, header);
+ if (state)
+ XPT_DestroyXDRState(state);
+ XPT_FREE(arena, whole);
+ flen = 0;
+
+ } else {
+ fclose(in);
+ perror("FAILED: file length <= 0");
+ return 1;
+ }
+ }
+
+ /* Make sure the last annotation is the only one marked as XP_ANN_LAST.
+ */
+ ann = first_ann;
+ while (ann->next != NULL) {
+ ann->flags &= ~XPT_ANN_LAST;
+ ann = ann->next;
+ }
+ ann->flags |= XPT_ANN_LAST;
+
+ /* Sort both IDE_array and fix_array by name so we can check for
+ * name_space::name collisions.
+ */
+ qsort(IDE_array,
+ totalNumberOfInterfaces,
+ sizeof(XPTInterfaceDirectoryEntry),
+ compare_IDEs_by_name);
+
+ qsort(fix_array,
+ totalNumberOfInterfaces,
+ sizeof(fixElement),
+ compare_fixElements_by_name);
+
+ /* trueNumberOfInterfaces == number of interfaces left after deletions
+ * are made. Initialize it here to be the same as the total number of
+ * interfaces we'ce encountered thus far.
+ */
+ trueNumberOfInterfaces = totalNumberOfInterfaces;
+
+ /* Iterate through the sorted interfaces. Start at one so we don't
+ * accidentally walk off the end of the array.
+ */
+ i = 1;
+ while (i != trueNumberOfInterfaces) {
+
+ /* Check for name_space::name collision.
+ */
+ if (compare_strings(IDE_array[i-1].name,
+ IDE_array[i].name) == 0 &&
+ compare_strings(IDE_array[i-1].name_space,
+ IDE_array[i].name_space) == 0) {
+
+ /* If one of the interfaces is unresolved, delete that one
+ * preferentailly.
+ */
+ if (!IDE_array[i-1].interface_descriptor) {
+ /* Shrink the IDE_array to delete the duplicate interface.
+ */
+ if (!shrink_IDE_array(IDE_array,
+ i-1,
+ trueNumberOfInterfaces)) {
+ perror("FAILED: shrink_IDE_array");
+ return 1;
+ }
+ /* Update the fix array. This involves moving the deleted
+ * entry to the end of the array (rather than deleting it)
+ * and mapping it to the "replacement" element so we can
+ * update interface indices appropriately later.
+ */
+ update_fix_array(arena, fix_array, i-1,
+ totalNumberOfInterfaces, i);
+ /* Decrement the true number of interfaces since we just
+ * deleted one. There's more than one way to get out of
+ * this loop.
+ */
+ trueNumberOfInterfaces--;
+ } else {
+ if (!IDE_array[i].interface_descriptor ||
+ (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0))
+ {
+ /* Shrink the IDE_array to delete the duplicate interface.
+ */
+ if (!shrink_IDE_array(IDE_array,
+ i,
+ trueNumberOfInterfaces)) {
+ perror("FAILED: shrink_IDE_array");
+ return 1;
+ }
+ /* Update the fix array. This involves moving the deleted
+ * entry to the end of the array (rather than deleting it)
+ * and mapping it to the "replacement" element so we can
+ * update interface indices appropriately later.
+ */
+ update_fix_array(arena, fix_array, i,
+ totalNumberOfInterfaces, i-1);
+ /* Decrement the true number of interfaces since we just
+ * deleted one. There's more than one way to get out of
+ * this loop.
+ */
+ trueNumberOfInterfaces--;
+ } else {
+ /* Found interfaces with duplicate names but different
+ * iids! */
+ char *ns = IDE_array[i].name_space;
+ fprintf(stderr,
+ "ERROR: found duplicate definitions of interface "
+ "%s%s%s with iids \n",
+ ns ? ns : "", ns ? "::" : "", IDE_array[i].name);
+ print_IID(&IDE_array[i].iid, stderr);
+ fprintf(stderr, " and ");
+ print_IID(&IDE_array[i-1].iid, stderr);
+ fprintf(stderr, "\n");
+ return 1;
+ }
+ }
+ } else {
+ /* Only increment if there was no name_space::name collision.
+ */
+ i++;
+ }
+ }
+
+ /* Sort the IDE_array (put them in their final order) so that updating
+ * of indices will be meaningful.
+ */
+ qsort(IDE_array,
+ trueNumberOfInterfaces,
+ sizeof(XPTInterfaceDirectoryEntry),
+ compare_IDEs_by_IID);
+
+ /* Sort the fix_array to match the IDE_array.
+ */
+ qsort(fix_array,
+ trueNumberOfInterfaces,
+ sizeof(fixElement),
+ compare_fixElements_by_IID);
+
+ /* Iterate through the remaining interfaces (those not deleted)
+ * looking for references to interfaces (such as id->parent_interface)
+ * which need an updated index number.
+ */
+ for (i=0; i<trueNumberOfInterfaces; i++) {
+
+ /* Define id to save some keystrokes.
+ */
+ id = IDE_array[i].interface_descriptor;
+
+ /* Check for unresolved interface.
+ */
+ if (id) {
+
+ /* Fix parent_interface first.
+ */
+ if (id->parent_interface && id->parent_interface != 0) {
+ id->parent_interface =
+ get_new_index(fix_array, totalNumberOfInterfaces,
+ fix_array[i].file_num, id->parent_interface);
+ }
+ /* Iterate through the method descriptors looking for params of
+ * type TD_INTERFACE_TYPE.
+ */
+ for (j=0; j<id->num_methods; j++) {
+ /* Cycle through the params first.
+ */
+ for (k=0; k<id->method_descriptors[j].num_args; k++) {
+ /* Define td to save some keystrokes.
+ */
+ td = &id->method_descriptors[j].params[k].type;
+
+ while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
+ td = &id->additional_types[td->type.additional_type];
+ }
+
+ if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) {
+ td->type.iface =
+ get_new_index(fix_array,
+ totalNumberOfInterfaces,
+ fix_array[i].file_num,
+ td->type.iface);
+ }
+ }
+
+ /* Check the result param too. Define td again to save
+ * some keystrokes.
+ */
+ td = &id->method_descriptors[j].result->type;
+ if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) {
+ td->type.iface =
+ get_new_index(fix_array, totalNumberOfInterfaces,
+ fix_array[i].file_num,
+ td->type.iface);
+ }
+ }
+ }
+ }
+
+ /* Iterate through the array quickly looking for duplicate IIDS.
+ * This shouldn't happen, i.e. is a failure condition, so bail
+ * if we find a duplicate. If we have more than one entry, start
+ * at one so we don't accidentally grep the ether.
+ */
+ if (trueNumberOfInterfaces>1) {
+ for (i=1; i<trueNumberOfInterfaces; i++) {
+ /* Only complain if the IIDs are identical and nonzero. */
+ if (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0 &&
+ compare_IDE_with_zero(&IDE_array[i]) != 0) {
+ fprintf(stderr, "FATAL ERROR:\n"
+ "Duplicate IID detected (");
+ print_IID(&IDE_array[i-1].iid, stderr);
+ fprintf(stderr, ") in\n"
+ "interface %s::%s from %s\n"
+ "and\n"
+ "interface %s::%s from %s\n",
+ IDE_array[i-1].name_space ?
+ IDE_array[i-1].name_space : "",
+ IDE_array[i-1].name,
+ argv[fix_array[i-1].file_num+2],
+ IDE_array[i].name_space ?
+ IDE_array[i].name_space : "",
+ IDE_array[i].name,
+ argv[fix_array[i].file_num+2]);
+ return 1;
+ }
+ }
+ }
+
+ header = XPT_NewHeader(arena, (PRUint16)trueNumberOfInterfaces,
+ major_version, minor_version);
+
+ header->annotations = first_ann;
+ for (i=0; i<trueNumberOfInterfaces; i++) {
+ if (!copy_IDE(&IDE_array[i], &header->interface_directory[i])) {
+ perror("FAILED: 2nd copying of IDE");
+ return 1;
+ }
+ }
+
+ header_sz = XPT_SizeOfHeaderBlock(header);
+
+ state = XPT_NewXDRState(XPT_ENCODE, NULL, 0);
+ if (!state) {
+ perror("FAILED: error creating XDRState");
+ return 1;
+ }
+
+ XPT_SetDataOffset(state, header_sz);
+
+ if (!XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor)) {
+ perror("FAILED: error making cursor");
+ return 1;
+ }
+ oldOffset = cursor->offset;
+ if (!XPT_DoHeader(arena, cursor, &header)) {
+ perror("FAILED: error doing Header");
+ return 1;
+ }
+ newOffset = cursor->offset;
+ XPT_GetXDRDataLength(state, XPT_HEADER, &len);
+ header->file_length = len;
+ XPT_GetXDRDataLength(state, XPT_DATA, &len);
+ header->file_length += len;
+ XPT_SeekTo(cursor, oldOffset);
+ if (!XPT_DoHeaderPrologue(arena, cursor, &header, NULL)) {
+ perror("FAILED: error doing Header");
+ return 1;
+ }
+ XPT_SeekTo(cursor, newOffset);
+ out = fopen(outFileName, "wb");
+ if (!out) {
+ perror("FAILED: fopen");
+ return 1;
+ }
+
+ XPT_GetXDRData(state, XPT_HEADER, &head, &len);
+ fwrite(head, len, 1, out);
+
+ XPT_GetXDRData(state, XPT_DATA, &data, &len);
+ fwrite(data, len, 1, out);
+
+ if (ferror(out) != 0 || fclose(out) != 0) {
+ fprintf(stderr, "Error writing file: %s\n", argv[1]);
+ } else {
+/* fprintf(stderr, "File written: %s\n", argv[1]); */
+ }
+
+ if (state)
+ XPT_DestroyXDRState(state);
+
+ XPT_DestroyArena(arena);
+
+ return 0;
+}
+
+static int
+compare_IDEs_by_IID(const void *ap,
+ const void *bp)
+{
+ const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
+
+ int answer = compare_IIDs(&ide1->iid, &ide2->iid);
+ if(!answer)
+ answer = compare_strings(ide1->name, ide2->name);
+
+ return answer;
+}
+
+/* For detecting unresolved interfaces. */
+const nsID iid_zero = { 0x0, 0x0, 0x0,
+ { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
+
+static int
+compare_IDE_with_zero(const void *ap)
+{
+ const XPTInterfaceDirectoryEntry *ide1 = ap;
+
+ return compare_IIDs(&ide1->iid, &iid_zero);
+}
+
+static int
+compare_fixElements_by_IID(const void *ap,
+ const void *bp)
+{
+ const fixElement *fix1 = ap, *fix2 = bp;
+
+ int answer = compare_IIDs(&fix1->iid, &fix2->iid);
+ if(!answer)
+ answer = compare_strings(fix1->name, fix2->name);
+
+ return answer;
+}
+
+static int
+compare_IDEs_by_name(const void *ap,
+ const void *bp)
+{
+ const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
+
+ int answer = compare_strings(ide1->name, ide2->name);
+ if(!answer)
+ answer = compare_pointers(ide1->name, ide2->name);
+
+ return answer;
+}
+
+static int
+compare_IDEs_by_name_space(const void *ap,
+ const void *bp)
+{
+ const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
+
+ return compare_strings(ide1->name_space, ide2->name_space);
+}
+
+static int
+compare_strings(const void *ap, const void *bp)
+{
+ const char *string1 = ap, *string2 = bp;
+
+ if (!string1 && !string2)
+ return 0;
+ if (!string1)
+ return -1;
+ if (!string2)
+ return 1;
+
+ return strcmp(string1, string2);
+}
+
+static int
+compare_pointers(const void *ap, const void *bp)
+{
+ if (ap == bp) {
+#ifdef DEBUG_jband
+ perror("name addresses were equal!");
+#endif
+ return 0;
+ }
+ if (ap > bp)
+ return 1;
+ return -1;
+}
+
+static int
+compare_fixElements_by_name(const void *ap,
+ const void *bp)
+{
+ const fixElement *fix1 = ap, *fix2 = bp;
+
+ int answer= compare_strings(fix1->name, fix2->name);
+ if(!answer)
+ answer = compare_pointers(fix1->name, fix2->name);
+
+ return answer;
+}
+
+static int
+compare_IIDs(const void *ap, const void *bp)
+{
+ const nsID *a = ap, *b = bp;
+ int i;
+#define COMPARE(field) if (a->field > b->field) return 1; \
+ if (b->field > a->field) return -1;
+ COMPARE(m0);
+ COMPARE(m1);
+ COMPARE(m2);
+ for (i = 0; i < 8; i++) {
+ COMPARE(m3[i]);
+ }
+ return 0;
+#undef COMPARE
+}
+
+PRBool
+shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, int element_to_delete,
+ int num_interfaces)
+{
+ int i;
+
+ if (element_to_delete >= num_interfaces) {
+ return PR_FALSE;
+ }
+
+ for (i=element_to_delete+1; i<num_interfaces; i++) {
+ if (!copy_IDE(&ide[i], &ide[i-1])) {
+ return PR_FALSE;
+ }
+ }
+
+ return PR_TRUE;
+}
+
+/* update_fix_array marks a fixElement as deleted, updates its mapping
+ * to point to the "replacement" element, and moves it to the end of
+ * the array.
+ */
+PRBool
+update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete,
+ int num_interfaces, int replacement)
+{
+ fixElement *deleted;
+ int i;
+
+ if (element_to_delete >= num_interfaces) {
+ return PR_FALSE;
+ }
+
+ deleted = XPT_CALLOC(arena, sizeof(fixElement));
+ if (!copy_fixElement(&fix[element_to_delete], deleted)) {
+ return PR_FALSE;
+ }
+ deleted->is_deleted = PR_TRUE;
+ deleted->maps_to_file_num = fix[replacement].file_num;
+ deleted->maps_to_interface_num = fix[replacement].interface_num;
+
+ for (i=element_to_delete+1; i<num_interfaces; i++) {
+ if (!copy_fixElement(&fix[i], &fix[i-1])) {
+ return PR_FALSE;
+ }
+ }
+
+ if (!copy_fixElement(deleted, &fix[num_interfaces-1])) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* get_new_index returns the new interface index by walking the fix_array
+ * until the file_num and interface_num match the target values. If a match
+ * is found, it checks to see if that element has been deleted. If it has
+ * been deleted, it follows that elements mapping until it gets to the
+ * proper interface (recursion). FYI, Indices are one-based; zero
+ * represents the special case (no parent interface).
+ */
+static int
+get_new_index(const fixElement *fix, int num_elements,
+ int target_file, int target_interface)
+{
+ int i;
+
+ for (i=0; i<num_elements; i++) {
+ if (fix[i].file_num == target_file &&
+ fix[i].interface_num == target_interface) {
+ if (fix[i].is_deleted) {
+ return get_new_index(fix, num_elements,
+ fix[i].maps_to_file_num,
+ fix[i].maps_to_interface_num);
+ }
+ return i+1;
+ }
+ }
+
+ return 0;
+}
+
+PRBool
+copy_IDE(XPTInterfaceDirectoryEntry *from, XPTInterfaceDirectoryEntry *to)
+{
+ if (!from || !to) {
+ return PR_FALSE;
+ }
+
+ to->iid = from->iid;
+ to->name = from->name;
+ to->name_space = from->name_space;
+ to->interface_descriptor = from->interface_descriptor;
+ return PR_TRUE;
+}
+
+PRBool
+copy_fixElement(fixElement *from, fixElement *to)
+{
+ if (!from || !to) {
+ return PR_FALSE;
+ }
+
+ to->iid = from->iid;
+ to->name = from->name;
+ to->file_num = from->file_num;
+ to->interface_num = from->interface_num;
+ to->is_deleted = from->is_deleted;
+ to->maps_to_file_num = from->maps_to_file_num;
+ to->maps_to_interface_num = from->maps_to_interface_num;
+
+ return PR_TRUE;
+}
+
+static void
+print_IID(struct nsID *iid, FILE *file)
+{
+ fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2,
+ (PRUint32) iid->m3[0], (PRUint32) iid->m3[1],
+ (PRUint32) iid->m3[2], (PRUint32) iid->m3[3],
+ (PRUint32) iid->m3[4], (PRUint32) iid->m3[5],
+ (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]);
+}
+
+static void
+xpt_link_usage(char *argv[])
+{
+ fprintf(stdout, "Usage: %s [-t version number] outfile file1.xpt file2.xpt ...\n"
+ " Links multiple typelib files into one outfile\n"
+ " -t create a typelib of an older version number\n", argv[0]);
+}
+