Back to index

lightning-sunbird  0.9+nobinonly
xpt_struct.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 /* Implementation of XDR routines for typelib structures. */
00039 
00040 #include "xpt_xdr.h"
00041 #include "xpt_struct.h"
00042 #include <string.h>
00043 #include <stdio.h>
00044 
00045 /***************************************************************************/
00046 /* Forward declarations. */
00047 
00048 static PRUint32
00049 SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id);
00050 
00051 static PRUint32
00052 SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id);
00053 
00054 static PRUint32
00055 SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id);
00056 
00057 static PRUint32
00058 SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id);
00059 
00060 static PRBool
00061 DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor,
00062                           XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index);
00063 
00064 static PRBool
00065 DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd,
00066                   XPTInterfaceDescriptor *id);
00067 
00068 static PRBool
00069 DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md, 
00070                    XPTInterfaceDescriptor *id);
00071 
00072 static PRBool
00073 DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp);
00074 
00075 static PRBool
00076 DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, XPTInterfaceDescriptor **idp);
00077 
00078 static PRBool
00079 DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp);
00080 
00081 static PRBool
00082 DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td,
00083                  XPTInterfaceDescriptor *id);
00084 
00085 static PRBool
00086 DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd,
00087                   XPTInterfaceDescriptor *id);
00088 
00089 /***************************************************************************/
00090 
00091 XPT_PUBLIC_API(PRUint32)
00092 XPT_SizeOfHeader(XPTHeader *header)
00093 {
00094     XPTAnnotation *ann, *last;
00095     PRUint32 size = 16 /* magic */ +
00096         1 /* major */ + 1 /* minor */ +
00097         2 /* num_interfaces */ + 4 /* file_length */ +
00098         4 /* interface_directory */ + 4 /* data_pool */;
00099 
00100     ann = header->annotations;
00101     do {
00102         size += 1; /* Annotation prefix */
00103         if (XPT_ANN_IS_PRIVATE(ann->flags))
00104             size += 2 + ann->creator->length + 2 + ann->private_data->length;
00105         last = ann;
00106         ann = ann->next;
00107     } while (!XPT_ANN_IS_LAST(last->flags));
00108         
00109     return size;
00110 }
00111 
00112 XPT_PUBLIC_API(PRUint32)
00113 XPT_SizeOfHeaderBlock(XPTHeader *header)
00114 {
00115     PRUint32 size = XPT_SizeOfHeader(header);
00116 
00117     size += header->num_interfaces * sizeof (XPTInterfaceDirectoryEntry);
00118 
00119     return size;
00120 }
00121 
00122 XPT_PUBLIC_API(XPTHeader *)
00123 XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, PRUint8 major_version, PRUint8 minor_version)
00124 {
00125     XPTHeader *header = XPT_NEWZAP(arena, XPTHeader);
00126     if (!header)
00127         return NULL;
00128     memcpy(header->magic, XPT_MAGIC, 16);
00129     header->major_version = major_version;
00130     header->minor_version = minor_version;
00131     header->num_interfaces = num_interfaces;
00132     if (num_interfaces) {
00133         header->interface_directory = 
00134             XPT_CALLOC(arena, 
00135                        num_interfaces * sizeof(XPTInterfaceDirectoryEntry));
00136         if (!header->interface_directory) {
00137             XPT_DELETE(arena, header);
00138             return NULL;
00139         }
00140     }
00141     header->data_pool = 0;      /* XXX do we even need this struct any more? */
00142     
00143     return header;
00144 }
00145 
00146 XPT_PUBLIC_API(void)
00147 XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader)
00148 {
00149     if (aHeader) {
00150         XPTAnnotation* ann;
00151         XPTInterfaceDirectoryEntry* entry = aHeader->interface_directory;
00152         XPTInterfaceDirectoryEntry* end = entry + aHeader->num_interfaces;
00153         for (; entry < end; entry++) {
00154             XPT_DestroyInterfaceDirectoryEntry(arena, entry);
00155         }
00156 
00157         ann = aHeader->annotations;
00158         while (ann) {
00159             XPTAnnotation* next = ann->next;
00160             if (XPT_ANN_IS_PRIVATE(ann->flags)) {
00161                 XPT_FREEIF(arena, ann->creator);
00162                 XPT_FREEIF(arena, ann->private_data);
00163             }
00164             XPT_DELETE(arena, ann);
00165             ann = next;
00166         }
00167 
00168         XPT_FREEIF(arena, aHeader->interface_directory);
00169         XPT_DELETE(arena, aHeader);
00170     }
00171 }
00172 
00173 XPT_PUBLIC_API(PRBool)
00174 XPT_DoHeaderPrologue(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp, PRUint32 * ide_offset)
00175 {
00176     XPTMode mode = cursor->state->mode;
00177     unsigned int i;
00178     XPTHeader * header;
00179 
00180     if (mode == XPT_DECODE) {
00181         header = XPT_NEWZAP(arena, XPTHeader);
00182         if (!header)
00183             return PR_FALSE;
00184         *headerp = header;
00185     } else {
00186         header = *headerp;
00187     }
00188 
00189     if (mode == XPT_ENCODE) {
00190         /* IDEs appear after header, including annotations */
00191         if (ide_offset != NULL)
00192         {
00193             *ide_offset = XPT_SizeOfHeader(*headerp) + 1; /* one-based offset */
00194         }
00195         header->data_pool = XPT_SizeOfHeaderBlock(*headerp);
00196         XPT_SetDataOffset(cursor->state, header->data_pool);
00197     }
00198 
00199     for (i = 0; i < sizeof(header->magic); i++) {
00200         if (!XPT_Do8(cursor, &header->magic[i]))
00201             goto error;
00202     }
00203 
00204     if (mode == XPT_DECODE && 
00205         strncmp((const char*)header->magic, XPT_MAGIC, 16) != 0)
00206     {
00207         /* Require that the header contain the proper magic */
00208         fprintf(stderr,
00209                 "libxpt: bad magic header in input file; "
00210                 "found '%s', expected '%s'\n",
00211                 header->magic, XPT_MAGIC_STRING);
00212         goto error;
00213     }
00214     
00215     if (!XPT_Do8(cursor, &header->major_version) ||
00216         !XPT_Do8(cursor, &header->minor_version)) {
00217         goto error;
00218     }
00219 
00220     if (mode == XPT_DECODE &&
00221         header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
00222         /* This file is newer than we are and set to an incompatible version
00223          * number. We must set the header state thusly and return.
00224          */
00225         header->num_interfaces = 0;
00226         header->file_length = 0;
00227         return PR_TRUE;
00228     }
00229 
00230     if (!XPT_Do16(cursor, &header->num_interfaces) ||
00231         !XPT_Do32(cursor, &header->file_length) ||
00232         (ide_offset != NULL && !XPT_Do32(cursor, ide_offset))) {
00233         goto error;
00234     }
00235     return PR_TRUE;
00236     /* XXX need to free child data sometimes! */
00237     XPT_ERROR_HANDLE(arena, header);    
00238 }
00239 
00240 XPT_PUBLIC_API(PRBool)
00241 XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp)
00242 {
00243     const int HEADER_SIZE = 24;
00244     XPTMode mode = cursor->state->mode;
00245     XPTHeader * header;
00246     PRUint32 ide_offset;
00247     int i;
00248     XPTAnnotation *ann, *next, **annp;
00249 
00250     if (!XPT_DoHeaderPrologue(arena, cursor, headerp, &ide_offset))
00251         return PR_FALSE;
00252     header = *headerp;
00253     /* 
00254      * Make sure the file length reported in the header is the same size as
00255      * as our buffer unless it is zero (not set) 
00256      */
00257     if (mode == XPT_DECODE && (header->file_length != 0 && 
00258         cursor->state->pool->allocated < header->file_length)) {
00259         fputs("libxpt: File length in header does not match actual length. File may be corrupt\n",
00260             stderr);
00261         goto error;
00262     }
00263 
00264     if (mode == XPT_ENCODE)
00265         XPT_DataOffset(cursor->state, &header->data_pool);
00266     if (!XPT_Do32(cursor, &header->data_pool))
00267         goto error;
00268     if (mode == XPT_DECODE)
00269         XPT_DataOffset(cursor->state, &header->data_pool);
00270 
00271     if (mode == XPT_DECODE && header->num_interfaces) {
00272         header->interface_directory = 
00273             XPT_CALLOC(arena, header->num_interfaces * 
00274                        sizeof(XPTInterfaceDirectoryEntry));
00275         if (!header->interface_directory)
00276             goto error;
00277     }
00278 
00279     /*
00280      * Iterate through the annotations rather than recurring, to avoid blowing
00281      * the stack on large xpt files.
00282      */
00283     ann = next = header->annotations;
00284     annp = &header->annotations;
00285     do {
00286         ann = next;
00287         if (!DoAnnotation(arena, cursor, &ann))
00288             goto error;
00289         if (mode == XPT_DECODE) {
00290             /*
00291              * Make sure that we store the address of the newly allocated
00292              * annotation in the previous annotation's ``next'' slot, or
00293              * header->annotations for the first one.
00294              */
00295             *annp = ann;
00296             annp = &ann->next;
00297         }
00298         next = ann->next;
00299     } while (!XPT_ANN_IS_LAST(ann->flags));
00300 
00301     /* shouldn't be necessary now, but maybe later */
00302     XPT_SeekTo(cursor, ide_offset); 
00303 
00304     for (i = 0; i < header->num_interfaces; i++) {
00305         if (!DoInterfaceDirectoryEntry(arena, cursor, 
00306                                        &header->interface_directory[i],
00307                                        (PRUint16)(i + 1)))
00308             goto error;
00309     }
00310     
00311     return PR_TRUE;
00312 
00313     /* XXX need to free child data sometimes! */
00314     XPT_ERROR_HANDLE(arena, header);    
00315 }   
00316 
00317 XPT_PUBLIC_API(PRBool)
00318 XPT_FillInterfaceDirectoryEntry(XPTArena *arena,
00319                                 XPTInterfaceDirectoryEntry *ide,
00320                                 nsID *iid, char *name, char *name_space,
00321                                 XPTInterfaceDescriptor *descriptor)
00322 {
00323     XPT_COPY_IID(ide->iid, *iid);
00324     ide->name = name ? XPT_STRDUP(arena, name) : NULL; /* what good is it w/o a name? */
00325     ide->name_space = name_space ? XPT_STRDUP(arena, name_space) : NULL;
00326     ide->interface_descriptor = descriptor;
00327     return PR_TRUE;
00328 }
00329 
00330 XPT_PUBLIC_API(void)
00331 XPT_DestroyInterfaceDirectoryEntry(XPTArena *arena,
00332                                    XPTInterfaceDirectoryEntry* ide)
00333 {
00334     if (ide) {
00335         if (ide->name) XPT_FREE(arena, ide->name);
00336         if (ide->name_space) XPT_FREE(arena, ide->name_space);
00337         XPT_FreeInterfaceDescriptor(arena, ide->interface_descriptor);
00338     }
00339 }
00340 
00341 /* InterfaceDirectoryEntry records go in the header */
00342 PRBool
00343 DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor,
00344                           XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index)
00345 {
00346     XPTMode mode = cursor->state->mode;
00347     
00348     /* write the IID in our cursor space */
00349     if (!XPT_DoIID(cursor, &(ide->iid)) ||
00350         
00351         /* write the name string in the data pool, and the offset in our
00352            cursor space */
00353         !XPT_DoCString(arena, cursor, &(ide->name)) ||
00354         
00355         /* write the name_space string in the data pool, and the offset in our
00356            cursor space */
00357         !XPT_DoCString(arena, cursor, &(ide->name_space)) ||
00358         
00359         /* do InterfaceDescriptors -- later, only on encode (see below) */
00360         !DoInterfaceDescriptor(arena, cursor, &ide->interface_descriptor)) {
00361         goto error;
00362     }
00363     
00364     if (mode == XPT_DECODE)
00365         XPT_SetOffsetForAddr(cursor, ide, entry_index);
00366 
00367     return PR_TRUE;
00368 
00369     XPT_ERROR_HANDLE(arena, ide);    
00370 }
00371 
00372 XPT_PUBLIC_API(XPTInterfaceDescriptor *)
00373 XPT_NewInterfaceDescriptor(XPTArena *arena, 
00374                            PRUint16 parent_interface, PRUint16 num_methods,
00375                            PRUint16 num_constants, PRUint8 flags)
00376 {
00377 
00378     XPTInterfaceDescriptor *id = XPT_NEWZAP(arena, XPTInterfaceDescriptor);
00379     if (!id)
00380         return NULL;
00381 
00382     if (num_methods) {
00383         id->method_descriptors = XPT_CALLOC(arena, num_methods *
00384                                             sizeof(XPTMethodDescriptor));
00385         if (!id->method_descriptors)
00386             goto free_id;
00387         id->num_methods = num_methods;
00388     }
00389 
00390     if (num_constants) {
00391         id->const_descriptors = XPT_CALLOC(arena, num_constants *
00392                                            sizeof(XPTConstDescriptor));
00393         if (!id->const_descriptors)
00394             goto free_meth;
00395         id->num_constants = num_constants;
00396     }
00397 
00398     if (parent_interface) {
00399         id->parent_interface = parent_interface;
00400     } else {
00401         id->parent_interface = 0;
00402     }
00403 
00404     id->flags = flags;
00405 
00406     return id;
00407 
00408  free_meth:
00409     XPT_FREEIF(arena, id->method_descriptors);
00410  free_id:
00411     XPT_DELETE(arena, id);
00412     return NULL;
00413 }
00414 
00415 XPT_PUBLIC_API(void)
00416 XPT_FreeInterfaceDescriptor(XPTArena *arena, XPTInterfaceDescriptor* id)
00417 {
00418     if (id) {
00419         XPTMethodDescriptor *md, *mdend;
00420         XPTConstDescriptor *cd, *cdend;
00421 
00422         /* Free up method descriptors */
00423         md = id->method_descriptors;
00424         mdend = md + id->num_methods;
00425         for (; md < mdend; md++) {
00426             XPT_FREEIF(arena, md->name);
00427             XPT_FREEIF(arena, md->params);
00428             XPT_FREEIF(arena, md->result);
00429         }
00430         XPT_FREEIF(arena, id->method_descriptors);
00431 
00432         /* Free up const descriptors */
00433         cd = id->const_descriptors;
00434         cdend = cd + id->num_constants;
00435         for (; cd < cdend; cd++) {
00436             XPT_FREEIF(arena, cd->name);
00437         }
00438         XPT_FREEIF(arena, id->const_descriptors);
00439 
00440         /* Free up type descriptors */
00441         XPT_FREEIF(arena, id->additional_types);
00442 
00443         XPT_DELETE(arena, id);
00444     }
00445 }
00446 
00447 XPT_PUBLIC_API(PRBool)
00448 XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id, 
00449                                 PRUint16 num)
00450 {
00451     XPTTypeDescriptor *old = id->additional_types;
00452     XPTTypeDescriptor *new;
00453     size_t old_size = id->num_additional_types * sizeof(XPTTypeDescriptor);
00454     size_t new_size = (num * sizeof(XPTTypeDescriptor)) + old_size;
00455 
00456     /* XXX should grow in chunks to minimize alloc overhead */
00457     new = XPT_CALLOC(arena, new_size);
00458     if (!new)
00459         return PR_FALSE;
00460     if (old) {
00461         if (old_size)
00462             memcpy(new, old, old_size);
00463         XPT_FREE(arena, old);
00464     }
00465     id->additional_types = new;
00466     id->num_additional_types += num;
00467     return PR_TRUE;
00468 }
00469 
00470 XPT_PUBLIC_API(PRBool)
00471 XPT_InterfaceDescriptorAddMethods(XPTArena *arena, XPTInterfaceDescriptor *id, 
00472                                   PRUint16 num)
00473 {
00474     XPTMethodDescriptor *old = id->method_descriptors;
00475     XPTMethodDescriptor *new;
00476     size_t old_size = id->num_methods * sizeof(XPTMethodDescriptor);
00477     size_t new_size = (num * sizeof(XPTMethodDescriptor)) + old_size;
00478 
00479     /* XXX should grow in chunks to minimize alloc overhead */
00480     new = XPT_CALLOC(arena, new_size);
00481     if (!new)
00482         return PR_FALSE;
00483     if (old) {
00484         if (old_size)
00485             memcpy(new, old, old_size);
00486         XPT_FREE(arena, old);
00487     }
00488     id->method_descriptors = new;
00489     id->num_methods += num;
00490     return PR_TRUE;
00491 }
00492 
00493 XPT_PUBLIC_API(PRBool)
00494 XPT_InterfaceDescriptorAddConsts(XPTArena *arena, XPTInterfaceDescriptor *id, 
00495                                  PRUint16 num)
00496 {
00497     XPTConstDescriptor *old = id->const_descriptors;
00498     XPTConstDescriptor *new;
00499     size_t old_size = id->num_constants * sizeof(XPTConstDescriptor);
00500     size_t new_size = (num * sizeof(XPTConstDescriptor)) + old_size;
00501 
00502     /* XXX should grow in chunks to minimize alloc overhead */
00503     new = XPT_CALLOC(arena, new_size);
00504     if (!new)
00505         return PR_FALSE;
00506     if (old) {
00507         if (old_size)
00508             memcpy(new, old, old_size);
00509         XPT_FREE(arena, old);
00510     }
00511     id->const_descriptors = new;
00512     id->num_constants += num;
00513     return PR_TRUE;
00514 }
00515 
00516 PRUint32
00517 SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id)
00518 {
00519     PRUint32 size = 1; /* prefix */
00520 
00521     switch (XPT_TDP_TAG(td->prefix)) {
00522       case TD_INTERFACE_TYPE:
00523         size += 2; /* interface_index */
00524         break;
00525       case TD_INTERFACE_IS_TYPE:
00526         size += 1; /* argnum */
00527         break;
00528       case TD_ARRAY:
00529         size += 2 + SizeOfTypeDescriptor(
00530                         &id->additional_types[td->type.additional_type], id);
00531         break;
00532       case TD_PSTRING_SIZE_IS:
00533         size += 2; /* argnum + argnum2 */
00534         break;
00535       case TD_PWSTRING_SIZE_IS:
00536         size += 2; /* argnum + argnum2 */
00537         break;
00538       default:
00539         /* nothing special */
00540         break;
00541     }
00542     return size;
00543 }
00544 
00545 PRUint32
00546 SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id)
00547 {
00548     PRUint32 i, size =  1 /* flags */ + 4 /* name */ + 1 /* num_args */;
00549 
00550     for (i = 0; i < md->num_args; i++) 
00551         size += 1 + SizeOfTypeDescriptor(&md->params[i].type, id);
00552 
00553     size += 1 + SizeOfTypeDescriptor(&md->result->type, id);
00554     return size;
00555 }
00556 
00557 PRUint32
00558 SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id)
00559 {
00560     PRUint32 size = 4 /* name */ + SizeOfTypeDescriptor(&cd->type, id);
00561 
00562     switch (XPT_TDP_TAG(cd->type.prefix)) {
00563       case TD_INT8:
00564       case TD_UINT8:
00565       case TD_CHAR:
00566         size ++;
00567         break;
00568       case TD_INT16:
00569       case TD_UINT16:
00570       case TD_WCHAR:
00571         size += 2;
00572         break;
00573       case TD_INT32:
00574       case TD_UINT32:
00575       case TD_PSTRING:
00576         size += 4;
00577         break;
00578       case TD_INT64:
00579       case TD_UINT64:
00580         size += 8;
00581         break;
00582       default:
00583         fprintf(stderr, "libxpt: illegal type in ConstDescriptor: 0x%02x\n",
00584                 XPT_TDP_TAG(cd->type.prefix));
00585         return 0;
00586     }
00587 
00588     return size;
00589 }
00590 
00591 PRUint32
00592 SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id)
00593 {
00594     PRUint32 size = 2 /* parent interface */ + 2 /* num_methods */
00595         + 2 /* num_constants */ + 1 /* flags */, i;
00596     for (i = 0; i < id->num_methods; i++)
00597         size += SizeOfMethodDescriptor(&id->method_descriptors[i], id);
00598     for (i = 0; i < id->num_constants; i++)
00599         size += SizeOfConstDescriptor(&id->const_descriptors[i], id);
00600     return size;
00601 }
00602 
00603 PRBool
00604 DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, 
00605                       XPTInterfaceDescriptor **idp)
00606 {
00607     XPTMode mode = outer->state->mode;
00608     XPTInterfaceDescriptor *id;
00609     XPTCursor curs, *cursor = &curs;
00610     PRUint32 i, id_sz = 0;
00611 
00612     if (mode == XPT_DECODE) {
00613         id = XPT_NEWZAP(arena, XPTInterfaceDescriptor);
00614         if (!id)
00615             return PR_FALSE;
00616         *idp = id;
00617     } else {
00618         id = *idp;
00619         if (!id) {
00620             id_sz = 0;
00621             return XPT_Do32(outer, &id_sz);
00622         }
00623         id_sz = SizeOfInterfaceDescriptor(id);
00624     }
00625 
00626     if (!XPT_MakeCursor(outer->state, XPT_DATA, id_sz, cursor))
00627         goto error;
00628 
00629     if (!XPT_Do32(outer, &cursor->offset))
00630         goto error;
00631     if (mode == XPT_DECODE && !cursor->offset) {
00632         XPT_DELETE(arena, *idp);
00633         return PR_TRUE;
00634     }
00635     if(!XPT_Do16(cursor, &id->parent_interface) ||
00636        !XPT_Do16(cursor, &id->num_methods)) {
00637         goto error;
00638     }
00639 
00640     if (mode == XPT_DECODE && id->num_methods) {
00641         id->method_descriptors = XPT_CALLOC(arena, id->num_methods *
00642                                             sizeof(XPTMethodDescriptor));
00643         if (!id->method_descriptors)
00644             goto error;
00645     }
00646     
00647     for (i = 0; i < id->num_methods; i++) {
00648         if (!DoMethodDescriptor(arena, cursor, &id->method_descriptors[i], id))
00649             goto error;   
00650     }
00651     
00652     if (!XPT_Do16(cursor, &id->num_constants)) {
00653         goto error;
00654     }
00655     
00656     if (mode == XPT_DECODE && id->num_constants) {
00657         id->const_descriptors = XPT_CALLOC(arena, id->num_constants * 
00658                                            sizeof(XPTConstDescriptor));
00659         if (!id->const_descriptors)
00660             goto error;
00661     }
00662     
00663     for (i = 0; i < id->num_constants; i++) {
00664         if (!DoConstDescriptor(arena, cursor, &id->const_descriptors[i], id)) {
00665             goto error;
00666         }
00667     }
00668 
00669     if (!XPT_Do8(cursor, &id->flags)) {
00670         goto error;
00671     }
00672     
00673     return PR_TRUE;
00674 
00675     XPT_ERROR_HANDLE(arena, id);    
00676 }
00677 
00678 PRBool
00679 DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd,
00680                   XPTInterfaceDescriptor *id)
00681 {
00682     PRBool ok = PR_FALSE;
00683 
00684     if (!XPT_DoCString(arena, cursor, &cd->name) ||
00685         !DoTypeDescriptor(arena, cursor, &cd->type, id)) {
00686 
00687         return PR_FALSE;
00688     }
00689 
00690     switch(XPT_TDP_TAG(cd->type.prefix)) {
00691       case TD_INT8:
00692         ok = XPT_Do8(cursor, (PRUint8*) &cd->value.i8);
00693         break;
00694       case TD_INT16:
00695         ok = XPT_Do16(cursor, (PRUint16*) &cd->value.i16);
00696         break;
00697       case TD_INT32:
00698         ok = XPT_Do32(cursor, (PRUint32*) &cd->value.i32);
00699         break;
00700       case TD_INT64:
00701         ok = XPT_Do64(cursor, &cd->value.i64);
00702         break;
00703       case TD_UINT8:
00704         ok = XPT_Do8(cursor, &cd->value.ui8);
00705         break;
00706       case TD_UINT16:
00707         ok = XPT_Do16(cursor, &cd->value.ui16);
00708         break;
00709       case TD_UINT32:
00710         ok = XPT_Do32(cursor, &cd->value.ui32);
00711         break;
00712       case TD_UINT64:
00713         ok = XPT_Do64(cursor, (PRInt64 *)&cd->value.ui64);
00714         break;
00715       case TD_CHAR:
00716         ok = XPT_Do8(cursor, (PRUint8*) &cd->value.ch);
00717         break;
00718       case TD_WCHAR:
00719         ok = XPT_Do16(cursor, &cd->value.wch);
00720         break;
00721         /* fall-through */
00722       default:
00723         fprintf(stderr, "illegal type!\n");
00724         break;
00725     }
00726 
00727     return ok;
00728 
00729 }
00730 
00731 XPT_PUBLIC_API(PRBool)
00732 XPT_FillMethodDescriptor(XPTArena *arena, XPTMethodDescriptor *meth, 
00733                          PRUint8 flags, char *name, PRUint8 num_args)
00734 {
00735     meth->flags = flags & XPT_MD_FLAGMASK;
00736     meth->name = XPT_STRDUP(arena, name);
00737     if (!meth->name)
00738         return PR_FALSE;
00739     meth->num_args = num_args;
00740     if (num_args) {
00741         meth->params = XPT_CALLOC(arena, num_args * sizeof(XPTParamDescriptor));
00742         if (!meth->params)
00743             goto free_name;
00744     } else {
00745         meth->params = NULL;
00746     }
00747     meth->result = XPT_NEWZAP(arena, XPTParamDescriptor);
00748     if (!meth->result)
00749         goto free_params;
00750     return PR_TRUE;
00751 
00752  free_params:
00753     XPT_DELETE(arena, meth->params);
00754  free_name:
00755     XPT_DELETE(arena, meth->name);
00756     return PR_FALSE;
00757 }
00758 
00759 PRBool
00760 DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md,
00761                    XPTInterfaceDescriptor *id)
00762 {
00763     XPTMode mode = cursor->state->mode;
00764     int i;
00765 
00766     if (!XPT_Do8(cursor, &md->flags) ||
00767         !XPT_DoCString(arena, cursor, &md->name) ||
00768         !XPT_Do8(cursor, &md->num_args))
00769         return PR_FALSE;
00770 
00771     if (mode == XPT_DECODE && md->num_args) {
00772         md->params = XPT_CALLOC(arena, md->num_args * sizeof(XPTParamDescriptor));
00773         if (!md->params)
00774             return PR_FALSE;
00775     }
00776 
00777     for(i = 0; i < md->num_args; i++) {
00778         if (!DoParamDescriptor(arena, cursor, &md->params[i], id))
00779             goto error;
00780     }
00781     
00782     if (mode == XPT_DECODE) {
00783         md->result = XPT_NEWZAP(arena, XPTParamDescriptor);
00784         if (!md->result)
00785             return PR_FALSE;
00786     }
00787 
00788     if (!md->result ||
00789         !DoParamDescriptor(arena, cursor, md->result, id))
00790         goto error;
00791     
00792     return PR_TRUE;
00793     
00794     XPT_ERROR_HANDLE(arena, md->params);    
00795 }
00796 
00797 XPT_PUBLIC_API(PRBool)
00798 XPT_FillParamDescriptor(XPTArena *arena, XPTParamDescriptor *pd, PRUint8 flags,
00799                         XPTTypeDescriptor *type)
00800 {
00801     pd->flags = flags & XPT_PD_FLAGMASK;
00802     XPT_COPY_TYPE(pd->type, *type);
00803     return PR_TRUE;
00804 }
00805 
00806 PRBool
00807 DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd, 
00808                   XPTInterfaceDescriptor *id)
00809 {
00810     if (!XPT_Do8(cursor, &pd->flags) ||
00811         !DoTypeDescriptor(arena, cursor, &pd->type, id))
00812         return PR_FALSE;
00813         
00814     return PR_TRUE;
00815 }
00816 
00817 PRBool
00818 DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp)
00819 {
00820     return XPT_Do8(cursor, &tdp->flags);
00821 }
00822 
00823 PRBool
00824 DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td,
00825                  XPTInterfaceDescriptor *id)
00826 {
00827     if (!DoTypeDescriptorPrefix(arena, cursor, &td->prefix)) {
00828         goto error;
00829     }
00830     
00831     switch (XPT_TDP_TAG(td->prefix)) {
00832       case TD_INTERFACE_TYPE:
00833         if (!XPT_Do16(cursor, &td->type.iface))
00834             goto error;
00835         break;
00836       case TD_INTERFACE_IS_TYPE:
00837         if (!XPT_Do8(cursor, &td->argnum))
00838             goto error;
00839         break;
00840       case TD_ARRAY:
00841         if (!XPT_Do8(cursor, &td->argnum) ||
00842             !XPT_Do8(cursor, &td->argnum2))
00843             goto error;
00844 
00845         if (cursor->state->mode == XPT_DECODE) {
00846             if(!XPT_InterfaceDescriptorAddTypes(arena, id, 1))
00847                 goto error;
00848             td->type.additional_type = id->num_additional_types - 1;
00849         }
00850 
00851         if (!DoTypeDescriptor(arena, cursor, 
00852                               &id->additional_types[td->type.additional_type], 
00853                               id))
00854             goto error;
00855         break;
00856       case TD_PSTRING_SIZE_IS:
00857       case TD_PWSTRING_SIZE_IS:
00858         if (!XPT_Do8(cursor, &td->argnum) ||
00859             !XPT_Do8(cursor, &td->argnum2))
00860             goto error;
00861         break;
00862 
00863       default:
00864         /* nothing special */
00865         break;
00866     }
00867     return PR_TRUE;
00868     
00869     XPT_ERROR_HANDLE(arena, td);    
00870 }
00871 
00872 XPT_PUBLIC_API(XPTAnnotation *)
00873 XPT_NewAnnotation(XPTArena *arena, PRUint8 flags, XPTString *creator, 
00874                   XPTString *private_data)
00875 {
00876     XPTAnnotation *ann = XPT_NEWZAP(arena, XPTAnnotation);
00877     if (!ann)
00878         return NULL;
00879     ann->flags = flags;
00880     if (XPT_ANN_IS_PRIVATE(flags)) {
00881         ann->creator = creator;
00882         ann->private_data = private_data;
00883     }
00884     return ann;
00885 }
00886 
00887 PRBool
00888 DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp)
00889 {
00890     XPTMode mode = cursor->state->mode;
00891     XPTAnnotation *ann;
00892     
00893     if (mode == XPT_DECODE) {
00894         ann = XPT_NEWZAP(arena, XPTAnnotation);
00895         if (!ann)
00896             return PR_FALSE;
00897         *annp = ann;
00898     } else {
00899         ann = *annp;
00900     }
00901     
00902     if (!XPT_Do8(cursor, &ann->flags))
00903         goto error;
00904 
00905     if (XPT_ANN_IS_PRIVATE(ann->flags)) {
00906         if (!XPT_DoStringInline(arena, cursor, &ann->creator) ||
00907             !XPT_DoStringInline(arena, cursor, &ann->private_data))
00908             goto error_2;
00909     }
00910 
00911     return PR_TRUE;
00912     
00913  error_2:
00914     if (ann && XPT_ANN_IS_PRIVATE(ann->flags)) {
00915         XPT_FREEIF(arena, ann->creator);
00916         XPT_FREEIF(arena, ann->private_data);
00917     }
00918     XPT_ERROR_HANDLE(arena, ann);
00919 }
00920 
00921 PRBool
00922 XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block,
00923                             PRUint16 num_interfaces, char *name, 
00924                             PRUint16 *indexp) 
00925 {
00926     int i;
00927     
00928     for (i=1; i<=num_interfaces; i++) {
00929         fprintf(stderr, "%s == %s ?\n", ide_block[i].name, name);
00930         if (strcmp(ide_block[i].name, name) == 0) {
00931             *indexp = i;
00932             return PR_TRUE;
00933         }
00934     }
00935     indexp = 0;
00936     return PR_FALSE;
00937 }
00938 
00939 static XPT_TYPELIB_VERSIONS_STRUCT versions[] = XPT_TYPELIB_VERSIONS;
00940 #define XPT_TYPELIB_VERSIONS_COUNT (sizeof(versions) / sizeof(versions[0]))
00941 
00942 XPT_PUBLIC_API(PRUint16)
00943 XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor)
00944 {
00945     int i;
00946     for (i = 0; i < XPT_TYPELIB_VERSIONS_COUNT; i++) {
00947         if (!strcmp(versions[i].str, str)) {
00948             *major = versions[i].major;
00949             *minor = versions[i].minor;
00950             return versions[i].code;
00951         }
00952     }
00953     return XPT_VERSION_UNKNOWN;
00954 }
00955 
00956