412 lines
10 KiB
C++
412 lines
10 KiB
C++
//+--------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1991 - 1992.
|
|
//
|
|
// File: stgview.cxx
|
|
//
|
|
// Contents: Storage viewer utility
|
|
//
|
|
// History: 10-Dec-91 DrewB Created
|
|
//
|
|
//---------------------------------------------------------------
|
|
|
|
#include <memory.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
|
|
#include <windows.h>
|
|
#if WIN32 != 300
|
|
#include <storage.h>
|
|
#endif
|
|
#include <wchar.h>
|
|
#include <dfmsp.hxx>
|
|
|
|
#define FLG_RECURSIVE 0x00000001
|
|
#define FLG_STREAMS 0x00000002
|
|
#define FLG_VERBOSE 0x00000004
|
|
|
|
#define DFTOUCH
|
|
|
|
#ifdef DFTOUCH
|
|
#define CB_BUFFER 1024
|
|
#else
|
|
#define CB_BUFFER 16
|
|
#endif
|
|
BYTE abBuffer[CB_BUFFER];
|
|
|
|
char *szTypes[] =
|
|
{
|
|
"", "IStorage", "IStream", "ILockBytes"
|
|
};
|
|
|
|
void utMemFree(void *pv)
|
|
{
|
|
IMalloc FAR* pMalloc;
|
|
if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
|
|
{
|
|
pMalloc->Free(pv);
|
|
pMalloc->Release();
|
|
}
|
|
}
|
|
|
|
void LevSpace(int iLevel)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i<iLevel; i++)
|
|
printf(" ");
|
|
}
|
|
|
|
void PrintStat(STATSTG *psstg, ULONG flOptions, int iLevel)
|
|
{
|
|
LevSpace(iLevel);
|
|
if (flOptions & FLG_VERBOSE)
|
|
{
|
|
#ifdef UNICODE
|
|
wprintf(L"%s:%hs =>\n", psstg->pwcsName, szTypes[psstg->type]);
|
|
#else
|
|
printf("%s:%s =>\n", psstg->pwcsName, szTypes[psstg->type]);
|
|
#endif
|
|
|
|
#ifdef FLAT
|
|
SYSTEMTIME systime;
|
|
struct tm stime;
|
|
|
|
LevSpace(iLevel+1);
|
|
if (((psstg->ctime.dwHighDateTime != 0) ||
|
|
(psstg->ctime.dwLowDateTime != 0 )) &&
|
|
FileTimeToSystemTime(&psstg->ctime, &systime))
|
|
{
|
|
stime.tm_sec = systime.wSecond;
|
|
stime.tm_min = systime.wMinute;
|
|
stime.tm_hour = systime.wHour;
|
|
stime.tm_mday = systime.wDay;
|
|
stime.tm_mon = systime.wMonth - 1;
|
|
stime.tm_year = systime.wYear - 1900;
|
|
stime.tm_wday = systime.wDayOfWeek;
|
|
stime.tm_yday = 0;
|
|
stime.tm_isdst = 0;
|
|
|
|
printf("Created : %s", asctime(&stime));
|
|
}
|
|
else
|
|
printf("Created : %lx %lx (conversion unavailable)\n",
|
|
psstg->ctime.dwHighDateTime, psstg->ctime.dwLowDateTime);
|
|
|
|
LevSpace(iLevel+1);
|
|
if (((psstg->mtime.dwHighDateTime != 0) ||
|
|
(psstg->mtime.dwLowDateTime != 0 )) &&
|
|
FileTimeToSystemTime(&psstg->mtime, &systime))
|
|
{
|
|
stime.tm_sec = systime.wSecond;
|
|
stime.tm_min = systime.wMinute;
|
|
stime.tm_hour = systime.wHour;
|
|
stime.tm_mday = systime.wDay;
|
|
stime.tm_mon = systime.wMonth - 1;
|
|
stime.tm_year = systime.wYear - 1900;
|
|
stime.tm_wday = systime.wDayOfWeek;
|
|
stime.tm_yday = 0;
|
|
stime.tm_isdst = 0;
|
|
|
|
printf("Modified : %s", asctime(&stime));
|
|
}
|
|
else
|
|
printf("Modified : %lx %lx (conversion unavailable)\n",
|
|
psstg->ctime.dwHighDateTime, psstg->ctime.dwLowDateTime);
|
|
|
|
LevSpace(iLevel+1);
|
|
if (((psstg->atime.dwHighDateTime != 0) ||
|
|
(psstg->atime.dwLowDateTime != 0 )) &&
|
|
FileTimeToSystemTime(&psstg->mtime, &systime))
|
|
{
|
|
stime.tm_sec = systime.wSecond;
|
|
stime.tm_min = systime.wMinute;
|
|
stime.tm_hour = systime.wHour;
|
|
stime.tm_mday = systime.wDay;
|
|
stime.tm_mon = systime.wMonth - 1;
|
|
stime.tm_year = systime.wYear - 1900;
|
|
stime.tm_wday = systime.wDayOfWeek;
|
|
stime.tm_yday = 0;
|
|
stime.tm_isdst = 0;
|
|
|
|
printf("Accessed : %s", asctime(&stime));
|
|
}
|
|
else
|
|
printf("Accessed : %lx %lx (conversion unavailable)\n",
|
|
psstg->ctime.dwHighDateTime, psstg->ctime.dwLowDateTime);
|
|
#else
|
|
LevSpace(iLevel+1);
|
|
printf("Created : %lx %lx (conversion unavailable)\n",
|
|
psstg->ctime.dwHighDateTime, psstg->ctime.dwLowDateTime);
|
|
LevSpace(iLevel+1);
|
|
printf("Modified : %lx %lx (conversion unavailable)\n",
|
|
psstg->mtime.dwHighDateTime, psstg->mtime.dwLowDateTime);
|
|
LevSpace(iLevel+1);
|
|
printf("Accessed : %lx %lx (conversion unavailable)\n",
|
|
psstg->atime.dwHighDateTime, psstg->atime.dwLowDateTime);
|
|
#endif
|
|
|
|
if (psstg->type == STGTY_STREAM || psstg->type == STGTY_LOCKBYTES)
|
|
{
|
|
LevSpace(iLevel+1);
|
|
printf("Size: %lu:%lu\n", ULIGetHigh(psstg->cbSize),
|
|
ULIGetLow(psstg->cbSize));
|
|
}
|
|
}
|
|
else
|
|
#ifdef UNICODE
|
|
wprintf(L"%s\n", psstg->pwcsName);
|
|
#else
|
|
printf("%s\n", psstg->pwcsName);
|
|
#endif
|
|
}
|
|
|
|
// ctype doesn't work properly
|
|
#define dfisprint(c) ((c) >= ' ' && (c) < 127)
|
|
|
|
void Stream(IStream *pstm, ULONG flOptions, int iLevel)
|
|
{
|
|
ULONG cbRead;
|
|
#ifdef DFTOUCH
|
|
ULONG cbTotal = 0;
|
|
#endif
|
|
SCODE sc;
|
|
|
|
sc = GetScode(pstm->Read(abBuffer, CB_BUFFER, &cbRead));
|
|
while (SUCCEEDED(sc) && (cbRead > 0))
|
|
{
|
|
LevSpace(iLevel);
|
|
#ifdef DFTOUCH
|
|
cbTotal += cbRead;
|
|
printf("Read %lu bytes\n", cbTotal);
|
|
#else
|
|
for (ULONG ib = 0; ib < cbRead; ib++)
|
|
{
|
|
printf("%.2X", (int)abBuffer[ib]);
|
|
}
|
|
for (ib = ib; ib < CB_BUFFER + 1; ib++)
|
|
{
|
|
printf(" ");
|
|
}
|
|
|
|
for (ib = 0; ib < cbRead; ib++)
|
|
{
|
|
printf("%c", dfisprint(abBuffer[ib]) ? abBuffer[ib] : '.');
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
|
|
sc = GetScode(pstm->Read(abBuffer, CB_BUFFER, &cbRead));
|
|
}
|
|
if (FAILED(sc))
|
|
printf("Read failed with 0x%lX\n", sc);
|
|
}
|
|
|
|
void Contents(IStorage *pdf, ULONG flOptions, int iLevel)
|
|
{
|
|
IEnumSTATSTG *pdfi;
|
|
SCODE sc;
|
|
IStorage *pdfChild;
|
|
IStream *pstmChild;
|
|
STATSTG sstg;
|
|
|
|
if (FAILED(pdf->EnumElements(0, NULL, 0, &pdfi)))
|
|
{
|
|
fprintf(stderr, "Unable to create iterator\n");
|
|
return;
|
|
}
|
|
for (;;)
|
|
{
|
|
sc = GetScode(pdfi->Next(1, &sstg, NULL));
|
|
if (sc != S_OK)
|
|
break;
|
|
PrintStat(&sstg, flOptions, iLevel);
|
|
if ((sstg.type == STGTY_STORAGE) && (flOptions & FLG_RECURSIVE))
|
|
{
|
|
if (SUCCEEDED(pdf->OpenStorage(sstg.pwcsName, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
NULL, 0, &pdfChild)))
|
|
{
|
|
Contents(pdfChild, flOptions, iLevel+1);
|
|
pdfChild->Release();
|
|
}
|
|
else
|
|
fprintf(stderr, "%s: Unable to recurse\n", sstg.pwcsName);
|
|
}
|
|
else
|
|
if ((sstg.type == STGTY_STREAM) && (flOptions & FLG_STREAMS))
|
|
{
|
|
if (SUCCEEDED(pdf->OpenStream(sstg.pwcsName, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
0, &pstmChild)))
|
|
{
|
|
Stream(pstmChild, flOptions, iLevel+1);
|
|
pstmChild->Release();
|
|
}
|
|
else
|
|
fprintf(stderr, "%s: Unable to open\n", sstg.pwcsName);
|
|
}
|
|
utMemFree(sstg.pwcsName);
|
|
}
|
|
pdfi->Release();
|
|
if (FAILED(sc))
|
|
printf("Enumeration failed with 0x%lX\n", sc);
|
|
}
|
|
|
|
void Descend(IStorage *pdf, char *pszPath, IStorage **ppdf)
|
|
{
|
|
IStorage *pdfNext;
|
|
char *pszNext = pszPath;
|
|
char *pszEnd = strchr(pszNext, '\\');
|
|
TCHAR atcName[CWCSTORAGENAME];
|
|
|
|
while (pszNext != NULL)
|
|
{
|
|
if (pszEnd != NULL)
|
|
{
|
|
*pszEnd = '\0';
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
if (mbstowcs(atcName, pszNext, CWCSTORAGENAME) == (size_t)-1)
|
|
{
|
|
pdf = NULL;
|
|
|
|
fprintf(stderr, "Unable to convert '%s' to Unicode\n", pszNext);
|
|
break;
|
|
}
|
|
#else
|
|
strcpy(atcName, pszNext);
|
|
#endif
|
|
if (SUCCEEDED(pdf->OpenStorage(atcName, NULL,
|
|
STGM_READ | STGM_SHARE_EXCLUSIVE,
|
|
NULL, 0, &pdfNext)))
|
|
{
|
|
pdf = pdfNext;
|
|
|
|
if (pszEnd != NULL)
|
|
{
|
|
*pszEnd = '\\';
|
|
|
|
pszNext = pszEnd + 1;
|
|
pszEnd = strchr(pszNext, '\\');
|
|
}
|
|
else
|
|
{
|
|
pszNext = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pdf = NULL;
|
|
|
|
fprintf(stderr, "Unable to open '%s' in docfile\n", pszPath);
|
|
break;
|
|
}
|
|
}
|
|
|
|
*ppdf = pdf;
|
|
}
|
|
|
|
void __cdecl main(int argc, char **argv)
|
|
{
|
|
ULONG flOptions = 0;
|
|
IStorage *pdf;
|
|
IStorage *pdfRoot;
|
|
STATSTG sstg;
|
|
|
|
argc--;
|
|
argv++;
|
|
while ((argc > 0) && ((*argv)[0] == '-'))
|
|
{
|
|
for (int ich = 1; (*argv)[ich] != '\0'; ich++)
|
|
{
|
|
switch((*argv)[ich])
|
|
{
|
|
case 's':
|
|
flOptions |= FLG_STREAMS;
|
|
break;
|
|
case 'v':
|
|
flOptions |= FLG_VERBOSE;
|
|
break;
|
|
case 'r':
|
|
flOptions |= FLG_RECURSIVE;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Unknown switch '%c'\n", (*argv)[ich]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if ((argc != 1) && (argc != 2))
|
|
{
|
|
printf("Usage: stgview [-v] [-s] [-r] docfile [path]\n");
|
|
exit(1);
|
|
}
|
|
|
|
SCODE sc;
|
|
|
|
#if WIN32 == 300
|
|
if (FAILED(sc = GetScode(CoInitializeEx(NULL, COINIT_MULTITHREADED))))
|
|
#else
|
|
if (FAILED(sc = GetScode(CoInitialize(NULL))))
|
|
#endif
|
|
{
|
|
fprintf(stderr, "CoInitialize failed with sc = %lx\n", sc);
|
|
exit(1);
|
|
}
|
|
|
|
TCHAR atcName[_MAX_PATH];
|
|
#ifdef UNICODE
|
|
if (mbstowcs(atcName, *argv, _MAX_PATH) == (size_t)-1)
|
|
{
|
|
fprintf(stderr, "Unable to convert '%s' to Unicode\n", *argv);
|
|
exit(1);
|
|
}
|
|
#else
|
|
strcpy(atcName, *argv);
|
|
#endif
|
|
if (FAILED(StgOpenStorage(atcName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE,
|
|
NULL, 0, &pdf)))
|
|
{
|
|
fprintf(stderr, "Unable to open '%s'\n", *argv);
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
if (argc == 2)
|
|
{
|
|
Descend(pdf, *(argv + 1), &pdfRoot);
|
|
}
|
|
else
|
|
{
|
|
pdf->AddRef();
|
|
pdfRoot = pdf;
|
|
}
|
|
|
|
if (pdfRoot != NULL)
|
|
{
|
|
if (FAILED(pdfRoot->Stat(&sstg, 0)))
|
|
fprintf(stderr, "Unable to stat root\n");
|
|
else
|
|
{
|
|
PrintStat(&sstg, flOptions, 0);
|
|
utMemFree(sstg.pwcsName);
|
|
}
|
|
Contents(pdfRoot, flOptions, 1);
|
|
pdfRoot->Release();
|
|
}
|
|
pdf->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|