📄 storage.c
字号:
while (cb) {
unsigned int cc;
if (!STORAGE_get_small_block(&This->str,blocknr,block)) {
WARN("small block read failed!!!\n");
return E_FAIL;
}
cc = cb;
if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
This->offset.u.LowPart+=cc;
pbv+=cc;
*bytesread+=cc;
cb-=cc;
blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
}
} else {
/* use big block reader */
blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
while (cb) {
unsigned int cc;
if (!STORAGE_get_big_block(&This->str,blocknr,block)) {
WARN("big block read failed!!!\n");
return E_FAIL;
}
cc = cb;
if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
This->offset.u.LowPart+=cc;
pbv+=cc;
*bytesread+=cc;
cb-=cc;
blocknr=STORAGE_get_next_big_blocknr(&This->str,blocknr);
}
}
return S_OK;
}
/******************************************************************************
* IStream16_Write [STORAGE.522]
*/
HRESULT CDECL IStream16_fnWrite(
IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
) {
IStream16Impl *This = (IStream16Impl *)iface;
BYTE block[BIGSIZE];
ULONG *byteswritten=pcbWrite,xxwritten;
int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
const BYTE* pbv = (const BYTE*)pv;
if (!pcbWrite) byteswritten=&xxwritten;
*byteswritten = 0;
TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbWrite);
/* do we need to junk some blocks? */
newsize = This->offset.u.LowPart+cb;
oldsize = This->stde.pps_size;
if (newsize < oldsize) {
if (oldsize < 0x1000) {
/* only small blocks */
blocknr=STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,newsize/SMALLSIZE);
assert(blocknr>=0);
/* will set the rest of the chain to 'free' */
if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return E_FAIL;
} else {
if (newsize >= 0x1000) {
blocknr=STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,newsize/BIGSIZE);
assert(blocknr>=0);
/* will set the rest of the chain to 'free' */
if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return E_FAIL;
} else {
/* Migrate large blocks to small blocks
* (we just migrate newsize bytes)
*/
LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
HRESULT r = E_FAIL;
cc = newsize;
blocknr = This->stde.pps_sb;
curdata = data;
while (cc>0) {
if (!STORAGE_get_big_block(&This->str,blocknr,curdata)) {
HeapFree(GetProcessHeap(),0,data);
return E_FAIL;
}
curdata += BIGSIZE;
cc -= BIGSIZE;
blocknr = STORAGE_get_next_big_blocknr(&This->str,blocknr);
}
/* frees complete chain for this stream */
if (!STORAGE_set_big_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
goto err;
curdata = data;
blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(&This->str);
if (blocknr<0)
goto err;
cc = newsize;
while (cc>0) {
if (!STORAGE_put_small_block(&This->str,blocknr,curdata))
goto err;
cc -= SMALLSIZE;
if (cc<=0) {
if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
goto err;
break;
} else {
int newblocknr = STORAGE_get_free_small_blocknr(&This->str);
if (newblocknr<0)
goto err;
if (!STORAGE_set_small_chain(&This->str,blocknr,newblocknr))
goto err;
blocknr = newblocknr;
}
curdata += SMALLSIZE;
}
r = S_OK;
err:
HeapFree(GetProcessHeap(),0,data);
if(r != S_OK)
return r;
}
}
This->stde.pps_size = newsize;
}
if (newsize > oldsize) {
if (oldsize >= 0x1000) {
/* should return the block right before the 'endofchain' */
blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
assert(blocknr>=0);
lastblocknr = blocknr;
for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
blocknr = STORAGE_get_free_big_blocknr(&This->str);
if (blocknr<0)
return E_FAIL;
if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
return E_FAIL;
lastblocknr = blocknr;
}
if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return E_FAIL;
} else {
if (newsize < 0x1000) {
/* find startblock */
if (!oldsize)
This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(&This->str);
else
blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
if (blocknr<0)
return E_FAIL;
/* allocate required new small blocks */
lastblocknr = blocknr;
for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
blocknr = STORAGE_get_free_small_blocknr(&This->str);
if (blocknr<0)
return E_FAIL;
if (!STORAGE_set_small_chain(&This->str,lastblocknr,blocknr))
return E_FAIL;
lastblocknr = blocknr;
}
/* and terminate the chain */
if (!STORAGE_set_small_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return E_FAIL;
} else {
if (!oldsize) {
/* no single block allocated yet */
blocknr=STORAGE_get_free_big_blocknr(&This->str);
if (blocknr<0)
return E_FAIL;
This->stde.pps_sb = blocknr;
} else {
/* Migrate small blocks to big blocks */
LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
HRESULT r = E_FAIL;
cc = oldsize;
blocknr = This->stde.pps_sb;
curdata = data;
/* slurp in */
while (cc>0) {
if (!STORAGE_get_small_block(&This->str,blocknr,curdata))
goto err2;
curdata += SMALLSIZE;
cc -= SMALLSIZE;
blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
}
/* free small block chain */
if (!STORAGE_set_small_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
goto err2;
curdata = data;
blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(&This->str);
if (blocknr<0)
goto err2;
/* put the data into the big blocks */
cc = This->stde.pps_size;
while (cc>0) {
if (!STORAGE_put_big_block(&This->str,blocknr,curdata))
goto err2;
cc -= BIGSIZE;
if (cc<=0) {
if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
goto err2;
break;
} else {
int newblocknr = STORAGE_get_free_big_blocknr(&This->str);
if (newblocknr<0)
goto err2;
if (!STORAGE_set_big_chain(&This->str,blocknr,newblocknr))
goto err2;
blocknr = newblocknr;
}
curdata += BIGSIZE;
}
r = S_OK;
err2:
HeapFree(GetProcessHeap(),0,data);
if(r != S_OK)
return r;
}
/* generate big blocks to fit the new data */
lastblocknr = blocknr;
for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
blocknr = STORAGE_get_free_big_blocknr(&This->str);
if (blocknr<0)
return E_FAIL;
if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
return E_FAIL;
lastblocknr = blocknr;
}
/* terminate chain */
if (!STORAGE_set_big_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return E_FAIL;
}
}
This->stde.pps_size = newsize;
}
/* There are just some cases where we didn't modify it, we write it out
* everytime
*/
if (!STORAGE_put_pps_entry(&This->str,This->ppsent,&(This->stde)))
return E_FAIL;
/* finally the write pass */
if (This->stde.pps_size < 0x1000) {
blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
assert(blocknr>=0);
while (cb>0) {
/* we ensured that it is allocated above */
assert(blocknr>=0);
/* Read old block everytime, since we can have
* overlapping data at START and END of the write
*/
if (!STORAGE_get_small_block(&This->str,blocknr,block))
return E_FAIL;
cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
if (cc>cb)
cc=cb;
memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
pbv+curoffset,
cc
);
if (!STORAGE_put_small_block(&This->str,blocknr,block))
return E_FAIL;
cb -= cc;
curoffset += cc;
pbv += cc;
This->offset.u.LowPart += cc;
*byteswritten += cc;
blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
}
} else {
blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
assert(blocknr>=0);
while (cb>0) {
/* we ensured that it is allocated above, so it better is */
assert(blocknr>=0);
/* read old block everytime, since we can have
* overlapping data at START and END of the write
*/
if (!STORAGE_get_big_block(&This->str,blocknr,block))
return E_FAIL;
cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
if (cc>cb)
cc=cb;
memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
pbv+curoffset,
cc
);
if (!STORAGE_put_big_block(&This->str,blocknr,block))
return E_FAIL;
cb -= cc;
curoffset += cc;
pbv += cc;
This->offset.u.LowPart += cc;
*byteswritten += cc;
blocknr = STORAGE_get_next_big_blocknr(&This->str,blocknr);
}
}
return S_OK;
}
/******************************************************************************
* _create_istream16 [Internal]
*/
static void _create_istream16(LPSTREAM16 *str) {
IStream16Impl* lpst;
if (!strvt16.QueryInterface) {
HMODULE16 wp = GetModuleHandle16("STORAGE");
if (wp>=32) {
/* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
#define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
VTENT(QueryInterface);
VTENT(AddRef);
VTENT(Release);
VTENT(Read);
VTENT(Write);
VTENT(Seek);
VTENT(SetSize);
VTENT(CopyTo);
VTENT(Commit);
VTENT(Revert);
VTENT(LockRegion);
VTENT(UnlockRegion);
VTENT(Stat);
VTENT(Clone);
#undef VTENT
segstrvt16 = (const IStream16Vtbl*)MapLS( &strvt16 );
} else {
#define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
VTENT(QueryInterface);
VTENT(AddRef);
VTENT(Release);
VTENT(Read);
VTENT(Write);
VTENT(Seek);
/*
VTENT(CopyTo);
VTENT(Commit);
VTENT(SetSize);
VTENT(Revert);
VTENT(LockRegion);
VTENT(UnlockRegion);
VTENT(Stat);
VTENT(Clone);
*/
#undef VTENT
segstrvt16 = &strvt16;
}
}
lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
lpst->lpVtbl = segstrvt16;
lpst->ref = 1;
lpst->thisptr = MapLS( lpst );
lpst->str.hf = NULL;
lpst->str.lockbytes = 0;
*str = (void*)lpst->thisptr;
}
/* --- IStream32 implementation */
typedef struct
{
/* IUnknown fields */
const IStreamVtbl *lpVtbl;
LONG ref;
/* IStream32 fields */
struct storage_pps_entry stde;
int ppsent;
HANDLE hf;
ULARGE_INTEGER offset;
} IStream32Impl;
/*****************************************************************************
* IStream32_QueryInterface [VTABLE]
*/
HRESULT WINAPI IStream_fnQueryInterface(
IStream* iface,REFIID refiid,LPVOID *obj
) {
IStream32Impl *This = (IStream32Impl *)iface;
TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
*obj = This;
return 0;
}
return OLE_E_ENUM_NOMORE;
}
/******************************************************************************
* IStream32_AddRef [VTABLE]
*/
ULONG WINAPI IStream_fnAddRef(IStream* iface) {
IStream32Impl *This = (IStream32Impl *)iface;
return InterlockedIncrement(&This->ref);
}
/******************************************************************************
* IStream32_Release [VTABLE]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -