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/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42 WINE_DECLARE_DEBUG_CHANNEL(relay);
44 struct storage_header {
45 BYTE magic[8]; /* 00: magic */
46 BYTE unknown1[36]; /* 08: unknown */
47 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
48 DWORD root_startblock;/* 30: root storage first big block */
49 DWORD unknown2[2]; /* 34: unknown */
50 DWORD sbd_startblock; /* 3C: small block depot first big block */
51 DWORD unknown3[3]; /* 40: unknown */
52 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
54 struct storage_pps_entry {
55 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
56 WORD pps_sizeofname; /* 40: namelength in bytes */
57 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
58 BYTE pps_unknown0; /* 43: unknown */
59 DWORD pps_prev; /* 44: previous pps */
60 DWORD pps_next; /* 48: next pps */
61 DWORD pps_dir; /* 4C: directory pps */
62 GUID pps_guid; /* 50: class ID */
63 DWORD pps_unknown1; /* 60: unknown */
64 FILETIME pps_ft1; /* 64: filetime1 */
65 FILETIME pps_ft2; /* 70: filetime2 */
66 DWORD pps_sb; /* 74: data startblock */
67 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
68 DWORD pps_unknown2; /* 7C: unknown */
71 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
72 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
73 #define STORAGE_CHAINENTRY_FREE 0xffffffff
76 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
81 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
83 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
84 static ICOM_VTABLE(IStorage16) stvt16;
85 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
86 static ICOM_VTABLE(IStream16) strvt16;
87 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
89 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
90 static void _create_istorage16(LPSTORAGE16 *stg);
91 static void _create_istream16(LPSTREAM16 *str);
96 /******************************************************************************
97 * STORAGE_get_big_block [Internal]
99 * Reading OLE compound storage
102 STORAGE_get_big_block(HANDLE hf,int n,BYTE *block)
107 if (!SetFilePointer( hf, (n+1)*BIGSIZE, NULL, SEEK_SET ))
109 WARN(" seek failed (%ld)\n",GetLastError());
112 if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
114 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
120 /******************************************************************************
121 * STORAGE_put_big_block [INTERNAL]
124 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
129 if (!SetFilePointer( hf, (n+1)*BIGSIZE, NULL, SEEK_SET ))
131 WARN(" seek failed (%ld)\n",GetLastError());
134 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
136 WARN(" write failed (%ld)\n",GetLastError());
142 /******************************************************************************
143 * STORAGE_get_next_big_blocknr [INTERNAL]
146 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
147 INT bbs[BIGSIZE/sizeof(INT)];
148 struct storage_header sth;
152 assert(blocknr>>7<sth.num_of_bbd_blocks);
153 if (sth.bbd_list[blocknr>>7]==0xffffffff)
155 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
157 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
158 return bbs[blocknr&0x7f];
161 /******************************************************************************
162 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
165 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
166 INT bbs[BIGSIZE/sizeof(INT)];
168 struct storage_header sth;
174 assert((blocknr>>7)<sth.num_of_bbd_blocks);
175 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
177 /* simple caching... */
178 if (lastblock!=sth.bbd_list[blocknr>>7]) {
179 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
180 lastblock = sth.bbd_list[blocknr>>7];
182 blocknr = bbs[blocknr&0x7f];
187 /******************************************************************************
188 * STORAGE_get_root_pps_entry [Internal]
191 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
194 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
195 struct storage_header sth;
198 blocknr = sth.root_startblock;
200 assert(STORAGE_get_big_block(hf,blocknr,block));
202 if (!stde[i].pps_sizeofname)
204 if (stde[i].pps_type==5) {
209 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
214 /******************************************************************************
215 * STORAGE_get_small_block [INTERNAL]
218 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
221 struct storage_pps_entry root;
224 assert(STORAGE_get_root_pps_entry(hf,&root));
225 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
226 assert(bigblocknr>=0);
227 assert(STORAGE_get_big_block(hf,bigblocknr,block));
229 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
233 /******************************************************************************
234 * STORAGE_put_small_block [INTERNAL]
237 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
240 struct storage_pps_entry root;
244 assert(STORAGE_get_root_pps_entry(hf,&root));
245 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
246 assert(bigblocknr>=0);
247 assert(STORAGE_get_big_block(hf,bigblocknr,block));
249 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
250 assert(STORAGE_put_big_block(hf,bigblocknr,block));
254 /******************************************************************************
255 * STORAGE_get_next_small_blocknr [INTERNAL]
258 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
260 LPINT sbd = (LPINT)block;
262 struct storage_header sth;
266 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
267 assert(bigblocknr>=0);
268 assert(STORAGE_get_big_block(hf,bigblocknr,block));
269 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
270 return sbd[blocknr & (128-1)];
273 /******************************************************************************
274 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
277 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
280 LPINT sbd = (LPINT)block;
281 struct storage_header sth;
286 while ((nr--) && (blocknr>=0)) {
287 if (lastblocknr/128!=blocknr/128) {
289 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
290 assert(bigblocknr>=0);
291 assert(STORAGE_get_big_block(hf,bigblocknr,block));
292 lastblocknr = blocknr;
294 assert(lastblocknr>=0);
296 blocknr=sbd[blocknr & (128-1)];
297 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
302 /******************************************************************************
303 * STORAGE_get_pps_entry [INTERNAL]
306 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
309 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
310 struct storage_header sth;
313 /* we have 4 pps entries per big block */
314 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
316 assert(STORAGE_get_big_block(hf,blocknr,block));
322 /******************************************************************************
323 * STORAGE_put_pps_entry [Internal]
326 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
329 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
330 struct storage_header sth;
334 /* we have 4 pps entries per big block */
335 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
337 assert(STORAGE_get_big_block(hf,blocknr,block));
339 assert(STORAGE_put_big_block(hf,blocknr,block));
343 /******************************************************************************
344 * STORAGE_look_for_named_pps [Internal]
347 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
348 struct storage_pps_entry stde;
353 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
356 if (!lstrcmpW(name,stde.pps_rawname))
358 if (stde.pps_prev != -1) {
359 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
363 if (stde.pps_next != -1) {
364 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
371 /******************************************************************************
372 * STORAGE_dump_pps_entry [Internal]
378 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
381 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
382 if (!stde->pps_sizeofname)
384 DPRINTF("name: %s\n",name);
385 DPRINTF("type: %d\n",stde->pps_type);
386 DPRINTF("prev pps: %ld\n",stde->pps_prev);
387 DPRINTF("next pps: %ld\n",stde->pps_next);
388 DPRINTF("dir pps: %ld\n",stde->pps_dir);
389 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
390 if (stde->pps_type !=2) {
393 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
395 DPRINTF("ts1: %s\n",ctime(&t));
396 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
398 DPRINTF("ts2: %s\n",ctime(&t));
400 DPRINTF("startblock: %ld\n",stde->pps_sb);
401 DPRINTF("size: %ld\n",stde->pps_size);
404 /******************************************************************************
405 * STORAGE_init_storage [INTERNAL]
408 STORAGE_init_storage(HANDLE hf) {
411 struct storage_header *sth;
412 struct storage_pps_entry *stde;
415 SetFilePointer( hf, 0, NULL, SEEK_SET );
416 /* block -1 is the storage header */
417 sth = (struct storage_header*)block;
418 memcpy(sth->magic,STORAGE_magic,8);
419 memset(sth->unknown1,0,sizeof(sth->unknown1));
420 memset(sth->unknown2,0,sizeof(sth->unknown2));
421 memset(sth->unknown3,0,sizeof(sth->unknown3));
422 sth->num_of_bbd_blocks = 1;
423 sth->root_startblock = 1;
424 sth->sbd_startblock = 0xffffffff;
425 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
426 sth->bbd_list[0] = 0;
427 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
428 /* block 0 is the big block directory */
430 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
431 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
432 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
433 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
434 /* block 1 is the root directory entry */
435 memset(block,0x00,sizeof(block));
436 stde = (struct storage_pps_entry*)block;
437 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
438 sizeof(stde->pps_rawname)/sizeof(WCHAR));
439 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
444 stde->pps_sb = 0xffffffff;
446 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
449 /******************************************************************************
450 * STORAGE_set_big_chain [Internal]
453 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
455 LPINT bbd = (LPINT)block;
456 int nextblocknr,bigblocknr;
457 struct storage_header sth;
460 assert(blocknr!=type);
462 bigblocknr = sth.bbd_list[blocknr/128];
463 assert(bigblocknr>=0);
464 assert(STORAGE_get_big_block(hf,bigblocknr,block));
466 nextblocknr = bbd[blocknr&(128-1)];
467 bbd[blocknr&(128-1)] = type;
470 assert(STORAGE_put_big_block(hf,bigblocknr,block));
471 type = STORAGE_CHAINENTRY_FREE;
472 blocknr = nextblocknr;
477 /******************************************************************************
478 * STORAGE_set_small_chain [Internal]
481 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
483 LPINT sbd = (LPINT)block;
484 int lastblocknr,nextsmallblocknr,bigblocknr;
485 struct storage_header sth;
489 assert(blocknr!=type);
490 lastblocknr=-129;bigblocknr=-2;
492 /* cache block ... */
493 if (lastblocknr/128!=blocknr/128) {
494 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
495 assert(bigblocknr>=0);
496 assert(STORAGE_get_big_block(hf,bigblocknr,block));
498 lastblocknr = blocknr;
499 nextsmallblocknr = sbd[blocknr&(128-1)];
500 sbd[blocknr&(128-1)] = type;
501 assert(STORAGE_put_big_block(hf,bigblocknr,block));
504 type = STORAGE_CHAINENTRY_FREE;
505 blocknr = nextsmallblocknr;
510 /******************************************************************************
511 * STORAGE_get_free_big_blocknr [Internal]
514 STORAGE_get_free_big_blocknr(HANDLE hf) {
516 LPINT sbd = (LPINT)block;
517 int lastbigblocknr,i,curblock,bigblocknr;
518 struct storage_header sth;
523 bigblocknr = sth.bbd_list[curblock];
524 while (curblock<sth.num_of_bbd_blocks) {
525 assert(bigblocknr>=0);
526 assert(STORAGE_get_big_block(hf,bigblocknr,block));
528 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
529 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
530 assert(STORAGE_put_big_block(hf,bigblocknr,block));
531 memset(block,0x42,sizeof(block));
532 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
533 return i+curblock*128;
535 lastbigblocknr = bigblocknr;
536 bigblocknr = sth.bbd_list[++curblock];
538 bigblocknr = curblock*128;
539 /* since we have marked all blocks from 0 up to curblock*128-1
540 * the next free one is curblock*128, where we happily put our
541 * next large block depot.
543 memset(block,0xff,sizeof(block));
544 /* mark the block allocated and returned by this function */
545 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
546 assert(STORAGE_put_big_block(hf,bigblocknr,block));
548 /* if we had a bbd block already (mostlikely) we need
549 * to link the new one into the chain
551 if (lastbigblocknr!=-1)
552 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
553 sth.bbd_list[curblock]=bigblocknr;
554 sth.num_of_bbd_blocks++;
555 assert(sth.num_of_bbd_blocks==curblock+1);
556 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
558 /* Set the end of the chain for the bigblockdepots */
559 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
560 /* add 1, for the first entry is used for the additional big block
561 * depot. (means we already used bigblocknr) */
562 memset(block,0x42,sizeof(block));
563 /* allocate this block (filled with 0x42) */
564 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
569 /******************************************************************************
570 * STORAGE_get_free_small_blocknr [Internal]
573 STORAGE_get_free_small_blocknr(HANDLE hf) {
575 LPINT sbd = (LPINT)block;
576 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
577 struct storage_pps_entry root;
578 struct storage_header sth;
581 bigblocknr = sth.sbd_startblock;
585 while (bigblocknr>=0) {
586 if (!STORAGE_get_big_block(hf,bigblocknr,block))
589 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
590 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
591 newblocknr = i+curblock*128;
596 lastbigblocknr = bigblocknr;
597 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
600 if (newblocknr==-1) {
601 bigblocknr = STORAGE_get_free_big_blocknr(hf);
605 memset(block,0xff,sizeof(block));
606 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
607 if (!STORAGE_put_big_block(hf,bigblocknr,block))
609 if (lastbigblocknr==-1) {
610 sth.sbd_startblock = bigblocknr;
611 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
614 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
617 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
619 newblocknr = curblock*128;
621 /* allocate enough big blocks for storing the allocated small block */
622 if (!STORAGE_get_root_pps_entry(hf,&root))
627 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
628 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
629 /* we need to allocate more stuff */
630 bigblocknr = STORAGE_get_free_big_blocknr(hf);
634 if (root.pps_sb==-1) {
635 root.pps_sb = bigblocknr;
636 root.pps_size += BIGSIZE;
638 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
640 root.pps_size += BIGSIZE;
642 lastbigblocknr = bigblocknr;
644 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
646 if (!STORAGE_put_pps_entry(hf,0,&root))
651 /******************************************************************************
652 * STORAGE_get_free_pps_entry [Internal]
655 STORAGE_get_free_pps_entry(HANDLE hf) {
656 int blocknr,i,curblock,lastblocknr;
658 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
659 struct storage_header sth;
662 blocknr = sth.root_startblock;
666 if (!STORAGE_get_big_block(hf,blocknr,block))
669 if (stde[i].pps_sizeofname==0) /* free */
671 lastblocknr = blocknr;
672 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
675 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
676 blocknr = STORAGE_get_free_big_blocknr(hf);
677 /* sth invalidated */
681 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
683 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
685 memset(block,0,sizeof(block));
686 STORAGE_put_big_block(hf,blocknr,block);
690 /* --- IStream16 implementation */
694 /* IUnknown fields */
695 ICOM_VFIELD(IStream16);
697 /* IStream16 fields */
698 SEGPTR thisptr; /* pointer to this struct as segmented */
699 struct storage_pps_entry stde;
702 ULARGE_INTEGER offset;
705 /******************************************************************************
706 * IStream16_QueryInterface [STORAGE.518]
708 HRESULT WINAPI IStream16_fnQueryInterface(
709 IStream16* iface,REFIID refiid,LPVOID *obj
711 ICOM_THIS(IStream16Impl,iface);
712 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
713 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
717 return OLE_E_ENUM_NOMORE;
721 /******************************************************************************
722 * IStream16_AddRef [STORAGE.519]
724 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
725 ICOM_THIS(IStream16Impl,iface);
726 return ++(This->ref);
729 /******************************************************************************
730 * IStream16_Release [STORAGE.520]
732 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
733 ICOM_THIS(IStream16Impl,iface);
734 FlushFileBuffers(This->hf);
737 CloseHandle(This->hf);
738 UnMapLS( This->thisptr );
739 HeapFree( GetProcessHeap(), 0, This );
745 /******************************************************************************
746 * IStream16_Seek [STORAGE.523]
749 * Does not handle 64 bits
751 HRESULT WINAPI IStream16_fnSeek(
752 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
754 ICOM_THIS(IStream16Impl,iface);
755 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
758 /* unix SEEK_xx should be the same as win95 ones */
760 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
763 assert(offset.s.HighPart==0);
764 This->offset.s.HighPart = offset.s.HighPart;
765 This->offset.s.LowPart = offset.s.LowPart;
768 if (offset.s.HighPart < 0) {
769 /* FIXME: is this negation correct ? */
770 offset.s.HighPart = -offset.s.HighPart;
771 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
773 assert(offset.s.HighPart==0);
774 assert(This->offset.s.LowPart >= offset.s.LowPart);
775 This->offset.s.LowPart -= offset.s.LowPart;
777 assert(offset.s.HighPart==0);
778 This->offset.s.LowPart+= offset.s.LowPart;
782 assert(offset.s.HighPart==0);
783 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
786 if (This->offset.s.LowPart>This->stde.pps_size)
787 This->offset.s.LowPart=This->stde.pps_size;
788 if (newpos) *newpos = This->offset;
792 /******************************************************************************
793 * IStream16_Read [STORAGE.521]
795 HRESULT WINAPI IStream16_fnRead(
796 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
798 ICOM_THIS(IStream16Impl,iface);
800 ULONG *bytesread=pcbRead,xxread;
803 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
804 if (!pcbRead) bytesread=&xxread;
807 if (cb>This->stde.pps_size-This->offset.s.LowPart)
808 cb=This->stde.pps_size-This->offset.s.LowPart;
809 if (This->stde.pps_size < 0x1000) {
810 /* use small block reader */
811 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
815 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
816 WARN("small block read failed!!!\n");
820 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
821 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
822 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
823 This->offset.s.LowPart+=cc;
827 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
830 /* use big block reader */
831 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
835 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
836 WARN("big block read failed!!!\n");
840 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
841 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
842 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
843 This->offset.s.LowPart+=cc;
847 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
853 /******************************************************************************
854 * IStream16_Write [STORAGE.522]
856 HRESULT WINAPI IStream16_fnWrite(
857 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
859 ICOM_THIS(IStream16Impl,iface);
861 ULONG *byteswritten=pcbWrite,xxwritten;
862 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
863 HANDLE hf = This->hf;
865 if (!pcbWrite) byteswritten=&xxwritten;
868 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
869 /* do we need to junk some blocks? */
870 newsize = This->offset.s.LowPart+cb;
871 oldsize = This->stde.pps_size;
872 if (newsize < oldsize) {
873 if (oldsize < 0x1000) {
874 /* only small blocks */
875 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
879 /* will set the rest of the chain to 'free' */
880 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
883 if (newsize >= 0x1000) {
884 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
887 /* will set the rest of the chain to 'free' */
888 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
891 /* Migrate large blocks to small blocks
892 * (we just migrate newsize bytes)
894 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
898 blocknr = This->stde.pps_sb;
901 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
902 HeapFree(GetProcessHeap(),0,data);
907 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
909 /* frees complete chain for this stream */
910 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
913 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
918 if (!STORAGE_put_small_block(hf,blocknr,curdata))
922 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
926 int newblocknr = STORAGE_get_free_small_blocknr(hf);
929 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
931 blocknr = newblocknr;
933 curdata += SMALLSIZE;
937 HeapFree(GetProcessHeap(),0,data);
942 This->stde.pps_size = newsize;
945 if (newsize > oldsize) {
946 if (oldsize >= 0x1000) {
947 /* should return the block right before the 'endofchain' */
948 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
950 lastblocknr = blocknr;
951 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
952 blocknr = STORAGE_get_free_big_blocknr(hf);
955 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
957 lastblocknr = blocknr;
959 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
962 if (newsize < 0x1000) {
963 /* find startblock */
965 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
967 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
971 /* allocate required new small blocks */
972 lastblocknr = blocknr;
973 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
974 blocknr = STORAGE_get_free_small_blocknr(hf);
977 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
979 lastblocknr = blocknr;
981 /* and terminate the chain */
982 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
986 /* no single block allocated yet */
987 blocknr=STORAGE_get_free_big_blocknr(hf);
990 This->stde.pps_sb = blocknr;
992 /* Migrate small blocks to big blocks */
993 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
997 blocknr = This->stde.pps_sb;
1001 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1003 curdata += SMALLSIZE;
1005 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1007 /* free small block chain */
1008 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1011 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1014 /* put the data into the big blocks */
1015 cc = This->stde.pps_size;
1017 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1021 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1025 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1028 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1030 blocknr = newblocknr;
1036 HeapFree(GetProcessHeap(),0,data);
1040 /* generate big blocks to fit the new data */
1041 lastblocknr = blocknr;
1042 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1043 blocknr = STORAGE_get_free_big_blocknr(hf);
1046 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1048 lastblocknr = blocknr;
1050 /* terminate chain */
1051 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1055 This->stde.pps_size = newsize;
1058 /* There are just some cases where we didn't modify it, we write it out
1061 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1064 /* finally the write pass */
1065 if (This->stde.pps_size < 0x1000) {
1066 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1069 /* we ensured that it is allocated above */
1071 /* Read old block everytime, since we can have
1072 * overlapping data at START and END of the write
1074 if (!STORAGE_get_small_block(hf,blocknr,block))
1077 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1080 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1081 (LPBYTE)((char *) pv+curoffset),
1084 if (!STORAGE_put_small_block(hf,blocknr,block))
1089 This->offset.s.LowPart += cc;
1090 *byteswritten += cc;
1091 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1094 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1097 /* we ensured that it is allocated above, so it better is */
1099 /* read old block everytime, since we can have
1100 * overlapping data at START and END of the write
1102 if (!STORAGE_get_big_block(hf,blocknr,block))
1105 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1108 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1109 (LPBYTE)((char *) pv+curoffset),
1112 if (!STORAGE_put_big_block(hf,blocknr,block))
1117 This->offset.s.LowPart += cc;
1118 *byteswritten += cc;
1119 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1125 /******************************************************************************
1126 * _create_istream16 [Internal]
1128 static void _create_istream16(LPSTREAM16 *str) {
1129 IStream16Impl* lpst;
1131 if (!strvt16.QueryInterface) {
1132 HMODULE16 wp = GetModuleHandle16("STORAGE");
1134 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1135 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1136 VTENT(QueryInterface);
1147 VTENT(UnlockRegion);
1151 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1153 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1154 VTENT(QueryInterface);
1166 VTENT(UnlockRegion);
1171 segstrvt16 = &strvt16;
1174 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1175 ICOM_VTBL(lpst) = segstrvt16;
1177 lpst->thisptr = MapLS( lpst );
1178 *str = (void*)lpst->thisptr;
1182 /* --- IStream32 implementation */
1186 /* IUnknown fields */
1187 ICOM_VFIELD(IStream);
1189 /* IStream32 fields */
1190 struct storage_pps_entry stde;
1193 ULARGE_INTEGER offset;
1196 /*****************************************************************************
1197 * IStream32_QueryInterface [VTABLE]
1199 HRESULT WINAPI IStream_fnQueryInterface(
1200 IStream* iface,REFIID refiid,LPVOID *obj
1202 ICOM_THIS(IStream32Impl,iface);
1204 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1205 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1209 return OLE_E_ENUM_NOMORE;
1213 /******************************************************************************
1214 * IStream32_AddRef [VTABLE]
1216 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1217 ICOM_THIS(IStream32Impl,iface);
1218 return ++(This->ref);
1221 /******************************************************************************
1222 * IStream32_Release [VTABLE]
1224 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1225 ICOM_THIS(IStream32Impl,iface);
1226 FlushFileBuffers(This->hf);
1229 CloseHandle(This->hf);
1230 HeapFree( GetProcessHeap(), 0, This );
1236 /* --- IStorage16 implementation */
1240 /* IUnknown fields */
1241 ICOM_VFIELD(IStorage16);
1243 /* IStorage16 fields */
1244 SEGPTR thisptr; /* pointer to this struct as segmented */
1245 struct storage_pps_entry stde;
1250 /******************************************************************************
1251 * IStorage16_QueryInterface [STORAGE.500]
1253 HRESULT WINAPI IStorage16_fnQueryInterface(
1254 IStorage16* iface,REFIID refiid,LPVOID *obj
1256 ICOM_THIS(IStorage16Impl,iface);
1258 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1260 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1264 return OLE_E_ENUM_NOMORE;
1267 /******************************************************************************
1268 * IStorage16_AddRef [STORAGE.501]
1270 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1271 ICOM_THIS(IStorage16Impl,iface);
1272 return ++(This->ref);
1275 /******************************************************************************
1276 * IStorage16_Release [STORAGE.502]
1278 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1279 ICOM_THIS(IStorage16Impl,iface);
1283 UnMapLS( This->thisptr );
1284 HeapFree( GetProcessHeap(), 0, This );
1288 /******************************************************************************
1289 * IStorage16_Stat [STORAGE.517]
1291 HRESULT WINAPI IStorage16_fnStat(
1292 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1294 ICOM_THIS(IStorage16Impl,iface);
1295 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1296 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1298 TRACE("(%p)->(%p,0x%08lx)\n",
1299 This,pstatstg,grfStatFlag
1301 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1302 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1303 pstatstg->type = This->stde.pps_type;
1304 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1305 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1306 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1307 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1308 pstatstg->grfMode = 0; /* FIXME */
1309 pstatstg->grfLocksSupported = 0; /* FIXME */
1310 pstatstg->clsid = This->stde.pps_guid;
1311 pstatstg->grfStateBits = 0; /* FIXME */
1312 pstatstg->reserved = 0;
1316 /******************************************************************************
1317 * IStorage16_Commit [STORAGE.509]
1319 HRESULT WINAPI IStorage16_fnCommit(
1320 LPSTORAGE16 iface,DWORD commitflags
1322 ICOM_THIS(IStorage16Impl,iface);
1323 FIXME("(%p)->(0x%08lx),STUB!\n",
1329 /******************************************************************************
1330 * IStorage16_CopyTo [STORAGE.507]
1332 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1333 ICOM_THIS(IStorage16Impl,iface);
1334 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1335 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1341 /******************************************************************************
1342 * IStorage16_CreateStorage [STORAGE.505]
1344 HRESULT WINAPI IStorage16_fnCreateStorage(
1345 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1347 ICOM_THIS(IStorage16Impl,iface);
1348 IStorage16Impl* lpstg;
1350 struct storage_pps_entry stde;
1351 struct storage_header sth;
1356 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1357 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1359 if (grfMode & STGM_TRANSACTED)
1360 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1361 _create_istorage16(ppstg);
1362 lpstg = MapSL((SEGPTR)*ppstg);
1363 lpstg->hf = This->hf;
1365 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1369 if (stde.pps_dir==-1) {
1370 stde.pps_dir = ppsent;
1373 FIXME(" use prev chain too ?\n");
1375 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1377 while (stde.pps_next!=-1) {
1379 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1382 stde.pps_next = ppsent;
1384 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1385 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1386 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1387 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1388 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1389 lpstg->stde.pps_next = -1;
1390 lpstg->stde.pps_prev = -1;
1391 lpstg->stde.pps_dir = -1;
1392 lpstg->stde.pps_sb = -1;
1393 lpstg->stde.pps_size = 0;
1394 lpstg->stde.pps_type = 1;
1395 lpstg->ppsent = ppsent;
1396 /* FIXME: timestamps? */
1397 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1402 /******************************************************************************
1403 * IStorage16_CreateStream [STORAGE.503]
1405 HRESULT WINAPI IStorage16_fnCreateStream(
1406 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1408 ICOM_THIS(IStorage16Impl,iface);
1409 IStream16Impl* lpstr;
1411 struct storage_pps_entry stde;
1413 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1414 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1416 if (grfMode & STGM_TRANSACTED)
1417 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1418 _create_istream16(ppstm);
1419 lpstr = MapSL((SEGPTR)*ppstm);
1420 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1421 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1422 lpstr->offset.s.LowPart = 0;
1423 lpstr->offset.s.HighPart = 0;
1425 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1429 if (stde.pps_next==-1)
1432 while (stde.pps_next!=-1) {
1434 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1437 stde.pps_next = ppsent;
1438 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1439 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1440 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1441 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1442 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1443 lpstr->stde.pps_next = -1;
1444 lpstr->stde.pps_prev = -1;
1445 lpstr->stde.pps_dir = -1;
1446 lpstr->stde.pps_sb = -1;
1447 lpstr->stde.pps_size = 0;
1448 lpstr->stde.pps_type = 2;
1449 lpstr->ppsent = ppsent;
1450 /* FIXME: timestamps? */
1451 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1456 /******************************************************************************
1457 * IStorage16_OpenStorage [STORAGE.506]
1459 HRESULT WINAPI IStorage16_fnOpenStorage(
1460 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1462 ICOM_THIS(IStorage16Impl,iface);
1463 IStream16Impl* lpstg;
1467 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1468 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1470 if (grfMode & STGM_TRANSACTED)
1471 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1472 _create_istorage16(ppstg);
1473 lpstg = MapSL((SEGPTR)*ppstg);
1474 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1475 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1476 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1477 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1479 IStream16_fnRelease((IStream16*)lpstg);
1483 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1484 IStream16_fnRelease((IStream16*)lpstg);
1487 lpstg->ppsent = newpps;
1491 /******************************************************************************
1492 * IStorage16_OpenStream [STORAGE.504]
1494 HRESULT WINAPI IStorage16_fnOpenStream(
1495 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1497 ICOM_THIS(IStorage16Impl,iface);
1498 IStream16Impl* lpstr;
1502 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1503 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1505 if (grfMode & STGM_TRANSACTED)
1506 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1507 _create_istream16(ppstm);
1508 lpstr = MapSL((SEGPTR)*ppstm);
1509 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1510 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1511 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1512 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1514 IStream16_fnRelease((IStream16*)lpstr);
1518 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1519 IStream16_fnRelease((IStream16*)lpstr);
1522 lpstr->offset.s.LowPart = 0;
1523 lpstr->offset.s.HighPart = 0;
1524 lpstr->ppsent = newpps;
1528 /******************************************************************************
1529 * _create_istorage16 [INTERNAL]
1531 static void _create_istorage16(LPSTORAGE16 *stg) {
1532 IStorage16Impl* lpst;
1534 if (!stvt16.QueryInterface) {
1535 HMODULE16 wp = GetModuleHandle16("STORAGE");
1537 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1538 VTENT(QueryInterface)
1543 VTENT(CreateStorage)
1546 VTENT(MoveElementTo)
1550 VTENT(DestroyElement)
1551 VTENT(RenameElement)
1552 VTENT(SetElementTimes)
1557 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1559 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1560 VTENT(QueryInterface)
1565 VTENT(CreateStorage)
1569 /* not (yet) implemented ...
1570 VTENT(MoveElementTo)
1573 VTENT(DestroyElement)
1574 VTENT(RenameElement)
1575 VTENT(SetElementTimes)
1581 segstvt16 = &stvt16;
1584 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1585 ICOM_VTBL(lpst) = segstvt16;
1587 lpst->thisptr = MapLS(lpst);
1588 *stg = (void*)lpst->thisptr;
1591 /******************************************************************************
1592 * Storage API functions
1595 /******************************************************************************
1596 * StgCreateDocFileA [STORAGE.1]
1598 HRESULT WINAPI StgCreateDocFile16(
1599 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1603 IStorage16Impl* lpstg;
1604 struct storage_pps_entry stde;
1606 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1607 pwcsName,grfMode,reserved,ppstgOpen
1609 _create_istorage16(ppstgOpen);
1610 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1611 if (hf==INVALID_HANDLE_VALUE) {
1612 WARN("couldn't open file for storage:%ld\n",GetLastError());
1615 lpstg = MapSL((SEGPTR)*ppstgOpen);
1617 /* FIXME: check for existence before overwriting? */
1618 if (!STORAGE_init_storage(hf)) {
1623 while (!ret) { /* neither 1 nor <0 */
1624 ret=STORAGE_get_pps_entry(hf,i,&stde);
1625 if ((ret==1) && (stde.pps_type==5)) {
1633 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1640 /******************************************************************************
1641 * StgIsStorageFile [STORAGE.5]
1643 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1644 UNICODE_STRING strW;
1647 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1648 ret = StgIsStorageFile( strW.Buffer );
1649 RtlFreeUnicodeString( &strW );
1654 /******************************************************************************
1655 * StgOpenStorage [STORAGE.3]
1657 HRESULT WINAPI StgOpenStorage16(
1658 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1659 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1663 IStorage16Impl* lpstg;
1664 struct storage_pps_entry stde;
1666 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1667 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1669 _create_istorage16(ppstgOpen);
1670 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1671 if (hf==INVALID_HANDLE_VALUE) {
1672 WARN("Couldn't open file for storage\n");
1675 lpstg = MapSL((SEGPTR)*ppstgOpen);
1679 while (!ret) { /* neither 1 nor <0 */
1680 ret=STORAGE_get_pps_entry(hf,i,&stde);
1681 if ((ret==1) && (stde.pps_type==5)) {
1688 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */