Back to index

lightning-sunbird  0.9+nobinonly
xpt_link.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * A utility for linking multiple typelib files. 
00040  */ 
00041 
00042 #include "xpt_xdr.h"
00043 #include <stdio.h>
00044 #ifdef XP_MAC
00045 #include <stat.h>
00046 #else
00047 #include <sys/stat.h>
00048 #endif
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include "prlong.h"
00052 
00053 #ifndef NULL
00054 #define NULL (void *) 0
00055 #endif
00056 
00057 /* Forward declarations. */
00058 typedef struct fixElement fixElement;
00059 static int compare_IDEs_by_IID(const void *ap, const void *bp);
00060 static int compare_IDE_with_zero(const void *ap);
00061 static int compare_IDEs_by_name(const void *ap, const void *bp);
00062 static int compare_IDEs_by_name_space(const void *ap, const void *bp);
00063 static int compare_strings(const void *ap, const void *bp);
00064 static int compare_pointers(const void *ap, const void *bp);
00065 static int compare_fixElements_by_IID(const void *ap, const void *bp);
00066 static int compare_fixElements_by_name(const void *ap, const void *bp);
00067 static int compare_IIDs(const void *ap, const void *bp);
00068 PRBool shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, 
00069                         int element_to_delete, int num_interfaces);
00070 PRBool update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete, 
00071                         int num_interfaces, int replacement); 
00072 static int get_new_index(const fixElement *fix, int num_elements,
00073                          int target_file, int target_interface);
00074 PRBool copy_IDE(XPTInterfaceDirectoryEntry *from, 
00075                 XPTInterfaceDirectoryEntry *to);
00076 PRBool copy_fixElement(fixElement *from, fixElement *to);
00077 static void print_IID(struct nsID *iid, FILE *file);
00078 static void xpt_link_usage(char *argv[]);
00079 
00080 struct fixElement {
00081     nsID iid;
00082     char* name;
00083     int file_num;
00084     int interface_num;
00085     PRBool is_deleted;
00086     /* These next two variables will point you to the substitute interface
00087      * if this one has been deleted.
00088      */
00089     int maps_to_file_num;
00090     int maps_to_interface_num;
00091 };
00092 
00093 /* Global variables. */
00094 PRUint16 trueNumberOfInterfaces = 0;
00095 PRUint16 totalNumberOfInterfaces = 0;
00096 PRUint16 oldTotalNumberOfInterfaces = 0;
00097 
00098 /* The following globals are explained in xpt_struct.h */
00099 PRUint8 major_version     = XPT_MAJOR_VERSION;
00100 PRUint8 minor_version     = XPT_MINOR_VERSION;
00101 
00102 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
00103 
00104 #define main xptlink_main
00105 int xptlink_main(int argc, char *argv[]);
00106 extern size_t mac_get_file_length(const char* filename);
00107 #define get_file_length mac_get_file_length
00108 
00109 #else
00110 
00111 static size_t get_file_length(const char* filename)
00112 {
00113     struct stat file_stat;
00114     if (stat(filename, &file_stat) != 0) {
00115         perror("FAILED: get_file_length");
00116         exit(1);
00117     }
00118     return file_stat.st_size;
00119 }
00120 
00121 #endif /* XP_MAC && XPIDL_PLUGIN */
00122 
00123 int 
00124 main(int argc, char **argv)
00125 {
00126     #ifdef XP_OS2   /* Shell does not expand wildcards on OS/2, doesn't work with OW */
00127     _wildcard (&argc, &argv);
00128     #endif
00129 
00130     XPTArena *arena;
00131     XPTState *state;
00132     XPTCursor curs, *cursor = &curs;
00133     XPTHeader *header;
00134     XPTInterfaceDirectoryEntry *IDE_array = NULL;
00135     XPTInterfaceDescriptor *id;
00136     XPTTypeDescriptor *td;
00137     XPTAnnotation *ann, *first_ann;
00138     PRUint32 header_sz, len;
00139     PRUint32 oldOffset;
00140     PRUint32 newOffset;
00141     size_t flen = 0;
00142     char *head, *data, *whole;
00143     const char *outFileName;
00144     FILE *in, *out;
00145     fixElement *fix_array = NULL;
00146     int i,j;
00147     int k = 0;
00148 
00149     if (argc < 3) {
00150         xpt_link_usage(argv);
00151         return 1;
00152     }
00153         
00154     arena = XPT_NewArena(1024 * 10, sizeof(double), "main xpt_link arena");
00155     if (!arena) {
00156         perror("FAILED: XPT_NewArena");
00157         return 1;
00158     }
00159 
00160     first_ann = XPT_NewAnnotation(arena, XPT_ANN_LAST, NULL, NULL);
00161 
00162     /* Check if the "-t version numnber" cmd line arg is present */
00163     i = 1;
00164     if (argv[i][0] == '-' && argv[i][1] == 't') {
00165         /* Parse for "-t version number" */
00166 
00167         /* If -t is the last argument on the command line, we have a problem */
00168         if (i + 1 == argc) {
00169             fprintf(stderr, "ERROR: missing version number after -t\n");
00170             xpt_link_usage(argv);
00171             return 1;
00172         }
00173 
00174         /*
00175          * Assume that the argument after "-t" is the version number string
00176          * and search for it in our internal list of acceptable version
00177          * numbers.
00178          */
00179 
00180         switch (XPT_ParseVersionString(argv[++i], &major_version, 
00181                                        &minor_version)) {
00182           case XPT_VERSION_CURRENT:            
00183           case XPT_VERSION_OLD: 
00184             break; 
00185           case XPT_VERSION_UNSUPPORTED: 
00186             fprintf(stderr, "ERROR: version \"%s\" not supported.\n", 
00187                     argv[i]);
00188             xpt_link_usage(argv);
00189             return 1;          
00190           case XPT_VERSION_UNKNOWN: 
00191           default:
00192             fprintf(stderr, "ERROR: version \"%s\" not recognised.\n", 
00193                     argv[i]);
00194             xpt_link_usage(argv);
00195             return 1;          
00196         }
00197             
00198         /* Hang onto the output file name. It's needed later. */
00199         outFileName = argv[++i];
00200 
00201         /* Increment i to the cmd line arg after outFileName */
00202         i++;
00203     }
00204     else {        
00205         outFileName = argv[1];
00206         i = 2;
00207     }
00208 
00209     for ( /* use i from earlier */ ; i < argc; i++) {
00210         char *name = argv[i];
00211 
00212         flen = get_file_length(name);
00213         if (!flen) {
00214             fprintf(stderr, "ERROR: file %s is zero length\n", name);
00215             return 1;
00216         }
00217 
00218         in = fopen(name, "rb");
00219         if (!in) {
00220             perror("FAILED: fopen");
00221             return 1;
00222         }
00223 
00224         whole = XPT_MALLOC(arena, flen);
00225         if (!whole) {
00226             perror("FAILED: XPT_MALLOC for whole");
00227             return 1;
00228         }
00229         
00230         if (flen > 0) {
00231             size_t rv = fread(whole, 1, flen, in);
00232             if (rv < flen) {
00233                 fprintf(stderr, "short read (%d vs %d)! ouch!\n", rv, flen);
00234                 return 1;
00235             }
00236             if (ferror(in) != 0 || fclose(in) != 0) {
00237                 perror("FAILED: Unable to read typelib file.\n");
00238                 return 1;
00239             }
00240             
00241             state = XPT_NewXDRState(XPT_DECODE, whole, flen);
00242             if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) {
00243                 fprintf(stdout, "XPT_MakeCursor failed for %s\n", name);
00244                 return 1;
00245             }
00246             if (!XPT_DoHeader(arena, cursor, &header)) {
00247                 fprintf(stdout,
00248                         "DoHeader failed for %s.  Is %s a valid .xpt file?\n",
00249                         name, name);
00250                 return 1;
00251             }
00252             
00253             /*
00254              * Make sure that the version of the typelib file is less than or
00255              * equal to the version specified in the -t cmd line arg.
00256              */
00257 
00258             if (header &&
00259                 (header->major_version > major_version ||
00260                 (header->major_version == major_version &&
00261                  header->minor_version > minor_version))) { 
00262                 fprintf(stderr, "FAILED: %s's version, %d.%d, is newer than "
00263                                 "the version (%d.%d) specified in the -t "
00264                                 "command line argument.\n", 
00265                                 name, header->major_version, header->minor_version,
00266                                 major_version, minor_version);
00267                 return 1;
00268             }
00269             
00270             oldTotalNumberOfInterfaces = totalNumberOfInterfaces;
00271             totalNumberOfInterfaces += header->num_interfaces;
00272             if (header->num_interfaces > 0) {
00273                 XPTInterfaceDirectoryEntry *newIDE;
00274                 fixElement *newFix;
00275   
00276                 newIDE = (XPTInterfaceDirectoryEntry *)
00277                     XPT_MALLOC(arena, totalNumberOfInterfaces * 
00278                                sizeof(XPTInterfaceDirectoryEntry));
00279                 if (!newIDE) {
00280                     perror("FAILED: XPT_MALLOC of IDE_array");
00281                     return 1;
00282                 }
00283 
00284                 if (IDE_array) {
00285                     if (oldTotalNumberOfInterfaces)
00286                         memcpy(newIDE, IDE_array,
00287                                oldTotalNumberOfInterfaces * 
00288                                sizeof(XPTInterfaceDirectoryEntry));
00289                     XPT_FREE(arena, IDE_array);
00290                 }
00291                 IDE_array = newIDE;
00292 
00293 
00294                 newFix = (fixElement *)
00295                     XPT_MALLOC(arena, 
00296                                totalNumberOfInterfaces * sizeof(fixElement));
00297                 if (!newFix) {
00298                     perror("FAILED: XPT_MALLOC of fix_array");
00299                     return 1;
00300                 }
00301 
00302                 if (fix_array) {
00303                     if (oldTotalNumberOfInterfaces)
00304                         memcpy(newFix, fix_array,
00305                                oldTotalNumberOfInterfaces * 
00306                                sizeof(fixElement));
00307                     XPT_FREE(arena, fix_array);
00308                 }
00309                 fix_array = newFix;
00310             
00311                 for (j=0; j<header->num_interfaces; j++) {
00312                     if (!copy_IDE(&header->interface_directory[j], 
00313                                   &IDE_array[k])) {
00314                         perror("FAILED: 1st copying of IDE");
00315                         return 1;
00316                     }
00317                     fix_array[k].iid = IDE_array[k].iid;
00318                     fix_array[k].name = IDE_array[k].name;
00319                     fix_array[k].file_num = i-2;
00320                     fix_array[k].interface_num = j+1;
00321                     fix_array[k].is_deleted = PR_FALSE;
00322                     fix_array[k].maps_to_file_num = i-2;
00323                     fix_array[k].maps_to_interface_num = j+1;
00324 
00325                     k++;
00326                 }
00327             }
00328             
00329             /* Copy the annotations if they are not 'empty'
00330              */
00331             if (header->annotations != NULL &&
00332                 header->annotations->flags != XPT_ANN_LAST) {
00333                 ann = first_ann;
00334                 while (ann->next != NULL) {
00335                     ann = ann->next;
00336                 }
00337                 ann->next = header->annotations;
00338             }
00339             
00340             XPT_FREEIF(arena, header);
00341             if (state)
00342                 XPT_DestroyXDRState(state);
00343             XPT_FREE(arena, whole);
00344             flen = 0;            
00345 
00346         } else {
00347             fclose(in);
00348             perror("FAILED: file length <= 0");
00349             return 1;
00350         }
00351     }
00352 
00353     /* Make sure the last annotation is the only one marked as XP_ANN_LAST.
00354      */
00355     ann = first_ann;
00356     while (ann->next != NULL) {
00357         ann->flags &= ~XPT_ANN_LAST;
00358         ann = ann->next;
00359     }    
00360     ann->flags |= XPT_ANN_LAST;
00361 
00362     /* Sort both IDE_array and fix_array by name so we can check for 
00363      * name_space::name collisions. 
00364      */
00365     qsort(IDE_array, 
00366           totalNumberOfInterfaces, 
00367           sizeof(XPTInterfaceDirectoryEntry), 
00368           compare_IDEs_by_name);
00369 
00370     qsort(fix_array, 
00371           totalNumberOfInterfaces, 
00372           sizeof(fixElement), 
00373           compare_fixElements_by_name);
00374 
00375     /* trueNumberOfInterfaces == number of interfaces left after deletions
00376      * are made. Initialize it here to be the same as the total number of
00377      * interfaces we'ce encountered thus far.
00378      */
00379     trueNumberOfInterfaces = totalNumberOfInterfaces;
00380 
00381     /* Iterate through the sorted interfaces. Start at one so we don't 
00382      * accidentally walk off the end of the array.
00383      */
00384     i = 1;
00385     while (i != trueNumberOfInterfaces) {
00386         
00387         /* Check for name_space::name collision. 
00388          */
00389         if (compare_strings(IDE_array[i-1].name, 
00390                             IDE_array[i].name) == 0 && 
00391             compare_strings(IDE_array[i-1].name_space, 
00392                              IDE_array[i].name_space) == 0) {
00393             
00394             /* If one of the interfaces is unresolved, delete that one 
00395              * preferentailly.
00396              */
00397             if (!IDE_array[i-1].interface_descriptor) {
00398                 /* Shrink the IDE_array to delete the duplicate interface.
00399                  */
00400                 if (!shrink_IDE_array(IDE_array, 
00401                                       i-1, 
00402                                       trueNumberOfInterfaces)) {
00403                     perror("FAILED: shrink_IDE_array");
00404                     return 1;
00405                 }
00406                 /* Update the fix array. This involves moving the deleted 
00407                  * entry to the end of the array (rather than deleting it)
00408                  * and mapping it to the "replacement" element so we can
00409                  * update interface indices appropriately later.
00410                  */
00411                 update_fix_array(arena, fix_array, i-1, 
00412                                  totalNumberOfInterfaces, i);
00413                 /* Decrement the true number of interfaces since we just
00414                  * deleted one. There's more than one way to get out of
00415                  * this loop.
00416                  */
00417                 trueNumberOfInterfaces--;
00418             } else {
00419                 if (!IDE_array[i].interface_descriptor ||
00420                     (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0))
00421                 {
00422                     /* Shrink the IDE_array to delete the duplicate interface.
00423                      */
00424                     if (!shrink_IDE_array(IDE_array, 
00425                                           i, 
00426                                           trueNumberOfInterfaces)) {
00427                         perror("FAILED: shrink_IDE_array");
00428                         return 1;
00429                     }
00430                     /* Update the fix array. This involves moving the deleted 
00431                      * entry to the end of the array (rather than deleting it)
00432                      * and mapping it to the "replacement" element so we can
00433                      * update interface indices appropriately later.
00434                      */
00435                     update_fix_array(arena, fix_array, i, 
00436                                      totalNumberOfInterfaces, i-1);
00437                     /* Decrement the true number of interfaces since we just
00438                      * deleted one. There's more than one way to get out of
00439                      * this loop.
00440                      */
00441                     trueNumberOfInterfaces--;
00442                 } else {
00443                     /* Found interfaces with duplicate names but different
00444                      * iids! */
00445                     char *ns = IDE_array[i].name_space;
00446                     fprintf(stderr,
00447                             "ERROR: found duplicate definitions of interface "
00448                             "%s%s%s with iids \n",
00449                             ns ? ns : "", ns ? "::" : "", IDE_array[i].name);
00450                     print_IID(&IDE_array[i].iid, stderr);
00451                     fprintf(stderr, " and ");
00452                     print_IID(&IDE_array[i-1].iid, stderr);
00453                     fprintf(stderr, "\n");
00454                     return 1;
00455                 }
00456             }
00457         } else {
00458             /* Only increment if there was no name_space::name collision.
00459              */
00460             i++;
00461         }
00462     }
00463 
00464     /* Sort the IDE_array (put them in their final order) so that updating
00465      * of indices will be meaningful.
00466      */
00467     qsort(IDE_array, 
00468           trueNumberOfInterfaces, 
00469           sizeof(XPTInterfaceDirectoryEntry), 
00470           compare_IDEs_by_IID);
00471 
00472     /* Sort the fix_array to match the IDE_array. 
00473      */
00474     qsort(fix_array, 
00475           trueNumberOfInterfaces, 
00476           sizeof(fixElement), 
00477           compare_fixElements_by_IID);
00478 
00479     /* Iterate through the remaining interfaces (those not deleted) 
00480      * looking for references to interfaces (such as id->parent_interface)
00481      * which need an updated index number.
00482      */
00483     for (i=0; i<trueNumberOfInterfaces; i++) {
00484         
00485         /* Define id to save some keystrokes.
00486          */
00487         id = IDE_array[i].interface_descriptor;
00488 
00489         /* Check for unresolved interface.
00490          */
00491         if (id) {
00492             
00493             /* Fix parent_interface first.
00494              */
00495             if (id->parent_interface && id->parent_interface != 0) {
00496                 id->parent_interface = 
00497                     get_new_index(fix_array, totalNumberOfInterfaces,
00498                                   fix_array[i].file_num, id->parent_interface);
00499             }
00500             /* Iterate through the method descriptors looking for params of
00501              * type TD_INTERFACE_TYPE.
00502              */
00503             for (j=0; j<id->num_methods; j++) {
00504                 /* Cycle through the params first.
00505                  */
00506                 for (k=0; k<id->method_descriptors[j].num_args; k++) {
00507                     /* Define td to save some keystrokes.
00508                      */
00509                     td = &id->method_descriptors[j].params[k].type;
00510 
00511                     while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
00512                         td = &id->additional_types[td->type.additional_type];
00513                     }
00514 
00515                     if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) {
00516                         td->type.iface = 
00517                             get_new_index(fix_array, 
00518                                           totalNumberOfInterfaces,
00519                                           fix_array[i].file_num, 
00520                                           td->type.iface);
00521                     }                                                
00522                 }
00523 
00524                 /* Check the result param too. Define td again to save 
00525                  * some keystrokes.
00526                  */
00527                 td = &id->method_descriptors[j].result->type;
00528                 if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) {
00529                     td->type.iface = 
00530                         get_new_index(fix_array, totalNumberOfInterfaces,
00531                                       fix_array[i].file_num, 
00532                                       td->type.iface);
00533                 }                
00534             }
00535         } 
00536     }
00537     
00538     /* Iterate through the array quickly looking for duplicate IIDS.
00539      * This shouldn't happen, i.e. is a failure condition, so bail
00540      * if we find a duplicate. If we have more than one entry, start 
00541      * at one so we don't accidentally grep the ether.
00542      */
00543     if (trueNumberOfInterfaces>1) {
00544         for (i=1; i<trueNumberOfInterfaces; i++) {
00545             /* Only complain if the IIDs are identical and nonzero. */
00546             if (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0 && 
00547                 compare_IDE_with_zero(&IDE_array[i]) != 0) {
00548                 fprintf(stderr, "FATAL ERROR:\n"
00549                         "Duplicate IID detected (");
00550                 print_IID(&IDE_array[i-1].iid, stderr);
00551                 fprintf(stderr, ") in\n"
00552                         "interface %s::%s from %s\n"
00553                         "and\n" 
00554                         "interface %s::%s from %s\n",
00555                         IDE_array[i-1].name_space ? 
00556                         IDE_array[i-1].name_space : "", 
00557                         IDE_array[i-1].name, 
00558                         argv[fix_array[i-1].file_num+2],
00559                         IDE_array[i].name_space ? 
00560                         IDE_array[i].name_space : "", 
00561                         IDE_array[i].name, 
00562                         argv[fix_array[i].file_num+2]);
00563                 return 1;
00564             }
00565         }
00566     }
00567 
00568     header = XPT_NewHeader(arena, (PRUint16)trueNumberOfInterfaces, 
00569                            major_version, minor_version);
00570 
00571     header->annotations = first_ann;
00572     for (i=0; i<trueNumberOfInterfaces; i++) {
00573         if (!copy_IDE(&IDE_array[i], &header->interface_directory[i])) {
00574             perror("FAILED: 2nd copying of IDE");
00575             return 1;
00576         }
00577     }
00578     
00579     header_sz = XPT_SizeOfHeaderBlock(header); 
00580 
00581     state = XPT_NewXDRState(XPT_ENCODE, NULL, 0);
00582     if (!state) {
00583         perror("FAILED: error creating XDRState");
00584         return 1;
00585     }
00586     
00587     XPT_SetDataOffset(state, header_sz);
00588 
00589     if (!XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor)) {
00590         perror("FAILED: error making cursor");
00591         return 1;
00592     }
00593     oldOffset = cursor->offset;
00594     if (!XPT_DoHeader(arena, cursor, &header)) {
00595         perror("FAILED: error doing Header");
00596         return 1;
00597     }
00598     newOffset = cursor->offset;
00599     XPT_GetXDRDataLength(state, XPT_HEADER, &len);
00600     header->file_length = len;
00601     XPT_GetXDRDataLength(state, XPT_DATA, &len);
00602     header->file_length += len;
00603     XPT_SeekTo(cursor, oldOffset);
00604     if (!XPT_DoHeaderPrologue(arena, cursor, &header, NULL)) {
00605         perror("FAILED: error doing Header");
00606         return 1;
00607     }
00608     XPT_SeekTo(cursor, newOffset);
00609     out = fopen(outFileName, "wb");
00610     if (!out) {
00611         perror("FAILED: fopen");
00612         return 1;
00613     }
00614 
00615     XPT_GetXDRData(state, XPT_HEADER, &head, &len);
00616     fwrite(head, len, 1, out);
00617  
00618     XPT_GetXDRData(state, XPT_DATA, &data, &len);
00619     fwrite(data, len, 1, out);
00620  
00621     if (ferror(out) != 0 || fclose(out) != 0) {
00622         fprintf(stderr, "Error writing file: %s\n", argv[1]);
00623     } else {
00624 /*        fprintf(stderr, "File written: %s\n", argv[1]); */
00625     }
00626  
00627     if (state)
00628         XPT_DestroyXDRState(state);
00629     
00630     XPT_DestroyArena(arena);
00631 
00632     return 0;        
00633 }
00634 
00635 static int 
00636 compare_IDEs_by_IID(const void *ap,
00637                     const void *bp)
00638 {
00639     const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
00640     
00641     int answer = compare_IIDs(&ide1->iid, &ide2->iid);
00642     if(!answer)
00643         answer = compare_strings(ide1->name, ide2->name);
00644 
00645     return answer;
00646 }  
00647 
00648 /* For detecting unresolved interfaces. */
00649 const nsID iid_zero = { 0x0, 0x0, 0x0,
00650                         { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
00651 
00652 static int
00653 compare_IDE_with_zero(const void *ap)
00654 {
00655     const XPTInterfaceDirectoryEntry *ide1 = ap;
00656 
00657     return compare_IIDs(&ide1->iid, &iid_zero);
00658 }
00659 
00660 static int 
00661 compare_fixElements_by_IID(const void *ap,
00662                            const void *bp)
00663 {
00664     const fixElement *fix1 = ap, *fix2 = bp;
00665     
00666     int answer = compare_IIDs(&fix1->iid, &fix2->iid);
00667     if(!answer)
00668         answer = compare_strings(fix1->name, fix2->name);
00669 
00670     return answer;
00671 }  
00672 
00673 static int 
00674 compare_IDEs_by_name(const void *ap,
00675                      const void *bp)
00676 {
00677     const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
00678 
00679     int answer = compare_strings(ide1->name, ide2->name);
00680     if(!answer)
00681         answer = compare_pointers(ide1->name, ide2->name);
00682 
00683     return answer;
00684 }
00685 
00686 static int 
00687 compare_IDEs_by_name_space(const void *ap,
00688                            const void *bp)
00689 {
00690     const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp;
00691     
00692     return compare_strings(ide1->name_space, ide2->name_space);
00693 }
00694 
00695 static int 
00696 compare_strings(const void *ap, const void *bp)
00697 {
00698     const char *string1 = ap, *string2 = bp;
00699 
00700     if (!string1 && !string2)
00701         return 0;
00702     if (!string1)
00703         return -1;
00704     if (!string2)
00705         return 1;
00706 
00707     return strcmp(string1, string2);    
00708 }     
00709 
00710 static int 
00711 compare_pointers(const void *ap, const void *bp)
00712 {
00713     if (ap == bp) {
00714 #ifdef DEBUG_jband
00715         perror("name addresses were equal!");
00716 #endif
00717         return 0;
00718     }
00719     if (ap > bp)
00720         return 1;
00721     return -1;
00722 }        
00723 
00724 static int 
00725 compare_fixElements_by_name(const void *ap,
00726                             const void *bp)
00727 {
00728     const fixElement *fix1 = ap, *fix2 = bp;
00729 
00730     int answer= compare_strings(fix1->name, fix2->name);
00731     if(!answer)
00732         answer = compare_pointers(fix1->name, fix2->name);
00733 
00734     return answer;
00735 }
00736 
00737 static int
00738 compare_IIDs(const void *ap, const void *bp)
00739 {
00740     const nsID *a = ap, *b = bp;
00741     int i;
00742 #define COMPARE(field) if (a->field > b->field) return 1; \
00743                        if (b->field > a->field) return -1;
00744     COMPARE(m0);
00745     COMPARE(m1);
00746     COMPARE(m2);
00747     for (i = 0; i < 8; i++) {
00748         COMPARE(m3[i]);
00749     }
00750     return 0;
00751 #undef COMPARE
00752 }
00753 
00754 PRBool 
00755 shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, int element_to_delete,
00756                     int num_interfaces)
00757 {
00758     int i;
00759 
00760     if (element_to_delete >= num_interfaces) {
00761         return PR_FALSE;
00762     }
00763 
00764     for (i=element_to_delete+1; i<num_interfaces; i++) {
00765         if (!copy_IDE(&ide[i], &ide[i-1])) {
00766             return PR_FALSE;
00767         }
00768     }
00769 
00770     return PR_TRUE;
00771 }
00772 
00773 /* update_fix_array marks a fixElement as deleted, updates its mapping 
00774  * to point to the "replacement" element, and moves it to the end of 
00775  * the array.
00776  */
00777 PRBool 
00778 update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete, 
00779                  int num_interfaces, int replacement) 
00780 {
00781     fixElement *deleted;
00782     int i;  
00783 
00784     if (element_to_delete >= num_interfaces) {
00785         return PR_FALSE;
00786     }
00787 
00788     deleted = XPT_CALLOC(arena, sizeof(fixElement));
00789     if (!copy_fixElement(&fix[element_to_delete], deleted)) {
00790         return PR_FALSE;
00791     }
00792     deleted->is_deleted = PR_TRUE;
00793     deleted->maps_to_file_num = fix[replacement].file_num;
00794     deleted->maps_to_interface_num = fix[replacement].interface_num;
00795     
00796     for (i=element_to_delete+1; i<num_interfaces; i++) {
00797         if (!copy_fixElement(&fix[i], &fix[i-1])) {
00798             return PR_FALSE;
00799         }
00800     }
00801 
00802     if (!copy_fixElement(deleted, &fix[num_interfaces-1])) {
00803         return PR_FALSE;
00804     }
00805     
00806     return PR_TRUE;
00807 }
00808 
00809 /* get_new_index returns the new interface index by walking the fix_array
00810  * until the file_num and interface_num match the target values. If a match
00811  * is found, it checks to see if that element has been deleted. If it has 
00812  * been deleted, it follows that elements mapping until it gets to the 
00813  * proper interface (recursion). FYI, Indices are one-based; zero 
00814  * represents the special case (no parent interface). 
00815  */
00816 static int 
00817 get_new_index(const fixElement *fix, int num_elements, 
00818               int target_file, int target_interface) 
00819 {
00820     int i;
00821     
00822     for (i=0; i<num_elements; i++) { 
00823         if (fix[i].file_num == target_file &&
00824             fix[i].interface_num == target_interface) {
00825             if (fix[i].is_deleted) {
00826                 return get_new_index(fix, num_elements, 
00827                                      fix[i].maps_to_file_num,
00828                                      fix[i].maps_to_interface_num);
00829             }
00830             return i+1;
00831         }
00832     }
00833     
00834     return 0;
00835 }
00836 
00837 PRBool
00838 copy_IDE(XPTInterfaceDirectoryEntry *from, XPTInterfaceDirectoryEntry *to) 
00839 {
00840     if (!from || !to) {
00841         return PR_FALSE;
00842     }
00843     
00844     to->iid = from->iid;
00845     to->name = from->name;
00846     to->name_space = from->name_space;
00847     to->interface_descriptor = from->interface_descriptor;
00848     return PR_TRUE;
00849 }
00850 
00851 PRBool
00852 copy_fixElement(fixElement *from, fixElement *to)
00853 {
00854     if (!from || !to) {
00855         return PR_FALSE;
00856     }
00857 
00858     to->iid = from->iid;
00859     to->name = from->name;
00860     to->file_num = from->file_num;
00861     to->interface_num = from->interface_num;
00862     to->is_deleted = from->is_deleted;
00863     to->maps_to_file_num = from->maps_to_file_num;
00864     to->maps_to_interface_num = from->maps_to_interface_num;
00865 
00866     return PR_TRUE;    
00867 }
00868 
00869 static void
00870 print_IID(struct nsID *iid, FILE *file)
00871 {
00872     fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
00873             (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2,
00874             (PRUint32) iid->m3[0], (PRUint32) iid->m3[1],
00875             (PRUint32) iid->m3[2], (PRUint32) iid->m3[3],
00876             (PRUint32) iid->m3[4], (PRUint32) iid->m3[5],
00877             (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]); 
00878 }
00879 
00880 static void
00881 xpt_link_usage(char *argv[]) 
00882 {
00883     fprintf(stdout, "Usage: %s [-t version number] outfile file1.xpt file2.xpt ...\n"
00884             "       Links multiple typelib files into one outfile\n"
00885             "       -t create a typelib of an older version number\n", argv[0]);
00886 }
00887