3 * Implemented using the documentation of the LAOLA project at
4 * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5 * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
7 * Copyright 1998 Marcus Meissner
20 #include "interfaces.h"
27 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
28 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
29 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
34 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
36 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
37 static IStorage16_VTable stvt16;
38 static IStorage16_VTable *segstvt16 = NULL;
39 static IStorage32_VTable stvt32;
40 static IStream16_VTable strvt16;
41 static IStream16_VTable *segstrvt16 = NULL;
42 static IStream32_VTable strvt32;
44 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);
45 static void _create_istorage16(LPSTORAGE16 *stg);
46 static void _create_istream16(LPSTREAM16 *str);
50 /******************************************************************************
51 * Reading OLE compound storage
54 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
56 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
57 fprintf(stderr,"STORAGE_get_big_block: seek failed (%ld)\n",GetLastError());
60 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
61 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
62 fprintf(stderr,"STORAGE_get_big_block(%d): read didn't (%ld)\n",n,GetLastError());
70 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
72 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
73 fprintf(stderr,"STORAGE_put_big_block: seek failed (%ld)\n",GetLastError());
76 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
77 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
78 fprintf(stderr,"STORAGE_put_big_block: write failed (%ld)\n",GetLastError());
85 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
86 INT32 bbs[BIGSIZE/sizeof(INT32)];
87 struct storage_header sth;
91 assert(blocknr>>7<sth.num_of_bbd_blocks);
92 if (sth.bbd_list[blocknr>>7]==0xffffffff)
94 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
96 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
97 return bbs[blocknr&0x7f];
101 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
102 INT32 bbs[BIGSIZE/sizeof(INT32)];
104 struct storage_header sth;
110 assert((blocknr>>7)<sth.num_of_bbd_blocks);
111 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
113 /* simple caching... */
114 if (lastblock!=sth.bbd_list[blocknr>>7]) {
115 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
116 lastblock = sth.bbd_list[blocknr>>7];
118 blocknr = bbs[blocknr&0x7f];
125 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
128 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
129 struct storage_header sth;
132 blocknr = sth.root_startblock;
134 assert(STORAGE_get_big_block(hf,blocknr,block));
136 if (!stde[i].pps_sizeofname)
138 if (stde[i].pps_type==5) {
143 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
149 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
152 struct storage_pps_entry root;
155 assert(STORAGE_get_root_pps_entry(hf,&root));
156 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
157 assert(bigblocknr>=0);
158 assert(STORAGE_get_big_block(hf,bigblocknr,block));
160 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
165 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
168 struct storage_pps_entry root;
172 assert(STORAGE_get_root_pps_entry(hf,&root));
173 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
174 assert(bigblocknr>=0);
175 assert(STORAGE_get_big_block(hf,bigblocknr,block));
177 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
178 assert(STORAGE_put_big_block(hf,bigblocknr,block));
184 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
186 LPINT32 sbd = (LPINT32)block;
188 struct storage_header sth;
192 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
193 assert(bigblocknr>=0);
194 assert(STORAGE_get_big_block(hf,bigblocknr,block));
195 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
196 return sbd[blocknr & (128-1)];
200 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
203 LPINT32 sbd = (LPINT32)block;
204 struct storage_header sth;
209 while ((nr--) && (blocknr>=0)) {
210 if (lastblocknr/128!=blocknr/128) {
212 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
213 assert(bigblocknr>=0);
214 assert(STORAGE_get_big_block(hf,bigblocknr,block));
215 lastblocknr = blocknr;
217 assert(lastblocknr>=0);
219 blocknr=sbd[blocknr & (128-1)];
220 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
226 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
229 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
230 struct storage_header sth;
233 /* we have 4 pps entries per big block */
234 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
236 assert(STORAGE_get_big_block(hf,blocknr,block));
243 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
246 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
247 struct storage_header sth;
251 /* we have 4 pps entries per big block */
252 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
254 assert(STORAGE_get_big_block(hf,blocknr,block));
256 assert(STORAGE_put_big_block(hf,blocknr,block));
261 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
262 struct storage_pps_entry stde;
267 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
270 if (!lstrcmp32W(name,stde.pps_rawname))
272 if (stde.pps_prev != -1) {
273 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
277 if (stde.pps_next != -1) {
278 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
286 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
287 char name[33],xguid[50];
289 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
291 lstrcpyWtoA(name,stde->pps_rawname);
292 if (!stde->pps_sizeofname)
294 fprintf(stderr,"name: %s\n",name);
295 fprintf(stderr,"type: %d\n",stde->pps_type);
296 fprintf(stderr,"prev pps: %ld\n",stde->pps_prev);
297 fprintf(stderr,"next pps: %ld\n",stde->pps_next);
298 fprintf(stderr,"dir pps: %ld\n",stde->pps_dir);
299 fprintf(stderr,"guid: %s\n",xguid);
300 if (stde->pps_type !=2) {
303 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
304 fprintf(stderr,"ts1: %s\n",ctime(&t));
305 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
306 fprintf(stderr,"ts2: %s\n",ctime(&t));
308 fprintf(stderr,"startblock: %ld\n",stde->pps_sb);
309 fprintf(stderr,"size: %ld\n",stde->pps_size);
313 STORAGE_init_storage(HFILE32 hf) {
316 struct storage_header *sth;
317 struct storage_pps_entry *stde;
319 assert(-1!=_llseek32(hf,0,SEEK_SET));
320 /* block -1 is the storage header */
321 sth = (struct storage_header*)block;
322 memcpy(sth->magic,STORAGE_magic,8);
323 memset(sth->unknown1,0,sizeof(sth->unknown1));
324 memset(sth->unknown2,0,sizeof(sth->unknown2));
325 memset(sth->unknown3,0,sizeof(sth->unknown3));
326 sth->num_of_bbd_blocks = 1;
327 sth->root_startblock = 1;
328 sth->sbd_startblock = 0xffffffff;
329 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
330 sth->bbd_list[0] = 0;
331 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
332 /* block 0 is the big block directory */
334 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
335 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
336 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
337 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
338 /* block 1 is the root directory entry */
339 memset(block,0x00,sizeof(block));
340 stde = (struct storage_pps_entry*)block;
341 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
342 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
347 stde->pps_sb = 0xffffffff;
349 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
354 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
356 LPINT32 bbd = (LPINT32)block;
357 int nextblocknr,bigblocknr;
358 struct storage_header sth;
361 assert(blocknr!=type);
363 bigblocknr = sth.bbd_list[blocknr/128];
364 assert(bigblocknr>=0);
365 assert(STORAGE_get_big_block(hf,bigblocknr,block));
367 nextblocknr = bbd[blocknr&(128-1)];
368 bbd[blocknr&(128-1)] = type;
371 assert(STORAGE_put_big_block(hf,bigblocknr,block));
372 type = STORAGE_CHAINENTRY_FREE;
373 blocknr = nextblocknr;
379 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
381 LPINT32 sbd = (LPINT32)block;
382 int lastblocknr,nextsmallblocknr,bigblocknr;
383 struct storage_header sth;
387 assert(blocknr!=type);
388 lastblocknr=-129;bigblocknr=-2;
390 /* cache block ... */
391 if (lastblocknr/128!=blocknr/128) {
392 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
393 assert(bigblocknr>=0);
394 assert(STORAGE_get_big_block(hf,bigblocknr,block));
396 lastblocknr = blocknr;
397 nextsmallblocknr = sbd[blocknr&(128-1)];
398 sbd[blocknr&(128-1)] = type;
399 assert(STORAGE_put_big_block(hf,bigblocknr,block));
402 type = STORAGE_CHAINENTRY_FREE;
403 blocknr = nextsmallblocknr;
409 STORAGE_get_free_big_blocknr(HFILE32 hf) {
411 LPINT32 sbd = (LPINT32)block;
412 int lastbigblocknr,i,curblock,bigblocknr;
413 struct storage_header sth;
418 bigblocknr = sth.bbd_list[curblock];
419 while (curblock<sth.num_of_bbd_blocks) {
420 assert(bigblocknr>=0);
421 assert(STORAGE_get_big_block(hf,bigblocknr,block));
423 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
424 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
425 assert(STORAGE_put_big_block(hf,bigblocknr,block));
426 memset(block,0x42,sizeof(block));
427 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
428 return i+curblock*128;
430 lastbigblocknr = bigblocknr;
431 bigblocknr = sth.bbd_list[++curblock];
433 bigblocknr = curblock*128;
434 /* since we have marked all blocks from 0 up to curblock*128-1
435 * the next free one is curblock*128, where we happily put our
436 * next large block depot.
438 memset(block,0xff,sizeof(block));
439 /* mark the block allocated and returned by this function */
440 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
441 assert(STORAGE_put_big_block(hf,bigblocknr,block));
443 /* if we had a bbd block already (mostlikely) we need
444 * to link the new one into the chain
446 if (lastbigblocknr!=-1)
447 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
448 sth.bbd_list[curblock]=bigblocknr;
449 sth.num_of_bbd_blocks++;
450 assert(sth.num_of_bbd_blocks==curblock+1);
451 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
453 /* Set the end of the chain for the bigblockdepots */
454 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
455 /* add 1, for the first entry is used for the additional big block
456 * depot. (means we already used bigblocknr) */
457 memset(block,0x42,sizeof(block));
458 /* allocate this block (filled with 0x42) */
459 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
465 STORAGE_get_free_small_blocknr(HFILE32 hf) {
467 LPINT32 sbd = (LPINT32)block;
468 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
469 struct storage_pps_entry root;
470 struct storage_header sth;
473 bigblocknr = sth.sbd_startblock;
477 while (bigblocknr>=0) {
478 if (!STORAGE_get_big_block(hf,bigblocknr,block))
481 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
482 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
483 newblocknr = i+curblock*128;
488 lastbigblocknr = bigblocknr;
489 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
492 if (newblocknr==-1) {
493 bigblocknr = STORAGE_get_free_big_blocknr(hf);
497 memset(block,0xff,sizeof(block));
498 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
499 if (!STORAGE_put_big_block(hf,bigblocknr,block))
501 if (lastbigblocknr==-1) {
502 sth.sbd_startblock = bigblocknr;
503 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
506 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
509 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
511 newblocknr = curblock*128;
513 /* allocate enough big blocks for storing the allocated small block */
514 if (!STORAGE_get_root_pps_entry(hf,&root))
519 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
520 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
521 /* we need to allocate more stuff */
522 bigblocknr = STORAGE_get_free_big_blocknr(hf);
526 if (root.pps_sb==-1) {
527 root.pps_sb = bigblocknr;
528 root.pps_size += BIGSIZE;
530 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
532 root.pps_size += BIGSIZE;
534 lastbigblocknr = bigblocknr;
536 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
538 if (!STORAGE_put_pps_entry(hf,0,&root))
544 STORAGE_get_free_pps_entry(HFILE32 hf) {
545 int blocknr,i,curblock,lastblocknr;
547 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
548 struct storage_header sth;
551 blocknr = sth.root_startblock;
555 if (!STORAGE_get_big_block(hf,blocknr,block))
558 if (stde[i].pps_sizeofname==0) /* free */
560 lastblocknr = blocknr;
561 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
564 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
565 blocknr = STORAGE_get_free_big_blocknr(hf);
566 /* sth invalidated */
570 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
572 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
574 memset(block,0,sizeof(block));
575 STORAGE_put_big_block(hf,blocknr,block);
579 /******************************************************************************
582 HRESULT WINAPI IStream16_QueryInterface(
583 LPSTREAM16 this,REFIID refiid,LPVOID *obj
587 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
588 TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",this,xrefiid,obj);
589 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
593 return OLE_E_ENUM_NOMORE;
597 ULONG WINAPI IStream16_AddRef(LPSTREAM16 this) {
598 return ++(this->ref);
601 ULONG WINAPI IStream16_Release(LPSTREAM16 this) {
602 FlushFileBuffers(this->hf);
605 CloseHandle(this->hf);
612 /* FIXME: not handling 64 bit */
613 HRESULT WINAPI IStream16_Seek(
614 LPSTREAM16 this,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
616 TRACE(relay,"(%p)->Seek([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
619 /* unix SEEK_xx should be the same as win95 ones */
621 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
624 assert(offset.HighPart==0);
625 this->offset.HighPart = offset.HighPart;
626 this->offset.LowPart = offset.LowPart;
629 if (offset.HighPart < 0) {
630 /* FIXME: is this negation correct ? */
631 offset.HighPart = -offset.HighPart;
632 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
634 assert(offset.HighPart==0);
635 assert(this->offset.LowPart >= offset.LowPart);
636 this->offset.LowPart -= offset.LowPart;
638 assert(offset.HighPart==0);
639 this->offset.LowPart+= offset.LowPart;
643 assert(offset.HighPart==0);
644 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
647 if (this->offset.LowPart>this->stde.pps_size)
648 this->offset.LowPart=this->stde.pps_size;
649 if (newpos) *newpos = this->offset;
653 HRESULT WINAPI IStream16_Read(
654 LPSTREAM16 this,void *pv,ULONG cb,ULONG *pcbRead
657 ULONG *bytesread=pcbRead,xxread;
660 TRACE(relay,"(%p)->Read(%p,%ld,%p)\n",this,pv,cb,pcbRead);
661 if (!pcbRead) bytesread=&xxread;
664 if (cb>this->stde.pps_size-this->offset.LowPart)
665 cb=this->stde.pps_size-this->offset.LowPart;
666 if (this->stde.pps_size < 0x1000) {
667 /* use small block reader */
668 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
672 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
673 fprintf(stderr,"small block read failed!!!!\n");
677 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
678 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
679 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
680 this->offset.LowPart+=cc;
684 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
687 /* use big block reader */
688 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
692 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
693 fprintf(stderr,"big block read failed!!!!\n");
697 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
698 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
699 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
700 this->offset.LowPart+=cc;
704 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
710 HRESULT WINAPI IStream16_Write(
711 LPSTREAM16 this,const void *pv,ULONG cb,ULONG *pcbWrite
714 ULONG *byteswritten=pcbWrite,xxwritten;
715 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
716 HFILE32 hf = this->hf;
718 if (!pcbWrite) byteswritten=&xxwritten;
721 TRACE(relay,"(%p)->Write(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
722 /* do we need to junk some blocks? */
723 newsize = this->offset.LowPart+cb;
724 oldsize = this->stde.pps_size;
725 if (newsize < oldsize) {
726 if (oldsize < 0x1000) {
727 /* only small blocks */
728 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
732 /* will set the rest of the chain to 'free' */
733 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
736 if (newsize >= 0x1000) {
737 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
740 /* will set the rest of the chain to 'free' */
741 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
744 /* Migrate large blocks to small blocks
745 * (we just migrate newsize bytes)
747 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
749 blocknr = this->stde.pps_sb;
752 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
753 HeapFree(GetProcessHeap(),0,data);
758 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
760 /* frees complete chain for this stream */
761 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
764 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
769 if (!STORAGE_put_small_block(hf,blocknr,curdata))
773 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
777 int newblocknr = STORAGE_get_free_small_blocknr(hf);
780 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
782 blocknr = newblocknr;
784 curdata += SMALLSIZE;
786 HeapFree(GetProcessHeap(),0,data);
789 this->stde.pps_size = newsize;
792 if (newsize > oldsize) {
793 if (oldsize >= 0x1000) {
794 /* should return the block right before the 'endofchain' */
795 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
797 lastblocknr = blocknr;
798 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
799 blocknr = STORAGE_get_free_big_blocknr(hf);
802 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
804 lastblocknr = blocknr;
806 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
809 if (newsize < 0x1000) {
810 /* find startblock */
812 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
814 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
818 /* allocate required new small blocks */
819 lastblocknr = blocknr;
820 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
821 blocknr = STORAGE_get_free_small_blocknr(hf);
824 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
826 lastblocknr = blocknr;
828 /* and terminate the chain */
829 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
833 /* no single block allocated yet */
834 blocknr=STORAGE_get_free_big_blocknr(hf);
837 this->stde.pps_sb = blocknr;
839 /* Migrate small blocks to big blocks */
840 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
842 blocknr = this->stde.pps_sb;
846 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
847 HeapFree(GetProcessHeap(),0,data);
850 curdata += SMALLSIZE;
852 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
854 /* free small block chain */
855 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
858 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
861 /* put the data into the big blocks */
862 cc = this->stde.pps_size;
864 if (!STORAGE_put_big_block(hf,blocknr,curdata))
868 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
872 int newblocknr = STORAGE_get_free_big_blocknr(hf);
875 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
877 blocknr = newblocknr;
881 HeapFree(GetProcessHeap(),0,data);
883 /* generate big blocks to fit the new data */
884 lastblocknr = blocknr;
885 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
886 blocknr = STORAGE_get_free_big_blocknr(hf);
889 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
891 lastblocknr = blocknr;
893 /* terminate chain */
894 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
898 this->stde.pps_size = newsize;
901 /* There are just some cases where we didn't modify it, we write it out
904 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
907 /* finally the write pass */
908 if (this->stde.pps_size < 0x1000) {
909 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
912 /* we ensured that it is allocated above */
914 /* Read old block everytime, since we can have
915 * overlapping data at START and END of the write
917 if (!STORAGE_get_small_block(hf,blocknr,block))
920 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
923 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
924 (LPBYTE)(pv+curoffset),
927 if (!STORAGE_put_small_block(hf,blocknr,block))
932 this->offset.LowPart += cc;
934 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
937 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
940 /* we ensured that it is allocated above, so it better is */
942 /* read old block everytime, since we can have
943 * overlapping data at START and END of the write
945 if (!STORAGE_get_big_block(hf,blocknr,block))
948 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
951 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
952 (LPBYTE)(pv+curoffset),
955 if (!STORAGE_put_big_block(hf,blocknr,block))
960 this->offset.LowPart += cc;
962 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
968 static void _create_istream16(LPSTREAM16 *str) {
971 if (!strvt16.fnQueryInterface) {
972 HMODULE16 wp = GetModuleHandle16("STORAGE");
974 #define VTENT(x) strvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#x);
975 VTENT(QueryInterface)
990 segstrvt16 = SEGPTR_NEW(IStream16_VTable);
991 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
992 segstrvt16 = (LPSTREAM16_VTABLE)SEGPTR_GET(segstrvt16);
994 #define VTENT(x) strvt16.fn##x = IStream16_##x;
995 VTENT(QueryInterface)
1012 segstrvt16 = &strvt16;
1015 lpst = SEGPTR_NEW(IStream16);
1016 lpst->lpvtbl = segstrvt16;
1018 lpst->thisptr = SEGPTR_GET(lpst);
1019 *str = (void*)lpst->thisptr;
1022 /*****************************************************************************
1025 HRESULT WINAPI IStream32_QueryInterface(
1026 LPSTREAM32 this,REFIID refiid,LPVOID *obj
1030 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1031 TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",this,xrefiid,obj);
1032 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1036 return OLE_E_ENUM_NOMORE;
1040 ULONG WINAPI IStream32_AddRef(LPSTREAM32 this) {
1041 return ++(this->ref);
1044 ULONG WINAPI IStream32_Release(LPSTREAM32 this) {
1045 FlushFileBuffers(this->hf);
1048 CloseHandle(this->hf);
1055 static IStream32_VTable strvt32 = {
1056 IStream32_QueryInterface,
1069 /******************************************************************************
1072 HRESULT WINAPI IStorage16_QueryInterface(
1073 LPSTORAGE16 this,REFIID refiid,LPVOID *obj
1077 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1078 TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",this,xrefiid,obj);
1080 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1084 return OLE_E_ENUM_NOMORE;
1087 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this) {
1088 return ++(this->ref);
1091 ULONG WINAPI IStorage16_Release(LPSTORAGE16 this) {
1099 HRESULT WINAPI IStorage16_Stat(
1100 LPSTORAGE16 this,STATSTG *pstatstg, DWORD grfStatFlag
1102 fprintf(stderr,"IStorage16(%p)->Stat(%p,0x%08lx)\n",
1103 this,pstatstg,grfStatFlag
1105 pstatstg->pwcsName=SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1106 pstatstg->type = this->stde.pps_type;
1107 pstatstg->cbSize.LowPart = this->stde.pps_size;
1108 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */
1109 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1110 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1111 pstatstg->grfMode = 0; /* FIXME */
1112 pstatstg->grfLocksSupported = 0; /* FIXME */
1113 pstatstg->clsid = this->stde.pps_guid;
1114 pstatstg->grfStateBits = 0; /* FIXME */
1115 pstatstg->reserved = 0;
1119 HRESULT WINAPI IStorage16_Commit(
1120 LPSTORAGE16 this,DWORD commitflags
1122 fprintf(stderr,"IStorage16(%p)->Commit(0x%08lx),STUB!\n",
1128 HRESULT WINAPI IStorage16_CopyTo(LPSTORAGE16 this,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1132 WINE_StringFromCLSID(rgiidExclude,xguid);
1134 strcpy(xguid,"<no guid>");
1135 fprintf(stderr,"IStorage16(%p)->CopyTo(0x%08lx,%s,%p,%p),stub!\n",
1136 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1143 HRESULT WINAPI IStorage16_CreateStorage(
1144 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1148 struct storage_pps_entry stde;
1149 struct storage_header sth;
1150 HFILE32 hf=this->hf;
1154 fprintf(stderr,"IStorage16(%p)->CreateStorage(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1155 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1157 if (grfMode & STGM_TRANSACTED)
1158 fprintf(stderr,"IStorage::CreateStorage:We do not support transacted Compound Storage. Using direct mode.\n");
1159 _create_istorage16(ppstg);
1160 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstg);
1161 lpstg->hf = this->hf;
1163 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1167 if (stde.pps_dir==-1) {
1168 stde.pps_dir = ppsent;
1171 /* FIXME: use prev chain too ? */
1173 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1175 while (stde.pps_next!=-1) {
1177 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1180 stde.pps_next = ppsent;
1182 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1183 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1184 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1185 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1186 lpstg->stde.pps_next = -1;
1187 lpstg->stde.pps_prev = -1;
1188 lpstg->stde.pps_dir = -1;
1189 lpstg->stde.pps_sb = -1;
1190 lpstg->stde.pps_size = 0;
1191 lpstg->stde.pps_type = 1;
1192 lpstg->ppsent = ppsent;
1193 /* FIXME: timestamps? */
1194 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1199 HRESULT WINAPI IStorage16_CreateStream(
1200 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1204 struct storage_pps_entry stde;
1206 fprintf(stderr,"IStorage16(%p)->CreateStream(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1207 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1209 if (grfMode & STGM_TRANSACTED)
1210 fprintf(stderr,"IStorage::CreateStream:We do not support transacted Compound Storage. Using direct mode.\n");
1211 _create_istream16(ppstm);
1212 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1213 lpstr->hf = FILE_Dup(this->hf);
1214 lpstr->offset.LowPart = 0;
1215 lpstr->offset.HighPart = 0;
1217 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1221 if (stde.pps_next==-1)
1224 while (stde.pps_next!=-1) {
1226 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1229 stde.pps_next = ppsent;
1230 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1231 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1232 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1233 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1234 lpstr->stde.pps_next = -1;
1235 lpstr->stde.pps_prev = -1;
1236 lpstr->stde.pps_dir = -1;
1237 lpstr->stde.pps_sb = -1;
1238 lpstr->stde.pps_size = 0;
1239 lpstr->stde.pps_type = 2;
1240 lpstr->ppsent = ppsent;
1241 /* FIXME: timestamps? */
1242 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1247 HRESULT WINAPI IStorage16_OpenStorage(
1248 LPSTORAGE16 this,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1254 TRACE(relay,"(%p)->OpenStorage(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1255 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1257 if (grfMode & STGM_TRANSACTED)
1258 fprintf(stderr,"IStorage::OpenStorage:We do not support transacted Compound Storage. Using direct mode.\n");
1259 _create_istorage16(ppstg);
1260 lpstg = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstg);
1261 lpstg->hf = FILE_Dup(this->hf);
1262 lstrcpyAtoW(name,pwcsName);
1263 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1265 IStream16_Release(lpstg);
1269 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1270 IStream16_Release(lpstg);
1273 lpstg->ppsent = newpps;
1277 HRESULT WINAPI IStorage16_OpenStream(
1278 LPSTORAGE16 this,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1284 TRACE(relay,"(%p)->OpenStream(%s,%p,0x%08lx,0x%08lx,%p)\n",
1285 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1287 if (grfMode & STGM_TRANSACTED)
1288 fprintf(stderr,"IStorage::OpenStream:We do not support transacted Compound Storage. Using direct mode.\n");
1289 _create_istream16(ppstm);
1290 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1291 lpstr->hf = FILE_Dup(this->hf);
1292 lstrcpyAtoW(name,pwcsName);
1293 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1295 IStream16_Release(lpstr);
1299 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1300 IStream16_Release(lpstr);
1303 lpstr->offset.LowPart = 0;
1304 lpstr->offset.HighPart = 0;
1305 lpstr->ppsent = newpps;
1309 static void _create_istorage16(LPSTORAGE16 *stg) {
1312 if (!stvt16.fnQueryInterface) {
1313 HMODULE16 wp = GetModuleHandle16("STORAGE");
1315 #define VTENT(x) stvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#x);
1316 VTENT(QueryInterface)
1321 VTENT(CreateStorage)
1324 VTENT(MoveElementTo)
1328 VTENT(DestroyElement)
1329 VTENT(RenameElement)
1330 VTENT(SetElementTimes)
1335 segstvt16 = SEGPTR_NEW(IStorage16_VTable);
1336 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1337 segstvt16 = (LPSTORAGE16_VTABLE)SEGPTR_GET(segstvt16);
1339 #define VTENT(x) stvt16.fn##x = IStorage16_##x;
1340 VTENT(QueryInterface)
1345 VTENT(CreateStorage)
1349 /* not (yet) implemented ...
1350 VTENT(MoveElementTo)
1353 VTENT(DestroyElement)
1354 VTENT(RenameElement)
1355 VTENT(SetElementTimes)
1361 segstvt16 = &stvt16;
1364 lpst = SEGPTR_NEW(IStorage16);
1365 lpst->lpvtbl = segstvt16;
1367 lpst->thisptr = SEGPTR_GET(lpst);
1368 *stg = (void*)lpst->thisptr;
1371 /******************************************************************************
1374 HRESULT WINAPI IStorage32_QueryInterface(
1375 LPSTORAGE32 this,REFIID refiid,LPVOID *obj
1379 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1380 TRACE(relay,"(%p)->QueryInterface(%s,%p)\n",this,xrefiid,obj);
1382 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1386 return OLE_E_ENUM_NOMORE;
1389 ULONG WINAPI IStorage32_AddRef(LPSTORAGE32 this) {
1390 return ++(this->ref);
1393 ULONG WINAPI IStorage32_Release(LPSTORAGE32 this) {
1397 HeapFree(GetProcessHeap(),0,this);
1401 HRESULT WINAPI IStorage32_CreateStream(
1402 LPSTORAGE32 this,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1404 fprintf(stderr,"IStorage32(%p)->CreateStream(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1405 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1407 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1408 (*ppstm)->lpvtbl= &strvt32;
1414 HRESULT WINAPI IStorage32_OpenStream(
1415 LPSTORAGE32 this,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1417 fprintf(stderr,"IStorage32(%p)->OpenStream(%p,%p,0x%08lx,0x%08lx,%p)\n",
1418 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1420 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1421 (*ppstm)->lpvtbl= &strvt32;
1426 static IStorage32_VTable stvt32 = {
1427 IStorage32_QueryInterface,
1430 IStorage32_CreateStream,
1431 IStorage32_OpenStream,
1444 /******************************************************************************
1445 * Storage API functions
1448 OLESTATUS WINAPI StgCreateDocFile16(
1449 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1454 struct storage_pps_entry stde;
1456 fprintf(stderr,"StgCreateDocfile(%s,0x%08lx,0x%08lx,%p)\n",
1457 pwcsName,grfMode,reserved,ppstgOpen
1459 _create_istorage16(ppstgOpen);
1460 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1461 if (hf==INVALID_HANDLE_VALUE32) {
1462 fprintf(stderr,"couldn't open file for storage:%ld\n",GetLastError());
1465 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1467 /* FIXME: check for existance before overwriting? */
1468 if (!STORAGE_init_storage(hf)) {
1473 while (!ret) { /* neither 1 nor <0 */
1474 ret=STORAGE_get_pps_entry(hf,i,&stde);
1475 if ((ret==1) && (stde.pps_type==5)) {
1483 IStorage16_Release(lpstg); /* will remove it */
1489 OLESTATUS WINAPI StgCreateDocFile32(
1490 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1492 fprintf(stderr,"StgCreateDocfile(%p,0x%08lx,0x%08lx,%p)\n",
1493 pwcsName,grfMode,reserved,ppstgOpen
1495 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1496 (*ppstgOpen)->ref = 1;
1497 (*ppstgOpen)->lpvtbl = &stvt32;
1501 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1506 fprintf(stderr,"StgIsStorageFile(%s)",fn);
1507 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1508 if (hf==HFILE_ERROR32)
1509 return STG_E_FILENOTFOUND;
1510 if (24!=_lread32(hf,magic,24)) {
1511 fprintf(stderr," too short\n");
1515 if (!memcmp(magic,STORAGE_magic,8)) {
1516 fprintf(stderr," -> YES\n");
1520 if (!memcmp(magic,STORAGE_notmagic,8)) {
1521 fprintf(stderr," -> NO\n");
1525 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1526 fprintf(stderr," -> old format\n");
1528 return STG_E_OLDFORMAT;
1530 fprintf(stderr," -> Invalid header.\n");
1532 return STG_E_INVALIDHEADER;
1535 OLESTATUS WINAPI StgIsStorageFile32(LPCOLESTR32 fn) {
1536 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1537 OLESTATUS ret = StgIsStorageFile16(xfn);
1539 HeapFree(GetProcessHeap(),0,xfn);
1545 OLESTATUS WINAPI StgOpenStorage16(
1546 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1547 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1552 struct storage_pps_entry stde;
1554 fprintf(stderr,"StgOpenStorage(%s,%p,0x%08lx,%p,%ld,%p)\n",
1555 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1557 _create_istorage16(ppstgOpen);
1558 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1559 if (hf==INVALID_HANDLE_VALUE32) {
1560 fprintf(stderr,"couldn't open file for storage\n");
1563 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1567 while (!ret) { /* neither 1 nor <0 */
1568 ret=STORAGE_get_pps_entry(hf,i,&stde);
1569 if ((ret==1) && (stde.pps_type==5)) {
1576 IStorage16_Release(lpstg); /* will remove it */
1583 OLESTATUS WINAPI StgOpenStorage32(
1584 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1585 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1587 fprintf(stderr,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1588 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1590 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1591 (*ppstgOpen)->ref = 1;
1592 (*ppstgOpen)->lpvtbl = &stvt32;