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