windows-nt/Source/XPSP1/NT/com/ole32/stg/async/layout/layscrpt.cxx
2020-09-26 16:20:57 +08:00

658 lines
18 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: layscrpt.cxx
//
// Contents: Code for the LayoutScript method
//
//
// History: 22-Apr-96 SusiA Created
//
//----------------------------------------------------------------------------
#include "layouthd.cxx"
#pragma hdrstop
#include <dirfunc.hxx>
#include "layout.hxx"
#include "laylkb.hxx"
#include "laywrap.hxx"
#define NULL_TERM L'\0'
#define BACKSLASH L'\\'
#define MAX_BUFFER 0x10000
//#define UNIT_TEST
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::FreeStmList
//
// Synopsis: Free the stream linked list
//
// Arguments: [pStmList] -- Pointer STREAMLIST node
//
//----------------------------------------------------------------------------
void CLayoutRootStorage::FreeStmList( STREAMLIST *pStmList)
{
STREAMLIST *ptmp = pStmList;
while (pStmList)
{
ptmp = pStmList->pnext;
#ifdef UNIT_TEST
wprintf(L"STGTY_STREAM %ls\n", pStmList->pwcsStmName );
#endif
CoTaskMemFree(pStmList->pwcsStmName);
pStmList->pStm->Release();
delete pStmList;
pStmList = ptmp;
}
}
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::FreeStgList
//
// Synopsis: Free the storage linked list
//
// Arguments: [pStgList] -- Pointer STORAGELIST node
//
//----------------------------------------------------------------------------
void CLayoutRootStorage::FreeStgList( STORAGELIST *pStgList)
{
STORAGELIST *ptmp;
while (pStgList)
{
ptmp = pStgList->pnext;
#ifdef UNIT_TEST
wprintf(L"STGTY_STORAGE %ls\n", pStgList->pwcsStgName );
#endif
CoTaskMemFree(pStgList->pwcsStgName);
pStgList->pStg->Release();
delete pStgList;
pStgList = ptmp;
}
}
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::ProcessOpen
//
// Synopsis: Open the storage or stream
//
// Arguments: [pwcsElementPathName] -- full "path" name of element to open
// [dwType] STGTY_STORAGE or STGTY_STREAM
// [ppIstgStm] interface pointer to the opened Storage or Stream
// [cOffset] offset of beginning of the read
//
// Returns: Appropriate status code
//
// History: 22-Apr-96 SusiA Created
//
//----------------------------------------------------------------------------
SCODE CLayoutRootStorage::ProcessOpen(OLECHAR *pwcsElementPathName,
DWORD dwType,
void **ppIStgStm,
LARGE_INTEGER cOffset)
{
SCODE sc = S_OK;
IStorage *pStgNew;
IStream *pStmNew;
IStorage *pStg = this;
STORAGELIST *pStgList;
STREAMLIST *pStmList;
OLECHAR *pwcsStg = pwcsElementPathName,
*pwcsTemp = pwcsElementPathName;
OLECHAR *pwcsBuffer;
if ( (!pwcsElementPathName) || (pwcsElementPathName[0] == NULL_TERM))
{
return STG_E_PATHNOTFOUND;
}
// process storage path
while (1)
{
while ((*pwcsTemp) && (*pwcsTemp != BACKSLASH))
{
pwcsTemp++;
}
pwcsBuffer = (OLECHAR *) CoTaskMemAlloc
((INT)(pwcsTemp - pwcsElementPathName + 1) *
sizeof(OLECHAR) );
if (!pwcsBuffer)
{
return STG_E_INSUFFICIENTMEMORY;
}
lstrcpynW (pwcsBuffer,
pwcsElementPathName,
(INT)(pwcsTemp - pwcsElementPathName + 1));
pwcsBuffer[pwcsTemp - pwcsElementPathName] = NULL_TERM;
if (!(*pwcsTemp))
{
//we are at the end, now handle leaf Storage or stream
break;
}
pStgList = _pStgList;
// see if this storage is already in the list
while (pStgList)
{
if (!(lstrcmpW(pwcsBuffer, pStgList->pwcsStgName )))
{
break;
}
pStgList = pStgList->pnext;
}
if (pStgList)
{
pStgNew = pStgList->pStg;
CoTaskMemFree(pwcsBuffer);
}
else
{
sc = pStg->OpenStorage(pwcsBuffer+(pwcsStg-pwcsElementPathName),
NULL,
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pStgNew);
if (FAILED(sc))
{
CoTaskMemFree(pwcsBuffer);
return sc;
}
// add the storage to the list
pStgList = _pStgList;
if (NULL == (_pStgList = new STORAGELIST))
{
CoTaskMemFree(pwcsBuffer);
pStgNew->Release();
return STG_E_INSUFFICIENTMEMORY;
}
_pStgList->pwcsStgName = pwcsBuffer;
_pStgList->pStg = pStgNew;
_pStgList->pnext = pStgList;
}
pStg = pStgNew;
pwcsStg = ++pwcsTemp;
}
//process leaf storage
if (dwType == STGTY_STORAGE)
{
sc = pStg->OpenStorage(pwcsBuffer+(pwcsStg-pwcsElementPathName),
NULL,
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pStgNew);
if (FAILED(sc))
{
CoTaskMemFree(pwcsBuffer);
return sc;
}
// add the storage to the list
pStgList = _pStgList;
if (NULL == (_pStgList = new STORAGELIST))
{
CoTaskMemFree(pwcsBuffer);
pStgNew->Release();
return STG_E_INSUFFICIENTMEMORY;
}
_pStgList->pwcsStgName = pwcsBuffer;
_pStgList->pStg = pStgNew;
_pStgList->pnext = pStgList;
*ppIStgStm = (void *) pStgNew;
}
//process leaf stream
else
{
sc = pStg->OpenStream(pwcsBuffer+(pwcsStg-pwcsElementPathName),
NULL,
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&pStmNew);
if (FAILED(sc))
{
CoTaskMemFree(pwcsBuffer);
return sc;
}
pStmList = _pStmList;
if (NULL == (_pStmList = new STREAMLIST))
{
CoTaskMemFree(pwcsBuffer);
pStmNew->Release();
return STG_E_INSUFFICIENTMEMORY;
}
_pStmList->pwcsStmName = pwcsBuffer;
_pStmList->pStm = pStmNew;
_pStmList->fDone = FALSE;
_pStmList->cOffset = cOffset;
_pStmList->pnext = pStmList;
*ppIStgStm = (void *) pStmNew;
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::ProcessItem
//
// Synopsis: Construct an unprocessed script from an app provided script
//
// Arguments: [pLayoutItem] -- Pointer to a StorageLayout element of the array
// [fStmDone] -- indicate whether the stream finished reading
//
// Returns: Appropriate status code
//
// History: 22-Apr-96 SusiA Created
//
//----------------------------------------------------------------------------
SCODE CLayoutRootStorage::ProcessItem( StorageLayout *pLayoutItem, BOOL *fStmDone )
{
SCODE sc = S_OK;
STREAMLIST *pStmList = _pStmList;
STORAGELIST *pStgList = _pStgList;
IStorage *pStgNew;
IStream *pStmNew;
ULARGE_INTEGER libNewPosition;
ULONG cbRead;
BYTE abBuffer[MAX_BUFFER];
BYTE *pb = abBuffer;
BOOL fBigBuffer = FALSE;
*fStmDone = FALSE;
if ((pLayoutItem->cOffset.QuadPart < 0) || (pLayoutItem->cBytes.QuadPart < 0))
{
return STG_E_INVALIDPARAMETER;
}
switch (pLayoutItem->LayoutType)
{
case STGTY_STORAGE:
#ifdef UNIT_TEST
wprintf(L"STGTY_STORAGE %ls %lu%lu %lu%lu\n",
pLayoutItem->pwcsElementName,
pLayoutItem->cOffset.HighPart,
pLayoutItem->cOffset.LowPart,
pLayoutItem->cBytes.HighPart,
pLayoutItem->cBytes.LowPart);
#endif
while (pStgList)
{
if (!(lstrcmpW(pLayoutItem->pwcsElementName,
pStgList->pwcsStgName )))
{
break;
}
pStgList = pStgList->pnext;
}
// if storage was not found in the list, open the storage
// and add it to the list
if (!pStgList)
{
sc = ProcessOpen(pLayoutItem->pwcsElementName,
STGTY_STORAGE,
(void **)&pStgNew,
pLayoutItem->cOffset);
if (FAILED(sc))
{
// the application may try to open Storages
// that do not really exist in the compound file,
// and we will let them try.
if (sc == STG_E_FILENOTFOUND)
{
return S_OK;
}
else
{
return sc;
}
}
}
break;
case STGTY_STREAM:
#ifdef UNIT_TEST
wprintf(L"STGTY_STREAM %ls %lu%lu %lu%lu\n",
pLayoutItem->pwcsElementName,
pLayoutItem->cOffset.HighPart,
pLayoutItem->cOffset.LowPart,
pLayoutItem->cBytes.HighPart,
pLayoutItem->cBytes.LowPart);
#endif
while (pStmList)
{
if (!(lstrcmpW(pLayoutItem->pwcsElementName,
pStmList->pwcsStmName )))
{
pStmNew = pStmList->pStm;
break;
}
pStmList = pStmList->pnext;
}
// if stream was not found in the list, open the stream,
// and add it to the list
if (pStmList)
{
if( pStmList->fDone )
{
*fStmDone = TRUE;
return S_OK;
}
}
else
{
sc = ProcessOpen(pLayoutItem->pwcsElementName,
STGTY_STREAM,
(void **)&pStmNew,
pLayoutItem->cOffset);
if (FAILED(sc))
{
// the application may try to open Streams
// that do not really exist in the compound file,
// and we will let them try.
if (sc == STG_E_FILENOTFOUND)
{
return S_OK;
}
else
{
return sc;
}
}
pStmList = _pStmList;
}
// seek to the correct position
sc = pStmNew->Seek(
pStmList->cOffset,
STREAM_SEEK_SET,
&libNewPosition );
if (FAILED(sc))
{
return sc;
}
// read the stream and update the script information
if (pLayoutItem->cBytes.LowPart > MAX_BUFFER)
{
if (NULL == (pb = (BYTE *) CoTaskMemAlloc(pLayoutItem->cBytes.LowPart)) )
{
return STG_E_INSUFFICIENTMEMORY;
}
fBigBuffer = TRUE;
}
sc = pStmNew->Read(pb,
pLayoutItem->cBytes.LowPart,
&cbRead);
if (fBigBuffer)
{
CoTaskMemFree(pb);
fBigBuffer = FALSE;
pb = abBuffer;
}
if (FAILED(sc))
{
return sc;
}
//we have reached the end of the stream, mark it as done
if (cbRead < pLayoutItem->cBytes.LowPart)
{
pStmList->fDone = TRUE;
}
pStmList->cOffset.QuadPart += cbRead;
break;
default:
// we just handle storages and stream types
return STG_E_INVALIDPARAMETER;
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::ProcessRepeatLoop
//
// Synopsis: Construct an unprocessed script from an app provided script
//
// Arguments: [pStorageLayout] -- Pointer to storage layout array
// [nEntries] -- Number of entries in the array
// [nRepeatStart] -- address of index of start of repeat loop
//
// Returns: Appropriate status code
//
// History: 22-Apr-96 SusiA Created
//
//----------------------------------------------------------------------------
SCODE CLayoutRootStorage::ProcessRepeatLoop( StorageLayout *pStorageLayout,
DWORD nEntries,
int * nRepeatStart)
{
SCODE sc = S_OK;
int i,
nLoopCount = 0,
nLoopTimes;
BOOL fDone = FALSE,
fUntilDone;
// Are we going to repeat until all streams are read to the end?
if ((nLoopTimes = (LONG) pStorageLayout[*nRepeatStart].cBytes.LowPart) != STG_TOEND)
fUntilDone = FALSE;
else
{
fUntilDone = TRUE;
nLoopTimes = 1;
}
// finished when all streams are completely read, or we have
// looped through the specified amount of times
while ((!fDone)&&(nLoopCount < nLoopTimes))
{
if (!fUntilDone)
nLoopCount ++;
i = *nRepeatStart;
fDone = TRUE;
// STGTY_REPEAT with 0 bytes indicates the end of this repeat block
while (!((pStorageLayout[++i].LayoutType == STGTY_REPEAT ) &&
(pStorageLayout[i].cBytes.QuadPart == 0)) )
{
if (i >= (LONG) nEntries)
{
return E_INVALIDARG;
}
// beginning of another repeat block
if (pStorageLayout[i].LayoutType == STGTY_REPEAT )
{
if ((pStorageLayout[i].pwcsElementName !=NULL) ||
(pStorageLayout[i].cOffset.QuadPart < 0) ||
(pStorageLayout[i].cBytes.QuadPart < 0) )
{
return STG_E_INVALIDPARAMETER;
}
layChk(ProcessRepeatLoop(pStorageLayout,
nEntries,
&i));
}
else
{
layChk(ProcessItem(&(pStorageLayout[i]), &fDone));
}
}
}
*nRepeatStart = i;
Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: CLayoutRootStorage::ProcessLayout
//
// Synopsis: Construct an unprocessed script from an app provided script
//
// Arguments: [pStorageLayout] -- Pointer to storage layout array
// [nEntries] -- Number of entries in the array
// [grfInterleavedFlag] -- Specifies disposition of control
// structures
//
// Returns: Appropriate status code
//
// History: 22-Apr-96 SusiA Created
//
//----------------------------------------------------------------------------
SCODE CLayoutRootStorage::ProcessLayout( StorageLayout *pStorageLayout,
DWORD nEntries,
DWORD glfInterleavedFlag)
{
SCODE sc = S_OK;
int i;
BOOL fUnused;
TCHAR *patcScriptName = _pllkb->GetScriptName();
for (i = 0; i < (LONG) nEntries; i++)
{
if (pStorageLayout[i].LayoutType == STGTY_REPEAT )
{
if (pStorageLayout[i].cBytes.QuadPart != 0)
{
if ((pStorageLayout[i].pwcsElementName !=NULL) ||
(pStorageLayout[i].cOffset.QuadPart < 0) ||
(pStorageLayout[i].cBytes.QuadPart < 0) )
{
return STG_E_INVALIDPARAMETER;
}
layChk(ProcessRepeatLoop(pStorageLayout,
nEntries,
&i));
}
else //end repeat block with no matching beginning
{
sc = E_INVALIDARG;
layChk(sc);
}
}
else // (pStorageLayout[i].LayoutType == STGTY_REPEAT )
{
layChk(ProcessItem(&(pStorageLayout[i]), &fUnused));
}
}
Err:
if (_pStgList)
{
FreeStgList(_pStgList);
_pStgList = NULL;
}
if (_pStmList)
{
FreeStmList(_pStmList);
_pStmList = NULL;
}
return sc;
}