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