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