_Tagged Data Storage Architectures_ by Jeremy Vineyard Listing One class CSizable { protected: CRect cs_dimensions; // Assume we already have a CRect class. public: virtual CRect GetDimensions(); virtual void Resize(CRect& rNewSize); ... } Listing Two class FT_TaggableObject { public: // Basic tag routines. virtual SN_Error AttachTag(FT_TagName tagName, FT_TagType tagType, FT_TagData tagData, FT_TagDataSize tagDataSize); virtual SN_Error RemoveTag(FT_TagName tagName); virtual SN_Error RemoveAllTags(); virtual SN_Error RetrieveTag(FT_TagName tagName, FT_Tag*& rpTag); virtual SN_Error CountTags(FT_TagIndex& rTagCount); ... }; Listing Three class FT_Tag { protected: FT_TagData ftt_tagData; FT_TagDataSize ftt_tagDataSize; FT_TagName ftt_tagName; FT_TagType ftt_tagType; ... }; Listing Four class TK_PackerObject { public: virtual SN_Error PackData(LB_DataChunk& rDataChunk); virtual SN_Error UnpackData(LB_DataChunk& rPackedData); ... }; Listing Five class TK_StorableObject { public: virtual SN_Error PackData(LB_DataChunk& rDataChunk); virtual SN_Error UnpackData(LB_DataChunk& rPackedData); public: virtual SN_Error AttachStorageTags(TK_PackerObject& rObject); virtual SN_Error ExtractStorageTags(TK_PackerObject& rObject); }; Listing Six class LB_DataChunk { public: virtual void* GetDataReference(); ... }; Listing Seven class TK_TagHeader { public: FT_TagType tkt_tagType; FT_TagName tkt_tagName; long tkt_unused; FT_TagDataSize tkt_tagDataSize; public: TK_TagHeader(); }; Listing Eight // This is the class ID of CA_ObjectPane. const long ca_kObjectPane = TcaOPU; Listing Nine SN_Error TK_StorableObject::PackData(LB_DataChunk& rDataChunk) { SN_Error result; TK_PackerObject tempObject; EX_TRY { EX_THROW_ERROR(AttachStorageTags(tempObject)); EX_THROW_ERROR(tempObject.PackData(rDataChunk)); } catch (SN_Exception& rException) { result = rException; } return result; } Listing Ten SN_Error CA_ColoredObject::AttachStorageTags(TK_PackerObject& rObject) { SN_Error result; EX_TRY { EX_THROW_ERROR(TK_AttachRGBColor(rObject, kColorName, cac_color.GetRGBColor())); } catch (SN_Exception& rException) { } return result; } Listing Eleven SN_Error TK_PackerObject::PackData(LB_DataChunk& rDataChunk) { SN_Error result; EX_TRY { // Pack the object's tags into a chunk of data. EX_THROW_ERROR(PrepareForPackingData(rDataChunk)); EX_THROW_ERROR(PackMyData(rDataChunk)); EX_THROW_ERROR(FinishPackingData(rDataChunk)); } catch (SN_Exception& rException) { result = rException; FailPackingData(rDataChunk); } return result; } SN_Error TK_PackerObject::PackMyData(LB_DataChunk& rDataChunk) { LB_DataSize totalSize, chunkSize; SN_Error result; EX_TRY { EX_THROW_ERROR(CalculateTotalDataSizeWithHeader(totalSize, sizeof(TK_TagHeader))); // Resize the chunk of data to fit all of the packed tag // data. chunkSize = totalSize; rDataChunk.SetDataSize(chunkSize); // Pack the object's tags into a chunk of data. long stuffOffset = 0; EX_THROW_ERROR(KeepPackingData(rDataChunk, stuffOffset)); } catch (SN_Exception& rException) { result = rException; } return result; } SN_Error TK_PackerObject::KeepPackingData(LB_DataChunk& rDataChunk, long& rStuffOffset) { TK_TagHeader tagHeader; FT_TagIndex tagCount; FT_Tag* pTag; FT_TagDataSize headerSize = sizeof(TK_TagHeader); SN_Error result; // KeepPackingData() stuffs tag info at specified offset into data. EX_TRY { EX_THROW_ERROR(CountTags(tagCount)); for (FT_TagIndex tagIndex = 1; tagIndex <= tagCount; tagIndex++) { // Retrieve the current tag. EX_THROW_ERROR(RetrieveTagWithIndex(tagIndex, pTag)); EX_THROW_NIL(pTag); // Stuff the tag information into the tag header. tagHeader.tkt_tagType = pTag->GetType(); tagHeader.tkt_tagName = pTag->GetName(); tagHeader.tkt_tagDataSize = pTag->GetDataSize(); // Stuff the tag info into the data chunk. rDataChunk.StuffAndOffsetData((Ptr) &tagHeader, rStuffOffset, headerSize); rDataChunk.StuffAndOffsetData(FT_GetTagDataReference( pTag->GetData()), rStuffOffset, pTag->GetDataSize()); } } catch (SN_Exception& rException) { result = rException; // The data chunk is no longer valid. rDataChunk.DestroyData(); } return result; } Listing Twelve void* CreateAnyObject(long objectType) { switch (objectType) { case ca_kObjectPane: return new CA_ObjectPane; break; case vp_kView: return new VP_View; break; ... default: return nil; } } Listing Thirteen SN_Error TK_PackerObject::UnpackMyData(LB_DataChunk& rPackedData) { TK_TagHeader* pTagHeader; FT_TagData tagData = nil; SN_Error result; LB_DataSize unpackOffset = 0; LB_DataSize dataSize = rPackedData.GetDataSize(); // Unpack the packed data to restore the object. Add each tag as you come // upon it in data chunk. For now, assume all data is packed tag data. EX_TRY { // Make sure that if the data is a handle, it doesn't get purged. LB_ChunkData chunkData; EX_THROW_ERROR(rPackedData.RetrieveData(chunkData)); EX_THROW_NIL(chunkData.GetData()); // Remove all existing tags. EX_THROW_ERROR(RemoveAllTags()); // This object has been stored with tags- extract them. while (unpackOffset < dataSize) { // Extract the current tag header. pTagHeader = (TK_TagHeader*) ((long) chunkData.GetData() + unpackOffset); tagData = nil; // Advance past the tag header. unpackOffset += sizeof(TK_TagHeader); if (pTagHeader->tkt_tagDataSize > 0) { // This tag has data. Allocate space in memory for tag data. tagData = GetAllocatedTagData(pTagHeader->tkt_tagDataSize); EX_THROW_NIL(tagData); EX_THROW_NIL(FT_GetTagDataReference(tagData)); { FT_UseTagData useTagData(tagData); // Copy the tag data into the pointer. BlockMove((Ptr) ((long) pTagHeader + sizeof(TK_TagHeader)), FT_GetTagDataReference(tagData), FT_GetTagDataSize(tagData)); // Advance past the tag data. unpackOffset += pTagHeader->tkt_tagDataSize; } } // Attach each tag. EX_THROW_ERROR(AttachTag(pTagHeader->tkt_tagName, pTagHeader->tkt_tagType, tagData, FT_GetTagDataSize(tagData))); } } catch (SN_Exception& rException) { result = rException; if (tagData) // Release the unused tag data from memory. DisposeTagData(tagData); } return result; } Listing Fourteen SN_Error CA_ColoredObject::ExtractStorageTags(TK_PackerObject& rObject) { SN_Error result; EX_TRY { RGBColor rgbColor; if (!TK_RetrieveRGBColor(rObject, kColorName, rgbColor).NoError()) // Use the default value. SetColor(0, 0, 0); else cac_color.SetRGBColor(rgbColor); } catch (SN_Exception& rException) { result = rException; } return result; }