mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1196 lines
41 KiB
1196 lines
41 KiB
/*
|
|
|
|
Title: Base routines for OLE2 Structured Storage file system
|
|
This file provide read access routines for OLE2 structured storage IO system.
|
|
However, it avoids using OLE2 calls to insure portability copnsistency
|
|
and speed improvement.
|
|
SCCIO_SS.C
|
|
|
|
Author: Randal Chao
|
|
|
|
History:
|
|
|
|
7-11-94 Initial Development
|
|
|
|
|
|
*/
|
|
|
|
#include "sccio_ss.h"
|
|
#include "sccio_ss.pro"
|
|
|
|
|
|
#define IOOLE2RootSectorOffset(pRoot, SectorNum) (IOOLE2RootHeaderSize + ((DWORD)(SectorNum) * (pRoot)->SectorSize))
|
|
|
|
|
|
WORD IOOLE2ReadWORD (BYTE FAR *pBuf, WORD ByteOrder) //func for code efficiency,
|
|
{
|
|
if (IOOLE2IntelByteOrder == ByteOrder)
|
|
return *pBuf + ( (WORD)(*(pBuf + 1)) << 8 );
|
|
else
|
|
return ((WORD)(*pBuf) << 8) + *(pBuf + 1);
|
|
}
|
|
|
|
LONG IOOLE2ReadLONG (BYTE FAR *pBuf, WORD ByteOrder)
|
|
{
|
|
if (IOOLE2IntelByteOrder == ByteOrder)
|
|
return IOOLE2ReadWORD(pBuf, ByteOrder) + ((LONG) IOOLE2ReadWORD(pBuf+2, ByteOrder) << 16);
|
|
else
|
|
return ((LONG) IOOLE2ReadWORD(pBuf, ByteOrder) << 16) + IOOLE2ReadWORD(pBuf+2, ByteOrder);
|
|
}
|
|
|
|
/***************************/
|
|
IOERR IOIsOLE2RootStorage (HIOFILE hFile)
|
|
{
|
|
BYTE Signiture[8];
|
|
DWORD Count;
|
|
|
|
IOSeek (hFile, IOSEEK_TOP, 0);
|
|
IORead (hFile, Signiture, 8, &Count);
|
|
IOSeek (hFile, IOSEEK_TOP, 0);
|
|
|
|
if (Count == 8 &&
|
|
Signiture[0] == 0xd0 &&
|
|
Signiture[1] == 0xcf &&
|
|
Signiture[2] == 0x11 &&
|
|
Signiture[3] == 0xe0 &&
|
|
Signiture[4] == 0xa1 &&
|
|
Signiture[5] == 0xb1 &&
|
|
Signiture[6] == 0x1a &&
|
|
Signiture[7] == 0xe1)
|
|
|
|
return (IOERR_TRUE);
|
|
else
|
|
return (IOERR_FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
*********************************************************
|
|
*
|
|
* OLE2 Root Storage IO Routines
|
|
*
|
|
*********************************************************
|
|
*/
|
|
|
|
void IOOLE2RootStorageFreeAlloc (PIOROOTSTORAGE pRoot)
|
|
{
|
|
if ((HANDLE)NULL != pRoot->hMiniStreamBuf)
|
|
{
|
|
UTGlobalUnlock (pRoot->hMiniStreamBuf);
|
|
UTGlobalFree (pRoot->hMiniStreamBuf);
|
|
}
|
|
|
|
if ((HANDLE)NULL != pRoot->hMiniFatBuf)
|
|
{
|
|
UTGlobalUnlock (pRoot->hMiniFatBuf);
|
|
UTGlobalFree (pRoot->hMiniFatBuf);
|
|
}
|
|
|
|
if ((HANDLE)NULL != pRoot->hDirBuf)
|
|
{
|
|
UTGlobalUnlock (pRoot->hDirBuf);
|
|
UTGlobalFree (pRoot->hDirBuf);
|
|
}
|
|
|
|
if ((HANDLE)NULL != pRoot->hFatBuf)
|
|
{
|
|
UTGlobalUnlock (pRoot->hFatBuf);
|
|
UTGlobalFree (pRoot->hFatBuf);
|
|
}
|
|
|
|
if ((HANDLE)NULL != pRoot->hDifBuf)
|
|
{
|
|
UTGlobalUnlock (pRoot->hDifBuf);
|
|
UTGlobalFree (pRoot->hDifBuf);
|
|
}
|
|
|
|
if ((HANDLE)NULL != pRoot->hThis)
|
|
{
|
|
HANDLE hRoot = pRoot->hThis;
|
|
UTGlobalUnlock (hRoot);
|
|
UTGlobalFree (hRoot);
|
|
}
|
|
}
|
|
|
|
/***************************/
|
|
IOERR IOOpenOLE2RootStorage(HIOFILE FAR * phFile, HIOSPEC hSpec, DWORD dwFlags)
|
|
{
|
|
DWORD Count = 0;
|
|
HANDLE hRoot; // hIORootStorage is too long, hRoot is better
|
|
PIOROOTSTORAGE pRoot;
|
|
|
|
|
|
//Alloctate Memory
|
|
if ( (HANDLE)NULL == (hRoot = UTGlobalAlloc(sizeof(IOROOTSTORAGE))) )
|
|
return (IOERR_ALLOCFAIL);
|
|
pRoot = (PIOROOTSTORAGE) UTGlobalLock(hRoot);
|
|
pRoot->hThis = hRoot;
|
|
pRoot->hFatBuf = (HANDLE)NULL;
|
|
pRoot->hDirBuf = (HANDLE)NULL;
|
|
pRoot->hMiniFatBuf = (HANDLE)NULL;
|
|
pRoot->hMiniStreamBuf = (HANDLE)NULL;
|
|
pRoot->hDifBuf = (HANDLE)NULL;
|
|
|
|
|
|
//Read Header Info
|
|
IOSeek (* phFile, IOSEEK_TOP, 0);
|
|
IORead (* phFile, pRoot->HeaderBuf, IOOLE2RootHeaderSize, &Count);
|
|
if (IOOLE2RootHeaderSize != Count)
|
|
{ // Bad Header read
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_UNKNOWN); // No other err type defined yet
|
|
}
|
|
pRoot->ByteOrder = ((WORD) (pRoot->HeaderBuf)[0x1c] << 8) + (pRoot->HeaderBuf)[0x1d]; // Either Intel or Mac
|
|
pRoot->SectorSize = 1 << IOOLE2ReadWORD (pRoot->HeaderBuf + 0x1E, pRoot->ByteOrder); // Constant integer is at least 2 bytes, so OK
|
|
pRoot->MiniSectorSize = 1 << IOOLE2ReadWORD (pRoot->HeaderBuf + 0x20, pRoot->ByteOrder);
|
|
pRoot->FatLength = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x2c, pRoot->ByteOrder);
|
|
pRoot->DirStart = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x30, pRoot->ByteOrder);
|
|
pRoot->MiniSectorCutoff = (DWORD)IOOLE2ReadLONG (pRoot->HeaderBuf + 0x38, pRoot->ByteOrder);
|
|
pRoot->MiniFatStart = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x3c, pRoot->ByteOrder);
|
|
pRoot->MiniFatLength = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x40, pRoot->ByteOrder);
|
|
pRoot->DifStart = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x44, pRoot->ByteOrder);
|
|
pRoot->DifLength = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x48, pRoot->ByteOrder);
|
|
|
|
// Init Fat Buffer
|
|
if ((HANDLE)NULL == (pRoot->hFatBuf = UTGlobalAlloc(pRoot->SectorSize)))
|
|
{ // Bad Allocation
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
pRoot->pFatBuf = UTGlobalLock(pRoot->hFatBuf);
|
|
pRoot->CurrFatOffset = 0;
|
|
Count = 0;
|
|
IOSeek (* phFile, IOSEEK_TOP, IOOLE2RootSectorOffset(pRoot, IOOLE2ReadLONG (pRoot->HeaderBuf + 0x4c, pRoot->ByteOrder)) );
|
|
IORead (* phFile, pRoot->pFatBuf, pRoot->SectorSize, &Count); // Assume OK now, May need to check read status
|
|
if (pRoot->SectorSize != Count)
|
|
{ // Bad Fat!
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_UNKNOWN);
|
|
}
|
|
|
|
// Init Directory Buffer
|
|
if ((HANDLE)NULL == (pRoot->hDirBuf = UTGlobalAlloc(pRoot->SectorSize)))
|
|
{ // Bad Allocation
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
pRoot->pDirBuf = UTGlobalLock(pRoot->hDirBuf);
|
|
pRoot->CurrDirOffset = 0;
|
|
pRoot->CurrDirSector = pRoot->DirStart;
|
|
Count = 0;
|
|
IOSeek (* phFile, IOSEEK_TOP, IOOLE2RootSectorOffset (pRoot, pRoot->CurrDirSector));
|
|
IORead (* phFile, pRoot->pDirBuf, pRoot->SectorSize, &Count); // Assume OK now, May need to check read status
|
|
if (pRoot->SectorSize != Count)
|
|
{ // Bad Dir!
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_UNKNOWN);
|
|
}
|
|
|
|
// Init MiniFat Buffer
|
|
if ((HANDLE)NULL == (pRoot->hMiniFatBuf = UTGlobalAlloc(pRoot->SectorSize)))
|
|
{ // Bad Allocation
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
pRoot->pMiniFatBuf = UTGlobalLock(pRoot->hMiniFatBuf);
|
|
pRoot->CurrMiniFatOffset = 0;
|
|
pRoot->CurrMiniFatSector = pRoot->MiniFatStart;
|
|
if (pRoot->CurrMiniFatSector!=-2 && pRoot->CurrMiniFatSector!=-1)//In case there is no mini fat!! RMC 2/1/95
|
|
{
|
|
Count = 0;
|
|
IOSeek (* phFile, IOSEEK_TOP, IOOLE2RootSectorOffset (pRoot, pRoot->CurrMiniFatSector));
|
|
IORead (* phFile, pRoot->pMiniFatBuf, pRoot->SectorSize, &Count); // Assume OK now, May need to check read status
|
|
if (pRoot->SectorSize != Count)
|
|
{ // Bad Dir!
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_UNKNOWN);
|
|
}
|
|
}
|
|
|
|
|
|
// Init MiniStream Buffer
|
|
if ((HANDLE)NULL == (pRoot->hMiniStreamBuf = UTGlobalAlloc(pRoot->SectorSize)))
|
|
{ // Bad Allocation
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
pRoot->pMiniStreamBuf = UTGlobalLock(pRoot->hMiniStreamBuf);
|
|
pRoot->CurrMiniSectorOffset = 0;
|
|
pRoot->CurrMiniStreamSector = pRoot->MiniStreamStart =
|
|
IOOLE2ReadLONG (pRoot->pDirBuf + 0x74, pRoot->ByteOrder); //The starting ministream sector
|
|
pRoot->MiniStreamSize = IOOLE2ReadLONG (pRoot->pDirBuf + 0x78, pRoot->ByteOrder); // MiniStream Size
|
|
if (pRoot->CurrMiniStreamSector!=-2 && pRoot->CurrMiniStreamSector!=-1)//In case there is no mini stream! RMC 2/1/95
|
|
{
|
|
Count = 0;
|
|
IOSeek (* phFile, IOSEEK_TOP, IOOLE2RootSectorOffset (pRoot, pRoot->CurrMiniStreamSector));
|
|
IORead (* phFile, pRoot->pMiniStreamBuf, pRoot->SectorSize, &Count); // Assume OK now, May need to check read status
|
|
if (pRoot->SectorSize != Count)
|
|
{
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
}
|
|
|
|
// Init Dif Buffer, it is too time consuming, we read it on the fly later to speed up open time
|
|
if (pRoot->FatLength > IOOLE2DifFatOffset) // Only large file has DIF
|
|
{
|
|
if ((HANDLE)NULL == (pRoot->hDifBuf = UTGlobalAlloc(pRoot->SectorSize)))
|
|
{ // Bad Allocation
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
pRoot->pDifBuf = UTGlobalLock(pRoot->hDifBuf);
|
|
pRoot->CurrDifOffset = pRoot->CurrDifSector = -1; // The first DIF Sector and fat sector offset, dummy value read them later
|
|
// IOSeek (* phFile, IOSEEK_TOP, IOOLE2RootSectorOffset (pRoot, pRoot->CurDifSector));
|
|
// IORead (* phFile, pRoot->pDifBuf, pRoot->SectorSize, &Count); // Assume OK now, May need to check read status
|
|
}
|
|
|
|
// Virtual Function Tables
|
|
pRoot->sBaseIO.pClose = IORootStgClose;
|
|
pRoot->sBaseIO.pRead = IORootStgRead;
|
|
pRoot->sBaseIO.pWrite = IORootStgWrite;
|
|
pRoot->sBaseIO.pSeek = IORootStgSeek;
|
|
pRoot->sBaseIO.pTell = IORootStgTell;
|
|
pRoot->sBaseIO.pGetInfo = IORootStgGetInfo;
|
|
pRoot->sBaseIO.pOpen = IOOpen;
|
|
|
|
// Other Internal data
|
|
pRoot->dwFlags = dwFlags; // Internal Data
|
|
pRoot->hRefFile = * phFile; // Original Flat file, will be used from now on
|
|
pRoot->hSpec = hSpec;
|
|
UTmemcpy (pRoot->ClassId, pRoot->pDirBuf + 0x50, 16); // Class Id for the root
|
|
|
|
|
|
*phFile = (HIOFILE)pRoot; // The new root storage file!
|
|
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
/*******************************/
|
|
IOERR IO_ENTRYMOD IOOLE2RootStgReadSector (PIOROOTSTORAGE pRoot, LONG Sector, BYTE FAR * pBuf)
|
|
{
|
|
DWORD Count = 0;
|
|
|
|
IOSeek (pRoot->hRefFile, IOSEEK_TOP, IOOLE2RootSectorOffset(pRoot, Sector));
|
|
IORead(pRoot->hRefFile, pBuf, pRoot->SectorSize, &Count);
|
|
// if (pRoot->SectorSize != Count)
|
|
if (!Count) //There are doc files that contain a partial sector, stupid!
|
|
return IOERR_UNKNOWN; //WARNINGGGG!!!!!!!! pBuf may have been changed!!!!!!!!!!!, Recovery for pRoot may needed
|
|
else
|
|
return IOERR_OK;
|
|
//All recovery is done through flag -1 if fat, dir, minifat or ministream buf corrupted
|
|
//This insures that if one substream fails, it does not affect other substreams
|
|
}
|
|
|
|
/*******************************/ //Read a number of continous sectors
|
|
IOERR IO_ENTRYMOD IOOLE2RootStgReadConsecutiveSector (PIOROOTSTORAGE pRoot, LONG StartSector, LONG SectorNum, BYTE FAR * pBuf)
|
|
{ DWORD Count = 0;
|
|
|
|
IOSeek (pRoot->hRefFile, IOSEEK_TOP, IOOLE2RootSectorOffset(pRoot, StartSector));
|
|
IORead(pRoot->hRefFile, pBuf, pRoot->SectorSize*SectorNum, &Count);
|
|
// if (pRoot->SectorSize * SectorNum != Count)
|
|
if (!Count) //There are doc files that contain a partial sector, stupid!
|
|
return IOERR_UNKNOWN; //WARNINGGGG!!!!!!!! pBuf may have been changed!!!!!!!!!!!
|
|
else
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
|
|
/*******************************/ // return -1 if err
|
|
LONG IOOLE2RootStgGetNextSector (PIOROOTSTORAGE pRoot, LONG Sector)
|
|
{
|
|
LONG RelativeOffset, FatBufEntry, FatRelativeOffset, FatBufSector;
|
|
WORD FatPerBuf = (WORD)(pRoot->SectorSize >> 2); // # of fat entries in a sector
|
|
WORD DifFatSize = FatPerBuf - 1; // # of fat sector entries in a dif
|
|
|
|
if (-1 == pRoot->CurrFatOffset) // In case fat are corrupted!
|
|
{
|
|
pRoot->CurrFatOffset = 0;
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, IOOLE2ReadLONG (pRoot->HeaderBuf + 0x4c, pRoot->ByteOrder), pRoot->pFatBuf))
|
|
{
|
|
pRoot->CurrFatOffset = -1; //Fat Corrupted
|
|
return -1; // Never come here!
|
|
}
|
|
}
|
|
|
|
RelativeOffset = Sector - pRoot->CurrFatOffset;
|
|
// See if it is in current fat buf, SectorSize >> 2 is the number of fat entries in one fat sector
|
|
if ( RelativeOffset >= 0 && RelativeOffset < (LONG) FatPerBuf )
|
|
return IOOLE2ReadLONG (pRoot->pFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range
|
|
|
|
// Have to fill the FAT buffer then
|
|
FatBufEntry = (Sector / FatPerBuf); // Which fat sector should the entry be?
|
|
if (FatBufEntry < IOOLE2DifFatOffset) // To see if dif is involved
|
|
{
|
|
FatBufSector = IOOLE2ReadLONG (pRoot->HeaderBuf + 0x4c + (FatBufEntry << 2), pRoot->ByteOrder);
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, FatBufSector, pRoot->pFatBuf))
|
|
{
|
|
pRoot->CurrFatOffset = -1; //Fat Corrupted,
|
|
return -1;
|
|
}
|
|
pRoot->CurrFatOffset = FatBufEntry * FatPerBuf;
|
|
RelativeOffset = Sector - pRoot->CurrFatOffset;
|
|
return IOOLE2ReadLONG (pRoot->pFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range now
|
|
}
|
|
|
|
// Have to deal with Dif, first deal with current dif buffer
|
|
if (-1 == pRoot->CurrDifOffset) // if Dif corrupted
|
|
{
|
|
pRoot->CurrDifOffset = IOOLE2DifFatOffset;
|
|
pRoot->CurrDifSector = pRoot->DifStart;
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->CurrDifSector, pRoot->pDifBuf))
|
|
{
|
|
pRoot->CurrDifOffset = -1; //Dif Corrupted,
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
FatRelativeOffset = (FatBufEntry - pRoot->CurrDifOffset); // distance from the curren dif buffer
|
|
if (FatRelativeOffset >=0 && FatRelativeOffset < (LONG)DifFatSize ) // is it in the current dif buffer?
|
|
{
|
|
FatBufSector = IOOLE2ReadLONG (pRoot->pDifBuf + (FatRelativeOffset << 2), pRoot->ByteOrder);
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, FatBufSector, pRoot->pFatBuf))
|
|
{
|
|
pRoot->CurrFatOffset = -1; // Fat corrupted
|
|
return -1;
|
|
}
|
|
pRoot->CurrFatOffset = FatBufEntry * FatPerBuf;
|
|
RelativeOffset = Sector - pRoot->CurrFatOffset;
|
|
return IOOLE2ReadLONG (pRoot->pFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range now
|
|
}
|
|
|
|
// Worst case, have to read dif also!
|
|
|
|
if (FatRelativeOffset < 0) // Whoops, we have to search from the beginning!
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->DifStart, pRoot->pDifBuf))
|
|
{
|
|
pRoot->CurrDifOffset = -1;
|
|
return -1; //Uhoh, can't read!
|
|
}
|
|
pRoot->CurrDifOffset = IOOLE2DifFatOffset;
|
|
pRoot->CurrDifSector = pRoot->DifStart;
|
|
FatRelativeOffset = FatBufEntry - pRoot->CurrDifOffset;
|
|
}
|
|
|
|
while (FatRelativeOffset >= 0)
|
|
{ // Still going, going, going, going, going going
|
|
FatRelativeOffset -= DifFatSize;
|
|
pRoot->CurrDifOffset += DifFatSize;
|
|
pRoot->CurrDifSector = IOOLE2ReadLONG (pRoot->pDifBuf + pRoot->SectorSize - 4, pRoot->ByteOrder);
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->CurrDifSector, pRoot->pDifBuf))
|
|
{
|
|
pRoot->CurrDifOffset = -1;
|
|
return -1; //Uhoh, can't read!
|
|
}
|
|
}
|
|
FatRelativeOffset += DifFatSize;
|
|
|
|
FatBufSector = IOOLE2ReadLONG (pRoot->pDifBuf + (FatRelativeOffset << 2), pRoot->ByteOrder);
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, FatBufSector, pRoot->pFatBuf))
|
|
{
|
|
pRoot->CurrFatOffset = -1;
|
|
return -1;
|
|
}
|
|
pRoot->CurrFatOffset = FatBufEntry * FatPerBuf;
|
|
RelativeOffset = Sector - pRoot->CurrFatOffset;
|
|
return IOOLE2ReadLONG (pRoot->pFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range now, finally
|
|
} // Whew, done for getnext sector !!!! ;)
|
|
|
|
|
|
|
|
/*******************************/
|
|
IOERR IO_ENTRYMOD IOOLE2RootStgReadMiniSector (PIOROOTSTORAGE pRoot, LONG MiniSector, BYTE FAR * pBuf)
|
|
{
|
|
LONG RelativeOffset;
|
|
WORD MiniSectorPerBuf = (WORD) (pRoot->SectorSize / pRoot->MiniSectorSize);
|
|
LONG NextSector, SectorOffset;
|
|
|
|
//See if the current mini stream buffer is corrupted
|
|
if (-1 == pRoot->CurrMiniSectorOffset)
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->MiniStreamStart, pRoot->pMiniStreamBuf))
|
|
return IOERR_UNKNOWN;
|
|
pRoot->CurrMiniStreamSector = pRoot->MiniStreamStart;
|
|
pRoot->CurrMiniSectorOffset = 0;
|
|
}
|
|
|
|
RelativeOffset = MiniSector - pRoot->CurrMiniSectorOffset;
|
|
//See if it is inthe current ministream buffer
|
|
if (RelativeOffset >= 0 && RelativeOffset < (LONG)MiniSectorPerBuf)
|
|
{
|
|
BYTE FAR * pSourceBuf = pRoot->pMiniStreamBuf + RelativeOffset * pRoot->MiniSectorSize;
|
|
UTmemcpy (pBuf, pSourceBuf, pRoot->MiniSectorSize);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
// Well, have to read the ministream buffer then
|
|
if (RelativeOffset < 0) //Search from the begining if this is the case!
|
|
{
|
|
RelativeOffset = MiniSector;
|
|
NextSector = pRoot->MiniStreamStart;
|
|
SectorOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
NextSector = pRoot->CurrMiniStreamSector; //Search from the current then
|
|
SectorOffset = pRoot->CurrMiniSectorOffset;
|
|
}
|
|
while (RelativeOffset >= (LONG)MiniSectorPerBuf)
|
|
{
|
|
if (-1 == (NextSector = IOOLE2RootStgGetNextSector (pRoot, NextSector)))
|
|
return IOERR_UNKNOWN;
|
|
RelativeOffset -= MiniSectorPerBuf;
|
|
SectorOffset += MiniSectorPerBuf;
|
|
}
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, NextSector, pRoot->pMiniStreamBuf))
|
|
{
|
|
pRoot->CurrMiniSectorOffset = -1;
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
pRoot->CurrMiniStreamSector = NextSector;
|
|
pRoot->CurrMiniSectorOffset = SectorOffset;
|
|
|
|
UTmemcpy (pBuf, pRoot->pMiniStreamBuf + RelativeOffset * pRoot->MiniSectorSize, pRoot->MiniSectorSize);
|
|
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
/*******************************/ //Read a number of continous minisectors
|
|
IOERR IO_ENTRYMOD IOOLE2RootStgReadConsecutiveMiniSector (PIOROOTSTORAGE pRoot, LONG StartMiniSector, LONG SectorNum, BYTE FAR * pBuf)
|
|
{ // For consecutive minisector, there is no optimization, not worth it, just read each minisector!
|
|
LONG i;
|
|
|
|
for (i = 0; i < SectorNum; i++)
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgReadMiniSector(pRoot, StartMiniSector + i, pBuf))
|
|
return IOERR_UNKNOWN; // Whoops, can't read anymore
|
|
#ifdef WIN16
|
|
pBuf = (BYTE FAR *) ((BYTE HUGE *)pBuf + pRoot->MiniSectorSize); // May be unnecessary, minisector never cross boundary
|
|
#else
|
|
pBuf += pRoot->MiniSectorSize;
|
|
#endif
|
|
}
|
|
return IOERR_OK;
|
|
}
|
|
|
|
/*******************************/
|
|
LONG IOOLE2RootStgGetNextMiniSector (PIOROOTSTORAGE pRoot, LONG MiniSector) // Return -1 if IO err
|
|
{
|
|
LONG RelativeOffset, SectorOffset, NextSector;
|
|
WORD MiniFatPerBuf = (WORD)(pRoot->SectorSize >> 2); // # of Minifat sector entries in a minifat sector
|
|
|
|
//See if minifat buffer corrupted
|
|
if (-1 == pRoot->CurrMiniFatOffset)
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->MiniFatStart, pRoot->pMiniFatBuf))
|
|
return -1;
|
|
RelativeOffset = MiniSector;
|
|
pRoot->CurrMiniFatOffset = 0;
|
|
pRoot->CurrMiniFatSector = pRoot->MiniFatStart;
|
|
}
|
|
|
|
RelativeOffset = MiniSector - pRoot->CurrMiniFatOffset;
|
|
// See if it is in current minifat buf
|
|
if ( RelativeOffset >= 0 && RelativeOffset < (LONG)MiniFatPerBuf )
|
|
return IOOLE2ReadLONG (pRoot->pMiniFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range
|
|
|
|
// Have to fill the MiniFAT buffer then
|
|
if (RelativeOffset < 0) // Whoops, we have to search from the beginning!
|
|
{
|
|
RelativeOffset = MiniSector;
|
|
SectorOffset = 0;
|
|
NextSector = pRoot->MiniFatStart;
|
|
}
|
|
else
|
|
{
|
|
SectorOffset = pRoot->CurrMiniFatOffset;
|
|
NextSector = pRoot->CurrMiniFatSector;
|
|
}
|
|
|
|
while (RelativeOffset >= (LONG)MiniFatPerBuf) //Search, search, search, search
|
|
{ // Still going, going, going, going, going going
|
|
if (-1 == (NextSector = IOOLE2RootStgGetNextSector (pRoot, NextSector)))
|
|
return -1;
|
|
RelativeOffset -= MiniFatPerBuf;
|
|
SectorOffset += MiniFatPerBuf;
|
|
}
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, NextSector, pRoot->pMiniFatBuf))
|
|
{
|
|
pRoot->CurrMiniFatOffset = -1;
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
pRoot->CurrMiniFatOffset = SectorOffset;
|
|
pRoot->CurrMiniFatSector = NextSector;
|
|
|
|
return IOOLE2ReadLONG (pRoot->pMiniFatBuf + (RelativeOffset<<2), pRoot->ByteOrder); // hey it is in the range now, finally
|
|
} // Whew, done for getnext minisector !!!! ;)
|
|
|
|
|
|
|
|
/********************************/
|
|
IOERR IO_ENTRYMOD IOOLE2RootStgGetDirEntry (PIOROOTSTORAGE pRoot, LONG DirEntry, BYTE FAR * pDirBuf)
|
|
{
|
|
LONG RelativeOffset, NextSector, SectorOffset;
|
|
WORD DirEntryPerBuf = (WORD) (pRoot->SectorSize >> 7);
|
|
|
|
// See if the current dir buffer is corrupted
|
|
if (-1 == pRoot->CurrDirOffset)
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, pRoot->CurrDirSector, pRoot->pDirBuf))
|
|
return IOERR_UNKNOWN;
|
|
pRoot->CurrDirSector = pRoot->DirStart;
|
|
pRoot->CurrDirOffset = 0;
|
|
}
|
|
|
|
RelativeOffset = DirEntry - pRoot->CurrDirOffset;
|
|
//See if it in the current dir buffer
|
|
if (RelativeOffset >= 0 && RelativeOffset < (LONG)DirEntryPerBuf)
|
|
{
|
|
BYTE FAR * pSourceBuf = pRoot->pDirBuf + (RelativeOffset << 7);
|
|
UTmemcpy (pDirBuf, pSourceBuf, 0x80);
|
|
return IOERR_OK; //Bingo!
|
|
}
|
|
|
|
// Well, have to read the directory sector first
|
|
if (RelativeOffset < 0) //Search from the begining if this is the case!
|
|
{
|
|
RelativeOffset = DirEntry;
|
|
SectorOffset = 0;
|
|
NextSector = pRoot->DirStart;
|
|
}
|
|
else
|
|
{
|
|
SectorOffset = pRoot->CurrDirOffset;
|
|
NextSector = pRoot->CurrDirSector;
|
|
}
|
|
|
|
while (RelativeOffset >= (LONG)DirEntryPerBuf)
|
|
{
|
|
if (-1 == (NextSector = IOOLE2RootStgGetNextSector (pRoot, NextSector)))
|
|
return IOERR_UNKNOWN;
|
|
RelativeOffset -= DirEntryPerBuf;
|
|
SectorOffset += DirEntryPerBuf;
|
|
}
|
|
if (IOERR_OK != IOOLE2RootStgReadSector (pRoot, NextSector, pRoot->pDirBuf))
|
|
{
|
|
pRoot->CurrDirOffset = -1;
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
pRoot->CurrDirOffset = SectorOffset;
|
|
pRoot->CurrDirSector = NextSector;
|
|
|
|
UTmemcpy (pDirBuf, pRoot->pDirBuf + (RelativeOffset << 7), 0x80);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
/****************************/
|
|
// 2 if DirName > name in DirBuf, -2 for <, 0 for =
|
|
SHORT IOOLE2DirNameCmp (BYTE FAR *pDirBuf, WORD ByteOrder, BYTE FAR *pDirName, WORD NameLength)
|
|
{
|
|
// OLE2 Dir name length are 2 more char longer! stupid!
|
|
LONG LengthCmp = 2 + (LONG)NameLength - (LONG) IOOLE2ReadWORD(pDirBuf + 0x40, ByteOrder);
|
|
|
|
if (LengthCmp > 0)
|
|
return 2;
|
|
else if (LengthCmp < 0)
|
|
return -2;
|
|
else
|
|
{
|
|
int NameCmp = UTmemcmp (pDirName, pDirBuf, NameLength);
|
|
if (NameCmp > 0)
|
|
return 2;
|
|
else if (NameCmp < 0)
|
|
return -2;
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/****************************/
|
|
IOERR IOOLE2RootStgFindChildEntry(HIOFILE hRefStorage, BYTE FAR * pChildName, BYTE FAR *pDirEntryBuf, LONG FAR *pDirEntry, PIOROOTSTORAGE FAR * ppRoot)
|
|
{
|
|
|
|
LONG Dummy; // Dummy
|
|
|
|
PIOROOTSTORAGE pRoot; //Point back to the root
|
|
BYTE DirBuf[0x80]; //A temporary buffer
|
|
LONG CurrDirEntry; //Parent Directory entry, 0 for root case
|
|
SHORT SearchDirection;
|
|
BYTE WideChildName[0x40];//contain the unicode name, the para childname is in ansi form!
|
|
WORD ChildNameLength;
|
|
WORD i;
|
|
|
|
//Could be root or sub storage
|
|
if (IOERR_TRUE == IOGetInfo(hRefStorage,IOGETINFO_ISOLE2SUBSTORAGE, &Dummy))
|
|
{
|
|
pRoot = ((PIOSUBSTORAGE) hRefStorage)->pRoot;
|
|
CurrDirEntry = ((PIOSUBSTORAGE) hRefStorage)->DirEntry;
|
|
}
|
|
else if (IOERR_TRUE == IOGetInfo(hRefStorage,IOGETINFO_ISOLE2ROOTSTORAGE, &Dummy))
|
|
{
|
|
pRoot = (PIOROOTSTORAGE) hRefStorage;
|
|
CurrDirEntry = 0;
|
|
}
|
|
else // parent is not an OLE2 at all!
|
|
return IOERR_UNKNOWN;
|
|
|
|
|
|
//Now Get CurrDirEntry's child!
|
|
if (IOERR_OK != IOOLE2RootStgGetDirEntry (pRoot, CurrDirEntry, DirBuf))
|
|
return (IOERR_UNKNOWN);
|
|
CurrDirEntry = IOOLE2ReadLONG (DirBuf + 0x4c, pRoot->ByteOrder); // Get the child!
|
|
if (IOERR_OK != IOOLE2RootStgGetDirEntry (pRoot, CurrDirEntry, DirBuf))
|
|
return IOERR_UNKNOWN;
|
|
|
|
//Search from here, first have to Convert to Unicode name, OK for ansi only! WARNINGGGGGGGGGGGGGGGGGGGGGGGGGGG!!!!!!!!!!!!!!
|
|
for (i=0; 0 != pChildName[i] && i<32; i++)
|
|
;
|
|
ChildNameLength = i; //Aparant Name length
|
|
for (i=0; i < ChildNameLength; i++)
|
|
{
|
|
WideChildName[i<<1] = pChildName[i];
|
|
WideChildName[(i<<1) + 1] = 0;
|
|
}
|
|
for (i = i<<1; i < 64; i++)
|
|
WideChildName[i] = 0;
|
|
ChildNameLength <<= 1; // This is the unicode length now
|
|
|
|
//Determine search direction and search
|
|
SearchDirection = IOOLE2DirNameCmp (DirBuf, pRoot->ByteOrder, WideChildName, ChildNameLength); // 0; -2 Left; 2 Right
|
|
if (0 != SearchDirection) // 0 means found it!!!!!!!!
|
|
{
|
|
LONG NextSib;
|
|
|
|
NextSib = IOOLE2ReadLONG ((BYTE FAR *)DirBuf + 0x46 + SearchDirection, pRoot->ByteOrder);
|
|
while (0xffffffff != NextSib && SearchDirection != 0)
|
|
{
|
|
if (IOERR_OK != IOOLE2RootStgGetDirEntry (pRoot, NextSib, DirBuf))
|
|
return IOERR_UNKNOWN;
|
|
CurrDirEntry = NextSib;
|
|
SearchDirection = IOOLE2DirNameCmp(DirBuf, pRoot->ByteOrder, WideChildName, ChildNameLength);
|
|
NextSib = IOOLE2ReadLONG (DirBuf + 0x46 + SearchDirection, pRoot->ByteOrder);
|
|
}
|
|
if (0 != SearchDirection)
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
|
|
//If it ever gets here, the current dir entry is what we want!
|
|
UTmemcpy (pDirEntryBuf, DirBuf, 0x80);
|
|
*pDirEntry = CurrDirEntry;
|
|
*ppRoot = pRoot;
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
|
|
/*******************************/
|
|
IOERR IO_ENTRYMOD IORootStgClose(HIOFILE hFile)
|
|
{
|
|
PIOROOTSTORAGE pRoot = (PIOROOTSTORAGE)hFile;
|
|
IOERR locRet = IOERR_OK;
|
|
|
|
locRet = IOClose (pRoot->hRefFile);
|
|
IOOLE2RootStorageFreeAlloc (pRoot); //Free all including itself!
|
|
return(locRet);
|
|
}
|
|
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IORootStgRead(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IORootStgWrite(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IORootStgSeek(HIOFILE hFile, WORD wFrom, LONG lOffset)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IORootStgTell(HIOFILE hFile, DWORD FAR * pOffset)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IORootStgGetInfo(HIOFILE hFile, DWORD dwInfoId, VOID FAR * pInfo)
|
|
{
|
|
PIOROOTSTORAGE pRoot = (PIOROOTSTORAGE)hFile;
|
|
IOERR locRet = IOERR_OK;
|
|
|
|
|
|
switch (dwInfoId)
|
|
{
|
|
case IOGETINFO_PARENTHANDLE:
|
|
* (HIOFILE FAR *)pInfo = pRoot->hRefFile;
|
|
break;
|
|
|
|
case IOGETINFO_ISOLE2STORAGE:
|
|
case IOGETINFO_ISOLE2ROOTSTORAGE:
|
|
locRet = IOERR_TRUE;
|
|
break;
|
|
|
|
case IOGETINFO_OLE2CLSID:
|
|
UTmemcpy (pInfo, pRoot->ClassId, 16);
|
|
locRet = IOERR_OK;
|
|
break;
|
|
|
|
default:
|
|
locRet = IOGetInfo(pRoot->hRefFile, dwInfoId, pInfo);
|
|
break;
|
|
}
|
|
return(locRet);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*************************************************************************
|
|
*
|
|
* OLE2 Sub Storage Routines
|
|
*
|
|
*************************************************************************
|
|
*/
|
|
IOERR IOOpenOLE2SubStorage(HIOFILE FAR * phFile, HIOSPEC hSpec, DWORD dwFlags)
|
|
{
|
|
PIOROOTSTORAGE pRoot; //Point back to the root
|
|
BYTE DirBuf[0x80]; //A temporary buffer
|
|
LONG DirEntry; //Dir entry #
|
|
HANDLE hSubStorage; //Handle to the new sub storage structure
|
|
PIOSUBSTORAGE pSubStorage; //File handle for the new sub storage, give back to phFile
|
|
IOSPECSUBSTORAGE SpecSubStorage = ((PIOSPEC) UTGlobalLock (hSpec))->uTypes.sSubStorage;
|
|
|
|
if (IOERR_OK != IOOLE2RootStgFindChildEntry(SpecSubStorage.hRefStorage, SpecSubStorage.szStorageName, DirBuf, &DirEntry, &pRoot))
|
|
{
|
|
UTGlobalUnlock (hSpec); // PJB
|
|
return IOERR_UNKNOWN; // Sorry can't find the child
|
|
}
|
|
if (STGTY_STORAGE != (DirBuf[0x42]))
|
|
{
|
|
UTGlobalUnlock (hSpec); // PJB
|
|
return IOERR_UNKNOWN; // Whoops, wrong type!
|
|
}
|
|
|
|
|
|
if ((HANDLE)NULL == (hSubStorage = UTGlobalAlloc(sizeof(IOSUBSTORAGE))) )
|
|
return IOERR_ALLOCFAIL;
|
|
|
|
// Alright, we finally got this sucker!
|
|
pSubStorage = (PIOSUBSTORAGE) UTGlobalLock(hSubStorage);
|
|
pSubStorage->sBaseIO.pClose = IOSubStgClose;
|
|
pSubStorage->sBaseIO.pRead = IOSubStgRead;
|
|
pSubStorage->sBaseIO.pWrite = IOSubStgWrite;
|
|
pSubStorage->sBaseIO.pSeek = IOSubStgSeek;
|
|
pSubStorage->sBaseIO.pTell = IOSubStgTell;
|
|
pSubStorage->sBaseIO.pGetInfo = IOSubStgGetInfo;
|
|
pSubStorage->sBaseIO.pOpen = IOOpen;
|
|
pSubStorage->dwFlags = dwFlags;
|
|
pSubStorage->hSpec = hSpec;
|
|
pSubStorage->hThis = hSubStorage;
|
|
pSubStorage->DirEntry = DirEntry;
|
|
pSubStorage->pRoot = pRoot;
|
|
UTmemcpy (pSubStorage->ClassId, DirBuf + 0x50, 0x10); // get Classs Id
|
|
|
|
*phFile = (HIOFILE)pSubStorage;
|
|
UTGlobalUnlock (hSpec);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************/
|
|
IOERR IO_ENTRYMOD IOSubStgClose(HIOFILE hFile)
|
|
{
|
|
HANDLE hSpec = ((PIOSUBSTORAGE) hFile)->hSpec;
|
|
HANDLE hSubStorage = ((PIOSUBSTORAGE) hFile)->hThis;
|
|
|
|
// UTGlobalUnlock (hSpec); PJB
|
|
UTGlobalFree (hSpec);
|
|
UTGlobalUnlock (hSubStorage);
|
|
UTGlobalFree (hSubStorage);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IOSubStgRead(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IOSubStgWrite(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IOSubStgSeek(HIOFILE hFile, WORD wFrom, LONG lOffset)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IOSubStgTell(HIOFILE hFile, DWORD FAR * pOffset)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
|
|
/*********************************/
|
|
IOERR IO_ENTRYMOD IOSubStgGetInfo(HIOFILE hFile, DWORD dwInfoId, VOID FAR * pInfo)
|
|
{
|
|
PIOSUBSTORAGE pSubStorage = (PIOSUBSTORAGE)hFile;
|
|
IOERR locRet = IOERR_OK;
|
|
|
|
switch (dwInfoId)
|
|
{
|
|
case IOGETINFO_PARENTHANDLE:
|
|
* (HIOFILE FAR *)pInfo = (HIOFILE) (pSubStorage->pRoot);
|
|
break;
|
|
|
|
case IOGETINFO_ISOLE2STORAGE:
|
|
case IOGETINFO_ISOLE2SUBSTORAGE:
|
|
locRet = IOERR_TRUE;
|
|
break;
|
|
|
|
case IOGETINFO_OLE2CLSID:
|
|
UTmemcpy (pInfo, pSubStorage->ClassId, 0x10);
|
|
break;
|
|
|
|
default:
|
|
locRet = IOGetInfo((HIOFILE)(pSubStorage->pRoot), dwInfoId, pInfo); //Call the root one, which will call the flat one
|
|
break;
|
|
}
|
|
return(locRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
**************************************************************************************
|
|
*
|
|
* OLE2 Sub Stream Routines
|
|
*
|
|
**************************************************************************************
|
|
*/
|
|
/*******************************/
|
|
IOERR IOOpenOLE2SubStream(HIOFILE FAR * phFile, HIOSPEC hSpec, DWORD dwFlags)
|
|
{
|
|
PIOROOTSTORAGE pRoot; //Point back to the root
|
|
BYTE DirBuf[0x80]; //A temporary buffer
|
|
LONG DirEntry; //Dir entry #
|
|
HANDLE hSubStream; //Handle to the new sub storage structure
|
|
PIOSUBSTREAM pSubStream; //File handle for the new sub storage, give back to phFile
|
|
IOSPECSUBSTREAM SpecSubStream = ((PIOSPEC) UTGlobalLock (hSpec))->uTypes.sSubStream;
|
|
|
|
if (IOERR_OK != IOOLE2RootStgFindChildEntry(SpecSubStream.hRefStorage, SpecSubStream.szStreamName, DirBuf, &DirEntry, &pRoot))
|
|
{
|
|
UTGlobalUnlock (hSpec); // PJB
|
|
return IOERR_UNKNOWN; // Sorry can't find the child
|
|
}
|
|
if (STGTY_STREAM != (DirBuf[0x42]))
|
|
{
|
|
UTGlobalUnlock (hSpec); // PJB
|
|
return IOERR_UNKNOWN; // Whoops, wrong type!
|
|
}
|
|
|
|
if ( (HANDLE)NULL == (hSubStream = UTGlobalAlloc(sizeof(IOSUBSTREAM))) )
|
|
return IOERR_ALLOCFAIL;
|
|
|
|
// Alright, we finally got this sucker!
|
|
pSubStream = (PIOSUBSTREAM) UTGlobalLock(hSubStream);
|
|
pSubStream->sBaseIO.pClose = IOSubStrClose;
|
|
pSubStream->sBaseIO.pRead = IOSubStrRead;
|
|
pSubStream->sBaseIO.pWrite = IOSubStrWrite;
|
|
pSubStream->sBaseIO.pSeek = IOSubStrSeek;
|
|
pSubStream->sBaseIO.pTell = IOSubStrTell;
|
|
pSubStream->sBaseIO.pGetInfo = IOSubStrGetInfo;
|
|
pSubStream->sBaseIO.pOpen = IOOpen;
|
|
pSubStream->dwFlags = dwFlags;
|
|
pSubStream->hSpec = hSpec;
|
|
pSubStream->hThis = hSubStream;
|
|
pSubStream->DirEntry = DirEntry;
|
|
pSubStream->pRoot = pRoot;
|
|
UTmemcpy (pSubStream->ClassId, DirBuf + 0x50, 0x10); // get Classs Id
|
|
|
|
pSubStream->StreamSize = (DWORD) IOOLE2ReadLONG (DirBuf + 0x78, pRoot->ByteOrder);
|
|
if (pSubStream->StreamSize >= pRoot->MiniSectorCutoff)
|
|
{
|
|
pSubStream->StreamBufSize = pRoot->SectorSize;
|
|
pSubStream->StreamReadSector = IOOLE2RootStgReadSector;
|
|
pSubStream->StreamReadConsecutiveSector = IOOLE2RootStgReadConsecutiveSector;
|
|
pSubStream->StreamGetNextSector = IOOLE2RootStgGetNextSector;
|
|
}
|
|
else
|
|
{
|
|
pSubStream->StreamBufSize = pRoot->MiniSectorSize;
|
|
pSubStream->StreamReadSector = IOOLE2RootStgReadMiniSector;
|
|
pSubStream->StreamReadConsecutiveSector = IOOLE2RootStgReadConsecutiveMiniSector;
|
|
pSubStream->StreamGetNextSector = IOOLE2RootStgGetNextMiniSector;
|
|
}
|
|
|
|
if ((HANDLE)NULL == (pSubStream->hStreamBuf = UTGlobalAlloc(pSubStream->StreamBufSize)))
|
|
{ // Bad Allocation
|
|
UTGlobalUnlock (hSubStream);
|
|
UTGlobalFree (hSubStream);
|
|
return (IOERR_ALLOCFAIL);
|
|
}
|
|
|
|
pSubStream->pStreamBuf = (BYTE FAR *) UTGlobalLock (pSubStream->hStreamBuf);
|
|
pSubStream->StreamStart = IOOLE2ReadLONG (DirBuf + 0x74, pRoot->ByteOrder);
|
|
pSubStream->CurrPosition = 0;
|
|
pSubStream->StreamBufOffset = 0xffffffff; // So read will load the buffer the first time!
|
|
pSubStream->StreamBufSector = pSubStream->StreamStart; // This is unnecessary, -1 already does the job!
|
|
|
|
*phFile = (HIOFILE)pSubStream;
|
|
UTGlobalUnlock (hSpec);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
/*****************************/
|
|
IOERR IO_ENTRYMOD IOSubStrRead(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
PIOSUBSTREAM pSubStream = (PIOSUBSTREAM) hFile;
|
|
BYTE FAR * pCurrData = pData;
|
|
DWORD ByteRemain = dwSize < pSubStream->StreamSize - pSubStream->CurrPosition ? dwSize : pSubStream->StreamSize - pSubStream->CurrPosition ;
|
|
DWORD CurrPositionInBuf;
|
|
DWORD ByteRead = 0, Count = 0;
|
|
LONG NextSector;
|
|
DWORD RelativeOffset, SectorOffset;
|
|
|
|
// if EOF
|
|
if (pSubStream->CurrPosition >= pSubStream->StreamSize)
|
|
return IOERR_EOF;
|
|
|
|
//if the buffer corrupted
|
|
if (0xffffffff == pSubStream->StreamBufOffset)
|
|
{
|
|
if (IOERR_OK != pSubStream->StreamReadSector(pSubStream->pRoot, pSubStream->StreamStart, pSubStream->pStreamBuf))
|
|
return IOERR_UNKNOWN;
|
|
pSubStream->StreamBufOffset = 0;
|
|
pSubStream->StreamBufSector = pSubStream->StreamStart;
|
|
}
|
|
|
|
//Load the buffer if necessary to synchronize the currposition
|
|
RelativeOffset = pSubStream->CurrPosition - pSubStream->StreamBufOffset;
|
|
if (pSubStream->CurrPosition < pSubStream->StreamBufOffset)
|
|
{
|
|
RelativeOffset = pSubStream->CurrPosition; //Have to search from the beginning
|
|
SectorOffset = 0;
|
|
NextSector = pSubStream->StreamStart;
|
|
}
|
|
else
|
|
{
|
|
NextSector = pSubStream->StreamBufSector;
|
|
SectorOffset = pSubStream->StreamBufOffset;
|
|
}
|
|
|
|
while (RelativeOffset >= pSubStream->StreamBufSize)
|
|
{
|
|
if (-1 == (NextSector = pSubStream->StreamGetNextSector(pSubStream->pRoot, NextSector)))
|
|
return IOERR_UNKNOWN; //Can't search to the current buffer
|
|
RelativeOffset -= pSubStream->StreamBufSize;
|
|
SectorOffset += pSubStream->StreamBufSize;
|
|
}
|
|
if (IOERR_OK != pSubStream->StreamReadSector(pSubStream->pRoot, NextSector, pSubStream->pStreamBuf))
|
|
{
|
|
pSubStream->StreamBufOffset = 0xffffffff; //StreamBuf corrupted
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
pSubStream->StreamBufSector = NextSector;
|
|
pSubStream->StreamBufOffset = SectorOffset;
|
|
|
|
//Read the first buffer
|
|
CurrPositionInBuf = pSubStream->CurrPosition % pSubStream->StreamBufSize;
|
|
if (ByteRemain <= pSubStream->StreamBufSize - CurrPositionInBuf)
|
|
{ // Done!
|
|
UTmemcpy (pData, pSubStream->pStreamBuf + CurrPositionInBuf, ByteRemain);
|
|
pSubStream->CurrPosition += ByteRemain;
|
|
* pCount = ByteRemain;
|
|
return IOERR_OK;
|
|
}
|
|
else
|
|
{
|
|
ByteRead = pSubStream->StreamBufSize - CurrPositionInBuf;
|
|
UTmemcpy (pData, pSubStream->pStreamBuf + CurrPositionInBuf, ByteRead);
|
|
ByteRemain -= ByteRead;
|
|
pCurrData += ByteRead;
|
|
}
|
|
|
|
NextSector = pSubStream->StreamGetNextSector(pSubStream->pRoot, pSubStream->StreamBufSector); // The next sector!
|
|
Count = 0; // Remember how many sectors to read
|
|
|
|
//Read following buffers until the last one, Streambuf is not updated to increase speed
|
|
//Try to read consecutive sectors at one time to increase speed
|
|
if (ByteRemain >= pSubStream->StreamBufSize)
|
|
{
|
|
LONG SectorCount = 0;
|
|
LONG CurrSector = NextSector, StartSector = NextSector;
|
|
|
|
while (ByteRemain >= pSubStream->StreamBufSize)
|
|
{
|
|
CurrSector = NextSector;
|
|
NextSector = pSubStream->StreamGetNextSector(pSubStream->pRoot, CurrSector);
|
|
Count ++;
|
|
SectorCount ++;
|
|
if (NextSector != CurrSector + 1 || ByteRemain < (DWORD)pSubStream->StreamBufSize * (SectorCount+1)) // Hey it is consecutive sector, wait to read later
|
|
{
|
|
if (IOERR_OK != pSubStream->StreamReadConsecutiveSector (pSubStream->pRoot, StartSector, SectorCount, pCurrData))
|
|
{
|
|
* pCount = ByteRead;
|
|
pSubStream->CurrPosition += ByteRead;
|
|
return IOERR_UNKNOWN;
|
|
}
|
|
#ifdef WIN16
|
|
pCurrData = (BYTE FAR *) ((BYTE HUGE *)pCurrData + pSubStream->StreamBufSize * SectorCount);
|
|
#else
|
|
pCurrData += pSubStream->StreamBufSize * SectorCount;
|
|
#endif
|
|
ByteRead += pSubStream->StreamBufSize * SectorCount;
|
|
ByteRemain -= pSubStream->StreamBufSize * SectorCount;
|
|
SectorCount = 0;
|
|
StartSector = NextSector;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read the last one if there is any
|
|
if (0 != ByteRemain)
|
|
{
|
|
if (IOERR_OK != pSubStream->StreamReadSector(pSubStream->pRoot, NextSector, pSubStream->pStreamBuf))
|
|
{ //Sorry, can't read anymore, give all I can have here!
|
|
*pCount = ByteRead;
|
|
pSubStream->CurrPosition += ByteRead;
|
|
pSubStream->StreamBufOffset = 0xffffffff; //Buffer corrupted
|
|
return IOERR_UNKNOWN; // This is abnormal error, may use IOERR_UNKNOWN
|
|
}
|
|
UTmemcpy (pCurrData, pSubStream->pStreamBuf, ByteRemain);
|
|
pSubStream->StreamBufSector = NextSector;
|
|
pSubStream->StreamBufOffset += pSubStream->StreamBufSize * (++Count);
|
|
ByteRead += ByteRemain;
|
|
}
|
|
|
|
*pCount = ByteRead;
|
|
pSubStream->CurrPosition += ByteRead;
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
IOERR IO_ENTRYMOD IOSubStrWrite(HIOFILE hFile, BYTE FAR * pData, DWORD dwSize, DWORD FAR * pCount)
|
|
{
|
|
return(IOERR_UNKNOWN);
|
|
}
|
|
|
|
IOERR IO_ENTRYMOD IOSubStrSeek(HIOFILE hFile, WORD wFrom, LONG lOffset)
|
|
{ PIOSUBSTREAM pSubStream = (PIOSUBSTREAM) hFile;
|
|
DWORD NewPosition;
|
|
|
|
switch (wFrom)
|
|
{
|
|
case IOSEEK_CURRENT:
|
|
NewPosition = pSubStream->CurrPosition + lOffset; // OK, lOffset promoted to DWORD, and result is OK even if offset is negative
|
|
break;
|
|
case IOSEEK_BOTTOM:
|
|
NewPosition = pSubStream->StreamSize + lOffset;
|
|
break;
|
|
case IOSEEK_TOP:
|
|
NewPosition = lOffset;
|
|
break;
|
|
default:
|
|
return (IOERR_BADPARAM);
|
|
break;
|
|
}
|
|
if (NewPosition > pSubStream->StreamSize)
|
|
return (IOERR_UNKNOWN); // Seek out of range
|
|
|
|
pSubStream->CurrPosition = NewPosition;
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
|
|
IOERR IO_ENTRYMOD IOSubStrTell(HIOFILE hFile, DWORD FAR * pOffset)
|
|
{
|
|
*pOffset = ((PIOSUBSTREAM) hFile)->CurrPosition;
|
|
return IOERR_OK;
|
|
}
|
|
|
|
IOERR IO_ENTRYMOD IOSubStrGetInfo(HIOFILE hFile, DWORD dwInfoId, VOID FAR * pInfo)
|
|
{
|
|
PIOSUBSTREAM pSubStream = (PIOSUBSTREAM)hFile;
|
|
IOERR locRet = IOERR_OK;
|
|
|
|
|
|
switch (dwInfoId)
|
|
{
|
|
case IOGETINFO_PARENTHANDLE:
|
|
* (HIOFILE FAR *)pInfo = (HIOFILE) pSubStream->pRoot;
|
|
break;
|
|
|
|
case IOGETINFO_ISOLE2SUBSTREAM:
|
|
locRet = IOERR_TRUE;
|
|
break;
|
|
|
|
case IOGETINFO_OLE2CLSID:
|
|
UTmemcpy (pInfo, pSubStream->ClassId, 16);
|
|
locRet = IOERR_OK;
|
|
break;
|
|
|
|
default:
|
|
locRet = IOGetInfo((HIOFILE) (pSubStream->pRoot), dwInfoId, pInfo);
|
|
break;
|
|
}
|
|
return(locRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
IOERR IO_ENTRYMOD IOSubStrClose(HIOFILE hFile)
|
|
{
|
|
HANDLE hStreamBuf = ((PIOSUBSTREAM) hFile)->hStreamBuf;
|
|
HANDLE hSpec = ((PIOSUBSTREAM) hFile)->hSpec;
|
|
HANDLE hSubStream = ((PIOSUBSTREAM) hFile)->hThis;
|
|
|
|
UTGlobalUnlock (hStreamBuf);
|
|
UTGlobalFree (hStreamBuf);
|
|
// UTGlobalUnlock (hSpec); PJB
|
|
UTGlobalFree (hSpec);
|
|
UTGlobalUnlock (hSubStream);
|
|
UTGlobalFree (hSubStream);
|
|
return IOERR_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//*****#@!^%^$#&%!%#^&!*^#&*!%#*&(!%#&^!(*&!%#&*!%#&!(*%#^*!(^#&*!^%#&*!(#%!&*(#%!^*(#&*(!
|
|
// A hiatus for 7/9 to 7/10
|
|
// Randal, 7/8
|
|
//*****#@!^%^$#&%!%#^&!*^#&*!%#*&(!%#&^!(*&!%#&*!%#&!(*%#^*!(^#&*!^%#&*!(#%!&*(#%!^*(#&*(!
|
|
|
|
|