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