_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;
}






