static VBoolean WriteAttr (FILE *f, VAttrListPosn *posn, int indent, VList *data_list, long *offset) { int i; char *str; VRepnKind repn; VAttrList sublist; VBundle b; DataBlock *db; VTypeMethods *methods; size_t length; VPointer value; VBoolean result; VAttrListPosn subposn; /* Indent by the specified amount: */ for (i = 0; i < indent; i++) FailTest (fputc ('\t', f)); indent++; /* Output the attribute's name: */ FailTest (fprintf (f, "%s: ", VGetAttrName (posn))); /* Ouput its value: */ switch (repn = VGetAttrRepn (posn)) { case VAttrListRepn: VGetAttrValue (posn, NULL, VAttrListRepn, (VPointer) & sublist); result = WriteAttrList (f, sublist, indent, data_list, offset); break; case VBundleRepn: VGetAttrValue (posn, NULL, VBundleRepn, (VBundle) & b); if (! WriteString (f, b->type_name)) return FALSE; FailTest (fputc (' ', f)); /* If it's a typed value with binary data... */ if (b->length > 0) { /* Include "data" and "length" attributes in its attribute list: */ VPrependAttr (b->list, VLengthAttr, NULL, VLongRepn, (VLong) b->length); VPrependAttr (b->list, VDataAttr, NULL, VLongRepn, (VLong) *offset); /* Add it to the queue of binary data blocks to be written: */ *offset += b->length; db = VNew (DataBlock); db->posn = *posn; db->list = b->list; db->length = b->length; VListAppend (*data_list, db); } /* Write the typed value's attribute list: */ result = WriteAttrList (f, b->list, indent, data_list, offset); /* Remove the "data" and "length" attributes added earlier: */ if (b->length > 0) { VFirstAttr (b->list, & subposn); VDeleteAttr (& subposn); VDeleteAttr (& subposn); } break; case VStringRepn: VGetAttrValue (posn, NULL, VStringRepn, (VPointer) & str); result = WriteString (f, str); break; default: if (! (methods = VRepnMethods (repn)) || ! methods->encode_attr || ! methods->encode_data) { VWarning ("VWriteFile: " "%s attribute has unwriteable representation: %s", VGetAttrName (posn), VRepnName (repn)); return FALSE; } /* Write the type name: */ if (! WriteString (f, VRepnName (repn))) return FALSE; FailTest (fputc (' ', f)); /* Invoke the object type's encode_attr method to obtain an attribute list: */ VGetAttrValue (posn, NULL, repn, & value); sublist = (methods->encode_attr) (value, & length); /* If binary data is indicated... */ if (length > 0) { /* Include "data" and "length" attributes in the attr list: */ VPrependAttr (sublist, VLengthAttr, NULL, VLongRepn, (VLong) length); VPrependAttr (sublist, VDataAttr, NULL, VLongRepn, (VLong) *offset); *offset += length; } /* Add the object to the queue of binary data blocks to be written: */ db = VNew (DataBlock); db->posn = *posn; db->list = sublist; db->length = length; VListAppend (*data_list, db); /* Write the typed value's attribute list: */ result = WriteAttrList (f, sublist, indent, data_list, offset); /* Remove the "data" and "length" attributes added earlier: */ if (length > 0) { VFirstAttr (sublist, & subposn); VDeleteAttr (& subposn); VDeleteAttr (& subposn); } } /* Output a trailing newline: */ if (result) FailTest (fputc ('\n', f)); return result; Fail: VWarning ("VWriteFile: Write to stream failed"); return FALSE; }
VBoolean VWriteFile (FILE *f, VAttrList list) { DataBlock *db; VBundle b; VTypeMethods *methods; VRepnKind repn; VPointer value, ptr; VBoolean result, free_it; VList data_list; /* Write the FIL_Vista data file header, attribute list, and delimeter while queuing on data_list any binary data blocks to be written: */ long offset = 0; data_list = VListCreate (); FailTest (fprintf (f, "%s %d ", VFileHeader, VFileVersion)); if (! WriteAttrList (f, list, 1, &data_list, &offset)) { VListDestroy (data_list, VFree); return FALSE; } FailTest (fputs ("\n" VFileDelimiter, f)); fflush (f); /* Traverse data_list to write the binary data blocks: */ for (db = VListFirst (data_list); db; db = VListNext (data_list)) { repn = VGetAttrRepn (& db->posn); if (repn == VBundleRepn) { /* A typed value includes its binary data block explicitly: */ VGetAttrValue (& db->posn, NULL, VBundleRepn, & b); ptr = b->data; free_it = FALSE; } else { /* For any other representation, obtain the binary data block from its encode_data method: */ VGetAttrValue (& db->posn, NULL, repn, & value); methods = VRepnMethods (repn); ptr = (methods->encode_data) (value, db->list, db->length, & free_it); if (! ptr) goto Fail; } /* Write the binary data and free the buffer containing it if it was allocated temporarily by an encode_data method: */ if (db->length > 0) { result = fwrite (ptr, 1, db->length, f) == db->length; if (free_it) VFree (ptr); if (! result) goto Fail; } } VListDestroy (data_list, VFree); return TRUE; Fail: VWarning ("VWriteFile: Write to stream failed"); VListDestroy (data_list, VFree); return FALSE; }
EXPORT_VISTA VistaIOBoolean VistaIOWriteFile (FILE * f, VistaIOAttrList list) { DataBlock *db; VistaIOBundle b; VistaIOTypeMethods *methods; VistaIORepnKind repn; VistaIOPointer value, ptr; VistaIOBoolean free_it; VistaIOBoolean result = 0; /* Write the Vista data file header, attribute list, and delimeter while queuing on data_list any binary data blocks to be written: */ offset = 0; data_list = VistaIOListCreate (); FailTest (fprintf (f, "%s %d ", VistaIOFileHeader, VistaIOFileVersion)); if (!WriteAttrList (f, list, 1)) { VistaIOListDestroy (data_list, VistaIOFree); return FALSE; } FailTest (fputs ("\n" VistaIOFileDelimiter, f)); fflush (f); /* Traverse data_list to write the binary data blocks: */ for (db = VistaIOListFirst (data_list); db; db = VistaIOListNext (data_list)) { repn = VistaIOGetAttrRepn (&db->posn); if (repn == VistaIOBundleRepn) { /* A typed value includes its binary data block explicitly: */ VistaIOGetAttrValue (&db->posn, NULL, VistaIOBundleRepn, &b); ptr = b->data; free_it = FALSE; } else { /* For any other representation, obtain the binary data block from its encode_data method: */ VistaIOGetAttrValue (&db->posn, NULL, repn, &value); methods = VistaIORepnMethods (repn); ptr = (methods->encode_data) (value, db->list, db->length, &free_it); if (!ptr) goto Fail; } /* Write the binary data and free the buffer containing it if it was allocated temporarily by an encode_data method: */ if (db->length > 0) { int togo = db->length; int pos = 0; while (togo) { size_t write_length = togo < 100000 ? togo: 100000; result = fwrite (((char *)ptr) + pos, 1, write_length, f) == write_length; pos += write_length; togo -= write_length; VistaIOShowWriteProgress(pos, db->length, VistaIOProgressData); } if (free_it) VistaIOFree (ptr); if (!result) goto Fail; } } VistaIOListDestroy (data_list, VistaIOFree); return TRUE; Fail: VistaIOWarning ("VistaIOWriteFile: Write to stream failed"); VistaIOListDestroy (data_list, VistaIOFree); return FALSE; }