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