#pragma pack(push,1)
class datBase {
public:
    datBase () {}
    virtual ~datBase () {}
};

struct RscHeader {
    DWORD   dwMagic;
    DWORD   dwVersion;
    DWORD   dwFlags;
};

// memory block descriptor for scatter/gather
struct BlockInfo {
    DWORD   dwOffset;   // offset in the resource (high 4 bits: 5 - virtual memory page, 6 - physical memory page)
    BYTE *  pData;      // pointer to the allocated memory block
    DWORD   dwSize;     // length of the block (must be power of 2)
};

struct BlockMap {
    WORD        wVirtualCount;      // number of virtual memory blocks
    WORD        wPhysicalCount;     // number of physical memory blocks
    BlockInfo   blocks[128];        // page descriptors

    BlockMap () { wVirtualCount = wPhysicalCount = 0; }
    void allocate (DWORD dwRscFlags);   // allocate memory for resource and initialize scatter/gather info
    void release ();                    // release memory block
    BYTE * getData() { return blocks[0].pData; }
};

struct RelocationInfo {
    BlockMap *  pBlockMap;
    RelocationInfo * pPrev;
    char *      pszDescription;
    BYTE        bDefrag;
    BYTE        __pad[3];

    void    relocate (void ** ptr); // convert offset to pointer in the allocated memory block(s)
};

// collection. really simple :-)
template <typename T> class CSimpleCollection {
public:
    CSimpleCollection () {
        m_pData = NULL;
        m_wCount = m_wSize = 0;
    }
    // streaming constructor
    CSimpleCollection (RelocationInfo * pRelInfo) {
        pRelInfo->relocate ((void **)&m_pData);
    }

    ~CSimpleCollection () { if (m_pData) delete m_pData; }

    T*      m_pData;    // +0 
    WORD    m_wCount;   // +4 number of used entries in m_pData
    WORD    m_wSize;    // +6 size of m_pData
};

template <typename T> class CPtrCollection : public CSimpleCollection<T*> {
public:
    // streaming constructor
    CPtrCollection(RelocationInfo * pRelInfo) : CSimpleCollection (pRelInfo) {
        if (m_pData)
            for (WORD i = 0; i < m_wCount; i++) 
                if (m_pData[i]) {
                    pRelInfo->relocate((void **)(m_pData+i));
                    new (m_pData[i]) T(pRelInfo);
                }
    }

    ~CPtrCollection () {
        for (WORD i = 0; i < m_wCount; i++)
            if (m_pData[i])
                delete m_pData[i];
    }
};

// base class for all streamed objects
class pgBase : public datBase {
public:
    pgBase () { m_pPageMap = NULL; }
    pgBase (RelocationInfo * pRelInfo);
    virtual ~pgBase () { if (m_pPageMap) delete m_pPageMap; }

    void * operator new (size_t size, void * ptr) { return ptr; }
    void operator delete (void * ptr) { }

protected:
    DWORD * m_pPageMap;
};

template <class T> class pgDictionary : public pgBase {
public:
    pgDictionary (RelocationInfo * pRelInfo) : pgBase (pRelInfo), m_hashes (pRelInfo), m_data (pRelInfo) {
        pRelInfo->relocate ((void **)&m_pParent);
    }

    virtual ~pgDictionary() {
        if (m_data.m_pData)
            for (WORD i = 0; i < m_data.m_wCount; i++)
                if (m_data.m_pData[i])
                    delete m_data.m_pData[i];
        // do not delete m_pData in the collections: it will be released with data block 
    }

//protected:
    pgDictionary<T> *           m_pParent;
    DWORD                       m_dwUsageCount;
    CSimpleCollection<DWORD>    m_hashes;
    CPtrCollection<T>           m_data;
};

// ############################################################################


#pragma pack(pop)
