static gboolean
typelib_prolog(TreeState *state)
{
    state->priv = calloc(1, sizeof(struct priv_data));
    if (!state->priv)
        return FALSE;
    IFACES(state) = 0;
    IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal);
    if (!IFACE_MAP(state)) {
        /* XXX report error */
        free(state->priv);
        return FALSE;
    }
    /* find all interfaces, top-level and referenced by others */
    IDL_tree_walk_in_order(state->tree, find_interfaces, state);
    ARENA(state) = XPT_NewArena(1024, sizeof(double), "main xpidl arena");
    HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state), 
                                  major_version, minor_version);

    /* fill IDEs from hash table */
    IFACES(state) = 0;
    g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state);

    /* if any are left then we must have failed in fill_ide_table */
    if (g_hash_table_size(IFACE_MAP(state)))
        return FALSE;

    /* sort the IDEs by IID order and store indices in the interface map */
    sort_ide_block(state);

    return TRUE;
}
// [scriptable, uuid(00000000-0000-0000-0000-000000000000)]
// interface axIFoo : axIBar
void DumpXPCOMInterfaceXPT(FILE *f, ITypeInfo *tiInterface)
{
    XPTArena *arena = XPT_NewArena(1024 * 10, sizeof(double), "main xpt_link arena");
    // TODO. Maybe it would be better to just feed an IDL through the regular compiler
    //       than try and generate some XPT here.
    XPT_DestroyArena(arena);
}
Example #3
0
XPT_NewXDRState(XPTMode mode, char *data, uint32_t len)
{
    XPTState *state;
    XPTArena *arena;

    arena = XPT_NewArena(512, sizeof(double), "an XDRState");
    if (!arena)
        return NULL;

    state = XPT_NEWZAP(arena, XPTState);
    if (!state)
        goto err_free_arena;

    state->arena = arena;
    state->mode = mode;
    state->pool = XPT_NEW(arena, XPTDatapool);
    state->next_cursor[0] = state->next_cursor[1] = 1;
    if (!state->pool)
        goto err_free_state;

    state->pool->count = 0;
    state->pool->offset_map = XPT_NewHashTable(arena);

    if (!state->pool->offset_map)
        goto err_free_pool;
    if (mode == XPT_DECODE) {
        state->pool->data = data;
        state->pool->allocated = len;
    } else {
        state->pool->data = (char*)XPT_MALLOC(arena, XPT_GROW_CHUNK);
        if (!state->pool->data)
            goto err_free_hash;
        state->pool->allocated = XPT_GROW_CHUNK;
    }

    return state;

 err_free_hash:
    XPT_HashTableDestroy(state->pool->offset_map);
 err_free_pool:
    XPT_DELETE(arena, state->pool);
 err_free_state:
    XPT_DELETE(arena, state);
 err_free_arena:
    if (arena)
        XPT_DestroyArena(arena);
    return NULL;
}
Example #4
0
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;        
}
int
main(int argc, char **argv)
{
    XPTArena *arena;
    XPTHeader *header;
    XPTAnnotation *ann;
    XPTInterfaceDescriptor *id;
    XPTMethodDescriptor *meth;

    XPTState *state;
    XPTCursor curs, *cursor = &curs;
    char *data, *head;
    FILE *out;
    uint32 len, header_sz;

    PRBool ok;

    td_void.prefix.flags = TD_VOID;

    if (argc != 2) {
	fprintf(stderr, "Usage: %s <filename.xpt>\n"
		"       Creates a simple typelib file.\n", argv[0]);
	
	return 1;
    }

    arena = XPT_NewArena(1024, sizeof(double), "main");
    TRY("XPT_NewArena", arena);

    /* construct a header */
    header = XPT_NewHeader(arena, 1, XPT_MAJOR_VERSION, XPT_MINOR_VERSION);
    TRY("NewHeader", header);

    
    ann = XPT_NewAnnotation(arena, XPT_ANN_LAST | XPT_ANN_PRIVATE,
                            XPT_NewStringZ(arena, "SimpleTypeLib 1.0"),
                            XPT_NewStringZ(arena, "See You In Rome"));
    TRY("NewAnnotation", ann);
    header->annotations = ann;

    header_sz = XPT_SizeOfHeaderBlock(header);

    id = XPT_NewInterfaceDescriptor(arena, 0, 2, 2, 0);
    TRY("NewInterfaceDescriptor", id);
    
    ok = XPT_FillInterfaceDirectoryEntry(arena, header->interface_directory, &iid,
					 "Interface", "NS", id);
    TRY("FillInterfaceDirectoryEntry", ok);

    /* void method1(void) */
    meth = &id->method_descriptors[0];
    ok = XPT_FillMethodDescriptor(arena, meth, 0, "method1", 0);
    TRY("FillMethodDescriptor", ok);
    meth->result->flags = 0;
    meth->result->type.prefix.flags = TD_VOID;

    /* wstring method2(in uint32, in bool) */
    meth = &id->method_descriptors[1];
    ok = XPT_FillMethodDescriptor(arena, meth, 0, "method2", 2);
    TRY("FillMethodDescriptor", ok);

    meth->result->flags = 0;
    meth->result->type.prefix.flags = TD_PSTRING | XPT_TDP_POINTER;
    meth->params[0].type.prefix.flags = TD_UINT32;
    meth->params[0].flags = XPT_PD_IN;
    meth->params[1].type.prefix.flags = TD_BOOL;
    meth->params[1].flags = XPT_PD_IN;

#if 0
    /* const one = 1; */
    id->const_descriptors[0].name = "one";
    id->const_descriptors[0].type.prefix.flags = TD_UINT16;
    id->const_descriptors[0].value.ui16 = 1;
    
    /* const squeamish = "ossifrage"; */
    id->const_descriptors[1].name = "squeamish";
    id->const_descriptors[1].type.prefix.flags = TD_PBSTR | XPT_TDP_POINTER;
    id->const_descriptors[1].value.string = XPT_NewStringZ(arena, "ossifrage");
#endif

    /* serialize it */
    state = XPT_NewXDRState(XPT_ENCODE, NULL, 0);
    TRY("NewState (ENCODE)", state);
    
    ok = XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor);
    TRY("MakeCursor", ok);

    ok = XPT_DoHeader(arena, cursor, &header);
    TRY("DoHeader", ok);

    out = fopen(argv[1], "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, "\nError writing file: %s\n\n", argv[1]);
    } else {
        fprintf(stderr, "\nFile written: %s\n\n", argv[1]);
    }
    XPT_DestroyXDRState(state);
    
    XPT_FreeHeader(arena, header);
    XPT_DestroyArena(arena);

    return 0;
}
int
main(int argc, char **argv)
{
    XPTArena *arena;
    XPTState *state;
    XPTCursor curs, *cursor = &curs;
    char *header, *data, *whole;
    uint32_t hlen, dlen, i;

    TRY("XPT_NewArena", (arena = XPT_NewArena(1024, sizeof(double), "main")));
    
    TRY("NewState (ENCODE)", (state = XPT_NewXDRState(XPT_ENCODE, NULL, 0)));

    XPT_SetDataOffset(state, sizeof input);

    TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor));

    dump_struct("before", &input);

    if (XDR(arena, cursor, &input))
	return 1;

    fprintf(stderr, "ENCODE successful\n");
    XPT_GetXDRData(state, XPT_HEADER, &header, &hlen);
    fprintf(stderr, "XDR header %d bytes at %p:",
	    hlen, header);
    for (i = 0; i < hlen; i++)
	fprintf(stderr, "%c%02x", i ? ',' : ' ', (uint8_t)header[i]);
    fprintf(stderr, "\n");

    XPT_GetXDRData(state, XPT_DATA, &data, &dlen);

    fprintf(stderr, "XDR data %d bytes at %p:",
	    dlen, data);
    for (i = 0; i < dlen; i++)
	fprintf(stderr, "%c%02x/%c", i ? ',' : ' ', (uint8_t)data[i],
		(uint8_t)data[i]);
    fprintf(stderr, "\n");

    whole = malloc(dlen + hlen);
    if (!whole) {
	fprintf(stderr, "malloc %d failed!\n", dlen + hlen);
	return 1;
    }

    /* TRY_Q("malloc", (data2 = malloc(len))); */
    memcpy(whole, header, hlen);
    memcpy(whole + hlen, data, dlen);
    XPT_DestroyXDRState(state);

    TRY("NewState (DECODE)", (state = XPT_NewXDRState(XPT_DECODE, whole,
						      hlen + dlen)));

    TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor));
    XPT_SetDataOffset(state, sizeof input);

    if (XDR(arena, cursor, &output))
	return 1;
    
    dump_struct("after", &output);
    XPT_DestroyXDRState(state);
    XPT_DestroyArena(arena);
    free(whole);

    return 0;
}