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