Fixed acmFormatChoose returned fields.
[wine] / dlls / ole32 / storage.c
1 /* Compound Storage
2  *
3  * Implemented using the documentation of the LAOLA project at
4  * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5  * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
6  *
7  * Copyright 1998 Marcus Meissner
8  */
9
10 #include <assert.h>
11 #include <time.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "ntddk.h"
17 #include "winerror.h"
18 #include "wine/winbase16.h"
19 #include "wingdi.h"
20 #include "wtypes.h"
21 #include "wine/obj_base.h"
22 #include "wine/obj_storage.h"
23 #include "heap.h"
24 #include "debugtools.h"
25
26 DEFAULT_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(" 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("(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(" 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(" 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];
360
361     WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
362         if (!stde->pps_sizeofname)
363                 return;
364         DPRINTF("name: %s\n",name);
365         DPRINTF("type: %d\n",stde->pps_type);
366         DPRINTF("prev pps: %ld\n",stde->pps_prev);
367         DPRINTF("next pps: %ld\n",stde->pps_next);
368         DPRINTF("dir pps: %ld\n",stde->pps_dir);
369         DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
370         if (stde->pps_type !=2) {
371                 time_t  t;
372                 DWORD dw;
373                 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
374                 t = dw;
375                 DPRINTF("ts1: %s\n",ctime(&t));
376                 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
377                 t = dw;
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         MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
417                              sizeof(stde->pps_rawname)/sizeof(WCHAR));
418         stde->pps_sizeofname    = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
419         stde->pps_type          = 5;
420         stde->pps_dir           = -1;
421         stde->pps_next          = -1;
422         stde->pps_prev          = -1;
423         stde->pps_sb            = 0xffffffff;
424         stde->pps_size          = 0;
425         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
426         return TRUE;
427 }
428
429 /******************************************************************************
430  *              STORAGE_set_big_chain   [Internal]
431  */
432 static BOOL
433 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
434         BYTE    block[BIGSIZE];
435         LPINT   bbd = (LPINT)block;
436         int     nextblocknr,bigblocknr;
437         struct storage_header sth;
438
439         READ_HEADER;
440         assert(blocknr!=type);
441         while (blocknr>=0) {
442                 bigblocknr = sth.bbd_list[blocknr/128];
443                 assert(bigblocknr>=0);
444                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
445
446                 nextblocknr = bbd[blocknr&(128-1)];
447                 bbd[blocknr&(128-1)] = type;
448                 if (type>=0)
449                         return TRUE;
450                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
451                 type = STORAGE_CHAINENTRY_FREE;
452                 blocknr = nextblocknr;
453         }
454         return TRUE;
455 }
456
457 /******************************************************************************
458  * STORAGE_set_small_chain [Internal]
459  */
460 static BOOL
461 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
462         BYTE    block[BIGSIZE];
463         LPINT   sbd = (LPINT)block;
464         int     lastblocknr,nextsmallblocknr,bigblocknr;
465         struct storage_header sth;
466
467         READ_HEADER;
468
469         assert(blocknr!=type);
470         lastblocknr=-129;bigblocknr=-2;
471         while (blocknr>=0) {
472                 /* cache block ... */
473                 if (lastblocknr/128!=blocknr/128) {
474                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
475                         assert(bigblocknr>=0);
476                         assert(STORAGE_get_big_block(hf,bigblocknr,block));
477                 }
478                 lastblocknr = blocknr;
479                 nextsmallblocknr = sbd[blocknr&(128-1)];
480                 sbd[blocknr&(128-1)] = type;
481                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
482                 if (type>=0)
483                         return TRUE;
484                 type = STORAGE_CHAINENTRY_FREE;
485                 blocknr = nextsmallblocknr;
486         }
487         return TRUE;
488 }
489
490 /******************************************************************************
491  *              STORAGE_get_free_big_blocknr    [Internal]
492  */
493 static int 
494 STORAGE_get_free_big_blocknr(HFILE hf) {
495         BYTE    block[BIGSIZE];
496         LPINT   sbd = (LPINT)block;
497         int     lastbigblocknr,i,curblock,bigblocknr;
498         struct storage_header sth;
499
500         READ_HEADER;
501         curblock        = 0;
502         lastbigblocknr  = -1;
503         bigblocknr      = sth.bbd_list[curblock];
504         while (curblock<sth.num_of_bbd_blocks) {
505                 assert(bigblocknr>=0);
506                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
507                 for (i=0;i<128;i++)
508                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
509                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
510                                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
511                                 memset(block,0x42,sizeof(block));
512                                 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
513                                 return i+curblock*128;
514                         }
515                 lastbigblocknr = bigblocknr;
516                 bigblocknr = sth.bbd_list[++curblock];
517         }
518         bigblocknr = curblock*128;
519         /* since we have marked all blocks from 0 up to curblock*128-1 
520          * the next free one is curblock*128, where we happily put our 
521          * next large block depot.
522          */
523         memset(block,0xff,sizeof(block));
524         /* mark the block allocated and returned by this function */
525         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
526         assert(STORAGE_put_big_block(hf,bigblocknr,block));
527
528         /* if we had a bbd block already (mostlikely) we need
529          * to link the new one into the chain 
530          */
531         if (lastbigblocknr!=-1)
532                 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
533         sth.bbd_list[curblock]=bigblocknr;
534         sth.num_of_bbd_blocks++;
535         assert(sth.num_of_bbd_blocks==curblock+1);
536         assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
537
538         /* Set the end of the chain for the bigblockdepots */
539         assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
540         /* add 1, for the first entry is used for the additional big block 
541          * depot. (means we already used bigblocknr) */
542         memset(block,0x42,sizeof(block));
543         /* allocate this block (filled with 0x42) */
544         assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
545         return bigblocknr+1;
546 }
547
548
549 /******************************************************************************
550  *              STORAGE_get_free_small_blocknr  [Internal]
551  */
552 static int 
553 STORAGE_get_free_small_blocknr(HFILE hf) {
554         BYTE    block[BIGSIZE];
555         LPINT   sbd = (LPINT)block;
556         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
557         struct storage_pps_entry        root;
558         struct storage_header sth;
559
560         READ_HEADER;
561         bigblocknr      = sth.sbd_startblock;
562         curblock        = 0;
563         lastbigblocknr  = -1;
564         newblocknr      = -1;
565         while (bigblocknr>=0) {
566                 if (!STORAGE_get_big_block(hf,bigblocknr,block))
567                         return -1;
568                 for (i=0;i<128;i++)
569                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
570                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
571                                 newblocknr = i+curblock*128;
572                                 break;
573                         }
574                 if (i!=128)
575                         break;
576                 lastbigblocknr = bigblocknr;
577                 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
578                 curblock++;
579         }
580         if (newblocknr==-1) {
581                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
582                 if (bigblocknr<0)
583                         return -1;
584                 READ_HEADER;
585                 memset(block,0xff,sizeof(block));
586                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
587                 if (!STORAGE_put_big_block(hf,bigblocknr,block))
588                         return -1;
589                 if (lastbigblocknr==-1) {
590                         sth.sbd_startblock = bigblocknr;
591                         if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
592                                 return -1;
593                 } else {
594                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
595                                 return -1;
596                 }
597                 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
598                         return -1;
599                 newblocknr = curblock*128;
600         }
601         /* allocate enough big blocks for storing the allocated small block */
602         if (!STORAGE_get_root_pps_entry(hf,&root))
603                 return -1;
604         if (root.pps_sb==-1)
605                 lastbigblocknr  = -1;
606         else
607                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
608         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
609                 /* we need to allocate more stuff */
610                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
611                 if (bigblocknr<0)
612                         return -1;
613                 READ_HEADER;
614                 if (root.pps_sb==-1) {
615                         root.pps_sb      = bigblocknr;
616                         root.pps_size   += BIGSIZE;
617                 } else {
618                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
619                                 return -1;
620                         root.pps_size   += BIGSIZE;
621                 }
622                 lastbigblocknr = bigblocknr;
623         }
624         if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
625                 return -1;
626         if (!STORAGE_put_pps_entry(hf,0,&root))
627                 return -1;
628         return newblocknr;
629 }
630
631 /******************************************************************************
632  *              STORAGE_get_free_pps_entry      [Internal]
633  */
634 static int
635 STORAGE_get_free_pps_entry(HFILE hf) {
636         int     blocknr,i,curblock,lastblocknr;
637         BYTE    block[BIGSIZE];
638         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
639         struct storage_header sth;
640
641         READ_HEADER;
642         blocknr = sth.root_startblock;
643         assert(blocknr>=0);
644         curblock=0;
645         while (blocknr>=0) {
646                 if (!STORAGE_get_big_block(hf,blocknr,block))
647                         return -1;
648                 for (i=0;i<4;i++) 
649                         if (stde[i].pps_sizeofname==0) /* free */
650                                 return curblock*4+i;
651                 lastblocknr = blocknr;
652                 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
653                 curblock++;
654         }
655         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
656         blocknr = STORAGE_get_free_big_blocknr(hf);
657         /* sth invalidated */
658         if (blocknr<0)
659                 return -1;
660         
661         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
662                 return -1;
663         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
664                 return -1;
665         memset(block,0,sizeof(block));
666         STORAGE_put_big_block(hf,blocknr,block);
667         return curblock*4;
668 }
669
670 /* --- IStream16 implementation */
671
672 typedef struct
673 {
674         /* IUnknown fields */
675         ICOM_VFIELD(IStream16);
676         DWORD                           ref;
677         /* IStream16 fields */
678         SEGPTR                          thisptr; /* pointer to this struct as segmented */
679         struct storage_pps_entry        stde;
680         int                             ppsent;
681         HFILE                         hf;
682         ULARGE_INTEGER                  offset;
683 } IStream16Impl;
684
685 /******************************************************************************
686  *              IStream16_QueryInterface        [STORAGE.518]
687  */
688 HRESULT WINAPI IStream16_fnQueryInterface(
689         IStream16* iface,REFIID refiid,LPVOID *obj
690 ) {
691         ICOM_THIS(IStream16Impl,iface);
692         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
693         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
694                 *obj = This;
695                 return 0;
696         }
697         return OLE_E_ENUM_NOMORE;
698         
699 }
700
701 /******************************************************************************
702  * IStream16_AddRef [STORAGE.519]
703  */
704 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
705         ICOM_THIS(IStream16Impl,iface);
706         return ++(This->ref);
707 }
708
709 /******************************************************************************
710  * IStream16_Release [STORAGE.520]
711  */
712 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
713         ICOM_THIS(IStream16Impl,iface);
714         FlushFileBuffers(This->hf);
715         This->ref--;
716         if (!This->ref) {
717                 CloseHandle(This->hf);
718                 SEGPTR_FREE(This);
719                 return 0;
720         }
721         return This->ref;
722 }
723
724 /******************************************************************************
725  *              IStream16_Seek  [STORAGE.523]
726  *
727  * FIXME
728  *    Does not handle 64 bits
729  */
730 HRESULT WINAPI IStream16_fnSeek(
731         IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
732 ) {
733         ICOM_THIS(IStream16Impl,iface);
734         TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
735
736         switch (whence) {
737         /* unix SEEK_xx should be the same as win95 ones */
738         case SEEK_SET:
739                 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
740                  * right now.
741                  */
742                 assert(offset.s.HighPart==0);
743                 This->offset.s.HighPart = offset.s.HighPart;
744                 This->offset.s.LowPart = offset.s.LowPart;
745                 break;
746         case SEEK_CUR:
747                 if (offset.s.HighPart < 0) {
748                         /* FIXME: is this negation correct ? */
749                         offset.s.HighPart = -offset.s.HighPart;
750                         offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
751
752                         assert(offset.s.HighPart==0);
753                         assert(This->offset.s.LowPart >= offset.s.LowPart);
754                         This->offset.s.LowPart -= offset.s.LowPart;
755                 } else {
756                         assert(offset.s.HighPart==0);
757                         This->offset.s.LowPart+= offset.s.LowPart;
758                 }
759                 break;
760         case SEEK_END:
761                 assert(offset.s.HighPart==0);
762                 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
763                 break;
764         }
765         if (This->offset.s.LowPart>This->stde.pps_size)
766                 This->offset.s.LowPart=This->stde.pps_size;
767         if (newpos) *newpos = This->offset;
768         return S_OK;
769 }
770
771 /******************************************************************************
772  *              IStream16_Read  [STORAGE.521]
773  */
774 HRESULT WINAPI IStream16_fnRead(
775         IStream16* iface,void  *pv,ULONG cb,ULONG  *pcbRead
776 ) {
777         ICOM_THIS(IStream16Impl,iface);
778         BYTE    block[BIGSIZE];
779         ULONG   *bytesread=pcbRead,xxread;
780         int     blocknr;
781
782         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
783         if (!pcbRead) bytesread=&xxread;
784         *bytesread = 0;
785
786         if (cb>This->stde.pps_size-This->offset.s.LowPart)
787                 cb=This->stde.pps_size-This->offset.s.LowPart;
788         if (This->stde.pps_size < 0x1000) {
789                 /* use small block reader */
790                 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
791                 while (cb) {
792                         int     cc;
793
794                         if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
795                            WARN("small block read failed!!!\n");
796                                 return E_FAIL;
797                         }
798                         cc = cb; 
799                         if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
800                                 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
801                         memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
802                         This->offset.s.LowPart+=cc;
803                         (LPBYTE)pv+=cc;
804                         *bytesread+=cc;
805                         cb-=cc;
806                         blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
807                 }
808         } else {
809                 /* use big block reader */
810                 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
811                 while (cb) {
812                         int     cc;
813
814                         if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
815                                 WARN("big block read failed!!!\n");
816                                 return E_FAIL;
817                         }
818                         cc = cb; 
819                         if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
820                                 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
821                         memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
822                         This->offset.s.LowPart+=cc;
823                         (LPBYTE)pv+=cc;
824                         *bytesread+=cc;
825                         cb-=cc;
826                         blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
827                 }
828         }
829         return S_OK;
830 }
831
832 /******************************************************************************
833  *              IStream16_Write [STORAGE.522]
834  */
835 HRESULT WINAPI IStream16_fnWrite(
836         IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
837 ) {
838         ICOM_THIS(IStream16Impl,iface);
839         BYTE    block[BIGSIZE];
840         ULONG   *byteswritten=pcbWrite,xxwritten;
841         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
842         HFILE   hf = This->hf;
843
844         if (!pcbWrite) byteswritten=&xxwritten;
845         *byteswritten = 0;
846
847         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
848         /* do we need to junk some blocks? */
849         newsize = This->offset.s.LowPart+cb;
850         oldsize = This->stde.pps_size;
851         if (newsize < oldsize) {
852                 if (oldsize < 0x1000) {
853                         /* only small blocks */
854                         blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
855
856                         assert(blocknr>=0);
857
858                         /* will set the rest of the chain to 'free' */
859                         if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
860                                 return E_FAIL;
861                 } else {
862                         if (newsize >= 0x1000) {
863                                 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
864                                 assert(blocknr>=0);
865
866                                 /* will set the rest of the chain to 'free' */
867                                 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
868                                         return E_FAIL;
869                         } else {
870                                 /* Migrate large blocks to small blocks 
871                                  * (we just migrate newsize bytes)
872                                  */
873                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
874                                 cc      = newsize;
875                                 blocknr = This->stde.pps_sb;
876                                 curdata = data;
877                                 while (cc>0) {
878                                         if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
879                                                 HeapFree(GetProcessHeap(),0,data);
880                                                 return E_FAIL;
881                                         }
882                                         curdata += BIGSIZE;
883                                         cc      -= BIGSIZE;
884                                         blocknr  = STORAGE_get_next_big_blocknr(hf,blocknr);
885                                 }
886                                 /* frees complete chain for this stream */
887                                 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
888                                         return E_FAIL;
889                                 curdata = data;
890                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
891                                 if (blocknr<0)
892                                         return E_FAIL;
893                                 cc      = newsize;
894                                 while (cc>0) {
895                                         if (!STORAGE_put_small_block(hf,blocknr,curdata))
896                                                 return E_FAIL;
897                                         cc      -= SMALLSIZE;
898                                         if (cc<=0) {
899                                                 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
900                                                         return E_FAIL;
901                                                 break;
902                                         } else {
903                                                 int newblocknr = STORAGE_get_free_small_blocknr(hf);
904                                                 if (newblocknr<0)
905                                                         return E_FAIL;
906                                                 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
907                                                         return E_FAIL;
908                                                 blocknr = newblocknr;
909                                         }
910                                         curdata += SMALLSIZE;
911                                 }
912                                 HeapFree(GetProcessHeap(),0,data);
913                         }
914                 }
915                 This->stde.pps_size = newsize;
916         }
917
918         if (newsize > oldsize) {
919                 if (oldsize >= 0x1000) {
920                         /* should return the block right before the 'endofchain' */
921                         blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
922                         assert(blocknr>=0);
923                         lastblocknr     = blocknr;
924                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
925                                 blocknr = STORAGE_get_free_big_blocknr(hf);
926                                 if (blocknr<0)
927                                         return E_FAIL;
928                                 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
929                                         return E_FAIL;
930                                 lastblocknr = blocknr;
931                         }
932                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933                                 return E_FAIL;
934                 } else {
935                         if (newsize < 0x1000) {
936                                 /* find startblock */
937                                 if (!oldsize)
938                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
939                                 else
940                                         blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
941                                 if (blocknr<0)
942                                         return E_FAIL;
943
944                                 /* allocate required new small blocks */
945                                 lastblocknr = blocknr;
946                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
947                                         blocknr = STORAGE_get_free_small_blocknr(hf);
948                                         if (blocknr<0)
949                                                 return E_FAIL;
950                                         if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
951                                                 return E_FAIL;
952                                         lastblocknr = blocknr;
953                                 }
954                                 /* and terminate the chain */
955                                 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
956                                         return E_FAIL;
957                         } else {
958                                 if (!oldsize) {
959                                         /* no single block allocated yet */
960                                         blocknr=STORAGE_get_free_big_blocknr(hf);
961                                         if (blocknr<0)
962                                                 return E_FAIL;
963                                         This->stde.pps_sb = blocknr;
964                                 } else {
965                                         /* Migrate small blocks to big blocks */
966                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
967                                         cc      = oldsize;
968                                         blocknr = This->stde.pps_sb;
969                                         curdata = data;
970                                         /* slurp in */
971                                         while (cc>0) {
972                                                 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
973                                                         HeapFree(GetProcessHeap(),0,data);
974                                                         return E_FAIL;
975                                                 }
976                                                 curdata += SMALLSIZE;
977                                                 cc      -= SMALLSIZE;
978                                                 blocknr  = STORAGE_get_next_small_blocknr(hf,blocknr);
979                                         }
980                                         /* free small block chain */
981                                         if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
982                                                 return E_FAIL;
983                                         curdata = data;
984                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
985                                         if (blocknr<0)
986                                                 return E_FAIL;
987                                         /* put the data into the big blocks */
988                                         cc      = This->stde.pps_size;
989                                         while (cc>0) {
990                                                 if (!STORAGE_put_big_block(hf,blocknr,curdata))
991                                                         return E_FAIL;
992                                                 cc      -= BIGSIZE;
993                                                 if (cc<=0) {
994                                                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
995                                                                 return E_FAIL;
996                                                         break;
997                                                 } else {
998                                                         int newblocknr = STORAGE_get_free_big_blocknr(hf);
999                                                         if (newblocknr<0)
1000                                                                 return E_FAIL;
1001                                                         if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1002                                                                 return E_FAIL;
1003                                                         blocknr = newblocknr;
1004                                                 }
1005                                                 curdata += BIGSIZE;
1006                                         }
1007                                         HeapFree(GetProcessHeap(),0,data);
1008                                 }
1009                                 /* generate big blocks to fit the new data */
1010                                 lastblocknr     = blocknr;
1011                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1012                                         blocknr = STORAGE_get_free_big_blocknr(hf);
1013                                         if (blocknr<0)
1014                                                 return E_FAIL;
1015                                         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1016                                                 return E_FAIL;
1017                                         lastblocknr = blocknr;
1018                                 }
1019                                 /* terminate chain */
1020                                 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1021                                         return E_FAIL;
1022                         }
1023                 }
1024                 This->stde.pps_size = newsize;
1025         }
1026
1027         /* There are just some cases where we didn't modify it, we write it out
1028          * everytime
1029          */
1030         if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1031                 return E_FAIL;
1032
1033         /* finally the write pass */
1034         if (This->stde.pps_size < 0x1000) {
1035                 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1036                 assert(blocknr>=0);
1037                 while (cb>0) {
1038                         /* we ensured that it is allocated above */
1039                         assert(blocknr>=0);
1040                         /* Read old block everytime, since we can have
1041                          * overlapping data at START and END of the write
1042                          */
1043                         if (!STORAGE_get_small_block(hf,blocknr,block))
1044                                 return E_FAIL;
1045
1046                         cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1047                         if (cc>cb)
1048                                 cc=cb;
1049                         memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1050                                 (LPBYTE)((char *) pv+curoffset),
1051                                 cc
1052                         );
1053                         if (!STORAGE_put_small_block(hf,blocknr,block))
1054                                 return E_FAIL;
1055                         cb                      -= cc;
1056                         curoffset               += cc;
1057                         (LPBYTE)pv              += cc;
1058                         This->offset.s.LowPart  += cc;
1059                         *byteswritten           += cc;
1060                         blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1061                 }
1062         } else {
1063                 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1064                 assert(blocknr>=0);
1065                 while (cb>0) {
1066                         /* we ensured that it is allocated above, so it better is */
1067                         assert(blocknr>=0);
1068                         /* read old block everytime, since we can have
1069                          * overlapping data at START and END of the write
1070                          */
1071                         if (!STORAGE_get_big_block(hf,blocknr,block))
1072                                 return E_FAIL;
1073
1074                         cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1075                         if (cc>cb)
1076                                 cc=cb;
1077                         memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1078                                 (LPBYTE)((char *) pv+curoffset),
1079                                 cc
1080                         );
1081                         if (!STORAGE_put_big_block(hf,blocknr,block))
1082                                 return E_FAIL;
1083                         cb                      -= cc;
1084                         curoffset               += cc;
1085                         (LPBYTE)pv              += cc;
1086                         This->offset.s.LowPart  += cc;
1087                         *byteswritten           += cc;
1088                         blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1089                 }
1090         }
1091         return S_OK;
1092 }
1093
1094 /******************************************************************************
1095  *              _create_istream16       [Internal]
1096  */
1097 static void _create_istream16(LPSTREAM16 *str) {
1098         IStream16Impl*  lpst;
1099
1100         if (!strvt16.QueryInterface) {
1101                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1102                 if (wp>=32) {
1103                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1104 #define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1105                         VTENT(QueryInterface);
1106                         VTENT(AddRef);
1107                         VTENT(Release);
1108                         VTENT(Read);
1109                         VTENT(Write);
1110                         VTENT(Seek);
1111                         VTENT(SetSize);
1112                         VTENT(CopyTo);
1113                         VTENT(Commit);
1114                         VTENT(Revert);
1115                         VTENT(LockRegion);
1116                         VTENT(UnlockRegion);
1117                         VTENT(Stat);
1118                         VTENT(Clone);
1119 #undef VTENT
1120                         segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1121                         memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1122                         segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1123                 } else {
1124 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1125                         VTENT(QueryInterface);
1126                         VTENT(AddRef);
1127                         VTENT(Release);
1128                         VTENT(Read);
1129                         VTENT(Write);
1130                         VTENT(Seek);
1131         /*
1132                         VTENT(CopyTo);
1133                         VTENT(Commit);
1134                         VTENT(SetSize);
1135                         VTENT(Revert);
1136                         VTENT(LockRegion);
1137                         VTENT(UnlockRegion);
1138                         VTENT(Stat);
1139                         VTENT(Clone);
1140         */
1141 #undef VTENT
1142                         segstrvt16 = &strvt16;
1143                 }
1144         }
1145         lpst = SEGPTR_NEW(IStream16Impl);
1146         ICOM_VTBL(lpst) = segstrvt16;
1147         lpst->ref       = 1;
1148         lpst->thisptr   = SEGPTR_GET(lpst);
1149         *str = (void*)lpst->thisptr;
1150 }
1151
1152
1153 /* --- IStream32 implementation */
1154
1155 typedef struct
1156 {
1157         /* IUnknown fields */
1158         ICOM_VFIELD(IStream);
1159         DWORD                           ref;
1160         /* IStream32 fields */
1161         struct storage_pps_entry        stde;
1162         int                             ppsent;
1163         HFILE                         hf;
1164         ULARGE_INTEGER                  offset;
1165 } IStream32Impl;
1166
1167 /*****************************************************************************
1168  *              IStream32_QueryInterface        [VTABLE]
1169  */
1170 HRESULT WINAPI IStream_fnQueryInterface(
1171         IStream* iface,REFIID refiid,LPVOID *obj
1172 ) {
1173         ICOM_THIS(IStream32Impl,iface);
1174
1175         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1176         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1177                 *obj = This;
1178                 return 0;
1179         }
1180         return OLE_E_ENUM_NOMORE;
1181         
1182 }
1183
1184 /******************************************************************************
1185  * IStream32_AddRef [VTABLE]
1186  */
1187 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1188         ICOM_THIS(IStream32Impl,iface);
1189         return ++(This->ref);
1190 }
1191
1192 /******************************************************************************
1193  * IStream32_Release [VTABLE]
1194  */
1195 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1196         ICOM_THIS(IStream32Impl,iface);
1197         FlushFileBuffers(This->hf);
1198         This->ref--;
1199         if (!This->ref) {
1200                 CloseHandle(This->hf);
1201                 SEGPTR_FREE(This);
1202                 return 0;
1203         }
1204         return This->ref;
1205 }
1206
1207 /* --- IStorage16 implementation */
1208
1209 typedef struct
1210 {
1211         /* IUnknown fields */
1212         ICOM_VFIELD(IStorage16);
1213         DWORD                           ref;
1214         /* IStorage16 fields */
1215         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1216         struct storage_pps_entry        stde;
1217         int                             ppsent;
1218         HFILE                         hf;
1219 } IStorage16Impl;
1220
1221 /******************************************************************************
1222  *              IStorage16_QueryInterface       [STORAGE.500]
1223  */
1224 HRESULT WINAPI IStorage16_fnQueryInterface(
1225         IStorage16* iface,REFIID refiid,LPVOID *obj
1226 ) {
1227         ICOM_THIS(IStorage16Impl,iface);
1228
1229         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1230
1231         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1232                 *obj = This;
1233                 return 0;
1234         }
1235         return OLE_E_ENUM_NOMORE;
1236 }
1237
1238 /******************************************************************************
1239  * IStorage16_AddRef [STORAGE.501]
1240  */
1241 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1242         ICOM_THIS(IStorage16Impl,iface);
1243         return ++(This->ref);
1244 }
1245
1246 /******************************************************************************
1247  * IStorage16_Release [STORAGE.502]
1248  */
1249 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1250         ICOM_THIS(IStorage16Impl,iface);
1251         This->ref--;
1252         if (This->ref)
1253                 return This->ref;
1254         SEGPTR_FREE(This);
1255         return 0;
1256 }
1257
1258 /******************************************************************************
1259  * IStorage16_Stat [STORAGE.517]
1260  */
1261 HRESULT WINAPI IStorage16_fnStat(
1262         LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1263 ) {
1264         ICOM_THIS(IStorage16Impl,iface);
1265         TRACE("(%p)->(%p,0x%08lx)\n",
1266                 This,pstatstg,grfStatFlag
1267         );
1268         pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1269         pstatstg->type = This->stde.pps_type;
1270         pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1271         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1272         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1273         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1274         pstatstg->grfMode       = 0; /* FIXME */
1275         pstatstg->grfLocksSupported = 0; /* FIXME */
1276         pstatstg->clsid         = This->stde.pps_guid;
1277         pstatstg->grfStateBits  = 0; /* FIXME */
1278         pstatstg->reserved      = 0;
1279         return S_OK;
1280 }
1281
1282 /******************************************************************************
1283  *              IStorage16_Commit       [STORAGE.509]
1284  */
1285 HRESULT WINAPI IStorage16_fnCommit(
1286         LPSTORAGE16 iface,DWORD commitflags
1287 ) {
1288         ICOM_THIS(IStorage16Impl,iface);
1289         FIXME("(%p)->(0x%08lx),STUB!\n",
1290                 This,commitflags
1291         );
1292         return S_OK;
1293 }
1294
1295 /******************************************************************************
1296  * IStorage16_CopyTo [STORAGE.507]
1297  */
1298 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1299         ICOM_THIS(IStorage16Impl,iface);
1300         FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1301                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1302         );
1303         return S_OK;
1304 }
1305
1306
1307 /******************************************************************************
1308  * IStorage16_CreateStorage [STORAGE.505]
1309  */
1310 HRESULT WINAPI IStorage16_fnCreateStorage(
1311         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1312 ) {
1313         ICOM_THIS(IStorage16Impl,iface);
1314         IStorage16Impl* lpstg;
1315         int             ppsent,x;
1316         struct storage_pps_entry        stde;
1317         struct storage_header sth;
1318         HFILE           hf=This->hf;
1319
1320         READ_HEADER;
1321
1322         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1323                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1324         );
1325         if (grfMode & STGM_TRANSACTED)
1326                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1327         _create_istorage16(ppstg);
1328         lpstg = MapSL((SEGPTR)*ppstg);
1329         lpstg->hf               = This->hf;
1330
1331         ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1332         if (ppsent<0)
1333                 return E_FAIL;
1334         stde=This->stde;
1335         if (stde.pps_dir==-1) {
1336                 stde.pps_dir = ppsent;
1337                 x = This->ppsent;
1338         } else {
1339                 FIXME(" use prev chain too ?\n");
1340                 x=stde.pps_dir;
1341                 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1342                         return E_FAIL;
1343                 while (stde.pps_next!=-1) {
1344                         x=stde.pps_next;
1345                         if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1346                                 return E_FAIL;
1347                 }
1348                 stde.pps_next = ppsent;
1349         }
1350         assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1351         assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1352         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1353                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1354         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1355         lpstg->stde.pps_next    = -1;
1356         lpstg->stde.pps_prev    = -1;
1357         lpstg->stde.pps_dir     = -1;
1358         lpstg->stde.pps_sb      = -1;
1359         lpstg->stde.pps_size    =  0;
1360         lpstg->stde.pps_type    =  1;
1361         lpstg->ppsent           = ppsent;
1362         /* FIXME: timestamps? */
1363         if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1364                 return E_FAIL;
1365         return S_OK;
1366 }
1367
1368 /******************************************************************************
1369  *              IStorage16_CreateStream [STORAGE.503]
1370  */
1371 HRESULT WINAPI IStorage16_fnCreateStream(
1372         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1373 ) {
1374         ICOM_THIS(IStorage16Impl,iface);
1375         IStream16Impl*  lpstr;
1376         int             ppsent,x;
1377         struct storage_pps_entry        stde;
1378
1379         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1380                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1381         );
1382         if (grfMode & STGM_TRANSACTED)
1383                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1384         _create_istream16(ppstm);
1385         lpstr = MapSL((SEGPTR)*ppstm);
1386         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1387                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1388         lpstr->offset.s.LowPart = 0;
1389         lpstr->offset.s.HighPart        = 0;
1390
1391         ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1392         if (ppsent<0)
1393                 return E_FAIL;
1394         stde=This->stde;
1395         if (stde.pps_next==-1)
1396                 x=This->ppsent;
1397         else
1398                 while (stde.pps_next!=-1) {
1399                         x=stde.pps_next;
1400                         if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1401                                 return E_FAIL;
1402                 }
1403         stde.pps_next = ppsent;
1404         assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1405         assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1406         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1407                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1408         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1409         lpstr->stde.pps_next    = -1;
1410         lpstr->stde.pps_prev    = -1;
1411         lpstr->stde.pps_dir     = -1;
1412         lpstr->stde.pps_sb      = -1;
1413         lpstr->stde.pps_size    =  0;
1414         lpstr->stde.pps_type    =  2;
1415         lpstr->ppsent           = ppsent;
1416         /* FIXME: timestamps? */
1417         if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1418                 return E_FAIL;
1419         return S_OK;
1420 }
1421
1422 /******************************************************************************
1423  *              IStorage16_OpenStorage  [STORAGE.506]
1424  */
1425 HRESULT WINAPI IStorage16_fnOpenStorage(
1426         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1427 ) {
1428         ICOM_THIS(IStorage16Impl,iface);
1429         IStream16Impl*  lpstg;
1430         WCHAR           name[33];
1431         int             newpps;
1432
1433         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1434                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1435         );
1436         if (grfMode & STGM_TRANSACTED)
1437                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1438         _create_istorage16(ppstg);
1439         lpstg = MapSL((SEGPTR)*ppstg);
1440         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1441                          &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1442         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1443         newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1444         if (newpps==-1) {
1445                 IStream16_fnRelease((IStream16*)lpstg);
1446                 return E_FAIL;
1447         }
1448
1449         if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1450                 IStream16_fnRelease((IStream16*)lpstg);
1451                 return E_FAIL;
1452         }
1453         lpstg->ppsent           = newpps;
1454         return S_OK;
1455 }
1456
1457 /******************************************************************************
1458  * IStorage16_OpenStream [STORAGE.504]
1459  */
1460 HRESULT WINAPI IStorage16_fnOpenStream(
1461         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1462 ) {
1463         ICOM_THIS(IStorage16Impl,iface);
1464         IStream16Impl*  lpstr;
1465         WCHAR           name[33];
1466         int             newpps;
1467
1468         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1469                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1470         );
1471         if (grfMode & STGM_TRANSACTED)
1472                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1473         _create_istream16(ppstm);
1474         lpstr = MapSL((SEGPTR)*ppstm);
1475         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1476                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1477         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1478         newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1479         if (newpps==-1) {
1480                 IStream16_fnRelease((IStream16*)lpstr);
1481                 return E_FAIL;
1482         }
1483
1484         if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1485                 IStream16_fnRelease((IStream16*)lpstr);
1486                 return E_FAIL;
1487         }
1488         lpstr->offset.s.LowPart = 0;
1489         lpstr->offset.s.HighPart        = 0;
1490         lpstr->ppsent           = newpps;
1491         return S_OK;
1492 }
1493
1494 /******************************************************************************
1495  * _create_istorage16 [INTERNAL]
1496  */
1497 static void _create_istorage16(LPSTORAGE16 *stg) {
1498         IStorage16Impl* lpst;
1499
1500         if (!stvt16.QueryInterface) {
1501                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1502                 if (wp>=32) {
1503 #define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1504                         VTENT(QueryInterface)
1505                         VTENT(AddRef)
1506                         VTENT(Release)
1507                         VTENT(CreateStream)
1508                         VTENT(OpenStream)
1509                         VTENT(CreateStorage)
1510                         VTENT(OpenStorage)
1511                         VTENT(CopyTo)
1512                         VTENT(MoveElementTo)
1513                         VTENT(Commit)
1514                         VTENT(Revert)
1515                         VTENT(EnumElements)
1516                         VTENT(DestroyElement)
1517                         VTENT(RenameElement)
1518                         VTENT(SetElementTimes)
1519                         VTENT(SetClass)
1520                         VTENT(SetStateBits)
1521                         VTENT(Stat)
1522 #undef VTENT
1523                         segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1524                         memcpy(segstvt16,&stvt16,sizeof(stvt16));
1525                         segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1526                 } else {
1527 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1528                         VTENT(QueryInterface)
1529                         VTENT(AddRef)
1530                         VTENT(Release)
1531                         VTENT(CreateStream)
1532                         VTENT(OpenStream)
1533                         VTENT(CreateStorage)
1534                         VTENT(OpenStorage)
1535                         VTENT(CopyTo)
1536                         VTENT(Commit)
1537         /*  not (yet) implemented ...
1538                         VTENT(MoveElementTo)
1539                         VTENT(Revert)
1540                         VTENT(EnumElements)
1541                         VTENT(DestroyElement)
1542                         VTENT(RenameElement)
1543                         VTENT(SetElementTimes)
1544                         VTENT(SetClass)
1545                         VTENT(SetStateBits)
1546                         VTENT(Stat)
1547         */
1548 #undef VTENT
1549                         segstvt16 = &stvt16;
1550                 }
1551         }
1552         lpst = SEGPTR_NEW(IStorage16Impl);
1553         ICOM_VTBL(lpst) = segstvt16;
1554         lpst->ref       = 1;
1555         lpst->thisptr   = SEGPTR_GET(lpst);
1556         *stg = (void*)lpst->thisptr;
1557 }
1558
1559 /******************************************************************************
1560  *      Storage API functions
1561  */
1562
1563 /******************************************************************************
1564  *              StgCreateDocFileA       [STORAGE.1]
1565  */
1566 HRESULT WINAPI StgCreateDocFile16(
1567         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1568 ) {
1569         HFILE           hf;
1570         int             i,ret;
1571         IStorage16Impl* lpstg;
1572         struct storage_pps_entry        stde;
1573
1574         TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1575                 pwcsName,grfMode,reserved,ppstgOpen
1576         );
1577         _create_istorage16(ppstgOpen);
1578         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1579         if (hf==INVALID_HANDLE_VALUE) {
1580                 WARN("couldn't open file for storage:%ld\n",GetLastError());
1581                 return E_FAIL;
1582         }
1583         lpstg = MapSL((SEGPTR)*ppstgOpen);
1584         lpstg->hf = hf;
1585         /* FIXME: check for existence before overwriting? */
1586         if (!STORAGE_init_storage(hf)) {
1587                 CloseHandle(hf);
1588                 return E_FAIL;
1589         }
1590         i=0;ret=0;
1591         while (!ret) { /* neither 1 nor <0 */
1592                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1593                 if ((ret==1) && (stde.pps_type==5)) {
1594                         lpstg->stde     = stde;
1595                         lpstg->ppsent   = i;
1596                         break;
1597                 }
1598                 i++;
1599         }
1600         if (ret!=1) {
1601                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1602                 return E_FAIL;
1603         }
1604
1605         return S_OK;
1606 }
1607
1608 /******************************************************************************
1609  * StgIsStorageFile [STORAGE.5]
1610  */
1611 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1612         HFILE           hf;
1613         OFSTRUCT        ofs;
1614         BYTE            magic[24];
1615
1616         TRACE("(\'%s\')\n",fn);
1617         hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1618         if (hf==HFILE_ERROR)
1619                 return STG_E_FILENOTFOUND;
1620         if (24!=_lread(hf,magic,24)) {
1621                 WARN(" too short\n");
1622                 _lclose(hf);
1623                 return S_FALSE;
1624         }
1625         if (!memcmp(magic,STORAGE_magic,8)) {
1626                 WARN(" -> YES\n");
1627                 _lclose(hf);
1628                 return S_OK;
1629         }
1630         if (!memcmp(magic,STORAGE_notmagic,8)) {
1631                 WARN(" -> NO\n");
1632                 _lclose(hf);
1633                 return S_FALSE;
1634         }
1635         if (!memcmp(magic,STORAGE_oldmagic,8)) {
1636                 WARN(" -> old format\n");
1637                 _lclose(hf);
1638                 return STG_E_OLDFORMAT;
1639         }
1640         WARN(" -> Invalid header.\n");
1641         _lclose(hf);
1642         return STG_E_INVALIDHEADER;
1643 }
1644
1645 /******************************************************************************
1646  * StgIsStorageFile [OLE32.146]
1647  */
1648 HRESULT WINAPI 
1649 StgIsStorageFile(LPCOLESTR fn) 
1650 {
1651         LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1652         HRESULT ret = StgIsStorageFile16(xfn);
1653
1654         HeapFree(GetProcessHeap(),0,xfn);
1655         return ret;
1656 }
1657
1658
1659 /******************************************************************************
1660  * StgOpenStorage [STORAGE.3]
1661  */
1662 HRESULT WINAPI StgOpenStorage16(
1663         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1664         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1665 ) {
1666         HFILE           hf;
1667         int             ret,i;
1668         IStorage16Impl* lpstg;
1669         struct storage_pps_entry        stde;
1670
1671         TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1672               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1673         );
1674         _create_istorage16(ppstgOpen);
1675         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1676         if (hf==INVALID_HANDLE_VALUE) {
1677                 WARN("Couldn't open file for storage\n");
1678                 return E_FAIL;
1679         }
1680         lpstg = MapSL((SEGPTR)*ppstgOpen);
1681         lpstg->hf = hf;
1682
1683         i=0;ret=0;
1684         while (!ret) { /* neither 1 nor <0 */
1685                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1686                 if ((ret==1) && (stde.pps_type==5)) {
1687                         lpstg->stde=stde;
1688                         break;
1689                 }
1690                 i++;
1691         }
1692         if (ret!=1) {
1693                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1694                 return E_FAIL;
1695         }
1696         return S_OK;
1697         
1698 }
1699
1700