windows-nt/Source/XPSP1/NT/com/ole32/stg/props/utest/propdump.cxx
2020-09-26 16:20:57 +08:00

1464 lines
35 KiB
C++

//+============================================================================
//
// File: PropDump.cxx
//
// Purpose:
// This file contains routines to dump all the properties of all
// the property sets of a DocFile. It's started by calling
// DumpOleStorage().
//
//+============================================================================
// --------
// Includes
// --------
#include "pch.cxx"
// -------
// Globals
// -------
OLECHAR *oszDays[] =
{
OLESTR("Sun"),
OLESTR("Mon"),
OLESTR("Tue"),
OLESTR("Wed"),
OLESTR("Thu"),
OLESTR("Fri"),
OLESTR("Sat")
};
OLECHAR *oszMonths[] =
{
OLESTR("Jan"), OLESTR("Feb"), OLESTR("Mar"), OLESTR("Apr"), OLESTR("May"), OLESTR("Jun"),
OLESTR("Jul"), OLESTR("Aug"), OLESTR("Sep"), OLESTR("Oct"), OLESTR("Nov"), OLESTR("Dec")
};
//+----------------------------------------------------------------------------
//+----------------------------------------------------------------------------
OLECHAR *
oszft(FILETIME *pft)
{
static OLECHAR oszbuf[32];
#ifdef _MAC
soprintf( oszbuf, OLESTR("%08X-%08X"), pft->dwHighDateTime, pft->dwLowDateTime );
#else
FILETIME ftlocal;
SYSTEMTIME st;
oszbuf[0] = '\0';
if (pft->dwHighDateTime != 0 || pft->dwLowDateTime != 0)
{
if (!FileTimeToLocalFileTime(pft, &ftlocal) ||
!FileTimeToSystemTime(&ftlocal, &st))
{
return(OLESTR("Time???"));
}
soprintf(
oszbuf,
OLESTR("%s %s %2d %2d:%02d:%02d %4d"),
oszDays[st.wDayOfWeek],
oszMonths[st.wMonth - 1],
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wYear);
}
#endif
return(oszbuf);
}
VOID
DumpTime(OLECHAR *pozname, FILETIME *pft)
{
LARGE_INTEGER UNALIGNED *pli = (LARGE_INTEGER UNALIGNED *) pft;
ASYNC_PRINTF(
"%s%08lx:%08lx%hs%s\n",
pozname,
pli->HighPart,
pli->LowPart,
pli->QuadPart == 0? g_szEmpty : " - ",
oszft((FILETIME *) pft));
}
VOID
PrintGuid(GUID *pguid)
{
ASYNC_PRINTF(
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
pguid->Data1,
pguid->Data2,
pguid->Data3,
pguid->Data4[0],
pguid->Data4[1],
pguid->Data4[2],
pguid->Data4[3],
pguid->Data4[4],
pguid->Data4[5],
pguid->Data4[6],
pguid->Data4[7]);
}
VOID
ListPropSetHeader(
STATPROPSETSTG *pspss,
OLECHAR *poszName)
{
BOOLEAN fDocumentSummarySection2;
OLECHAR oszStream[CCH_PROPSETSZ];
fDocumentSummarySection2 = (BOOLEAN)
memcmp(&pspss->fmtid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0;
ASYNC_PRINTF(" Property set ");
PrintGuid(&pspss->fmtid);
RtlGuidToPropertySetName(&pspss->fmtid, oszStream);
ASYNC_OPRINTF(
OLESTR("\n %hs Name %s"),
(pspss->grfFlags & PROPSETFLAG_NONSIMPLE)?
"Embedding" : "Stream",
oszStream);
if (poszName != NULL || fDocumentSummarySection2)
{
ASYNC_OPRINTF(
OLESTR(" (%s)"),
poszName != NULL? poszName : OLESTR("User defined properties"));
}
ASYNC_PRINTF("\n");
if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
{
DumpTime(OLESTR(" Create Time "), &pspss->ctime);
}
DumpTime(OLESTR(" Modify Time "), &pspss->mtime);
if (pspss->grfFlags & PROPSETFLAG_NONSIMPLE)
{
DumpTime(OLESTR(" Access Time "), &pspss->atime);
}
}
typedef enum _PUBLICPROPSET
{
PUBPS_UNKNOWN = 0,
PUBPS_SUMMARYINFO = 3,
PUBPS_DOCSUMMARYINFO = 4,
PUBPS_USERDEFINED = 5,
} PUBLICPROPSET;
#define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
ULONG
SizeProp(PROPVARIANT *pv)
{
ULONG j;
ULONG cbprop = 0;
switch (pv->vt)
{
default:
case VT_EMPTY:
case VT_NULL:
break;
case VT_UI1:
cbprop = sizeof(pv->bVal);
break;
case VT_I2:
case VT_UI2:
case VT_BOOL:
cbprop = sizeof(pv->iVal);
break;
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR:
cbprop = sizeof(pv->lVal);
break;
case VT_I8:
case VT_UI8:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_FILETIME:
cbprop = sizeof(pv->hVal);
break;
case VT_CLSID:
cbprop = sizeof(*pv->puuid);
break;
case VT_BLOB_OBJECT:
case VT_BLOB:
cbprop = pv->blob.cbSize + sizeof(pv->blob.cbSize);
break;
case VT_CF:
cbprop = sizeof(pv->pclipdata->cbSize) +
pv->pclipdata->cbSize;
break;
case VT_BSTR:
// count + string
cbprop = sizeof(ULONG);
if (pv->bstrVal != NULL)
{
cbprop += BSTRLEN(pv->bstrVal);
}
break;
case VT_LPSTR:
// count + string + null char
cbprop = sizeof(ULONG);
if (pv->pszVal != NULL)
{
cbprop += strlen(pv->pszVal) + 1;
}
break;
case VT_STREAM:
case VT_STREAMED_OBJECT:
case VT_STORAGE:
case VT_STORED_OBJECT:
case VT_LPWSTR:
// count + string + null char
cbprop = sizeof(ULONG);
if (pv->pwszVal != NULL)
{
cbprop += sizeof(pv->pwszVal[0]) * (wcslen(pv->pwszVal) + 1);
}
break;
// vectors
case VT_VECTOR | VT_UI1:
cbprop = sizeof(pv->caub.cElems) +
pv->caub.cElems * sizeof(pv->caub.pElems[0]);
break;
case VT_VECTOR | VT_I2:
case VT_VECTOR | VT_UI2:
case VT_VECTOR | VT_BOOL:
cbprop = sizeof(pv->cai.cElems) +
pv->cai.cElems * sizeof(pv->cai.pElems[0]);
break;
case VT_VECTOR | VT_I4:
case VT_VECTOR | VT_UI4:
case VT_VECTOR | VT_R4:
case VT_VECTOR | VT_ERROR:
cbprop = sizeof(pv->cal.cElems) +
pv->cal.cElems * sizeof(pv->cal.pElems[0]);
break;
case VT_VECTOR | VT_I8:
case VT_VECTOR | VT_UI8:
case VT_VECTOR | VT_R8:
case VT_VECTOR | VT_CY:
case VT_VECTOR | VT_DATE:
case VT_VECTOR | VT_FILETIME:
cbprop = sizeof(pv->cah.cElems) +
pv->cah.cElems * sizeof(pv->cah.pElems[0]);
break;
case VT_VECTOR | VT_CLSID:
cbprop = sizeof(pv->cauuid.cElems) +
pv->cauuid.cElems * sizeof(pv->cauuid.pElems[0]);
break;
case VT_VECTOR | VT_CF:
cbprop = sizeof(pv->caclipdata.cElems);
for (j = 0; j < pv->caclipdata.cElems; j++)
{
cbprop += sizeof(pv->caclipdata.pElems[j].cbSize) +
DwordAlign(pv->caclipdata.pElems[j].cbSize);
}
break;
case VT_VECTOR | VT_BSTR:
cbprop = sizeof(pv->cabstr.cElems);
for (j = 0; j < pv->cabstr.cElems; j++)
{
// count + string + null char
cbprop += sizeof(ULONG);
if (pv->cabstr.pElems[j] != NULL)
{
cbprop += DwordAlign(BSTRLEN(pv->cabstr.pElems[j]));
}
}
break;
case VT_VECTOR | VT_LPSTR:
cbprop = sizeof(pv->calpstr.cElems);
for (j = 0; j < pv->calpstr.cElems; j++)
{
// count + string + null char
cbprop += sizeof(ULONG);
if (pv->calpstr.pElems[j] != NULL)
{
cbprop += DwordAlign(strlen(pv->calpstr.pElems[j]) + 1);
}
}
break;
case VT_VECTOR | VT_LPWSTR:
cbprop = sizeof(pv->calpwstr.cElems);
for (j = 0; j < pv->calpwstr.cElems; j++)
{
// count + string + null char
cbprop += sizeof(ULONG);
if (pv->calpwstr.pElems[j] != NULL)
{
cbprop += DwordAlign(
sizeof(pv->calpwstr.pElems[j][0]) *
(wcslen(pv->calpwstr.pElems[j]) + 1));
}
}
break;
case VT_VECTOR | VT_VARIANT:
cbprop = sizeof(pv->calpwstr.cElems);
for (j = 0; j < pv->calpwstr.cElems; j++)
{
cbprop += SizeProp(&pv->capropvar.pElems[j]);
}
break;
}
return(DwordAlign(cbprop) + DwordAlign(sizeof(pv->vt)));
}
PUBLICPROPSET
GuidToPropSet(GUID *pguid)
{
PUBLICPROPSET pubps = PUBPS_UNKNOWN;
if (pguid != NULL)
{
if (memcmp(pguid, &FMTID_SummaryInformation, sizeof(GUID)) == 0)
{
pubps = PUBPS_SUMMARYINFO;
}
else if (memcmp(pguid, &FMTID_DocSummaryInformation, sizeof(GUID)) == 0)
{
pubps = PUBPS_DOCSUMMARYINFO;
}
else if (memcmp(pguid, &FMTID_UserDefinedProperties, sizeof(GUID)) == 0)
{
pubps = PUBPS_USERDEFINED;
}
}
return(pubps);
}
char
PrintableChar(char ch)
{
if (ch < ' ' || ch > '~')
{
ch = '.';
}
return(ch);
}
VOID
DumpHex(BYTE *pb, ULONG cb, ULONG base)
{
char *pszsep;
ULONG r, i, cbremain;
int fZero = FALSE;
int fSame = FALSE;
for (r = 0; r < cb; r += 16)
{
cbremain = cb - r;
if (r != 0 && cbremain >= 16)
{
if (pb[r] == 0)
{
ULONG j;
for (j = r + 1; j < cb; j++)
{
if (pb[j] != 0)
{
break;
}
}
if (j == cb)
{
fZero = TRUE;
break;
}
}
if (memcmp(&pb[r], &pb[r - 16], 16) == 0)
{
fSame = TRUE;
continue;
}
}
if (fSame)
{
ASYNC_PRINTF("\n\t *");
fSame = FALSE;
}
for (i = 0; i < min(cbremain, 16); i++)
{
pszsep = " ";
if ((i % 8) == 0) // 0 or 8
{
pszsep = " ";
if (i == 0) // 0
{
// start a new line
ASYNC_PRINTF("%s %04x:", r == 0? "" : "\n", r + base);
pszsep = " ";
}
}
ASYNC_PRINTF("%s%02x", pszsep, pb[r + i]);
}
if (i != 0)
{
ASYNC_PRINTF("%*s", 3 + (16 - i)*3 + ((i <= 8)? 1 : 0), "");
for (i = 0; i < min(cbremain, 16); i++)
{
ASYNC_PRINTF("%c", PrintableChar(pb[r + i]));
}
}
}
if (r != 0)
{
ASYNC_PRINTF("\n");
}
if (fZero)
{
ASYNC_PRINTF(" Remaining %lx bytes are zero\n", cbremain);
}
}
// Property Id's for Summary Info
#define PID_TITLE 0x00000002L // VT_LPSTR
#define PID_SUBJECT 0x00000003L // VT_LPSTR
#define PID_AUTHOR 0x00000004L // VT_LPSTR
#define PID_KEYWORDS 0x00000005L // VT_LPSTR
#define PID_COMMENTS 0x00000006L // VT_LPSTR
#define PID_TEMPLATE 0x00000007L // VT_LPSTR
#define PID_LASTAUTHOR 0x00000008L // VT_LPSTR
#define PID_REVNUMBER 0x00000009L // VT_LPSTR
#define PID_EDITTIME 0x0000000aL // VT_FILETIME
#define PID_LASTPRINTED 0x0000000bL // VT_FILETIME
#define PID_CREATE_DTM 0x0000000cL // VT_FILETIME
#define PID_LASTSAVE_DTM 0x0000000dL // VT_FILETIME
#define PID_PAGECOUNT 0x0000000eL // VT_I4
#define PID_WORDCOUNT 0x0000000fL // VT_I4
#define PID_CHARCOUNT 0x00000010L // VT_I4
#define PID_THUMBNAIL 0x00000011L // VT_CF
#define PID_APPNAME 0x00000012L // VT_LPSTR
#define PID_SECURITY_DSI 0x00000013L // VT_I4
// Property Id's for Document Summary Info
#define PID_CATEGORY 0x00000002L // VT_LPSTR
#define PID_PRESFORMAT 0x00000003L // VT_LPSTR
#define PID_BYTECOUNT 0x00000004L // VT_I4
#define PID_LINECOUNT 0x00000005L // VT_I4
#define PID_PARACOUNT 0x00000006L // VT_I4
#define PID_SLIDECOUNT 0x00000007L // VT_I4
#define PID_NOTECOUNT 0x00000008L // VT_I4
#define PID_HIDDENCOUNT 0x00000009L // VT_I4
#define PID_MMCLIPCOUNT 0x0000000aL // VT_I4
#define PID_SCALE 0x0000000bL // VT_BOOL
#define PID_HEADINGPAIR 0x0000000cL // VT_VECTOR | VT_VARIANT
#define PID_DOCPARTS 0x0000000dL // VT_VECTOR | VT_LPSTR
#define PID_MANAGER 0x0000000eL // VT_LPSTR
#define PID_COMPANY 0x0000000fL // VT_LPSTR
#define PID_LINKSDIRTY 0x00000010L // VT_BOOL
#define PID_CCHWITHSPACES 0x00000011L // VT_I4
#define PID_GUID 0x00000012L // VT_LPSTR
#define PID_SHAREDDOC 0x00000013L // VT_BOOL
#define PID_LINKBASE 0x00000014L // VT_LPSTR
#define PID_HLINKS 0x00000015L // VT_VECTOR | VT_VARIANT
#define PID_HYPERLINKSCHANGED 0x00000016L // VT_BOOL
VOID
DisplayProps(
GUID *pguid,
ULONG cprop,
PROPID apid[],
STATPROPSTG asps[],
PROPVARIANT *av,
BOOLEAN fsumcat,
ULONG *pcbprop)
{
PROPVARIANT *pv;
PROPVARIANT *pvend;
STATPROPSTG *psps;
BOOLEAN fVariantVector;
PUBLICPROPSET pubps;
fVariantVector = (asps == NULL);
pubps = GuidToPropSet(pguid);
pvend = &av[cprop];
for (pv = av, psps = asps; pv < pvend; pv++, psps++)
{
ULONG j;
ULONG cbprop;
PROPID propid;
OLECHAR *postrName;
char *psz;
BOOLEAN fNewLine = TRUE;
int ccol;
static char szNoFormat[] = " (no display format)";
char achvt[19 + 8 + 1];
cbprop = SizeProp(pv);
*pcbprop += cbprop;
postrName = NULL;
if (asps != NULL)
{
propid = psps->propid;
postrName = psps->lpwstrName;
}
else
{
ASSERT(apid != NULL);
propid = apid[0];
}
ASYNC_PRINTF(" ");
ccol = 0;
if (propid != PID_ILLEGAL)
{
ASYNC_PRINTF(" %04x", propid);
ccol += 5;
if (propid & (0xf << 28))
{
ccol += 4;
}
else if (propid & (0xf << 24))
{
ccol += 3;
}
else if (propid & (0xf << 20))
{
ccol += 2;
}
else if (propid & (0xf << 16))
{
ccol++;
}
}
if (postrName != NULL)
{
ASYNC_OPRINTF(OLESTR(" '%s'"), postrName);
ccol += ocslen(postrName) + 3;
}
else if (fVariantVector)
{
ULONG i = (ULONG) ((ULONG_PTR)pv - (ULONG_PTR)av);
ASYNC_PRINTF("[%x]", i);
do
{
ccol++;
i >>= 4;
} while (i != 0);
ccol += 2;
}
else
{
psz = NULL;
switch (propid)
{
case PID_LOCALE: psz = "Locale"; break;
case PID_SECURITY: psz = "SecurityId"; break;
case PID_MODIFY_TIME: psz = "ModifyTime"; break;
case PID_CODEPAGE: psz = "CodePage"; break;
case PID_DICTIONARY: psz = "Dictionary"; break;
}
if (psz == NULL)
switch (pubps)
{
case PUBPS_SUMMARYINFO:
switch (propid)
{
case PID_TITLE: psz = "Title"; break;
case PID_SUBJECT: psz = "Subject"; break;
case PID_AUTHOR: psz = "Author"; break;
case PID_KEYWORDS: psz = "Keywords"; break;
case PID_COMMENTS: psz = "Comments"; break;
case PID_TEMPLATE: psz = "Template"; break;
case PID_LASTAUTHOR: psz = "LastAuthor"; break;
case PID_REVNUMBER: psz = "RevNumber"; break;
case PID_EDITTIME: psz = "EditTime"; break;
case PID_LASTPRINTED: psz = "LastPrinted"; break;
case PID_CREATE_DTM: psz = "CreateDateTime"; break;
case PID_LASTSAVE_DTM: psz = "LastSaveDateTime";break;
case PID_PAGECOUNT: psz = "PageCount"; break;
case PID_WORDCOUNT: psz = "WordCount"; break;
case PID_CHARCOUNT: psz = "CharCount"; break;
case PID_THUMBNAIL: psz = "ThumbNail"; break;
case PID_APPNAME: psz = "AppName"; break;
case PID_DOC_SECURITY: psz = "Security"; break;
}
break;
case PUBPS_DOCSUMMARYINFO:
switch (propid)
{
case PID_CATEGORY: psz = "Category"; break;
case PID_PRESFORMAT: psz = "PresFormat"; break;
case PID_BYTECOUNT: psz = "ByteCount"; break;
case PID_LINECOUNT: psz = "LineCount"; break;
case PID_PARACOUNT: psz = "ParaCount"; break;
case PID_SLIDECOUNT: psz = "SlideCount"; break;
case PID_NOTECOUNT: psz = "NoteCount"; break;
case PID_HIDDENCOUNT: psz = "HiddenCount"; break;
case PID_MMCLIPCOUNT: psz = "MmClipCount"; break;
case PID_SCALE: psz = "Scale"; break;
case PID_HEADINGPAIR: psz = "HeadingPair"; break;
case PID_DOCPARTS: psz = "DocParts"; break;
case PID_MANAGER: psz = "Manager"; break;
case PID_COMPANY: psz = "Company"; break;
case PID_LINKSDIRTY: psz = "LinksDirty"; break;
case PID_CCHWITHSPACES: psz = "CchWithSpaces"; break;
case PID_GUID: psz = "Guid"; break;
case PID_SHAREDDOC: psz = "SharedDoc"; break;
case PID_LINKBASE: psz = "LinkBase"; break;
case PID_HLINKS: psz = "HLinks"; break;
case PID_HYPERLINKSCHANGED: psz = "HyperLinksChanged";break;
}
break;
}
if (psz != NULL)
{
ASYNC_PRINTF(" %s", psz);
ccol += strlen(psz) + 1;
}
}
#define CCOLPROPID 20
if (ccol != CCOLPROPID)
{
if (ccol > CCOLPROPID)
{
ccol = -1;
}
ASYNC_PRINTF("%s%*s", ccol == -1? "\n" : "", CCOLPROPID - ccol, "");
}
ASYNC_PRINTF(" %08x %04x %04x ", propid, cbprop, pv->vt);
psz = "";
switch (pv->vt)
{
default:
psz = achvt;
sprintf(psz, "Unknown (vt = %hx)", pv->vt);
break;
case VT_EMPTY:
ASYNC_PRINTF("EMPTY");
break;
case VT_NULL:
ASYNC_PRINTF("NULL");
break;
case VT_UI1:
ASYNC_PRINTF("UI1 = %02lx", pv->bVal);
psz = "";
break;
case VT_I2:
psz = "I2";
goto doshort;
case VT_UI2:
psz = "UI2";
goto doshort;
case VT_BOOL:
psz = "BOOL";
doshort:
ASYNC_PRINTF("%s = %04hx", psz, pv->iVal);
psz = g_szEmpty;
break;
case VT_I4:
psz = "I4";
goto dolong;
case VT_UI4:
psz = "UI4";
goto dolong;
case VT_R4:
psz = "R4";
goto dolong;
case VT_ERROR:
psz = "ERROR";
dolong:
ASYNC_PRINTF("%s = %08lx", psz, pv->lVal);
psz = g_szEmpty;
break;
case VT_I8:
psz = "I8";
goto dolonglong;
case VT_UI8:
psz = "UI8";
goto dolonglong;
case VT_R8:
psz = "R8";
goto dolonglong;
case VT_CY:
psz = "R8";
goto dolonglong;
case VT_DATE:
psz = "R8";
dolonglong:
ASYNC_PRINTF(
"%s = %08lx:%08lx",
psz,
pv->hVal.HighPart,
pv->hVal.LowPart);
psz = g_szEmpty;
break;
case VT_FILETIME:
DumpTime(OLESTR("FILETIME =\n\t "), &pv->filetime);
fNewLine = FALSE; // skip newline printf
break;
case VT_CLSID:
ASYNC_PRINTF("CLSID =\n\t ");
PrintGuid(pv->puuid);
break;
case VT_BLOB:
psz = "BLOB";
goto doblob;
case VT_BLOB_OBJECT:
psz = "BLOB_OBJECT";
doblob:
ASYNC_PRINTF("%s (cbSize %x)", psz, pv->blob.cbSize);
if (pv->blob.cbSize != 0)
{
ASYNC_PRINTF(" =\n");
DumpHex(pv->blob.pBlobData, pv->blob.cbSize, 0);
}
psz = g_szEmpty;
break;
case VT_CF:
ASYNC_PRINTF(
"CF (cbSize %x, ulClipFmt %x)\n",
pv->pclipdata->cbSize,
pv->pclipdata->ulClipFmt);
DumpHex(pv->pclipdata->pClipData,
pv->pclipdata->cbSize - sizeof(pv->pclipdata->ulClipFmt),
0);
break;
case VT_STREAM:
psz = "STREAM";
goto dostring;
case VT_STREAMED_OBJECT:
psz = "STREAMED_OBJECT";
goto dostring;
case VT_STORAGE:
psz = "STORAGE";
goto dostring;
case VT_STORED_OBJECT:
psz = "STORED_OBJECT";
goto dostring;
case VT_BSTR:
ASYNC_PRINTF(
"BSTR (cb = %04lx)%s\n",
pv->bstrVal == NULL? 0 : BSTRLEN(pv->bstrVal),
pv->bstrVal == NULL? " NULL" : g_szEmpty);
if (pv->bstrVal != NULL)
{
DumpHex(
(BYTE *) pv->bstrVal,
BSTRLEN(pv->bstrVal) + sizeof(WCHAR),
0);
}
break;
case VT_LPSTR:
psz = "LPSTR";
ASYNC_PRINTF(
"%s = %s%s%s",
psz,
pv->pszVal == NULL? g_szEmpty : "'",
pv->pszVal == NULL? "NULL" : pv->pszVal,
pv->pszVal == NULL? g_szEmpty : "'");
psz = g_szEmpty;
break;
case VT_LPWSTR:
psz = "LPWSTR";
dostring:
ASYNC_PRINTF(
"%s = %s%ws%s",
psz,
pv->pwszVal == NULL? g_szEmpty : "'",
pv->pwszVal == NULL? L"NULL" : pv->pwszVal,
pv->pwszVal == NULL? g_szEmpty : "'");
psz = g_szEmpty;
break;
// vectors
case VT_VECTOR | VT_UI1:
ASYNC_PRINTF("UI1[%x] =", pv->caub.cElems);
for (j = 0; j < pv->caub.cElems; j++)
{
if ((j % 16) == 0)
{
ASYNC_PRINTF("\n %02hx:", j);
}
ASYNC_PRINTF(" %02hx", pv->caub.pElems[j]);
}
break;
case VT_VECTOR | VT_I2:
psz = "I2";
goto doshortvector;
case VT_VECTOR | VT_UI2:
psz = "UI2";
goto doshortvector;
case VT_VECTOR | VT_BOOL:
psz = "BOOL";
doshortvector:
ASYNC_PRINTF("%s[%x] =", psz, pv->cai.cElems);
for (j = 0; j < pv->cai.cElems; j++)
{
if ((j % 8) == 0)
{
ASYNC_PRINTF("\n %04hx:", j);
}
ASYNC_PRINTF(" %04hx", pv->cai.pElems[j]);
}
psz = g_szEmpty;
break;
case VT_VECTOR | VT_I4:
psz = "I4";
goto dolongvector;
case VT_VECTOR | VT_UI4:
psz = "UI4";
goto dolongvector;
case VT_VECTOR | VT_R4:
psz = "R4";
goto dolongvector;
case VT_VECTOR | VT_ERROR:
psz = "ERROR";
dolongvector:
ASYNC_PRINTF("%s[%x] =", psz, pv->cal.cElems);
for (j = 0; j < pv->cal.cElems; j++)
{
if ((j % 4) == 0)
{
ASYNC_PRINTF("\n %04x:", j);
}
ASYNC_PRINTF(" %08lx", pv->cal.pElems[j]);
}
psz = g_szEmpty;
break;
case VT_VECTOR | VT_I8:
psz = "I8";
goto dolonglongvector;
case VT_VECTOR | VT_UI8:
psz = "UI8";
goto dolonglongvector;
case VT_VECTOR | VT_R8:
psz = "R8";
goto dolonglongvector;
case VT_VECTOR | VT_CY:
psz = "CY";
goto dolonglongvector;
case VT_VECTOR | VT_DATE:
psz = "DATE";
dolonglongvector:
ASYNC_PRINTF("%s[%x] =", psz, pv->cah.cElems);
for (j = 0; j < pv->cah.cElems; j++)
{
if ((j % 2) == 0)
{
ASYNC_PRINTF("\n %04x:", j);
}
ASYNC_PRINTF(
" %08lx:%08lx",
pv->cah.pElems[j].HighPart,
pv->cah.pElems[j].LowPart);
}
psz = g_szEmpty;
break;
case VT_VECTOR | VT_FILETIME:
ASYNC_PRINTF("FILETIME[%x] =\n", pv->cafiletime.cElems);
for (j = 0; j < pv->cafiletime.cElems; j++)
{
ASYNC_PRINTF(" %04x: ", j);
DumpTime(OLESTR(""), &pv->cafiletime.pElems[j]);
}
fNewLine = FALSE; // skip newline printf
break;
case VT_VECTOR | VT_CLSID:
ASYNC_PRINTF("CLSID[%x] =", pv->cauuid.cElems);
for (j = 0; j < pv->cauuid.cElems; j++)
{
ASYNC_PRINTF("\n %04x: ", j);
PrintGuid(&pv->cauuid.pElems[j]);
}
break;
case VT_VECTOR | VT_CF:
ASYNC_PRINTF("CF[%x] =", pv->caclipdata.cElems);
for (j = 0; j < pv->caclipdata.cElems; j++)
{
ASYNC_PRINTF("\n %04x: (cbSize %x, ulClipFmt %x) =\n",
j,
pv->caclipdata.pElems[j].cbSize,
pv->caclipdata.pElems[j].ulClipFmt);
DumpHex(
pv->caclipdata.pElems[j].pClipData,
pv->caclipdata.pElems[j].cbSize - sizeof(pv->caclipdata.pElems[j].ulClipFmt),
0);
}
break;
case VT_VECTOR | VT_BSTR:
ASYNC_PRINTF("BSTR[%x] =", pv->cabstr.cElems);
for (j = 0; j < pv->cabstr.cElems; j++)
{
BSTR bstr = pv->cabstr.pElems[j];
ASYNC_PRINTF(
"\n %04x: cb = %04lx%s\n",
j,
bstr == NULL? 0 : BSTRLEN(pv->cabstr.pElems[j]),
bstr == NULL? " NULL" : g_szEmpty);
if (bstr != NULL)
{
DumpHex((BYTE *) bstr, BSTRLEN(bstr) + sizeof(WCHAR), 0);
}
}
break;
case VT_VECTOR | VT_LPSTR:
ASYNC_PRINTF("LPSTR[%x] =", pv->calpstr.cElems);
for (j = 0; j < pv->calpstr.cElems; j++)
{
CHAR *psz = pv->calpstr.pElems[j];
ASYNC_PRINTF(
"\n %04x: %s%s%s",
j,
psz == NULL? g_szEmpty : "'",
psz == NULL? "NULL" : psz,
psz == NULL? g_szEmpty : "'");
}
break;
case VT_VECTOR | VT_LPWSTR:
ASYNC_PRINTF("LPWSTR[%x] =", pv->calpwstr.cElems);
for (j = 0; j < pv->calpwstr.cElems; j++)
{
WCHAR *pwsz = pv->calpwstr.pElems[j];
ASYNC_PRINTF(
"\n %04x: %s%ws%s",
j,
pwsz == NULL? g_szEmpty : "'",
pwsz == NULL? L"NULL" : pwsz,
pwsz == NULL? g_szEmpty : "'");
}
break;
case VT_VECTOR | VT_VARIANT:
ASYNC_PRINTF("VARIANT[%x] =\n", pv->capropvar.cElems);
DisplayProps(
pguid,
pv->capropvar.cElems,
&propid,
NULL,
pv->capropvar.pElems,
fsumcat,
pcbprop);
fNewLine = FALSE; // skip newline printf
break;
}
if (*psz != '\0')
{
ASYNC_PRINTF("%s", psz);
if (pv->vt & VT_VECTOR)
{
ASYNC_PRINTF("[%x]", pv->cal.cElems);
}
ASYNC_PRINTF("%s", szNoFormat);
}
if (!fVariantVector && apid != NULL && apid[pv - av] != propid)
{
ASYNC_PRINTF(" (bad PROPID: %04x)", apid[pv - av]);
fNewLine = TRUE;
}
if (asps != NULL && pv->vt != psps->vt)
{
ASYNC_PRINTF(" (bad STATPROPSTG VARTYPE: %04x)", psps->vt);
fNewLine = TRUE;
}
if (fNewLine)
{
ASYNC_PRINTF("\n");
}
}
}
STATPROPSTG aspsStatic[] = {
{ NULL, PID_CODEPAGE, VT_I2 },
{ NULL, PID_MODIFY_TIME, VT_FILETIME },
{ NULL, PID_SECURITY, VT_UI4 },
};
#define CPROPSTATIC (sizeof(aspsStatic)/sizeof(aspsStatic[0]))
#define CB_STREAM_OVERHEAD 28
#define CB_PROPSET_OVERHEAD (CB_STREAM_OVERHEAD + 8)
#define CB_PROP_OVERHEAD 8
HRESULT
DumpOlePropertySet(
IPropertySetStorage *ppsstg,
STATPROPSETSTG *pspss,
ULONG *pcprop,
ULONG *pcbprop)
{
HRESULT hr;
IEnumSTATPROPSTG *penumsps = NULL;
IPropertyStorage *pps;
ULONG cprop, cbpropset;
PROPID propid;
OLECHAR *poszName;
ULONG ispsStatic;
*pcprop = *pcbprop = 0;
hr = ppsstg->Open(
pspss->fmtid,
STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
&pps);
if( FAILED(hr) )
return(hr);
propid = PID_DICTIONARY;
hr = pps->ReadPropertyNames(1, &propid, &poszName);
if( (HRESULT) S_FALSE == hr )
hr = S_OK;
Check( S_OK, hr );
ListPropSetHeader(pspss, poszName);
if (poszName != NULL)
{
CoTaskMemFree(poszName);
}
cprop = cbpropset = 0;
Check(S_OK, pps->Enum(&penumsps) );
ispsStatic = 0;
hr = S_OK;
while (hr == S_OK)
{
STATPROPSTG sps;
PROPSPEC propspec;
PROPVARIANT propvar;
ULONG count;
hr = (HRESULT) S_FALSE;
if (ispsStatic == 0)
{
hr = penumsps->Next(1, &sps, &count);
}
if (hr != S_OK)
{
if (hr == (HRESULT) S_FALSE)
{
hr = S_OK;
if (ispsStatic >= CPROPSTATIC)
{
break;
}
sps = aspsStatic[ispsStatic];
ispsStatic++;
count = 1;
}
Check( S_OK, hr );
}
PropVariantInit(&propvar);
if (sps.lpwstrName != NULL)
{
propspec.ulKind = PRSPEC_LPWSTR;
propspec.lpwstr = sps.lpwstrName;
}
else
{
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = sps.propid;
}
hr = pps->ReadMultiple(1, &propspec, &propvar);
if (hr == (HRESULT) S_FALSE)
{
if (g_fVerbose)
{
ASYNC_PRINTF(
"%s(%u, %x) vt=%x returned hr=%x\n",
"IPropertyStorage::ReadMultiple",
ispsStatic,
propspec.propid,
propvar.vt,
hr);
}
ASSERT(propvar.vt == VT_EMPTY);
hr = S_OK;
}
Check( S_OK, hr );
if (ispsStatic == 0 || propvar.vt != VT_EMPTY)
{
ASSERT(count == 1);
cprop += count;
if (cprop == 1)
{
ASYNC_PRINTF(g_szPropHeader);
}
DisplayProps(
&pspss->fmtid,
1,
NULL,
&sps,
&propvar,
FALSE,
&cbpropset);
g_pfnPropVariantClear(&propvar);
}
if (sps.lpwstrName != NULL)
{
CoTaskMemFree(sps.lpwstrName);
}
}
if (penumsps != NULL)
{
penumsps->Release();
}
pps->Release();
if (cprop != 0)
{
cbpropset += CB_PROPSET_OVERHEAD + cprop * CB_PROP_OVERHEAD;
ASYNC_PRINTF(" %04x bytes in %u properties\n\n", cbpropset, cprop);
}
*pcprop = cprop;
*pcbprop = cbpropset;
return(hr);
}
HRESULT
DumpOlePropertySets(
IStorage *pstg,
IPropertySetStorage *pIPropSetStorage,
OLECHAR *aocpath)
{
HRESULT hr = S_OK;
IPropertySetStorage *ppsstg = pIPropSetStorage;
ULONG cbproptotal = 0;
ULONG cproptotal = 0;
ULONG cpropset = 0;
IID IIDpsstg = IID_IPropertySetStorage;
if (ppsstg == NULL)
{
Check(S_OK, StgToPropSetStg( pstg, &ppsstg ));
}
{
IEnumSTATPROPSETSTG *penumspss = NULL;
Check(S_OK, ppsstg->Enum(&penumspss) );
while (hr == S_OK)
{
STATPROPSETSTG spss;
ULONG count;
BOOLEAN fDocumentSummarySection2;
hr = penumspss->Next(1, &spss, &count);
if (hr != S_OK)
{
if (hr == (HRESULT) S_FALSE)
{
hr = (HRESULT) S_OK;
}
Check( (HRESULT) S_OK, hr );
break;
}
ASSERT(count == 1);
fDocumentSummarySection2 = FALSE;
while (TRUE)
{
ULONG cprop, cbprop;
HRESULT hr;
hr = DumpOlePropertySet(
ppsstg,
&spss,
&cprop,
&cbprop);
if( (HRESULT) STG_E_FILENOTFOUND == hr
&&
fDocumentSummarySection2 )
{
hr = S_OK;
}
cpropset++;
cproptotal += cprop;
cbproptotal += cbprop;
if (memcmp(&spss.fmtid, &FMTID_DocSummaryInformation, sizeof(FMTID)))
{
break;
}
spss.fmtid = FMTID_UserDefinedProperties;
fDocumentSummarySection2 = TRUE;
}
}
if (penumspss != NULL)
{
penumspss->Release();
}
ppsstg->Release();
}
if ((cbproptotal | cproptotal | cpropset) != 0)
{
ASYNC_PRINTF(
" %04x bytes in %u properties in %u property sets\n",
cbproptotal,
cproptotal,
cpropset);
}
return(hr);
}
NTSTATUS
DumpOleStream(
LPSTREAM pstm,
ULONG cb)
{
ULONG cbTotal = 0;
while (TRUE)
{
ULONG cbOut;
BYTE ab[4096];
Check(S_OK, pstm->Read(ab, min(cb, sizeof(ab)), &cbOut) );
if (cbOut == 0)
{
break;
}
if (g_fVerbose)
{
DumpHex(ab, cbOut, cbTotal);
}
cb -= cbOut;
cbTotal += cbOut;
}
return(STATUS_SUCCESS);
}
VOID
DumpOleStorage(
IStorage *pstg,
IPropertySetStorage *pIPropertySetStorage,
LPOLESTR aocpath )
{
LPENUMSTATSTG penum;
STATSTG ss;
IStorage* pstgChild;
LPSTREAM pstmChild;
char *szType;
OLECHAR *pocChild;
HRESULT hr;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
Check( S_OK, DumpOlePropertySets(pstg, pIPropertySetStorage, aocpath) );
if (NULL == pstg)
{
return;
}
Check( S_OK, pstg->EnumElements(0, NULL, 0, &penum) );
pocChild = &aocpath[ocslen(aocpath)];
// Continue enumeration until IEnumStatStg::Next returns non-S_OK
while (TRUE)
{
ULONG ulCount;
// Enumerate one element at a time
hr = penum->Next(1, &ss, &ulCount);
if( (HRESULT) S_FALSE == hr )
break;
else
Check( S_OK, hr );
// Select the human-readable type of object to display
switch (ss.type)
{
case STGTY_STREAM: szType = "Stream"; break;
case STGTY_STORAGE: szType = "Storage"; break;
case STGTY_LOCKBYTES: szType = "LockBytes"; break;
case STGTY_PROPERTY: szType = "Property"; break;
default: szType = "<Unknown>"; break;
}
if (g_fVerbose)
{
ASYNC_OPRINTF(
OLESTR("Type=%hs Size=%lx Mode=%lx LocksSupported=%lx StateBits=%lx '%s' + '%s'\n"),
szType,
ss.cbSize.LowPart,
ss.grfMode,
ss.grfLocksSupported,
ss.grfStateBits,
aocpath,
ss.pwcsName);
ASYNC_PRINTF("ss.clsid = ");
PrintGuid(&ss.clsid);
ASYNC_PRINTF("\n");
}
// If a stream, output the data in hex format.
if (ss.type == STGTY_STREAM)
{
ASYNC_OPRINTF(
OLESTR("Stream %s:%s, Size=%lx\n"),
aocpath,
ss.pwcsName,
ss.cbSize.LowPart);
Check(S_OK, pstg->OpenStream(
ss.pwcsName,
NULL,
STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
0,
&pstmChild) );
Check(S_OK, DumpOleStream(pstmChild, ss.cbSize.LowPart) );
pstmChild->Release();
}
// If a storage, recurse
if (ss.type == STGTY_STORAGE)
{
ASYNC_OPRINTF(
OLESTR("Storage %s\\%s, Size=%lx\n"),
aocpath,
ss.pwcsName,
ss.cbSize.LowPart);
Check( S_OK, pstg->OpenStorage(
ss.pwcsName,
NULL,
STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pstgChild) );
*pocChild = L'\\';
ocscpy(pocChild + 1, ss.pwcsName);
DumpOleStorage(pstgChild, NULL, aocpath);
pstgChild->Release();
*pocChild = L'\0';
}
CoTaskMemFree(ss.pwcsName);
PRINTF( "\n" );
}
penum->Release();
return;
}