⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stg_prop.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
    return hr;
}

static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm,
 PROPERTYSECTIONHEADER *hdr)
{
    BYTE buf[sizeof(PROPERTYSECTIONHEADER)];
    ULONG count = 0;
    HRESULT hr;

    assert(stm);
    assert(hdr);
    hr = IStream_Read(stm, buf, sizeof(buf), &count);
    if (SUCCEEDED(hr))
    {
        if (count != sizeof(buf))
        {
            WARN("read only %d\n", count);
            hr = STG_E_INVALIDHEADER;
        }
        else
        {
            StorageUtl_ReadDWord(buf, offsetof(PROPERTYSECTIONHEADER,
             cbSection), &hdr->cbSection);
            StorageUtl_ReadDWord(buf, offsetof(PROPERTYSECTIONHEADER,
             cProperties), &hdr->cProperties);
        }
    }
    TRACE("returning 0x%08x\n", hr);
    return hr;
}

static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This)
{
    PROPERTYSETHEADER hdr;
    FORMATIDOFFSET fmtOffset;
    PROPERTYSECTIONHEADER sectionHdr;
    LARGE_INTEGER seek;
    ULONG i;
    STATSTG stat;
    HRESULT hr;
    BYTE *buf = NULL;
    ULONG count = 0;
    DWORD dictOffset = 0;

    This->dirty = FALSE;
    This->highestProp = 0;
    hr = IStream_Stat(This->stm, &stat, STATFLAG_NONAME);
    if (FAILED(hr))
        goto end;
    if (stat.cbSize.u.HighPart)
    {
        WARN("stream too big\n");
        /* maximum size varies, but it can't be this big */
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    if (stat.cbSize.u.LowPart == 0)
    {
        /* empty stream is okay */
        hr = S_OK;
        goto end;
    }
    else if (stat.cbSize.u.LowPart < sizeof(PROPERTYSETHEADER) +
     sizeof(FORMATIDOFFSET))
    {
        WARN("stream too small\n");
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    seek.QuadPart = 0;
    hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL);
    if (FAILED(hr))
        goto end;
    hr = PropertyStorage_ReadHeaderFromStream(This->stm, &hdr);
    /* I've only seen reserved == 1, but the article says I shouldn't disallow
     * higher values.
     */
    if (hdr.wByteOrder != PROPSETHDR_BYTEORDER_MAGIC || hdr.reserved < 1)
    {
        WARN("bad magic in prop set header\n");
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    if (hdr.wFormat != 0 && hdr.wFormat != 1)
    {
        WARN("bad format version %d\n", hdr.wFormat);
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    This->format = hdr.wFormat;
    memcpy(&This->clsid, &hdr.clsid, sizeof(This->clsid));
    This->originatorOS = hdr.dwOSVer;
    if (PROPSETHDR_OSVER_KIND(hdr.dwOSVer) == PROPSETHDR_OSVER_KIND_MAC)
        WARN("File comes from a Mac, strings will probably be screwed up\n");
    hr = PropertyStorage_ReadFmtIdOffsetFromStream(This->stm, &fmtOffset);
    if (FAILED(hr))
        goto end;
    if (fmtOffset.dwOffset > stat.cbSize.u.LowPart)
    {
        WARN("invalid offset %d (stream length is %d)\n", fmtOffset.dwOffset,
         stat.cbSize.u.LowPart);
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    /* wackiness alert: if the format ID is FMTID_DocSummaryInformation, there
     * follow not one, but two sections.  The first is the standard properties
     * for the document summary information, and the second is user-defined
     * properties.  This is the only case in which multiple sections are
     * allowed.
     * Reading the second stream isn't implemented yet.
     */
    hr = PropertyStorage_ReadSectionHeaderFromStream(This->stm, &sectionHdr);
    if (FAILED(hr))
        goto end;
    /* The section size includes the section header, so check it */
    if (sectionHdr.cbSection < sizeof(PROPERTYSECTIONHEADER))
    {
        WARN("section header too small, got %d\n", sectionHdr.cbSection);
        hr = STG_E_INVALIDHEADER;
        goto end;
    }
    buf = HeapAlloc(GetProcessHeap(), 0, sectionHdr.cbSection -
     sizeof(PROPERTYSECTIONHEADER));
    if (!buf)
    {
        hr = STG_E_INSUFFICIENTMEMORY;
        goto end;
    }
    hr = IStream_Read(This->stm, buf, sectionHdr.cbSection -
     sizeof(PROPERTYSECTIONHEADER), &count);
    if (FAILED(hr))
        goto end;
    TRACE("Reading %d properties:\n", sectionHdr.cProperties);
    for (i = 0; SUCCEEDED(hr) && i < sectionHdr.cProperties; i++)
    {
        PROPERTYIDOFFSET *idOffset = (PROPERTYIDOFFSET *)(buf +
         i * sizeof(PROPERTYIDOFFSET));

        if (idOffset->dwOffset < sizeof(PROPERTYSECTIONHEADER) ||
         idOffset->dwOffset >= sectionHdr.cbSection - sizeof(DWORD))
            hr = STG_E_INVALIDPOINTER;
        else
        {
            if (idOffset->propid >= PID_FIRST_USABLE &&
             idOffset->propid < PID_MIN_READONLY && idOffset->propid >
             This->highestProp)
                This->highestProp = idOffset->propid;
            if (idOffset->propid == PID_DICTIONARY)
            {
                /* Don't read the dictionary yet, its entries depend on the
                 * code page.  Just store the offset so we know to read it
                 * later.
                 */
                dictOffset = idOffset->dwOffset;
                TRACE("Dictionary offset is %d\n", dictOffset);
            }
            else
            {
                PROPVARIANT prop;

                PropVariantInit(&prop);
                if (SUCCEEDED(PropertyStorage_ReadProperty(This, &prop,
                 buf + idOffset->dwOffset - sizeof(PROPERTYSECTIONHEADER))))
                {
                    TRACE("Read property with ID 0x%08x, type %d\n",
                     idOffset->propid, prop.vt);
                    switch(idOffset->propid)
                    {
                    case PID_CODEPAGE:
                        if (prop.vt == VT_I2)
                            This->codePage = (UINT)prop.u.iVal;
                        break;
                    case PID_LOCALE:
                        if (prop.vt == VT_I4)
                            This->locale = (LCID)prop.u.lVal;
                        break;
                    case PID_BEHAVIOR:
                        if (prop.vt == VT_I4 && prop.u.lVal)
                            This->grfFlags |= PROPSETFLAG_CASE_SENSITIVE;
                        /* The format should already be 1, but just in case */
                        This->format = 1;
                        break;
                    default:
                        hr = PropertyStorage_StorePropWithId(This,
                         idOffset->propid, &prop, This->codePage);
                    }
                }
            }
        }
    }
    if (!This->codePage)
    {
        /* default to Unicode unless told not to, as specified here:
         * http://msdn.microsoft.com/library/en-us/stg/stg/names_in_istorage.asp
         */
        if (This->grfFlags & PROPSETFLAG_ANSI)
            This->codePage = GetACP();
        else
            This->codePage = CP_UNICODE;
    }
    if (!This->locale)
        This->locale = LOCALE_SYSTEM_DEFAULT;
    TRACE("Code page is %d, locale is %d\n", This->codePage, This->locale);
    if (dictOffset)
        hr = PropertyStorage_ReadDictionary(This,
         buf + dictOffset - sizeof(PROPERTYSECTIONHEADER));

end:
    HeapFree(GetProcessHeap(), 0, buf);
    if (FAILED(hr))
    {
        dictionary_destroy(This->name_to_propid);
        This->name_to_propid = NULL;
        dictionary_destroy(This->propid_to_name);
        This->propid_to_name = NULL;
        dictionary_destroy(This->propid_to_prop);
        This->propid_to_prop = NULL;
    }
    return hr;
}

static void PropertyStorage_MakeHeader(PropertyStorage_impl *This,
 PROPERTYSETHEADER *hdr)
{
    assert(hdr);
    StorageUtl_WriteWord((BYTE *)&hdr->wByteOrder, 0,
     PROPSETHDR_BYTEORDER_MAGIC);
    StorageUtl_WriteWord((BYTE *)&hdr->wFormat, 0, This->format);
    StorageUtl_WriteDWord((BYTE *)&hdr->dwOSVer, 0, This->originatorOS);
    StorageUtl_WriteGUID((BYTE *)&hdr->clsid, 0, &This->clsid);
    StorageUtl_WriteDWord((BYTE *)&hdr->reserved, 0, 1);
}

static void PropertyStorage_MakeFmtIdOffset(PropertyStorage_impl *This,
 FORMATIDOFFSET *fmtOffset)
{
    assert(fmtOffset);
    StorageUtl_WriteGUID((BYTE *)fmtOffset, 0, &This->fmtid);
    StorageUtl_WriteDWord((BYTE *)fmtOffset, offsetof(FORMATIDOFFSET, dwOffset),
     sizeof(PROPERTYSETHEADER) + sizeof(FORMATIDOFFSET));
}

static void PropertyStorage_MakeSectionHdr(DWORD cbSection, DWORD numProps,
 PROPERTYSECTIONHEADER *hdr)
{
    assert(hdr);
    StorageUtl_WriteDWord((BYTE *)hdr, 0, cbSection);
    StorageUtl_WriteDWord((BYTE *)hdr,
     offsetof(PROPERTYSECTIONHEADER, cProperties), numProps);
}

static void PropertyStorage_MakePropertyIdOffset(DWORD propid, DWORD dwOffset,
 PROPERTYIDOFFSET *propIdOffset)
{
    assert(propIdOffset);
    StorageUtl_WriteDWord((BYTE *)propIdOffset, 0, propid);
    StorageUtl_WriteDWord((BYTE *)propIdOffset,
     offsetof(PROPERTYIDOFFSET, dwOffset), dwOffset);
}

struct DictionaryClosure
{
    HRESULT hr;
    DWORD bytesWritten;
};

static BOOL PropertyStorage_DictionaryWriter(const void *key,
 const void *value, void *extra, void *closure)
{
    PropertyStorage_impl *This = (PropertyStorage_impl *)extra;
    struct DictionaryClosure *c = (struct DictionaryClosure *)closure;
    DWORD propid;
    ULONG count;

    assert(key);
    assert(closure);
    StorageUtl_WriteDWord((LPBYTE)&propid, 0, (DWORD)value);
    c->hr = IStream_Write(This->stm, &propid, sizeof(propid), &count);
    if (FAILED(c->hr))
        goto end;
    c->bytesWritten += sizeof(DWORD);
    if (This->codePage == CP_UNICODE)
    {
        DWORD keyLen, pad = 0;

        StorageUtl_WriteDWord((LPBYTE)&keyLen, 0,
         (lstrlenW((LPCWSTR)key) + 1) * sizeof(WCHAR));
        c->hr = IStream_Write(This->stm, &keyLen, sizeof(keyLen), &count);
        if (FAILED(c->hr))
            goto end;
        c->bytesWritten += sizeof(DWORD);
        /* Rather than allocate a copy, I'll swap the string to little-endian
         * in-place, write it, then swap it back.
         */
        PropertyStorage_ByteSwapString(key, keyLen);
        c->hr = IStream_Write(This->stm, key, keyLen, &count);
        PropertyStorage_ByteSwapString(key, keyLen);
        if (FAILED(c->hr))
            goto end;
        c->bytesWritten += keyLen;
        if (keyLen % sizeof(DWORD))
        {
            c->hr = IStream_Write(This->stm, &pad,
             sizeof(DWORD) - keyLen % sizeof(DWORD), &count);
            if (FAILED(c->hr))
                goto end;
            c->bytesWritten += sizeof(DWORD) - keyLen % sizeof(DWORD);
        }
    }
    else
    {
        DWORD keyLen;

        StorageUtl_WriteDWord((LPBYTE)&keyLen, 0, strlen((LPCSTR)key) + 1);
        c->hr = IStream_Write(This->stm, &keyLen, sizeof(keyLen), &count);
        if (FAILED(c->hr))
            goto end;
        c->bytesWritten += sizeof(DWORD);
        c->hr = IStream_Write(This->stm, key, keyLen, &count);
        if (FAILED(c->hr))
            goto end;
        c->bytesWritten += keyLen;
    }
end:
    return SUCCEEDED(c->hr);
}

#define SECTIONHEADER_OFFSET sizeof(PROPERTYSETHEADER) + sizeof(FORMATIDOFFSET)

/* Writes the dictionary to the stream.  Assumes without checking that the
 * dictionary isn't empty.
 */
static HRESULT PropertyStorage_WriteDictionaryToStream(
 PropertyStorage_impl *This, DWORD *sectionOffset)
{
    HRESULT hr;
    LARGE_INTEGER seek;
    PROPERTYIDOFFSET propIdOffset;
    ULONG count;
    DWORD dwTemp;
    struct DictionaryClosure closure;

    assert(sectionOffset);

    /* The dictionary's always the first property written, so seek to its
     * spot.
     */
    seek.QuadPart = SECTIONHEADER_OFFSET + sizeof(PROPERTYSECTIONHEADER);
    hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL);
    if (FAILED(hr))
        goto end;
    PropertyStorage_MakePropertyIdOffset(PID_DICTIONARY, *sectionOffset,
     &propIdOffset);
    hr = IStream_Write(This->stm, &propIdOffset, sizeof(propIdOffset), &count);
    if (FAILED(hr))
        goto end;

    seek.QuadPart = SECTIONHEADER_OFFSET + *sectionOffset;
    hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL);
    if (FAILED(hr))
        goto end;
    StorageUtl_WriteDWord((LPBYTE)&dwTemp, 0,
     dictionary_num_entries(This->name_to_propid));
    hr = IStream_Write(This->stm, &dwTemp, sizeof(dwTemp), &count);
    if (FAILED(hr))
        goto end;
    *sectionOffset += sizeof(dwTemp);

    closure.hr = S_OK;
    closure.bytesWritten = 0;
    dictionary_enumerate(This->name_to_propid, PropertyStorage_DictionaryWriter,
     &closure);
    hr = closure.hr;
    if (FAILED(hr))
        goto end;
    *sectionOffset += closure.bytesWritten;
    if (closure.bytesWritten % sizeof(DWORD))
    {
        DWORD padding = sizeof(DWORD) - closure.bytesWritten % sizeof(DWORD);
        TRACE("adding %d bytes of padding\n", padding);
        *sectionOffset += padding;
    }

end:
    return hr;
}

static HRESULT PropertyStorage_WritePropertyToStream(PropertyStorage_impl *This,
 DWORD propNum, DWORD propid, const PROPVARIANT *var, DWORD *sectionOffset)
{
    HRESULT hr;
    LARGE_INTEGER seek;
    PROPERTYIDOFFSET propIdOffset;
    ULONG count;
    DWORD dwType, bytesWritten;

    assert(var);
    assert(sectionOffset);

    TRACE("%p, %d, 0x%08x, (%d), (%d)\n", This, propNum, propid, var->vt,
     *sectionOffset);

    seek.QuadPart = SECTIONHEADER_OFFSET + sizeof(PROPERTYSECTIONHEADER) +
     propNum * sizeof(PROPERTYIDOFFSET);
    hr = IStream_Seek(This->stm, seek, STREAM_SEEK_SET, NULL);
    if (FAILED(hr))
        goto end;
    PropertyStorage_MakePropertyIdOffset(propid, *sectionOffset, &propIdOffset);
    hr = IStream_Write(This->stm, &propIdOffset, sizeof(propIdOffset), &count);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -