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