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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
36 #include "wine/winbase16.h"
37 #include "wine/unicode.h"
39 #include "wine/obj_base.h"
40 #include "wine/obj_storage.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 WINE_DECLARE_DEBUG_CHANNEL(relay);
46 struct storage_header {
47 BYTE magic[8]; /* 00: magic */
48 BYTE unknown1[36]; /* 08: unknown */
49 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
50 DWORD root_startblock;/* 30: root storage first big block */
51 DWORD unknown2[2]; /* 34: unknown */
52 DWORD sbd_startblock; /* 3C: small block depot first big block */
53 DWORD unknown3[3]; /* 40: unknown */
54 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
56 struct storage_pps_entry {
57 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
58 WORD pps_sizeofname; /* 40: namelength in bytes */
59 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
60 BYTE pps_unknown0; /* 43: unknown */
61 DWORD pps_prev; /* 44: previous pps */
62 DWORD pps_next; /* 48: next pps */
63 DWORD pps_dir; /* 4C: directory pps */
64 GUID pps_guid; /* 50: class ID */
65 DWORD pps_unknown1; /* 60: unknown */
66 FILETIME pps_ft1; /* 64: filetime1 */
67 FILETIME pps_ft2; /* 70: filetime2 */
68 DWORD pps_sb; /* 74: data startblock */
69 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
70 DWORD pps_unknown2; /* 7C: unknown */
73 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
74 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
75 #define STORAGE_CHAINENTRY_FREE 0xffffffff
78 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
79 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
80 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
85 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
87 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
88 static ICOM_VTABLE(IStorage16) stvt16;
89 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
90 static ICOM_VTABLE(IStream16) strvt16;
91 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
93 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
94 static void _create_istorage16(LPSTORAGE16 *stg);
95 static void _create_istream16(LPSTREAM16 *str);
100 /******************************************************************************
101 * STORAGE_get_big_block [Internal]
103 * Reading OLE compound storage
106 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
108 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
109 WARN(" seek failed (%ld)\n",GetLastError());
112 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
113 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
114 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
121 /******************************************************************************
122 * STORAGE_put_big_block [INTERNAL]
125 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
127 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
128 WARN(" seek failed (%ld)\n",GetLastError());
131 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
132 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
133 WARN(" write failed (%ld)\n",GetLastError());
139 /******************************************************************************
140 * STORAGE_get_next_big_blocknr [INTERNAL]
143 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
144 INT bbs[BIGSIZE/sizeof(INT)];
145 struct storage_header sth;
149 assert(blocknr>>7<sth.num_of_bbd_blocks);
150 if (sth.bbd_list[blocknr>>7]==0xffffffff)
152 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
154 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
155 return bbs[blocknr&0x7f];
158 /******************************************************************************
159 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
162 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
163 INT bbs[BIGSIZE/sizeof(INT)];
165 struct storage_header sth;
171 assert((blocknr>>7)<sth.num_of_bbd_blocks);
172 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
174 /* simple caching... */
175 if (lastblock!=sth.bbd_list[blocknr>>7]) {
176 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
177 lastblock = sth.bbd_list[blocknr>>7];
179 blocknr = bbs[blocknr&0x7f];
184 /******************************************************************************
185 * STORAGE_get_root_pps_entry [Internal]
188 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
191 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
192 struct storage_header sth;
195 blocknr = sth.root_startblock;
197 assert(STORAGE_get_big_block(hf,blocknr,block));
199 if (!stde[i].pps_sizeofname)
201 if (stde[i].pps_type==5) {
206 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
211 /******************************************************************************
212 * STORAGE_get_small_block [INTERNAL]
215 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
218 struct storage_pps_entry root;
221 assert(STORAGE_get_root_pps_entry(hf,&root));
222 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
223 assert(bigblocknr>=0);
224 assert(STORAGE_get_big_block(hf,bigblocknr,block));
226 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
230 /******************************************************************************
231 * STORAGE_put_small_block [INTERNAL]
234 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
237 struct storage_pps_entry root;
241 assert(STORAGE_get_root_pps_entry(hf,&root));
242 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
243 assert(bigblocknr>=0);
244 assert(STORAGE_get_big_block(hf,bigblocknr,block));
246 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
247 assert(STORAGE_put_big_block(hf,bigblocknr,block));
251 /******************************************************************************
252 * STORAGE_get_next_small_blocknr [INTERNAL]
255 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
257 LPINT sbd = (LPINT)block;
259 struct storage_header sth;
263 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
264 assert(bigblocknr>=0);
265 assert(STORAGE_get_big_block(hf,bigblocknr,block));
266 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
267 return sbd[blocknr & (128-1)];
270 /******************************************************************************
271 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
274 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
277 LPINT sbd = (LPINT)block;
278 struct storage_header sth;
283 while ((nr--) && (blocknr>=0)) {
284 if (lastblocknr/128!=blocknr/128) {
286 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
287 assert(bigblocknr>=0);
288 assert(STORAGE_get_big_block(hf,bigblocknr,block));
289 lastblocknr = blocknr;
291 assert(lastblocknr>=0);
293 blocknr=sbd[blocknr & (128-1)];
294 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
299 /******************************************************************************
300 * STORAGE_get_pps_entry [INTERNAL]
303 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
306 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
307 struct storage_header sth;
310 /* we have 4 pps entries per big block */
311 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
313 assert(STORAGE_get_big_block(hf,blocknr,block));
319 /******************************************************************************
320 * STORAGE_put_pps_entry [Internal]
323 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
326 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
327 struct storage_header sth;
331 /* we have 4 pps entries per big block */
332 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
334 assert(STORAGE_get_big_block(hf,blocknr,block));
336 assert(STORAGE_put_big_block(hf,blocknr,block));
340 /******************************************************************************
341 * STORAGE_look_for_named_pps [Internal]
344 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
345 struct storage_pps_entry stde;
350 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
353 if (!lstrcmpW(name,stde.pps_rawname))
355 if (stde.pps_prev != -1) {
356 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
360 if (stde.pps_next != -1) {
361 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
368 /******************************************************************************
369 * STORAGE_dump_pps_entry [Internal]
375 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
378 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
379 if (!stde->pps_sizeofname)
381 DPRINTF("name: %s\n",name);
382 DPRINTF("type: %d\n",stde->pps_type);
383 DPRINTF("prev pps: %ld\n",stde->pps_prev);
384 DPRINTF("next pps: %ld\n",stde->pps_next);
385 DPRINTF("dir pps: %ld\n",stde->pps_dir);
386 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
387 if (stde->pps_type !=2) {
390 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
392 DPRINTF("ts1: %s\n",ctime(&t));
393 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
395 DPRINTF("ts2: %s\n",ctime(&t));
397 DPRINTF("startblock: %ld\n",stde->pps_sb);
398 DPRINTF("size: %ld\n",stde->pps_size);
401 /******************************************************************************
402 * STORAGE_init_storage [INTERNAL]
405 STORAGE_init_storage(HFILE hf) {
408 struct storage_header *sth;
409 struct storage_pps_entry *stde;
411 assert(-1!=_llseek(hf,0,SEEK_SET));
412 /* block -1 is the storage header */
413 sth = (struct storage_header*)block;
414 memcpy(sth->magic,STORAGE_magic,8);
415 memset(sth->unknown1,0,sizeof(sth->unknown1));
416 memset(sth->unknown2,0,sizeof(sth->unknown2));
417 memset(sth->unknown3,0,sizeof(sth->unknown3));
418 sth->num_of_bbd_blocks = 1;
419 sth->root_startblock = 1;
420 sth->sbd_startblock = 0xffffffff;
421 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
422 sth->bbd_list[0] = 0;
423 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
424 /* block 0 is the big block directory */
426 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
427 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
428 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
429 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
430 /* block 1 is the root directory entry */
431 memset(block,0x00,sizeof(block));
432 stde = (struct storage_pps_entry*)block;
433 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
434 sizeof(stde->pps_rawname)/sizeof(WCHAR));
435 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
440 stde->pps_sb = 0xffffffff;
442 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
446 /******************************************************************************
447 * STORAGE_set_big_chain [Internal]
450 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
452 LPINT bbd = (LPINT)block;
453 int nextblocknr,bigblocknr;
454 struct storage_header sth;
457 assert(blocknr!=type);
459 bigblocknr = sth.bbd_list[blocknr/128];
460 assert(bigblocknr>=0);
461 assert(STORAGE_get_big_block(hf,bigblocknr,block));
463 nextblocknr = bbd[blocknr&(128-1)];
464 bbd[blocknr&(128-1)] = type;
467 assert(STORAGE_put_big_block(hf,bigblocknr,block));
468 type = STORAGE_CHAINENTRY_FREE;
469 blocknr = nextblocknr;
474 /******************************************************************************
475 * STORAGE_set_small_chain [Internal]
478 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
480 LPINT sbd = (LPINT)block;
481 int lastblocknr,nextsmallblocknr,bigblocknr;
482 struct storage_header sth;
486 assert(blocknr!=type);
487 lastblocknr=-129;bigblocknr=-2;
489 /* cache block ... */
490 if (lastblocknr/128!=blocknr/128) {
491 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
492 assert(bigblocknr>=0);
493 assert(STORAGE_get_big_block(hf,bigblocknr,block));
495 lastblocknr = blocknr;
496 nextsmallblocknr = sbd[blocknr&(128-1)];
497 sbd[blocknr&(128-1)] = type;
498 assert(STORAGE_put_big_block(hf,bigblocknr,block));
501 type = STORAGE_CHAINENTRY_FREE;
502 blocknr = nextsmallblocknr;
507 /******************************************************************************
508 * STORAGE_get_free_big_blocknr [Internal]
511 STORAGE_get_free_big_blocknr(HFILE hf) {
513 LPINT sbd = (LPINT)block;
514 int lastbigblocknr,i,curblock,bigblocknr;
515 struct storage_header sth;
520 bigblocknr = sth.bbd_list[curblock];
521 while (curblock<sth.num_of_bbd_blocks) {
522 assert(bigblocknr>=0);
523 assert(STORAGE_get_big_block(hf,bigblocknr,block));
525 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
526 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
527 assert(STORAGE_put_big_block(hf,bigblocknr,block));
528 memset(block,0x42,sizeof(block));
529 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
530 return i+curblock*128;
532 lastbigblocknr = bigblocknr;
533 bigblocknr = sth.bbd_list[++curblock];
535 bigblocknr = curblock*128;
536 /* since we have marked all blocks from 0 up to curblock*128-1
537 * the next free one is curblock*128, where we happily put our
538 * next large block depot.
540 memset(block,0xff,sizeof(block));
541 /* mark the block allocated and returned by this function */
542 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
543 assert(STORAGE_put_big_block(hf,bigblocknr,block));
545 /* if we had a bbd block already (mostlikely) we need
546 * to link the new one into the chain
548 if (lastbigblocknr!=-1)
549 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
550 sth.bbd_list[curblock]=bigblocknr;
551 sth.num_of_bbd_blocks++;
552 assert(sth.num_of_bbd_blocks==curblock+1);
553 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
555 /* Set the end of the chain for the bigblockdepots */
556 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
557 /* add 1, for the first entry is used for the additional big block
558 * depot. (means we already used bigblocknr) */
559 memset(block,0x42,sizeof(block));
560 /* allocate this block (filled with 0x42) */
561 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
566 /******************************************************************************
567 * STORAGE_get_free_small_blocknr [Internal]
570 STORAGE_get_free_small_blocknr(HFILE hf) {
572 LPINT sbd = (LPINT)block;
573 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
574 struct storage_pps_entry root;
575 struct storage_header sth;
578 bigblocknr = sth.sbd_startblock;
582 while (bigblocknr>=0) {
583 if (!STORAGE_get_big_block(hf,bigblocknr,block))
586 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
587 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
588 newblocknr = i+curblock*128;
593 lastbigblocknr = bigblocknr;
594 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
597 if (newblocknr==-1) {
598 bigblocknr = STORAGE_get_free_big_blocknr(hf);
602 memset(block,0xff,sizeof(block));
603 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
604 if (!STORAGE_put_big_block(hf,bigblocknr,block))
606 if (lastbigblocknr==-1) {
607 sth.sbd_startblock = bigblocknr;
608 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
611 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
614 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
616 newblocknr = curblock*128;
618 /* allocate enough big blocks for storing the allocated small block */
619 if (!STORAGE_get_root_pps_entry(hf,&root))
624 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
625 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
626 /* we need to allocate more stuff */
627 bigblocknr = STORAGE_get_free_big_blocknr(hf);
631 if (root.pps_sb==-1) {
632 root.pps_sb = bigblocknr;
633 root.pps_size += BIGSIZE;
635 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
637 root.pps_size += BIGSIZE;
639 lastbigblocknr = bigblocknr;
641 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
643 if (!STORAGE_put_pps_entry(hf,0,&root))
648 /******************************************************************************
649 * STORAGE_get_free_pps_entry [Internal]
652 STORAGE_get_free_pps_entry(HFILE hf) {
653 int blocknr,i,curblock,lastblocknr;
655 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
656 struct storage_header sth;
659 blocknr = sth.root_startblock;
663 if (!STORAGE_get_big_block(hf,blocknr,block))
666 if (stde[i].pps_sizeofname==0) /* free */
668 lastblocknr = blocknr;
669 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
672 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
673 blocknr = STORAGE_get_free_big_blocknr(hf);
674 /* sth invalidated */
678 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
680 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
682 memset(block,0,sizeof(block));
683 STORAGE_put_big_block(hf,blocknr,block);
687 /* --- IStream16 implementation */
691 /* IUnknown fields */
692 ICOM_VFIELD(IStream16);
694 /* IStream16 fields */
695 SEGPTR thisptr; /* pointer to this struct as segmented */
696 struct storage_pps_entry stde;
699 ULARGE_INTEGER offset;
702 /******************************************************************************
703 * IStream16_QueryInterface [STORAGE.518]
705 HRESULT WINAPI IStream16_fnQueryInterface(
706 IStream16* iface,REFIID refiid,LPVOID *obj
708 ICOM_THIS(IStream16Impl,iface);
709 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
710 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
714 return OLE_E_ENUM_NOMORE;
718 /******************************************************************************
719 * IStream16_AddRef [STORAGE.519]
721 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
722 ICOM_THIS(IStream16Impl,iface);
723 return ++(This->ref);
726 /******************************************************************************
727 * IStream16_Release [STORAGE.520]
729 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
730 ICOM_THIS(IStream16Impl,iface);
731 FlushFileBuffers(This->hf);
734 CloseHandle(This->hf);
735 UnMapLS( This->thisptr );
736 HeapFree( GetProcessHeap(), 0, This );
742 /******************************************************************************
743 * IStream16_Seek [STORAGE.523]
746 * Does not handle 64 bits
748 HRESULT WINAPI IStream16_fnSeek(
749 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
751 ICOM_THIS(IStream16Impl,iface);
752 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
755 /* unix SEEK_xx should be the same as win95 ones */
757 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
760 assert(offset.s.HighPart==0);
761 This->offset.s.HighPart = offset.s.HighPart;
762 This->offset.s.LowPart = offset.s.LowPart;
765 if (offset.s.HighPart < 0) {
766 /* FIXME: is this negation correct ? */
767 offset.s.HighPart = -offset.s.HighPart;
768 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
770 assert(offset.s.HighPart==0);
771 assert(This->offset.s.LowPart >= offset.s.LowPart);
772 This->offset.s.LowPart -= offset.s.LowPart;
774 assert(offset.s.HighPart==0);
775 This->offset.s.LowPart+= offset.s.LowPart;
779 assert(offset.s.HighPart==0);
780 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
783 if (This->offset.s.LowPart>This->stde.pps_size)
784 This->offset.s.LowPart=This->stde.pps_size;
785 if (newpos) *newpos = This->offset;
789 /******************************************************************************
790 * IStream16_Read [STORAGE.521]
792 HRESULT WINAPI IStream16_fnRead(
793 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
795 ICOM_THIS(IStream16Impl,iface);
797 ULONG *bytesread=pcbRead,xxread;
800 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
801 if (!pcbRead) bytesread=&xxread;
804 if (cb>This->stde.pps_size-This->offset.s.LowPart)
805 cb=This->stde.pps_size-This->offset.s.LowPart;
806 if (This->stde.pps_size < 0x1000) {
807 /* use small block reader */
808 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
812 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
813 WARN("small block read failed!!!\n");
817 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
818 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
819 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
820 This->offset.s.LowPart+=cc;
824 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
827 /* use big block reader */
828 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
832 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
833 WARN("big block read failed!!!\n");
837 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
838 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
839 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
840 This->offset.s.LowPart+=cc;
844 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
850 /******************************************************************************
851 * IStream16_Write [STORAGE.522]
853 HRESULT WINAPI IStream16_fnWrite(
854 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
856 ICOM_THIS(IStream16Impl,iface);
858 ULONG *byteswritten=pcbWrite,xxwritten;
859 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
862 if (!pcbWrite) byteswritten=&xxwritten;
865 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
866 /* do we need to junk some blocks? */
867 newsize = This->offset.s.LowPart+cb;
868 oldsize = This->stde.pps_size;
869 if (newsize < oldsize) {
870 if (oldsize < 0x1000) {
871 /* only small blocks */
872 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
876 /* will set the rest of the chain to 'free' */
877 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
880 if (newsize >= 0x1000) {
881 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
884 /* will set the rest of the chain to 'free' */
885 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
888 /* Migrate large blocks to small blocks
889 * (we just migrate newsize bytes)
891 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
895 blocknr = This->stde.pps_sb;
898 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
899 HeapFree(GetProcessHeap(),0,data);
904 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
906 /* frees complete chain for this stream */
907 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
910 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
915 if (!STORAGE_put_small_block(hf,blocknr,curdata))
919 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
923 int newblocknr = STORAGE_get_free_small_blocknr(hf);
926 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
928 blocknr = newblocknr;
930 curdata += SMALLSIZE;
934 HeapFree(GetProcessHeap(),0,data);
939 This->stde.pps_size = newsize;
942 if (newsize > oldsize) {
943 if (oldsize >= 0x1000) {
944 /* should return the block right before the 'endofchain' */
945 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
947 lastblocknr = blocknr;
948 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
949 blocknr = STORAGE_get_free_big_blocknr(hf);
952 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
954 lastblocknr = blocknr;
956 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
959 if (newsize < 0x1000) {
960 /* find startblock */
962 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
964 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
968 /* allocate required new small blocks */
969 lastblocknr = blocknr;
970 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
971 blocknr = STORAGE_get_free_small_blocknr(hf);
974 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
976 lastblocknr = blocknr;
978 /* and terminate the chain */
979 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
983 /* no single block allocated yet */
984 blocknr=STORAGE_get_free_big_blocknr(hf);
987 This->stde.pps_sb = blocknr;
989 /* Migrate small blocks to big blocks */
990 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
994 blocknr = This->stde.pps_sb;
998 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1000 curdata += SMALLSIZE;
1002 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1004 /* free small block chain */
1005 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1008 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1011 /* put the data into the big blocks */
1012 cc = This->stde.pps_size;
1014 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1018 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1022 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1025 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1027 blocknr = newblocknr;
1033 HeapFree(GetProcessHeap(),0,data);
1037 /* generate big blocks to fit the new data */
1038 lastblocknr = blocknr;
1039 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1040 blocknr = STORAGE_get_free_big_blocknr(hf);
1043 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1045 lastblocknr = blocknr;
1047 /* terminate chain */
1048 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1052 This->stde.pps_size = newsize;
1055 /* There are just some cases where we didn't modify it, we write it out
1058 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1061 /* finally the write pass */
1062 if (This->stde.pps_size < 0x1000) {
1063 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1066 /* we ensured that it is allocated above */
1068 /* Read old block everytime, since we can have
1069 * overlapping data at START and END of the write
1071 if (!STORAGE_get_small_block(hf,blocknr,block))
1074 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1077 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1078 (LPBYTE)((char *) pv+curoffset),
1081 if (!STORAGE_put_small_block(hf,blocknr,block))
1086 This->offset.s.LowPart += cc;
1087 *byteswritten += cc;
1088 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1091 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1094 /* we ensured that it is allocated above, so it better is */
1096 /* read old block everytime, since we can have
1097 * overlapping data at START and END of the write
1099 if (!STORAGE_get_big_block(hf,blocknr,block))
1102 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1105 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1106 (LPBYTE)((char *) pv+curoffset),
1109 if (!STORAGE_put_big_block(hf,blocknr,block))
1114 This->offset.s.LowPart += cc;
1115 *byteswritten += cc;
1116 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1122 /******************************************************************************
1123 * _create_istream16 [Internal]
1125 static void _create_istream16(LPSTREAM16 *str) {
1126 IStream16Impl* lpst;
1128 if (!strvt16.QueryInterface) {
1129 HMODULE16 wp = GetModuleHandle16("STORAGE");
1131 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1132 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1133 VTENT(QueryInterface);
1144 VTENT(UnlockRegion);
1148 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1150 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1151 VTENT(QueryInterface);
1163 VTENT(UnlockRegion);
1168 segstrvt16 = &strvt16;
1171 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1172 ICOM_VTBL(lpst) = segstrvt16;
1174 lpst->thisptr = MapLS( lpst );
1175 *str = (void*)lpst->thisptr;
1179 /* --- IStream32 implementation */
1183 /* IUnknown fields */
1184 ICOM_VFIELD(IStream);
1186 /* IStream32 fields */
1187 struct storage_pps_entry stde;
1190 ULARGE_INTEGER offset;
1193 /*****************************************************************************
1194 * IStream32_QueryInterface [VTABLE]
1196 HRESULT WINAPI IStream_fnQueryInterface(
1197 IStream* iface,REFIID refiid,LPVOID *obj
1199 ICOM_THIS(IStream32Impl,iface);
1201 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1202 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1206 return OLE_E_ENUM_NOMORE;
1210 /******************************************************************************
1211 * IStream32_AddRef [VTABLE]
1213 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1214 ICOM_THIS(IStream32Impl,iface);
1215 return ++(This->ref);
1218 /******************************************************************************
1219 * IStream32_Release [VTABLE]
1221 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1222 ICOM_THIS(IStream32Impl,iface);
1223 FlushFileBuffers(This->hf);
1226 CloseHandle(This->hf);
1227 HeapFree( GetProcessHeap(), 0, This );
1233 /* --- IStorage16 implementation */
1237 /* IUnknown fields */
1238 ICOM_VFIELD(IStorage16);
1240 /* IStorage16 fields */
1241 SEGPTR thisptr; /* pointer to this struct as segmented */
1242 struct storage_pps_entry stde;
1247 /******************************************************************************
1248 * IStorage16_QueryInterface [STORAGE.500]
1250 HRESULT WINAPI IStorage16_fnQueryInterface(
1251 IStorage16* iface,REFIID refiid,LPVOID *obj
1253 ICOM_THIS(IStorage16Impl,iface);
1255 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1257 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1261 return OLE_E_ENUM_NOMORE;
1264 /******************************************************************************
1265 * IStorage16_AddRef [STORAGE.501]
1267 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1268 ICOM_THIS(IStorage16Impl,iface);
1269 return ++(This->ref);
1272 /******************************************************************************
1273 * IStorage16_Release [STORAGE.502]
1275 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1276 ICOM_THIS(IStorage16Impl,iface);
1280 UnMapLS( This->thisptr );
1281 HeapFree( GetProcessHeap(), 0, This );
1285 /******************************************************************************
1286 * IStorage16_Stat [STORAGE.517]
1288 HRESULT WINAPI IStorage16_fnStat(
1289 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1291 ICOM_THIS(IStorage16Impl,iface);
1292 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1293 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1295 TRACE("(%p)->(%p,0x%08lx)\n",
1296 This,pstatstg,grfStatFlag
1298 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1299 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1300 pstatstg->type = This->stde.pps_type;
1301 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1302 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1303 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1304 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1305 pstatstg->grfMode = 0; /* FIXME */
1306 pstatstg->grfLocksSupported = 0; /* FIXME */
1307 pstatstg->clsid = This->stde.pps_guid;
1308 pstatstg->grfStateBits = 0; /* FIXME */
1309 pstatstg->reserved = 0;
1313 /******************************************************************************
1314 * IStorage16_Commit [STORAGE.509]
1316 HRESULT WINAPI IStorage16_fnCommit(
1317 LPSTORAGE16 iface,DWORD commitflags
1319 ICOM_THIS(IStorage16Impl,iface);
1320 FIXME("(%p)->(0x%08lx),STUB!\n",
1326 /******************************************************************************
1327 * IStorage16_CopyTo [STORAGE.507]
1329 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1330 ICOM_THIS(IStorage16Impl,iface);
1331 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1332 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1338 /******************************************************************************
1339 * IStorage16_CreateStorage [STORAGE.505]
1341 HRESULT WINAPI IStorage16_fnCreateStorage(
1342 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1344 ICOM_THIS(IStorage16Impl,iface);
1345 IStorage16Impl* lpstg;
1347 struct storage_pps_entry stde;
1348 struct storage_header sth;
1353 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1354 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1356 if (grfMode & STGM_TRANSACTED)
1357 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1358 _create_istorage16(ppstg);
1359 lpstg = MapSL((SEGPTR)*ppstg);
1360 lpstg->hf = This->hf;
1362 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1366 if (stde.pps_dir==-1) {
1367 stde.pps_dir = ppsent;
1370 FIXME(" use prev chain too ?\n");
1372 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1374 while (stde.pps_next!=-1) {
1376 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1379 stde.pps_next = ppsent;
1381 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1382 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1383 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1384 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1385 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1386 lpstg->stde.pps_next = -1;
1387 lpstg->stde.pps_prev = -1;
1388 lpstg->stde.pps_dir = -1;
1389 lpstg->stde.pps_sb = -1;
1390 lpstg->stde.pps_size = 0;
1391 lpstg->stde.pps_type = 1;
1392 lpstg->ppsent = ppsent;
1393 /* FIXME: timestamps? */
1394 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1399 /******************************************************************************
1400 * IStorage16_CreateStream [STORAGE.503]
1402 HRESULT WINAPI IStorage16_fnCreateStream(
1403 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1405 ICOM_THIS(IStorage16Impl,iface);
1406 IStream16Impl* lpstr;
1408 struct storage_pps_entry stde;
1410 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1411 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1413 if (grfMode & STGM_TRANSACTED)
1414 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1415 _create_istream16(ppstm);
1416 lpstr = MapSL((SEGPTR)*ppstm);
1417 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1418 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1419 lpstr->offset.s.LowPart = 0;
1420 lpstr->offset.s.HighPart = 0;
1422 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1426 if (stde.pps_next==-1)
1429 while (stde.pps_next!=-1) {
1431 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1434 stde.pps_next = ppsent;
1435 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1436 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1437 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1438 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1439 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1440 lpstr->stde.pps_next = -1;
1441 lpstr->stde.pps_prev = -1;
1442 lpstr->stde.pps_dir = -1;
1443 lpstr->stde.pps_sb = -1;
1444 lpstr->stde.pps_size = 0;
1445 lpstr->stde.pps_type = 2;
1446 lpstr->ppsent = ppsent;
1447 /* FIXME: timestamps? */
1448 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1453 /******************************************************************************
1454 * IStorage16_OpenStorage [STORAGE.506]
1456 HRESULT WINAPI IStorage16_fnOpenStorage(
1457 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1459 ICOM_THIS(IStorage16Impl,iface);
1460 IStream16Impl* lpstg;
1464 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1465 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1467 if (grfMode & STGM_TRANSACTED)
1468 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1469 _create_istorage16(ppstg);
1470 lpstg = MapSL((SEGPTR)*ppstg);
1471 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1472 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1473 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1474 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1476 IStream16_fnRelease((IStream16*)lpstg);
1480 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1481 IStream16_fnRelease((IStream16*)lpstg);
1484 lpstg->ppsent = newpps;
1488 /******************************************************************************
1489 * IStorage16_OpenStream [STORAGE.504]
1491 HRESULT WINAPI IStorage16_fnOpenStream(
1492 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1494 ICOM_THIS(IStorage16Impl,iface);
1495 IStream16Impl* lpstr;
1499 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1500 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1502 if (grfMode & STGM_TRANSACTED)
1503 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1504 _create_istream16(ppstm);
1505 lpstr = MapSL((SEGPTR)*ppstm);
1506 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1507 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1508 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1509 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1511 IStream16_fnRelease((IStream16*)lpstr);
1515 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1516 IStream16_fnRelease((IStream16*)lpstr);
1519 lpstr->offset.s.LowPart = 0;
1520 lpstr->offset.s.HighPart = 0;
1521 lpstr->ppsent = newpps;
1525 /******************************************************************************
1526 * _create_istorage16 [INTERNAL]
1528 static void _create_istorage16(LPSTORAGE16 *stg) {
1529 IStorage16Impl* lpst;
1531 if (!stvt16.QueryInterface) {
1532 HMODULE16 wp = GetModuleHandle16("STORAGE");
1534 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1535 VTENT(QueryInterface)
1540 VTENT(CreateStorage)
1543 VTENT(MoveElementTo)
1547 VTENT(DestroyElement)
1548 VTENT(RenameElement)
1549 VTENT(SetElementTimes)
1554 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1556 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1557 VTENT(QueryInterface)
1562 VTENT(CreateStorage)
1566 /* not (yet) implemented ...
1567 VTENT(MoveElementTo)
1570 VTENT(DestroyElement)
1571 VTENT(RenameElement)
1572 VTENT(SetElementTimes)
1578 segstvt16 = &stvt16;
1581 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1582 ICOM_VTBL(lpst) = segstvt16;
1584 lpst->thisptr = MapLS(lpst);
1585 *stg = (void*)lpst->thisptr;
1588 /******************************************************************************
1589 * Storage API functions
1592 /******************************************************************************
1593 * StgCreateDocFileA [STORAGE.1]
1595 HRESULT WINAPI StgCreateDocFile16(
1596 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1600 IStorage16Impl* lpstg;
1601 struct storage_pps_entry stde;
1603 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1604 pwcsName,grfMode,reserved,ppstgOpen
1606 _create_istorage16(ppstgOpen);
1607 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1608 if (hf==INVALID_HANDLE_VALUE) {
1609 WARN("couldn't open file for storage:%ld\n",GetLastError());
1612 lpstg = MapSL((SEGPTR)*ppstgOpen);
1614 /* FIXME: check for existence before overwriting? */
1615 if (!STORAGE_init_storage(hf)) {
1620 while (!ret) { /* neither 1 nor <0 */
1621 ret=STORAGE_get_pps_entry(hf,i,&stde);
1622 if ((ret==1) && (stde.pps_type==5)) {
1630 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1637 /******************************************************************************
1638 * StgIsStorageFile [STORAGE.5]
1640 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1645 TRACE("(\'%s\')\n",fn);
1646 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1647 if (hf==HFILE_ERROR)
1648 return STG_E_FILENOTFOUND;
1649 if (24!=_lread(hf,magic,24)) {
1650 WARN(" too short\n");
1654 if (!memcmp(magic,STORAGE_magic,8)) {
1659 if (!memcmp(magic,STORAGE_notmagic,8)) {
1664 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1665 WARN(" -> old format\n");
1667 return STG_E_OLDFORMAT;
1669 WARN(" -> Invalid header.\n");
1671 return STG_E_INVALIDHEADER;
1674 /******************************************************************************
1675 * StgIsStorageFile [OLE32.146]
1678 StgIsStorageFile(LPCOLESTR fn)
1681 DWORD len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL );
1682 LPSTR strA = HeapAlloc( GetProcessHeap(), 0, len );
1684 WideCharToMultiByte( CP_ACP, 0, fn, -1, strA, len, NULL, NULL );
1685 ret = StgIsStorageFile16(strA);
1686 HeapFree( GetProcessHeap(), 0, strA );
1691 /******************************************************************************
1692 * StgOpenStorage [STORAGE.3]
1694 HRESULT WINAPI StgOpenStorage16(
1695 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1696 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1700 IStorage16Impl* lpstg;
1701 struct storage_pps_entry stde;
1703 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1704 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1706 _create_istorage16(ppstgOpen);
1707 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1708 if (hf==INVALID_HANDLE_VALUE) {
1709 WARN("Couldn't open file for storage\n");
1712 lpstg = MapSL((SEGPTR)*ppstgOpen);
1716 while (!ret) { /* neither 1 nor <0 */
1717 ret=STORAGE_get_pps_entry(hf,i,&stde);
1718 if ((ret==1) && (stde.pps_type==5)) {
1725 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */