📄 storage.c
字号:
/******************************************************************************
* STORAGE_set_small_chain [Internal]
*/
static BOOL
STORAGE_set_small_chain(stream_access16*str,int blocknr,INT type) {
BYTE block[BIGSIZE];
LPINT sbd = (LPINT)block;
int lastblocknr,nextsmallblocknr,bigblocknr;
struct storage_header sth;
BOOL ret;
READ_HEADER(str);
assert(blocknr!=type);
lastblocknr=-129;bigblocknr=-2;
while (blocknr>=0) {
/* cache block ... */
if (lastblocknr/128!=blocknr/128) {
bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
assert(bigblocknr>=0);
ret = STORAGE_get_big_block(str,bigblocknr,block);
assert(ret);
}
lastblocknr = blocknr;
nextsmallblocknr = sbd[blocknr&(128-1)];
sbd[blocknr&(128-1)] = type;
ret = STORAGE_put_big_block(str,bigblocknr,block);
assert(ret);
if (type>=0)
return TRUE;
type = STORAGE_CHAINENTRY_FREE;
blocknr = nextsmallblocknr;
}
return TRUE;
}
/******************************************************************************
* STORAGE_get_free_big_blocknr [Internal]
*/
static int
STORAGE_get_free_big_blocknr(stream_access16 *str) {
BYTE block[BIGSIZE];
LPINT sbd = (LPINT)block;
int lastbigblocknr,i,bigblocknr;
unsigned int curblock;
struct storage_header sth;
BOOL ret;
READ_HEADER(str);
curblock = 0;
lastbigblocknr = -1;
bigblocknr = sth.bbd_list[curblock];
while (curblock<sth.num_of_bbd_blocks) {
assert(bigblocknr>=0);
ret = STORAGE_get_big_block(str,bigblocknr,block);
assert(ret);
for (i=0;i<128;i++)
if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
ret = STORAGE_put_big_block(str,bigblocknr,block);
assert(ret);
memset(block,0x42,sizeof(block));
ret = STORAGE_put_big_block(str,i+curblock*128,block);
assert(ret);
return i+curblock*128;
}
lastbigblocknr = bigblocknr;
bigblocknr = sth.bbd_list[++curblock];
}
bigblocknr = curblock*128;
/* since we have marked all blocks from 0 up to curblock*128-1
* the next free one is curblock*128, where we happily put our
* next large block depot.
*/
memset(block,0xff,sizeof(block));
/* mark the block allocated and returned by this function */
sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
ret = STORAGE_put_big_block(str,bigblocknr,block);
assert(ret);
/* if we had a bbd block already (mostlikely) we need
* to link the new one into the chain
*/
if (lastbigblocknr!=-1) {
ret = STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr);
assert(ret);
}
sth.bbd_list[curblock]=bigblocknr;
sth.num_of_bbd_blocks++;
assert(sth.num_of_bbd_blocks==curblock+1);
ret = STORAGE_put_big_block(str,-1,(LPBYTE)&sth);
assert(ret);
/* Set the end of the chain for the bigblockdepots */
ret = STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
assert(ret);
/* add 1, for the first entry is used for the additional big block
* depot. (means we already used bigblocknr) */
memset(block,0x42,sizeof(block));
/* allocate this block (filled with 0x42) */
ret = STORAGE_put_big_block(str,bigblocknr+1,block);
assert(ret);
return bigblocknr+1;
}
/******************************************************************************
* STORAGE_get_free_small_blocknr [Internal]
*/
static int
STORAGE_get_free_small_blocknr(stream_access16 *str) {
BYTE block[BIGSIZE];
LPINT sbd = (LPINT)block;
int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
struct storage_pps_entry root;
struct storage_header sth;
READ_HEADER(str);
bigblocknr = sth.sbd_startblock;
curblock = 0;
lastbigblocknr = -1;
newblocknr = -1;
while (bigblocknr>=0) {
if (!STORAGE_get_big_block(str,bigblocknr,block))
return -1;
for (i=0;i<128;i++)
if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
newblocknr = i+curblock*128;
break;
}
if (i!=128)
break;
lastbigblocknr = bigblocknr;
bigblocknr = STORAGE_get_next_big_blocknr(str,bigblocknr);
curblock++;
}
if (newblocknr==-1) {
bigblocknr = STORAGE_get_free_big_blocknr(str);
if (bigblocknr<0)
return -1;
READ_HEADER(str);
memset(block,0xff,sizeof(block));
sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
if (!STORAGE_put_big_block(str,bigblocknr,block))
return -1;
if (lastbigblocknr==-1) {
sth.sbd_startblock = bigblocknr;
if (!STORAGE_put_big_block(str,-1,(LPBYTE)&sth)) /* need to write it */
return -1;
} else {
if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
return -1;
}
if (!STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return -1;
newblocknr = curblock*128;
}
/* allocate enough big blocks for storing the allocated small block */
if (!STORAGE_get_root_pps_entry(str,&root))
return -1;
if (root.pps_sb==-1)
lastbigblocknr = -1;
else
lastbigblocknr = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,(root.pps_size-1)/BIGSIZE);
while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
/* we need to allocate more stuff */
bigblocknr = STORAGE_get_free_big_blocknr(str);
if (bigblocknr<0)
return -1;
READ_HEADER(str);
if (root.pps_sb==-1) {
root.pps_sb = bigblocknr;
root.pps_size += BIGSIZE;
} else {
if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
return -1;
root.pps_size += BIGSIZE;
}
lastbigblocknr = bigblocknr;
}
if (!STORAGE_set_big_chain(str,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return -1;
if (!STORAGE_put_pps_entry(str,0,&root))
return -1;
return newblocknr;
}
/******************************************************************************
* STORAGE_get_free_pps_entry [Internal]
*/
static int
STORAGE_get_free_pps_entry(stream_access16*str) {
int blocknr, i, curblock, lastblocknr=-1;
BYTE block[BIGSIZE];
struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
struct storage_header sth;
READ_HEADER(str);
blocknr = sth.root_startblock;
assert(blocknr>=0);
curblock=0;
while (blocknr>=0) {
if (!STORAGE_get_big_block(str,blocknr,block))
return -1;
for (i=0;i<4;i++)
if (stde[i].pps_sizeofname==0) /* free */
return curblock*4+i;
lastblocknr = blocknr;
blocknr = STORAGE_get_next_big_blocknr(str,blocknr);
curblock++;
}
assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
blocknr = STORAGE_get_free_big_blocknr(str);
/* sth invalidated */
if (blocknr<0)
return -1;
if (!STORAGE_set_big_chain(str,lastblocknr,blocknr))
return -1;
if (!STORAGE_set_big_chain(str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
return -1;
memset(block,0,sizeof(block));
STORAGE_put_big_block(str,blocknr,block);
return curblock*4;
}
/* --- IStream16 implementation */
typedef struct
{
/* IUnknown fields */
const IStream16Vtbl *lpVtbl;
LONG ref;
/* IStream16 fields */
SEGPTR thisptr; /* pointer to this struct as segmented */
struct storage_pps_entry stde;
int ppsent;
ULARGE_INTEGER offset;
stream_access16 str;
} IStream16Impl;
/******************************************************************************
* IStream16_QueryInterface [STORAGE.518]
*/
HRESULT CDECL IStream16_fnQueryInterface(
IStream16* iface,REFIID refiid,LPVOID *obj
) {
IStream16Impl *This = (IStream16Impl *)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;
}
/******************************************************************************
* IStream16_AddRef [STORAGE.519]
*/
ULONG CDECL IStream16_fnAddRef(IStream16* iface) {
IStream16Impl *This = (IStream16Impl *)iface;
return InterlockedIncrement(&This->ref);
}
static void
_ilockbytes16_addref(SEGPTR lockbytes) {
DWORD args[1];
HRESULT hres;
args[0] = (DWORD)lockbytes; /* iface */
if (!WOWCallback16Ex(
(DWORD)((const ILockBytes16Vtbl*)MapSL(
(SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
)->AddRef,
WCB16_PASCAL,
1*sizeof(DWORD),
(LPVOID)args,
(LPDWORD)&hres
))
ERR("CallTo16 ILockBytes16::AddRef() failed, hres %x\n",hres);
}
static void
_ilockbytes16_release(SEGPTR lockbytes) {
DWORD args[1];
HRESULT hres;
args[0] = (DWORD)lockbytes; /* iface */
if (!WOWCallback16Ex(
(DWORD)((const ILockBytes16Vtbl*)MapSL(
(SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
)->Release,
WCB16_PASCAL,
1*sizeof(DWORD),
(LPVOID)args,
(LPDWORD)&hres
))
ERR("CallTo16 ILockBytes16::Release() failed, hres %x\n",hres);
}
static void
_ilockbytes16_flush(SEGPTR lockbytes) {
DWORD args[1];
HRESULT hres;
args[0] = (DWORD)lockbytes; /* iface */
if (!WOWCallback16Ex(
(DWORD)((const ILockBytes16Vtbl*)MapSL(
(SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
)->Flush,
WCB16_PASCAL,
1*sizeof(DWORD),
(LPVOID)args,
(LPDWORD)&hres
))
ERR("CallTo16 ILockBytes16::Flush() failed, hres %x\n",hres);
}
/******************************************************************************
* IStream16_Release [STORAGE.520]
*/
ULONG CDECL IStream16_fnRelease(IStream16* iface) {
IStream16Impl *This = (IStream16Impl *)iface;
ULONG ref;
if (This->str.hf)
FlushFileBuffers(This->str.hf);
else
_ilockbytes16_flush(This->str.lockbytes);
ref = InterlockedDecrement(&This->ref);
if (ref)
return ref;
if (This->str.hf)
CloseHandle(This->str.hf);
else
_ilockbytes16_release(This->str.lockbytes);
UnMapLS( This->thisptr );
HeapFree( GetProcessHeap(), 0, This );
return 0;
}
/******************************************************************************
* IStream16_Seek [STORAGE.523]
*
* FIXME
* Does not handle 64 bits
*/
HRESULT CDECL IStream16_fnSeek(
IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
) {
IStream16Impl *This = (IStream16Impl *)iface;
TRACE_(relay)("(%p)->([%d.%d],%d,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
switch (whence) {
/* unix SEEK_xx should be the same as win95 ones */
case SEEK_SET:
/* offset must be ==0 (<0 is invalid, and >0 cannot be handled
* right now.
*/
assert(offset.u.HighPart==0);
This->offset.u.HighPart = offset.u.HighPart;
This->offset.u.LowPart = offset.u.LowPart;
break;
case SEEK_CUR:
if (offset.u.HighPart < 0) {
/* FIXME: is this negation correct ? */
offset.u.HighPart = -offset.u.HighPart;
offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
assert(offset.u.HighPart==0);
assert(This->offset.u.LowPart >= offset.u.LowPart);
This->offset.u.LowPart -= offset.u.LowPart;
} else {
assert(offset.u.HighPart==0);
This->offset.u.LowPart+= offset.u.LowPart;
}
break;
case SEEK_END:
assert(offset.u.HighPart==0);
This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
break;
}
if (This->offset.u.LowPart>This->stde.pps_size)
This->offset.u.LowPart=This->stde.pps_size;
if (newpos) *newpos = This->offset;
return S_OK;
}
/******************************************************************************
* IStream16_Read [STORAGE.521]
*/
HRESULT CDECL IStream16_fnRead(
IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
) {
IStream16Impl *This = (IStream16Impl *)iface;
BYTE block[BIGSIZE];
ULONG *bytesread=pcbRead,xxread;
int blocknr;
LPBYTE pbv = pv;
TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbRead);
if (!pcbRead) bytesread=&xxread;
*bytesread = 0;
if (cb>This->stde.pps_size-This->offset.u.LowPart)
cb=This->stde.pps_size-This->offset.u.LowPart;
if (This->stde.pps_size < 0x1000) {
/* use small block reader */
blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -