Don't include windows.h internally.
[wine] / dlls / ole32 / storage.c
1 /* Compound Storage
2  *
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>)
6  *
7  * Copyright 1998 Marcus Meissner
8  */
9
10 #include <assert.h>
11 #include <time.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "ntddk.h"
17 #include "winerror.h"
18 #include "wine/winbase16.h"
19 #include "wingdi.h"
20 #include "wtypes.h"
21 #include "wine/obj_base.h"
22 #include "wine/obj_storage.h"
23 #include "heap.h"
24 #include "module.h"
25 #include "ldt.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(ole);
29 DECLARE_DEBUG_CHANNEL(relay);
30
31 struct storage_header {
32         BYTE    magic[8];       /* 00: magic */
33         BYTE    unknown1[36];   /* 08: unknown */
34         DWORD   num_of_bbd_blocks;/* 2C: length of big datablocks */
35         DWORD   root_startblock;/* 30: root storage first big block */
36         DWORD   unknown2[2];    /* 34: unknown */
37         DWORD   sbd_startblock; /* 3C: small block depot first big block */
38         DWORD   unknown3[3];    /* 40: unknown */
39         DWORD   bbd_list[109];  /* 4C: big data block list (up to end of sector)*/
40 };
41 struct storage_pps_entry {
42         WCHAR   pps_rawname[32];/* 00: \0 terminated widechar name */
43         WORD    pps_sizeofname; /* 40: namelength in bytes */
44         BYTE    pps_type;       /* 42: flags, 1 storage/dir, 2 stream, 5 root */
45         BYTE    pps_unknown0;   /* 43: unknown */
46         DWORD   pps_prev;       /* 44: previous pps */
47         DWORD   pps_next;       /* 48: next pps */
48         DWORD   pps_dir;        /* 4C: directory pps */
49         GUID    pps_guid;       /* 50: class ID */
50         DWORD   pps_unknown1;   /* 60: unknown */
51         FILETIME pps_ft1;       /* 64: filetime1 */
52         FILETIME pps_ft2;       /* 70: filetime2 */
53         DWORD   pps_sb;         /* 74: data startblock */
54         DWORD   pps_size;       /* 78: datalength. (<0x1000)?small:big blocks*/
55         DWORD   pps_unknown2;   /* 7C: unknown */
56 };
57
58 #define STORAGE_CHAINENTRY_FAT          0xfffffffd
59 #define STORAGE_CHAINENTRY_ENDOFCHAIN   0xfffffffe
60 #define STORAGE_CHAINENTRY_FREE         0xffffffff
61
62
63 static const BYTE STORAGE_magic[8]   ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
64 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
65 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
66
67 #define BIGSIZE         512
68 #define SMALLSIZE               64
69
70 #define SMALLBLOCKS_PER_BIGBLOCK        (BIGSIZE/SMALLSIZE)
71
72 #define READ_HEADER     assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
73 static ICOM_VTABLE(IStorage16) stvt16;
74 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
75 static ICOM_VTABLE(IStream16) strvt16;
76 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
77
78 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
79 static void _create_istorage16(LPSTORAGE16 *stg);
80 static void _create_istream16(LPSTREAM16 *str);
81
82 #define IMPLEMENTED 1
83
84
85 /******************************************************************************
86  *              STORAGE_get_big_block   [Internal]
87  *
88  * Reading OLE compound storage
89  */
90 static BOOL
91 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
92         assert(n>=-1);
93         if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
94                 WARN(" seek failed (%ld)\n",GetLastError());
95                 return FALSE;
96         }
97         assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
98         if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
99                 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
100                 assert(0);
101                 return FALSE;
102         }
103         return TRUE;
104 }
105
106 /******************************************************************************
107  * STORAGE_put_big_block [INTERNAL]
108  */
109 static BOOL
110 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
111         assert(n>=-1);
112         if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
113                 WARN(" seek failed (%ld)\n",GetLastError());
114                 return FALSE;
115         }
116         assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
117         if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
118                 WARN(" write failed (%ld)\n",GetLastError());
119                 return FALSE;
120         }
121         return TRUE;
122 }
123
124 /******************************************************************************
125  * STORAGE_get_next_big_blocknr [INTERNAL]
126  */
127 static int
128 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
129         INT     bbs[BIGSIZE/sizeof(INT)];
130         struct  storage_header  sth;
131
132         READ_HEADER;
133         
134         assert(blocknr>>7<sth.num_of_bbd_blocks);
135         if (sth.bbd_list[blocknr>>7]==0xffffffff)
136                 return -5;
137         if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
138                 return -5;
139         assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
140         return bbs[blocknr&0x7f];
141 }
142
143 /******************************************************************************
144  * STORAGE_get_nth_next_big_blocknr [INTERNAL]
145  */
146 static int
147 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
148         INT     bbs[BIGSIZE/sizeof(INT)];
149         int     lastblock = -1;
150         struct storage_header sth;
151
152         READ_HEADER;
153         
154         assert(blocknr>=0);
155         while (nr--) {
156                 assert((blocknr>>7)<sth.num_of_bbd_blocks);
157                 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
158
159                 /* simple caching... */
160                 if (lastblock!=sth.bbd_list[blocknr>>7]) {
161                         assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
162                         lastblock = sth.bbd_list[blocknr>>7];
163                 }
164                 blocknr = bbs[blocknr&0x7f];
165         }
166         return blocknr;
167 }
168
169 /******************************************************************************
170  *              STORAGE_get_root_pps_entry      [Internal]
171  */
172 static BOOL
173 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
174         int     blocknr,i;
175         BYTE    block[BIGSIZE];
176         struct storage_pps_entry        *stde=(struct storage_pps_entry*)block;
177         struct storage_header sth;
178
179         READ_HEADER;
180         blocknr = sth.root_startblock;
181         while (blocknr>=0) {
182                 assert(STORAGE_get_big_block(hf,blocknr,block));
183                 for (i=0;i<4;i++) {
184                         if (!stde[i].pps_sizeofname)
185                                 continue;
186                         if (stde[i].pps_type==5) {
187                                 *pstde=stde[i];
188                                 return TRUE;
189                         }
190                 }
191                 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
192         }
193         return FALSE;
194 }
195
196 /******************************************************************************
197  * STORAGE_get_small_block [INTERNAL]
198  */
199 static BOOL
200 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
201         BYTE                            block[BIGSIZE];
202         int                             bigblocknr;
203         struct storage_pps_entry        root;
204
205         assert(blocknr>=0);
206         assert(STORAGE_get_root_pps_entry(hf,&root));
207         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
208         assert(bigblocknr>=0);
209         assert(STORAGE_get_big_block(hf,bigblocknr,block));
210
211         memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
212         return TRUE;
213 }
214
215 /******************************************************************************
216  * STORAGE_put_small_block [INTERNAL]
217  */
218 static BOOL
219 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
220         BYTE                            block[BIGSIZE];
221         int                             bigblocknr;
222         struct storage_pps_entry        root;
223
224         assert(blocknr>=0);
225
226         assert(STORAGE_get_root_pps_entry(hf,&root));
227         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
228         assert(bigblocknr>=0);
229         assert(STORAGE_get_big_block(hf,bigblocknr,block));
230
231         memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
232         assert(STORAGE_put_big_block(hf,bigblocknr,block));
233         return TRUE;
234 }
235
236 /******************************************************************************
237  * STORAGE_get_next_small_blocknr [INTERNAL]
238  */
239 static int
240 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
241         BYTE                            block[BIGSIZE];
242         LPINT                           sbd = (LPINT)block;
243         int                             bigblocknr;
244         struct storage_header           sth;
245
246         READ_HEADER;
247         assert(blocknr>=0);
248         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
249         assert(bigblocknr>=0);
250         assert(STORAGE_get_big_block(hf,bigblocknr,block));
251         assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
252         return sbd[blocknr & (128-1)];
253 }
254
255 /******************************************************************************
256  * STORAGE_get_nth_next_small_blocknr [INTERNAL]
257  */
258 static int
259 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
260         int     lastblocknr;
261         BYTE    block[BIGSIZE];
262         LPINT   sbd = (LPINT)block;
263         struct storage_header sth;
264
265         READ_HEADER;
266         lastblocknr=-1;
267         assert(blocknr>=0);
268         while ((nr--) && (blocknr>=0)) {
269                 if (lastblocknr/128!=blocknr/128) {
270                         int     bigblocknr;
271                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
272                         assert(bigblocknr>=0);
273                         assert(STORAGE_get_big_block(hf,bigblocknr,block));
274                         lastblocknr = blocknr;
275                 }
276                 assert(lastblocknr>=0);
277                 lastblocknr=blocknr;
278                 blocknr=sbd[blocknr & (128-1)];
279                 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
280         }
281         return blocknr;
282 }
283
284 /******************************************************************************
285  * STORAGE_get_pps_entry [INTERNAL]
286  */
287 static int
288 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
289         int     blocknr;
290         BYTE    block[BIGSIZE];
291         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
292         struct storage_header sth;
293
294         READ_HEADER;
295         /* we have 4 pps entries per big block */
296         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
297         assert(blocknr>=0);
298         assert(STORAGE_get_big_block(hf,blocknr,block));
299
300         *pstde=*stde;
301         return 1;
302 }
303
304 /******************************************************************************
305  *              STORAGE_put_pps_entry   [Internal]
306  */
307 static int
308 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
309         int     blocknr;
310         BYTE    block[BIGSIZE];
311         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
312         struct storage_header sth;
313
314         READ_HEADER;
315
316         /* we have 4 pps entries per big block */
317         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
318         assert(blocknr>=0);
319         assert(STORAGE_get_big_block(hf,blocknr,block));
320         *stde=*pstde;
321         assert(STORAGE_put_big_block(hf,blocknr,block));
322         return 1;
323 }
324
325 /******************************************************************************
326  *              STORAGE_look_for_named_pps      [Internal]
327  */
328 static int
329 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
330         struct storage_pps_entry        stde;
331         int                             ret;
332
333         if (n==-1)
334                 return -1;
335         if (1!=STORAGE_get_pps_entry(hf,n,&stde))
336                 return -1;
337
338         if (!lstrcmpW(name,stde.pps_rawname))
339                 return n;
340         if (stde.pps_prev != -1) {
341                 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
342                 if (ret!=-1)
343                         return ret;
344         }
345         if (stde.pps_next != -1) {
346                 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
347                 if (ret!=-1)
348                         return ret;
349         }
350         return -1;
351 }
352
353 /******************************************************************************
354  *              STORAGE_dump_pps_entry  [Internal]
355  *
356  * FIXME
357  *    Function is unused
358  */
359 void
360 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
361     char        name[33];
362
363     WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
364         if (!stde->pps_sizeofname)
365                 return;
366         DPRINTF("name: %s\n",name);
367         DPRINTF("type: %d\n",stde->pps_type);
368         DPRINTF("prev pps: %ld\n",stde->pps_prev);
369         DPRINTF("next pps: %ld\n",stde->pps_next);
370         DPRINTF("dir pps: %ld\n",stde->pps_dir);
371         DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
372         if (stde->pps_type !=2) {
373                 time_t  t;
374                 DWORD dw;
375                 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
376                 t = dw;
377                 DPRINTF("ts1: %s\n",ctime(&t));
378                 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
379                 t = dw;
380                 DPRINTF("ts2: %s\n",ctime(&t));
381         }
382         DPRINTF("startblock: %ld\n",stde->pps_sb);
383         DPRINTF("size: %ld\n",stde->pps_size);
384 }
385
386 /******************************************************************************
387  * STORAGE_init_storage [INTERNAL]
388  */
389 static BOOL 
390 STORAGE_init_storage(HFILE hf) {
391         BYTE    block[BIGSIZE];
392         LPDWORD bbs;
393         struct storage_header *sth;
394         struct storage_pps_entry *stde;
395
396         assert(-1!=_llseek(hf,0,SEEK_SET));
397         /* block -1 is the storage header */
398         sth = (struct storage_header*)block;
399         memcpy(sth->magic,STORAGE_magic,8);
400         memset(sth->unknown1,0,sizeof(sth->unknown1));
401         memset(sth->unknown2,0,sizeof(sth->unknown2));
402         memset(sth->unknown3,0,sizeof(sth->unknown3));
403         sth->num_of_bbd_blocks  = 1;
404         sth->root_startblock    = 1;
405         sth->sbd_startblock     = 0xffffffff;
406         memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
407         sth->bbd_list[0]        = 0;
408         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
409         /* block 0 is the big block directory */
410         bbs=(LPDWORD)block;
411         memset(block,0xff,sizeof(block)); /* mark all blocks as free */
412         bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
413         bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
414         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
415         /* block 1 is the root directory entry */
416         memset(block,0x00,sizeof(block));
417         stde = (struct storage_pps_entry*)block;
418         MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
419                              sizeof(stde->pps_rawname)/sizeof(WCHAR));
420         stde->pps_sizeofname    = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
421         stde->pps_type          = 5;
422         stde->pps_dir           = -1;
423         stde->pps_next          = -1;
424         stde->pps_prev          = -1;
425         stde->pps_sb            = 0xffffffff;
426         stde->pps_size          = 0;
427         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
428         return TRUE;
429 }
430
431 /******************************************************************************
432  *              STORAGE_set_big_chain   [Internal]
433  */
434 static BOOL
435 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
436         BYTE    block[BIGSIZE];
437         LPINT   bbd = (LPINT)block;
438         int     nextblocknr,bigblocknr;
439         struct storage_header sth;
440
441         READ_HEADER;
442         assert(blocknr!=type);
443         while (blocknr>=0) {
444                 bigblocknr = sth.bbd_list[blocknr/128];
445                 assert(bigblocknr>=0);
446                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
447
448                 nextblocknr = bbd[blocknr&(128-1)];
449                 bbd[blocknr&(128-1)] = type;
450                 if (type>=0)
451                         return TRUE;
452                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
453                 type = STORAGE_CHAINENTRY_FREE;
454                 blocknr = nextblocknr;
455         }
456         return TRUE;
457 }
458
459 /******************************************************************************
460  * STORAGE_set_small_chain [Internal]
461  */
462 static BOOL
463 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
464         BYTE    block[BIGSIZE];
465         LPINT   sbd = (LPINT)block;
466         int     lastblocknr,nextsmallblocknr,bigblocknr;
467         struct storage_header sth;
468
469         READ_HEADER;
470
471         assert(blocknr!=type);
472         lastblocknr=-129;bigblocknr=-2;
473         while (blocknr>=0) {
474                 /* cache block ... */
475                 if (lastblocknr/128!=blocknr/128) {
476                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
477                         assert(bigblocknr>=0);
478                         assert(STORAGE_get_big_block(hf,bigblocknr,block));
479                 }
480                 lastblocknr = blocknr;
481                 nextsmallblocknr = sbd[blocknr&(128-1)];
482                 sbd[blocknr&(128-1)] = type;
483                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
484                 if (type>=0)
485                         return TRUE;
486                 type = STORAGE_CHAINENTRY_FREE;
487                 blocknr = nextsmallblocknr;
488         }
489         return TRUE;
490 }
491
492 /******************************************************************************
493  *              STORAGE_get_free_big_blocknr    [Internal]
494  */
495 static int 
496 STORAGE_get_free_big_blocknr(HFILE hf) {
497         BYTE    block[BIGSIZE];
498         LPINT   sbd = (LPINT)block;
499         int     lastbigblocknr,i,curblock,bigblocknr;
500         struct storage_header sth;
501
502         READ_HEADER;
503         curblock        = 0;
504         lastbigblocknr  = -1;
505         bigblocknr      = sth.bbd_list[curblock];
506         while (curblock<sth.num_of_bbd_blocks) {
507                 assert(bigblocknr>=0);
508                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
509                 for (i=0;i<128;i++)
510                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
511                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
512                                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
513                                 memset(block,0x42,sizeof(block));
514                                 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
515                                 return i+curblock*128;
516                         }
517                 lastbigblocknr = bigblocknr;
518                 bigblocknr = sth.bbd_list[++curblock];
519         }
520         bigblocknr = curblock*128;
521         /* since we have marked all blocks from 0 up to curblock*128-1 
522          * the next free one is curblock*128, where we happily put our 
523          * next large block depot.
524          */
525         memset(block,0xff,sizeof(block));
526         /* mark the block allocated and returned by this function */
527         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
528         assert(STORAGE_put_big_block(hf,bigblocknr,block));
529
530         /* if we had a bbd block already (mostlikely) we need
531          * to link the new one into the chain 
532          */
533         if (lastbigblocknr!=-1)
534                 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
535         sth.bbd_list[curblock]=bigblocknr;
536         sth.num_of_bbd_blocks++;
537         assert(sth.num_of_bbd_blocks==curblock+1);
538         assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
539
540         /* Set the end of the chain for the bigblockdepots */
541         assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
542         /* add 1, for the first entry is used for the additional big block 
543          * depot. (means we already used bigblocknr) */
544         memset(block,0x42,sizeof(block));
545         /* allocate this block (filled with 0x42) */
546         assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
547         return bigblocknr+1;
548 }
549
550
551 /******************************************************************************
552  *              STORAGE_get_free_small_blocknr  [Internal]
553  */
554 static int 
555 STORAGE_get_free_small_blocknr(HFILE hf) {
556         BYTE    block[BIGSIZE];
557         LPINT   sbd = (LPINT)block;
558         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
559         struct storage_pps_entry        root;
560         struct storage_header sth;
561
562         READ_HEADER;
563         bigblocknr      = sth.sbd_startblock;
564         curblock        = 0;
565         lastbigblocknr  = -1;
566         newblocknr      = -1;
567         while (bigblocknr>=0) {
568                 if (!STORAGE_get_big_block(hf,bigblocknr,block))
569                         return -1;
570                 for (i=0;i<128;i++)
571                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
572                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
573                                 newblocknr = i+curblock*128;
574                                 break;
575                         }
576                 if (i!=128)
577                         break;
578                 lastbigblocknr = bigblocknr;
579                 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
580                 curblock++;
581         }
582         if (newblocknr==-1) {
583                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
584                 if (bigblocknr<0)
585                         return -1;
586                 READ_HEADER;
587                 memset(block,0xff,sizeof(block));
588                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
589                 if (!STORAGE_put_big_block(hf,bigblocknr,block))
590                         return -1;
591                 if (lastbigblocknr==-1) {
592                         sth.sbd_startblock = bigblocknr;
593                         if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
594                                 return -1;
595                 } else {
596                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
597                                 return -1;
598                 }
599                 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
600                         return -1;
601                 newblocknr = curblock*128;
602         }
603         /* allocate enough big blocks for storing the allocated small block */
604         if (!STORAGE_get_root_pps_entry(hf,&root))
605                 return -1;
606         if (root.pps_sb==-1)
607                 lastbigblocknr  = -1;
608         else
609                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
610         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
611                 /* we need to allocate more stuff */
612                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
613                 if (bigblocknr<0)
614                         return -1;
615                 READ_HEADER;
616                 if (root.pps_sb==-1) {
617                         root.pps_sb      = bigblocknr;
618                         root.pps_size   += BIGSIZE;
619                 } else {
620                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
621                                 return -1;
622                         root.pps_size   += BIGSIZE;
623                 }
624                 lastbigblocknr = bigblocknr;
625         }
626         if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
627                 return -1;
628         if (!STORAGE_put_pps_entry(hf,0,&root))
629                 return -1;
630         return newblocknr;
631 }
632
633 /******************************************************************************
634  *              STORAGE_get_free_pps_entry      [Internal]
635  */
636 static int
637 STORAGE_get_free_pps_entry(HFILE hf) {
638         int     blocknr,i,curblock,lastblocknr;
639         BYTE    block[BIGSIZE];
640         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
641         struct storage_header sth;
642
643         READ_HEADER;
644         blocknr = sth.root_startblock;
645         assert(blocknr>=0);
646         curblock=0;
647         while (blocknr>=0) {
648                 if (!STORAGE_get_big_block(hf,blocknr,block))
649                         return -1;
650                 for (i=0;i<4;i++) 
651                         if (stde[i].pps_sizeofname==0) /* free */
652                                 return curblock*4+i;
653                 lastblocknr = blocknr;
654                 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
655                 curblock++;
656         }
657         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
658         blocknr = STORAGE_get_free_big_blocknr(hf);
659         /* sth invalidated */
660         if (blocknr<0)
661                 return -1;
662         
663         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
664                 return -1;
665         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
666                 return -1;
667         memset(block,0,sizeof(block));
668         STORAGE_put_big_block(hf,blocknr,block);
669         return curblock*4;
670 }
671
672 /* --- IStream16 implementation */
673
674 typedef struct
675 {
676         /* IUnknown fields */
677         ICOM_VFIELD(IStream16);
678         DWORD                           ref;
679         /* IStream16 fields */
680         SEGPTR                          thisptr; /* pointer to this struct as segmented */
681         struct storage_pps_entry        stde;
682         int                             ppsent;
683         HFILE                         hf;
684         ULARGE_INTEGER                  offset;
685 } IStream16Impl;
686
687 /******************************************************************************
688  *              IStream16_QueryInterface        [STORAGE.518]
689  */
690 HRESULT WINAPI IStream16_fnQueryInterface(
691         IStream16* iface,REFIID refiid,LPVOID *obj
692 ) {
693         ICOM_THIS(IStream16Impl,iface);
694         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
695         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
696                 *obj = This;
697                 return 0;
698         }
699         return OLE_E_ENUM_NOMORE;
700         
701 }
702
703 /******************************************************************************
704  * IStream16_AddRef [STORAGE.519]
705  */
706 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
707         ICOM_THIS(IStream16Impl,iface);
708         return ++(This->ref);
709 }
710
711 /******************************************************************************
712  * IStream16_Release [STORAGE.520]
713  */
714 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
715         ICOM_THIS(IStream16Impl,iface);
716         FlushFileBuffers(This->hf);
717         This->ref--;
718         if (!This->ref) {
719                 CloseHandle(This->hf);
720                 SEGPTR_FREE(This);
721                 return 0;
722         }
723         return This->ref;
724 }
725
726 /******************************************************************************
727  *              IStream16_Seek  [STORAGE.523]
728  *
729  * FIXME
730  *    Does not handle 64 bits
731  */
732 HRESULT WINAPI IStream16_fnSeek(
733         IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
734 ) {
735         ICOM_THIS(IStream16Impl,iface);
736         TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
737
738         switch (whence) {
739         /* unix SEEK_xx should be the same as win95 ones */
740         case SEEK_SET:
741                 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
742                  * right now.
743                  */
744                 assert(offset.s.HighPart==0);
745                 This->offset.s.HighPart = offset.s.HighPart;
746                 This->offset.s.LowPart = offset.s.LowPart;
747                 break;
748         case SEEK_CUR:
749                 if (offset.s.HighPart < 0) {
750                         /* FIXME: is this negation correct ? */
751                         offset.s.HighPart = -offset.s.HighPart;
752                         offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
753
754                         assert(offset.s.HighPart==0);
755                         assert(This->offset.s.LowPart >= offset.s.LowPart);
756                         This->offset.s.LowPart -= offset.s.LowPart;
757                 } else {
758                         assert(offset.s.HighPart==0);
759                         This->offset.s.LowPart+= offset.s.LowPart;
760                 }
761                 break;
762         case SEEK_END:
763                 assert(offset.s.HighPart==0);
764                 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
765                 break;
766         }
767         if (This->offset.s.LowPart>This->stde.pps_size)
768                 This->offset.s.LowPart=This->stde.pps_size;
769         if (newpos) *newpos = This->offset;
770         return S_OK;
771 }
772
773 /******************************************************************************
774  *              IStream16_Read  [STORAGE.521]
775  */
776 HRESULT WINAPI IStream16_fnRead(
777         IStream16* iface,void  *pv,ULONG cb,ULONG  *pcbRead
778 ) {
779         ICOM_THIS(IStream16Impl,iface);
780         BYTE    block[BIGSIZE];
781         ULONG   *bytesread=pcbRead,xxread;
782         int     blocknr;
783
784         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
785         if (!pcbRead) bytesread=&xxread;
786         *bytesread = 0;
787
788         if (cb>This->stde.pps_size-This->offset.s.LowPart)
789                 cb=This->stde.pps_size-This->offset.s.LowPart;
790         if (This->stde.pps_size < 0x1000) {
791                 /* use small block reader */
792                 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
793                 while (cb) {
794                         int     cc;
795
796                         if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
797                            WARN("small block read failed!!!\n");
798                                 return E_FAIL;
799                         }
800                         cc = cb; 
801                         if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
802                                 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
803                         memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
804                         This->offset.s.LowPart+=cc;
805                         (LPBYTE)pv+=cc;
806                         *bytesread+=cc;
807                         cb-=cc;
808                         blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
809                 }
810         } else {
811                 /* use big block reader */
812                 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
813                 while (cb) {
814                         int     cc;
815
816                         if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
817                                 WARN("big block read failed!!!\n");
818                                 return E_FAIL;
819                         }
820                         cc = cb; 
821                         if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
822                                 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
823                         memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
824                         This->offset.s.LowPart+=cc;
825                         (LPBYTE)pv+=cc;
826                         *bytesread+=cc;
827                         cb-=cc;
828                         blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
829                 }
830         }
831         return S_OK;
832 }
833
834 /******************************************************************************
835  *              IStream16_Write [STORAGE.522]
836  */
837 HRESULT WINAPI IStream16_fnWrite(
838         IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
839 ) {
840         ICOM_THIS(IStream16Impl,iface);
841         BYTE    block[BIGSIZE];
842         ULONG   *byteswritten=pcbWrite,xxwritten;
843         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
844         HFILE   hf = This->hf;
845
846         if (!pcbWrite) byteswritten=&xxwritten;
847         *byteswritten = 0;
848
849         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
850         /* do we need to junk some blocks? */
851         newsize = This->offset.s.LowPart+cb;
852         oldsize = This->stde.pps_size;
853         if (newsize < oldsize) {
854                 if (oldsize < 0x1000) {
855                         /* only small blocks */
856                         blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
857
858                         assert(blocknr>=0);
859
860                         /* will set the rest of the chain to 'free' */
861                         if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
862                                 return E_FAIL;
863                 } else {
864                         if (newsize >= 0x1000) {
865                                 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
866                                 assert(blocknr>=0);
867
868                                 /* will set the rest of the chain to 'free' */
869                                 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
870                                         return E_FAIL;
871                         } else {
872                                 /* Migrate large blocks to small blocks 
873                                  * (we just migrate newsize bytes)
874                                  */
875                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
876                                 cc      = newsize;
877                                 blocknr = This->stde.pps_sb;
878                                 curdata = data;
879                                 while (cc>0) {
880                                         if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
881                                                 HeapFree(GetProcessHeap(),0,data);
882                                                 return E_FAIL;
883                                         }
884                                         curdata += BIGSIZE;
885                                         cc      -= BIGSIZE;
886                                         blocknr  = STORAGE_get_next_big_blocknr(hf,blocknr);
887                                 }
888                                 /* frees complete chain for this stream */
889                                 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
890                                         return E_FAIL;
891                                 curdata = data;
892                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
893                                 if (blocknr<0)
894                                         return E_FAIL;
895                                 cc      = newsize;
896                                 while (cc>0) {
897                                         if (!STORAGE_put_small_block(hf,blocknr,curdata))
898                                                 return E_FAIL;
899                                         cc      -= SMALLSIZE;
900                                         if (cc<=0) {
901                                                 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
902                                                         return E_FAIL;
903                                                 break;
904                                         } else {
905                                                 int newblocknr = STORAGE_get_free_small_blocknr(hf);
906                                                 if (newblocknr<0)
907                                                         return E_FAIL;
908                                                 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
909                                                         return E_FAIL;
910                                                 blocknr = newblocknr;
911                                         }
912                                         curdata += SMALLSIZE;
913                                 }
914                                 HeapFree(GetProcessHeap(),0,data);
915                         }
916                 }
917                 This->stde.pps_size = newsize;
918         }
919
920         if (newsize > oldsize) {
921                 if (oldsize >= 0x1000) {
922                         /* should return the block right before the 'endofchain' */
923                         blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
924                         assert(blocknr>=0);
925                         lastblocknr     = blocknr;
926                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
927                                 blocknr = STORAGE_get_free_big_blocknr(hf);
928                                 if (blocknr<0)
929                                         return E_FAIL;
930                                 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
931                                         return E_FAIL;
932                                 lastblocknr = blocknr;
933                         }
934                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
935                                 return E_FAIL;
936                 } else {
937                         if (newsize < 0x1000) {
938                                 /* find startblock */
939                                 if (!oldsize)
940                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
941                                 else
942                                         blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
943                                 if (blocknr<0)
944                                         return E_FAIL;
945
946                                 /* allocate required new small blocks */
947                                 lastblocknr = blocknr;
948                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
949                                         blocknr = STORAGE_get_free_small_blocknr(hf);
950                                         if (blocknr<0)
951                                                 return E_FAIL;
952                                         if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
953                                                 return E_FAIL;
954                                         lastblocknr = blocknr;
955                                 }
956                                 /* and terminate the chain */
957                                 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
958                                         return E_FAIL;
959                         } else {
960                                 if (!oldsize) {
961                                         /* no single block allocated yet */
962                                         blocknr=STORAGE_get_free_big_blocknr(hf);
963                                         if (blocknr<0)
964                                                 return E_FAIL;
965                                         This->stde.pps_sb = blocknr;
966                                 } else {
967                                         /* Migrate small blocks to big blocks */
968                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
969                                         cc      = oldsize;
970                                         blocknr = This->stde.pps_sb;
971                                         curdata = data;
972                                         /* slurp in */
973                                         while (cc>0) {
974                                                 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
975                                                         HeapFree(GetProcessHeap(),0,data);
976                                                         return E_FAIL;
977                                                 }
978                                                 curdata += SMALLSIZE;
979                                                 cc      -= SMALLSIZE;
980                                                 blocknr  = STORAGE_get_next_small_blocknr(hf,blocknr);
981                                         }
982                                         /* free small block chain */
983                                         if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
984                                                 return E_FAIL;
985                                         curdata = data;
986                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
987                                         if (blocknr<0)
988                                                 return E_FAIL;
989                                         /* put the data into the big blocks */
990                                         cc      = This->stde.pps_size;
991                                         while (cc>0) {
992                                                 if (!STORAGE_put_big_block(hf,blocknr,curdata))
993                                                         return E_FAIL;
994                                                 cc      -= BIGSIZE;
995                                                 if (cc<=0) {
996                                                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
997                                                                 return E_FAIL;
998                                                         break;
999                                                 } else {
1000                                                         int newblocknr = STORAGE_get_free_big_blocknr(hf);
1001                                                         if (newblocknr<0)
1002                                                                 return E_FAIL;
1003                                                         if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1004                                                                 return E_FAIL;
1005                                                         blocknr = newblocknr;
1006                                                 }
1007                                                 curdata += BIGSIZE;
1008                                         }
1009                                         HeapFree(GetProcessHeap(),0,data);
1010                                 }
1011                                 /* generate big blocks to fit the new data */
1012                                 lastblocknr     = blocknr;
1013                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1014                                         blocknr = STORAGE_get_free_big_blocknr(hf);
1015                                         if (blocknr<0)
1016                                                 return E_FAIL;
1017                                         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1018                                                 return E_FAIL;
1019                                         lastblocknr = blocknr;
1020                                 }
1021                                 /* terminate chain */
1022                                 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1023                                         return E_FAIL;
1024                         }
1025                 }
1026                 This->stde.pps_size = newsize;
1027         }
1028
1029         /* There are just some cases where we didn't modify it, we write it out
1030          * everytime
1031          */
1032         if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1033                 return E_FAIL;
1034
1035         /* finally the write pass */
1036         if (This->stde.pps_size < 0x1000) {
1037                 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1038                 assert(blocknr>=0);
1039                 while (cb>0) {
1040                         /* we ensured that it is allocated above */
1041                         assert(blocknr>=0);
1042                         /* Read old block everytime, since we can have
1043                          * overlapping data at START and END of the write
1044                          */
1045                         if (!STORAGE_get_small_block(hf,blocknr,block))
1046                                 return E_FAIL;
1047
1048                         cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1049                         if (cc>cb)
1050                                 cc=cb;
1051                         memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1052                                 (LPBYTE)((char *) pv+curoffset),
1053                                 cc
1054                         );
1055                         if (!STORAGE_put_small_block(hf,blocknr,block))
1056                                 return E_FAIL;
1057                         cb                      -= cc;
1058                         curoffset               += cc;
1059                         (LPBYTE)pv              += cc;
1060                         This->offset.s.LowPart  += cc;
1061                         *byteswritten           += cc;
1062                         blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1063                 }
1064         } else {
1065                 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1066                 assert(blocknr>=0);
1067                 while (cb>0) {
1068                         /* we ensured that it is allocated above, so it better is */
1069                         assert(blocknr>=0);
1070                         /* read old block everytime, since we can have
1071                          * overlapping data at START and END of the write
1072                          */
1073                         if (!STORAGE_get_big_block(hf,blocknr,block))
1074                                 return E_FAIL;
1075
1076                         cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1077                         if (cc>cb)
1078                                 cc=cb;
1079                         memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1080                                 (LPBYTE)((char *) pv+curoffset),
1081                                 cc
1082                         );
1083                         if (!STORAGE_put_big_block(hf,blocknr,block))
1084                                 return E_FAIL;
1085                         cb                      -= cc;
1086                         curoffset               += cc;
1087                         (LPBYTE)pv              += cc;
1088                         This->offset.s.LowPart  += cc;
1089                         *byteswritten           += cc;
1090                         blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1091                 }
1092         }
1093         return S_OK;
1094 }
1095
1096 /******************************************************************************
1097  *              _create_istream16       [Internal]
1098  */
1099 static void _create_istream16(LPSTREAM16 *str) {
1100         IStream16Impl*  lpst;
1101
1102         if (!strvt16.fnQueryInterface) {
1103                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1104                 if (wp>=32) {
1105                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1106 #define VTENT(xfn)  strvt16.fn##xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1107                         VTENT(QueryInterface);
1108                         VTENT(AddRef);
1109                         VTENT(Release);
1110                         VTENT(Read);
1111                         VTENT(Write);
1112                         VTENT(Seek);
1113                         VTENT(SetSize);
1114                         VTENT(CopyTo);
1115                         VTENT(Commit);
1116                         VTENT(Revert);
1117                         VTENT(LockRegion);
1118                         VTENT(UnlockRegion);
1119                         VTENT(Stat);
1120                         VTENT(Clone);
1121 #undef VTENT
1122                         segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1123                         memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1124                         segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1125                 } else {
1126 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1127                         VTENT(QueryInterface);
1128                         VTENT(AddRef);
1129                         VTENT(Release);
1130                         VTENT(Read);
1131                         VTENT(Write);
1132                         VTENT(Seek);
1133         /*
1134                         VTENT(CopyTo);
1135                         VTENT(Commit);
1136                         VTENT(SetSize);
1137                         VTENT(Revert);
1138                         VTENT(LockRegion);
1139                         VTENT(UnlockRegion);
1140                         VTENT(Stat);
1141                         VTENT(Clone);
1142         */
1143 #undef VTENT
1144                         segstrvt16 = &strvt16;
1145                 }
1146         }
1147         lpst = SEGPTR_NEW(IStream16Impl);
1148         ICOM_VTBL(lpst) = segstrvt16;
1149         lpst->ref       = 1;
1150         lpst->thisptr   = SEGPTR_GET(lpst);
1151         *str = (void*)lpst->thisptr;
1152 }
1153
1154
1155 /* --- IStream32 implementation */
1156
1157 typedef struct
1158 {
1159         /* IUnknown fields */
1160         ICOM_VFIELD(IStream);
1161         DWORD                           ref;
1162         /* IStream32 fields */
1163         struct storage_pps_entry        stde;
1164         int                             ppsent;
1165         HFILE                         hf;
1166         ULARGE_INTEGER                  offset;
1167 } IStream32Impl;
1168
1169 /*****************************************************************************
1170  *              IStream32_QueryInterface        [VTABLE]
1171  */
1172 HRESULT WINAPI IStream_fnQueryInterface(
1173         IStream* iface,REFIID refiid,LPVOID *obj
1174 ) {
1175         ICOM_THIS(IStream32Impl,iface);
1176
1177         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1178         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1179                 *obj = This;
1180                 return 0;
1181         }
1182         return OLE_E_ENUM_NOMORE;
1183         
1184 }
1185
1186 /******************************************************************************
1187  * IStream32_AddRef [VTABLE]
1188  */
1189 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1190         ICOM_THIS(IStream32Impl,iface);
1191         return ++(This->ref);
1192 }
1193
1194 /******************************************************************************
1195  * IStream32_Release [VTABLE]
1196  */
1197 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1198         ICOM_THIS(IStream32Impl,iface);
1199         FlushFileBuffers(This->hf);
1200         This->ref--;
1201         if (!This->ref) {
1202                 CloseHandle(This->hf);
1203                 SEGPTR_FREE(This);
1204                 return 0;
1205         }
1206         return This->ref;
1207 }
1208
1209 /* --- IStorage16 implementation */
1210
1211 typedef struct
1212 {
1213         /* IUnknown fields */
1214         ICOM_VFIELD(IStorage16);
1215         DWORD                           ref;
1216         /* IStorage16 fields */
1217         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1218         struct storage_pps_entry        stde;
1219         int                             ppsent;
1220         HFILE                         hf;
1221 } IStorage16Impl;
1222
1223 /******************************************************************************
1224  *              IStorage16_QueryInterface       [STORAGE.500]
1225  */
1226 HRESULT WINAPI IStorage16_fnQueryInterface(
1227         IStorage16* iface,REFIID refiid,LPVOID *obj
1228 ) {
1229         ICOM_THIS(IStorage16Impl,iface);
1230
1231         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1232
1233         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1234                 *obj = This;
1235                 return 0;
1236         }
1237         return OLE_E_ENUM_NOMORE;
1238 }
1239
1240 /******************************************************************************
1241  * IStorage16_AddRef [STORAGE.501]
1242  */
1243 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1244         ICOM_THIS(IStorage16Impl,iface);
1245         return ++(This->ref);
1246 }
1247
1248 /******************************************************************************
1249  * IStorage16_Release [STORAGE.502]
1250  */
1251 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1252         ICOM_THIS(IStorage16Impl,iface);
1253         This->ref--;
1254         if (This->ref)
1255                 return This->ref;
1256         SEGPTR_FREE(This);
1257         return 0;
1258 }
1259
1260 /******************************************************************************
1261  * IStorage16_Stat [STORAGE.517]
1262  */
1263 HRESULT WINAPI IStorage16_fnStat(
1264         LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1265 ) {
1266         ICOM_THIS(IStorage16Impl,iface);
1267         TRACE("(%p)->(%p,0x%08lx)\n",
1268                 This,pstatstg,grfStatFlag
1269         );
1270         pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1271         pstatstg->type = This->stde.pps_type;
1272         pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1273         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1274         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1275         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1276         pstatstg->grfMode       = 0; /* FIXME */
1277         pstatstg->grfLocksSupported = 0; /* FIXME */
1278         pstatstg->clsid         = This->stde.pps_guid;
1279         pstatstg->grfStateBits  = 0; /* FIXME */
1280         pstatstg->reserved      = 0;
1281         return S_OK;
1282 }
1283
1284 /******************************************************************************
1285  *              IStorage16_Commit       [STORAGE.509]
1286  */
1287 HRESULT WINAPI IStorage16_fnCommit(
1288         LPSTORAGE16 iface,DWORD commitflags
1289 ) {
1290         ICOM_THIS(IStorage16Impl,iface);
1291         FIXME("(%p)->(0x%08lx),STUB!\n",
1292                 This,commitflags
1293         );
1294         return S_OK;
1295 }
1296
1297 /******************************************************************************
1298  * IStorage16_CopyTo [STORAGE.507]
1299  */
1300 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1301         ICOM_THIS(IStorage16Impl,iface);
1302         FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1303                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1304         );
1305         return S_OK;
1306 }
1307
1308
1309 /******************************************************************************
1310  * IStorage16_CreateStorage [STORAGE.505]
1311  */
1312 HRESULT WINAPI IStorage16_fnCreateStorage(
1313         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1314 ) {
1315         ICOM_THIS(IStorage16Impl,iface);
1316         IStorage16Impl* lpstg;
1317         int             ppsent,x;
1318         struct storage_pps_entry        stde;
1319         struct storage_header sth;
1320         HFILE           hf=This->hf;
1321
1322         READ_HEADER;
1323
1324         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1325                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1326         );
1327         if (grfMode & STGM_TRANSACTED)
1328                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1329         _create_istorage16(ppstg);
1330         lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1331         lpstg->hf               = This->hf;
1332
1333         ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1334         if (ppsent<0)
1335                 return E_FAIL;
1336         stde=This->stde;
1337         if (stde.pps_dir==-1) {
1338                 stde.pps_dir = ppsent;
1339                 x = This->ppsent;
1340         } else {
1341                 FIXME(" use prev chain too ?\n");
1342                 x=stde.pps_dir;
1343                 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1344                         return E_FAIL;
1345                 while (stde.pps_next!=-1) {
1346                         x=stde.pps_next;
1347                         if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1348                                 return E_FAIL;
1349                 }
1350                 stde.pps_next = ppsent;
1351         }
1352         assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1353         assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1354         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1355                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1356         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1357         lpstg->stde.pps_next    = -1;
1358         lpstg->stde.pps_prev    = -1;
1359         lpstg->stde.pps_dir     = -1;
1360         lpstg->stde.pps_sb      = -1;
1361         lpstg->stde.pps_size    =  0;
1362         lpstg->stde.pps_type    =  1;
1363         lpstg->ppsent           = ppsent;
1364         /* FIXME: timestamps? */
1365         if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1366                 return E_FAIL;
1367         return S_OK;
1368 }
1369
1370 /******************************************************************************
1371  *              IStorage16_CreateStream [STORAGE.503]
1372  */
1373 HRESULT WINAPI IStorage16_fnCreateStream(
1374         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1375 ) {
1376         ICOM_THIS(IStorage16Impl,iface);
1377         IStream16Impl*  lpstr;
1378         int             ppsent,x;
1379         struct storage_pps_entry        stde;
1380
1381         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1382                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1383         );
1384         if (grfMode & STGM_TRANSACTED)
1385                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1386         _create_istream16(ppstm);
1387         lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1388         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1389                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1390         lpstr->offset.s.LowPart = 0;
1391         lpstr->offset.s.HighPart        = 0;
1392
1393         ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1394         if (ppsent<0)
1395                 return E_FAIL;
1396         stde=This->stde;
1397         if (stde.pps_next==-1)
1398                 x=This->ppsent;
1399         else
1400                 while (stde.pps_next!=-1) {
1401                         x=stde.pps_next;
1402                         if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1403                                 return E_FAIL;
1404                 }
1405         stde.pps_next = ppsent;
1406         assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1407         assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1408         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1409                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1410         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1411         lpstr->stde.pps_next    = -1;
1412         lpstr->stde.pps_prev    = -1;
1413         lpstr->stde.pps_dir     = -1;
1414         lpstr->stde.pps_sb      = -1;
1415         lpstr->stde.pps_size    =  0;
1416         lpstr->stde.pps_type    =  2;
1417         lpstr->ppsent           = ppsent;
1418         /* FIXME: timestamps? */
1419         if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1420                 return E_FAIL;
1421         return S_OK;
1422 }
1423
1424 /******************************************************************************
1425  *              IStorage16_OpenStorage  [STORAGE.506]
1426  */
1427 HRESULT WINAPI IStorage16_fnOpenStorage(
1428         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1429 ) {
1430         ICOM_THIS(IStorage16Impl,iface);
1431         IStream16Impl*  lpstg;
1432         WCHAR           name[33];
1433         int             newpps;
1434
1435         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1436                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1437         );
1438         if (grfMode & STGM_TRANSACTED)
1439                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1440         _create_istorage16(ppstg);
1441         lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1442         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1443                          &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1444         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1445         newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1446         if (newpps==-1) {
1447                 IStream16_fnRelease((IStream16*)lpstg);
1448                 return E_FAIL;
1449         }
1450
1451         if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1452                 IStream16_fnRelease((IStream16*)lpstg);
1453                 return E_FAIL;
1454         }
1455         lpstg->ppsent           = newpps;
1456         return S_OK;
1457 }
1458
1459 /******************************************************************************
1460  * IStorage16_OpenStream [STORAGE.504]
1461  */
1462 HRESULT WINAPI IStorage16_fnOpenStream(
1463         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1464 ) {
1465         ICOM_THIS(IStorage16Impl,iface);
1466         IStream16Impl*  lpstr;
1467         WCHAR           name[33];
1468         int             newpps;
1469
1470         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1471                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1472         );
1473         if (grfMode & STGM_TRANSACTED)
1474                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1475         _create_istream16(ppstm);
1476         lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1477         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1478                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1479         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1480         newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1481         if (newpps==-1) {
1482                 IStream16_fnRelease((IStream16*)lpstr);
1483                 return E_FAIL;
1484         }
1485
1486         if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1487                 IStream16_fnRelease((IStream16*)lpstr);
1488                 return E_FAIL;
1489         }
1490         lpstr->offset.s.LowPart = 0;
1491         lpstr->offset.s.HighPart        = 0;
1492         lpstr->ppsent           = newpps;
1493         return S_OK;
1494 }
1495
1496 /******************************************************************************
1497  * _create_istorage16 [INTERNAL]
1498  */
1499 static void _create_istorage16(LPSTORAGE16 *stg) {
1500         IStorage16Impl* lpst;
1501
1502         if (!stvt16.fnQueryInterface) {
1503                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1504                 if (wp>=32) {
1505 #define VTENT(xfn)  stvt16.fn##xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1506                         VTENT(QueryInterface)
1507                         VTENT(AddRef)
1508                         VTENT(Release)
1509                         VTENT(CreateStream)
1510                         VTENT(OpenStream)
1511                         VTENT(CreateStorage)
1512                         VTENT(OpenStorage)
1513                         VTENT(CopyTo)
1514                         VTENT(MoveElementTo)
1515                         VTENT(Commit)
1516                         VTENT(Revert)
1517                         VTENT(EnumElements)
1518                         VTENT(DestroyElement)
1519                         VTENT(RenameElement)
1520                         VTENT(SetElementTimes)
1521                         VTENT(SetClass)
1522                         VTENT(SetStateBits)
1523                         VTENT(Stat)
1524 #undef VTENT
1525                         segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1526                         memcpy(segstvt16,&stvt16,sizeof(stvt16));
1527                         segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1528                 } else {
1529 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1530                         VTENT(QueryInterface)
1531                         VTENT(AddRef)
1532                         VTENT(Release)
1533                         VTENT(CreateStream)
1534                         VTENT(OpenStream)
1535                         VTENT(CreateStorage)
1536                         VTENT(OpenStorage)
1537                         VTENT(CopyTo)
1538                         VTENT(Commit)
1539         /*  not (yet) implemented ...
1540                         VTENT(MoveElementTo)
1541                         VTENT(Revert)
1542                         VTENT(EnumElements)
1543                         VTENT(DestroyElement)
1544                         VTENT(RenameElement)
1545                         VTENT(SetElementTimes)
1546                         VTENT(SetClass)
1547                         VTENT(SetStateBits)
1548                         VTENT(Stat)
1549         */
1550 #undef VTENT
1551                         segstvt16 = &stvt16;
1552                 }
1553         }
1554         lpst = SEGPTR_NEW(IStorage16Impl);
1555         ICOM_VTBL(lpst) = segstvt16;
1556         lpst->ref       = 1;
1557         lpst->thisptr   = SEGPTR_GET(lpst);
1558         *stg = (void*)lpst->thisptr;
1559 }
1560
1561 /******************************************************************************
1562  *      Storage API functions
1563  */
1564
1565 /******************************************************************************
1566  *              StgCreateDocFile16      [STORAGE.1]
1567  */
1568 HRESULT WINAPI StgCreateDocFile16(
1569         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1570 ) {
1571         HFILE           hf;
1572         int             i,ret;
1573         IStorage16Impl* lpstg;
1574         struct storage_pps_entry        stde;
1575
1576         TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1577                 pwcsName,grfMode,reserved,ppstgOpen
1578         );
1579         _create_istorage16(ppstgOpen);
1580         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1581         if (hf==INVALID_HANDLE_VALUE) {
1582                 WARN("couldn't open file for storage:%ld\n",GetLastError());
1583                 return E_FAIL;
1584         }
1585         lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1586         lpstg->hf = hf;
1587         /* FIXME: check for existance before overwriting? */
1588         if (!STORAGE_init_storage(hf)) {
1589                 CloseHandle(hf);
1590                 return E_FAIL;
1591         }
1592         i=0;ret=0;
1593         while (!ret) { /* neither 1 nor <0 */
1594                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1595                 if ((ret==1) && (stde.pps_type==5)) {
1596                         lpstg->stde     = stde;
1597                         lpstg->ppsent   = i;
1598                         break;
1599                 }
1600                 i++;
1601         }
1602         if (ret!=1) {
1603                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1604                 return E_FAIL;
1605         }
1606
1607         return S_OK;
1608 }
1609
1610 /******************************************************************************
1611  * StgIsStorageFile16 [STORAGE.5]
1612  */
1613 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1614         HFILE           hf;
1615         OFSTRUCT        ofs;
1616         BYTE            magic[24];
1617
1618         TRACE("(\'%s\')\n",fn);
1619         hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1620         if (hf==HFILE_ERROR)
1621                 return STG_E_FILENOTFOUND;
1622         if (24!=_lread(hf,magic,24)) {
1623                 WARN(" too short\n");
1624                 _lclose(hf);
1625                 return S_FALSE;
1626         }
1627         if (!memcmp(magic,STORAGE_magic,8)) {
1628                 WARN(" -> YES\n");
1629                 _lclose(hf);
1630                 return S_OK;
1631         }
1632         if (!memcmp(magic,STORAGE_notmagic,8)) {
1633                 WARN(" -> NO\n");
1634                 _lclose(hf);
1635                 return S_FALSE;
1636         }
1637         if (!memcmp(magic,STORAGE_oldmagic,8)) {
1638                 WARN(" -> old format\n");
1639                 _lclose(hf);
1640                 return STG_E_OLDFORMAT;
1641         }
1642         WARN(" -> Invalid header.\n");
1643         _lclose(hf);
1644         return STG_E_INVALIDHEADER;
1645 }
1646
1647 /******************************************************************************
1648  * StgIsStorageFile [OLE32.146]
1649  */
1650 HRESULT WINAPI 
1651 StgIsStorageFile(LPCOLESTR fn) 
1652 {
1653         LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1654         HRESULT ret = StgIsStorageFile16(xfn);
1655
1656         HeapFree(GetProcessHeap(),0,xfn);
1657         return ret;
1658 }
1659
1660
1661 /******************************************************************************
1662  * StgOpenStorage16 [STORAGE.3]
1663  */
1664 HRESULT WINAPI StgOpenStorage16(
1665         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1666         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1667 ) {
1668         HFILE           hf;
1669         int             ret,i;
1670         IStorage16Impl* lpstg;
1671         struct storage_pps_entry        stde;
1672
1673         TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1674               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1675         );
1676         _create_istorage16(ppstgOpen);
1677         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1678         if (hf==INVALID_HANDLE_VALUE) {
1679                 WARN("Couldn't open file for storage\n");
1680                 return E_FAIL;
1681         }
1682         lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1683         lpstg->hf = hf;
1684
1685         i=0;ret=0;
1686         while (!ret) { /* neither 1 nor <0 */
1687                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1688                 if ((ret==1) && (stde.pps_type==5)) {
1689                         lpstg->stde=stde;
1690                         break;
1691                 }
1692                 i++;
1693         }
1694         if (ret!=1) {
1695                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1696                 return E_FAIL;
1697         }
1698         return S_OK;
1699         
1700 }
1701
1702