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