static void FreeAttrValue (VStringConst routine, VAttrRec *a) { VTypeMethods *methods; switch (a->repn) { case VAttrListRepn: VDestroyAttrList (a->value); break; case VBundleRepn: VDestroyBundle (a->value); break; case VPointerRepn: case VStringRepn: break; default: if (! (methods = VRepnMethods (a->repn))) VError ("%s: %s attribute has invalid repn %d", routine, a->name, a->repn); (methods->destroy) (a->value); } }
static VBoolean ReadData (FILE *f, VAttrList list, VReadFileFilterProc *filter, long *offset) { VAttrListPosn posn, subposn; VAttrList sublist; VBundle b; VRepnKind repn; VBoolean read_data, data_found, length_found; VLong data, length; VTypeMethods *methods; VPointer value; for (VFirstAttr (list, & posn); VAttrExists (& posn); VNextAttr (& posn)) { switch (VGetAttrRepn (& posn)) { case VAttrListRepn: /* Recurse on nested attribute list: */ VGetAttrValue (& posn, NULL, VAttrListRepn, & sublist); if (! ReadData (f, sublist, filter, offset)) return FALSE; break; case VBundleRepn: VGetAttrValue (& posn, NULL, VBundleRepn, & b); repn = VLookupType (b->type_name); /* If a filter routine was supplied, ask it whether to bother with the binary data: */ read_data = ! filter || (*filter) (b, repn); /* Extract any data and length attributes in the object's value: */ data_found = VLookupAttr (b->list, VDataAttr, & subposn); if (data_found) { if (! VGetAttrValue (& subposn, NULL, VLongRepn, & data)) { VWarning ("VReadFile: " "%s attribute's data attribute incorrect", VGetAttrName (& posn)); return FALSE; } VDeleteAttr (& subposn); } length_found = VLookupAttr (b->list, VLengthAttr, & subposn); if (length_found) { if (! VGetAttrValue (& subposn, NULL, VLongRepn, & length)) { VWarning ("VReadFile: " "%s attribute's length attribute incorrect", VGetAttrName (& posn)); return FALSE; } VDeleteAttr (& subposn); } /* None or both must be present: */ if (data_found ^ length_found) { VWarning ("VReadFile: %s attribute has %s but not %s", VGetAttrName (& posn), data_found ? "data" : "length", data_found ? "length" : "data"); return FALSE; } /* Read the binary data associated with the object: */ if (data_found) { if (data < *offset) { VWarning ("VReadFile: " "%s attribute's data attribute incorrect", VGetAttrName (& posn)); return FALSE; } if (! read_data) data += length; /* To seek forward to the start of the data block we first try fseek. That will fail on a pipe, in which case we seek by reading. */ if (data != *offset && fseek (f, (long) data - *offset, SEEK_CUR) == -1 && errno == ESPIPE && ! MySeek (f, data - *offset)) { VSystemWarning ("VReadFile: Seek within file failed"); return FALSE; } if (read_data) { b->data = VMalloc (b->length = length); if (fread (b->data, 1, length, f) != length) { VWarning ("VReadFile: Read from stream failed"); return FALSE; } *offset = data + length; } else /* bug: read error occured when bundle was not read by a filter function. FK 24/03/98 */ *offset = data; } /* Recurse to read binary data for sublist attributes: */ if (! ReadData (f, b->list, filter, offset)) return FALSE; /* If the object's type is registered and has a decode method, invoke it to decode the binary data: */ if (read_data && repn != VUnknownRepn && (methods = VRepnMethods (repn)) && methods->decode) { if (! (value = (methods->decode) (VGetAttrName (& posn), b))) return FALSE; /* Replace the old typed value with the newly decoded one: */ VSetAttrValue (& posn, NULL, repn, value); VDestroyBundle (b); } break; default: break; } } return TRUE; }