Fixed prototype for MmSetAddressRangeModified().
[reactos.git] / lib / ole32 / Storage.c
1 /* Compound Storage
2  *
3  * Implemented using the documentation of the LAOLA project at
4  * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5  * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
6  *
7  * Copyright 1998 Marcus Meissner
8  */
9
10 #include <time.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <windows.h>
16 #include <ddk/ntddk.h>
17 #include <ole32/ole32.h>
18 #include <compobj.h>
19 #include <storage32.h>
20
21 #include <debug.h>
22
23 struct storage_header {
24         BYTE    magic[8];       /* 00: magic */
25         BYTE    unknown1[36];   /* 08: unknown */
26         DWORD   num_of_bbd_blocks;/* 2C: length of big datablocks */
27         DWORD   root_startblock;/* 30: root storage first big block */
28         DWORD   unknown2[2];    /* 34: unknown */
29         DWORD   sbd_startblock; /* 3C: small block depot first big block */
30         DWORD   unknown3[3];    /* 40: unknown */
31         DWORD   bbd_list[109];  /* 4C: big data block list (up to end of sector)*/
32 };
33 struct storage_pps_entry {
34         WCHAR   pps_rawname[32];/* 00: \0 terminated widechar name */
35         WORD    pps_sizeofname; /* 40: namelength in bytes */
36         BYTE    pps_type;       /* 42: flags, 1 storage/dir, 2 stream, 5 root */
37         BYTE    pps_unknown0;   /* 43: unknown */
38         DWORD   pps_prev;       /* 44: previous pps */
39         DWORD   pps_next;       /* 48: next pps */
40         DWORD   pps_dir;        /* 4C: directory pps */
41         GUID    pps_guid;       /* 50: class ID */
42         DWORD   pps_unknown1;   /* 60: unknown */
43         FILETIME pps_ft1;       /* 64: filetime1 */
44         FILETIME pps_ft2;       /* 70: filetime2 */
45         DWORD   pps_sb;         /* 74: data startblock */
46         DWORD   pps_size;       /* 78: datalength. (<0x1000)?small:big blocks*/
47         DWORD   pps_unknown2;   /* 7C: unknown */
48 };
49
50 #define STORAGE_CHAINENTRY_FAT          0xfffffffd
51 #define STORAGE_CHAINENTRY_ENDOFCHAIN   0xfffffffe
52 #define STORAGE_CHAINENTRY_FREE         0xffffffff
53
54
55 //static const BYTE STORAGE_magic[8]   ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
56 //static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
57 //static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
58
59 #define BIGSIZE         512
60 #define SMALLSIZE               64
61
62 #define SMALLBLOCKS_PER_BIGBLOCK        (BIGSIZE/SMALLSIZE)
63
64 #define READ_HEADER     assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
65 static ICOM_VTABLE(IStorage16) stvt16;
66 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
67 static ICOM_VTABLE(IStream16) strvt16;
68 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
69
70 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
71 static void _create_istorage16(LPSTORAGE16 *stg);
72 static void _create_istream16(LPSTREAM16 *str);
73
74 #define IMPLEMENTED 1
75
76
77 /******************************************************************************
78  *              STORAGE_get_big_block   [Internal]
79  *
80  * Reading OLE compound storage
81  */
82 static BOOL
83 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
84         assert(n>=-1);
85         if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
86                 Print(MID_TRACE, (" seek failed (%ld)\n",GetLastError()));
87                 return FALSE;
88         }
89         assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
90         if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
91                 Print(MID_TRACE, ("(block size %d): read didn't read (%ld)\n",n,GetLastError()));
92                 assert(0);
93                 return FALSE;
94         }
95         return TRUE;
96 }
97
98 /******************************************************************************
99  * STORAGE_put_big_block [INTERNAL]
100  */
101 static BOOL
102 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
103         assert(n>=-1);
104         if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
105                 Print(MID_TRACE, (" seek failed (%ld)\n",GetLastError()));
106                 return FALSE;
107         }
108         assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
109         if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
110                 Print(MID_TRACE, (" write failed (%ld)\n",GetLastError()));
111                 return FALSE;
112         }
113         return TRUE;
114 }
115
116 /******************************************************************************
117  * STORAGE_get_next_big_blocknr [INTERNAL]
118  */
119 static int
120 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
121         INT     bbs[BIGSIZE/sizeof(INT)];
122         struct  storage_header  sth;
123
124         READ_HEADER;
125         
126         assert(blocknr>>7<sth.num_of_bbd_blocks);
127         if (sth.bbd_list[blocknr>>7]==0xffffffff)
128                 return -5;
129         if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
130                 return -5;
131         assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
132         return bbs[blocknr&0x7f];
133 }
134
135 /******************************************************************************
136  * STORAGE_get_nth_next_big_blocknr [INTERNAL]
137  */
138 static int
139 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
140         INT     bbs[BIGSIZE/sizeof(INT)];
141         int     lastblock = -1;
142         struct storage_header sth;
143
144         READ_HEADER;
145         
146         assert(blocknr>=0);
147         while (nr--) {
148                 assert((blocknr>>7)<sth.num_of_bbd_blocks);
149                 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
150
151                 /* simple caching... */
152                 if (lastblock!=sth.bbd_list[blocknr>>7]) {
153                         assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
154                         lastblock = sth.bbd_list[blocknr>>7];
155                 }
156                 blocknr = bbs[blocknr&0x7f];
157         }
158         return blocknr;
159 }
160
161 /******************************************************************************
162  *              STORAGE_get_root_pps_entry      [Internal]
163  */
164 static BOOL
165 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
166         int     blocknr,i;
167         BYTE    block[BIGSIZE];
168         struct storage_pps_entry        *stde=(struct storage_pps_entry*)block;
169         struct storage_header sth;
170
171         READ_HEADER;
172         blocknr = sth.root_startblock;
173         while (blocknr>=0) {
174                 assert(STORAGE_get_big_block(hf,blocknr,block));
175                 for (i=0;i<4;i++) {
176                         if (!stde[i].pps_sizeofname)
177                                 continue;
178                         if (stde[i].pps_type==5) {
179                                 *pstde=stde[i];
180                                 return TRUE;
181                         }
182                 }
183                 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
184         }
185         return FALSE;
186 }
187
188 /******************************************************************************
189  * STORAGE_get_small_block [INTERNAL]
190  */
191 static BOOL
192 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
193         BYTE                            block[BIGSIZE];
194         int                             bigblocknr;
195         struct storage_pps_entry        root;
196
197         assert(blocknr>=0);
198         assert(STORAGE_get_root_pps_entry(hf,&root));
199         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
200         assert(bigblocknr>=0);
201         assert(STORAGE_get_big_block(hf,bigblocknr,block));
202
203         memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
204         return TRUE;
205 }
206
207 /******************************************************************************
208  * STORAGE_put_small_block [INTERNAL]
209  */
210 static BOOL
211 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
212         BYTE                            block[BIGSIZE];
213         int                             bigblocknr;
214         struct storage_pps_entry        root;
215
216         assert(blocknr>=0);
217
218         assert(STORAGE_get_root_pps_entry(hf,&root));
219         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
220         assert(bigblocknr>=0);
221         assert(STORAGE_get_big_block(hf,bigblocknr,block));
222
223         memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
224         assert(STORAGE_put_big_block(hf,bigblocknr,block));
225         return TRUE;
226 }
227
228 /******************************************************************************
229  * STORAGE_get_next_small_blocknr [INTERNAL]
230  */
231 static int
232 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
233         BYTE                            block[BIGSIZE];
234         LPINT                           sbd = (LPINT)block;
235         int                             bigblocknr;
236         struct storage_header           sth;
237
238         READ_HEADER;
239         assert(blocknr>=0);
240         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
241         assert(bigblocknr>=0);
242         assert(STORAGE_get_big_block(hf,bigblocknr,block));
243         assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
244         return sbd[blocknr & (128-1)];
245 }
246
247 /******************************************************************************
248  * STORAGE_get_nth_next_small_blocknr [INTERNAL]
249  */
250 static int
251 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
252         int     lastblocknr;
253         BYTE    block[BIGSIZE];
254         LPINT   sbd = (LPINT)block;
255         struct storage_header sth;
256
257         READ_HEADER;
258         lastblocknr=-1;
259         assert(blocknr>=0);
260         while ((nr--) && (blocknr>=0)) {
261                 if (lastblocknr/128!=blocknr/128) {
262                         int     bigblocknr;
263                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
264                         assert(bigblocknr>=0);
265                         assert(STORAGE_get_big_block(hf,bigblocknr,block));
266                         lastblocknr = blocknr;
267                 }
268                 assert(lastblocknr>=0);
269                 lastblocknr=blocknr;
270                 blocknr=sbd[blocknr & (128-1)];
271                 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
272         }
273         return blocknr;
274 }
275
276 /******************************************************************************
277  * STORAGE_get_pps_entry [INTERNAL]
278  */
279 static int
280 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
281         int     blocknr;
282         BYTE    block[BIGSIZE];
283         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
284         struct storage_header sth;
285
286         READ_HEADER;
287         /* we have 4 pps entries per big block */
288         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
289         assert(blocknr>=0);
290         assert(STORAGE_get_big_block(hf,blocknr,block));
291
292         *pstde=*stde;
293         return 1;
294 }
295
296 /******************************************************************************
297  *              STORAGE_put_pps_entry   [Internal]
298  */
299 static int
300 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
301         int     blocknr;
302         BYTE    block[BIGSIZE];
303         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
304         struct storage_header sth;
305
306         READ_HEADER;
307
308         /* we have 4 pps entries per big block */
309         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
310         assert(blocknr>=0);
311         assert(STORAGE_get_big_block(hf,blocknr,block));
312         *stde=*pstde;
313         assert(STORAGE_put_big_block(hf,blocknr,block));
314         return 1;
315 }
316
317 /******************************************************************************
318  *              STORAGE_look_for_named_pps      [Internal]
319  */
320 static int
321 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
322         struct storage_pps_entry        stde;
323         int                             ret;
324
325         if (n==-1)
326                 return -1;
327         if (1!=STORAGE_get_pps_entry(hf,n,&stde))
328                 return -1;
329
330         if (!lstrcmpW(name,stde.pps_rawname))
331                 return n;
332         if (stde.pps_prev != -1) {
333                 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
334                 if (ret!=-1)
335                         return ret;
336         }
337         if (stde.pps_next != -1) {
338                 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
339                 if (ret!=-1)
340                         return ret;
341         }
342         return -1;
343 }
344
345 /******************************************************************************
346  *              STORAGE_dump_pps_entry  [Internal]
347  *
348  * FIXME
349  *    Function is unused
350  */
351 void
352 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
353 #if 0
354     char        name[33];
355
356     WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
357         if (!stde->pps_sizeofname)
358                 return;
359         Print(MAX_TRACE, ("name: %s\n",name));
360         Print(MAX_TRACE, ("type: %d\n",stde->pps_type));
361         Print(MAX_TRACE, ("prev pps: %ld\n",stde->pps_prev));
362         Print(MAX_TRACE, ("next pps: %ld\n",stde->pps_next));
363         Print(MAX_TRACE, ("dir pps: %ld\n",stde->pps_dir));
364         Print(MAX_TRACE, ("guid: %s\n",PRINT_GUID(&(stde->pps_guid))));
365         if (stde->pps_type !=2) {
366                 time_t  t;
367                 DWORD dw;
368                 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
369                 t = dw;
370                 Print(MAX_TRACE, ("ts1: %s\n",ctime(&t)));
371                 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
372                 t = dw;
373                 Print(MAX_TRACE, ("ts2: %s\n",ctime(&t)));
374         }
375         Print(MAX_TRACE, ("startblock: %ld\n",stde->pps_sb));
376         Print(MAX_TRACE, ("size: %ld\n",stde->pps_size));
377 #endif
378 }
379
380 /******************************************************************************
381  * STORAGE_init_storage [INTERNAL]
382  */
383 static BOOL 
384 STORAGE_init_storage(HFILE hf) {
385         BYTE    block[BIGSIZE];
386         LPDWORD bbs;
387         struct storage_header *sth;
388         struct storage_pps_entry *stde;
389
390         assert(-1!=_llseek(hf,0,SEEK_SET));
391         /* block -1 is the storage header */
392         sth = (struct storage_header*)block;
393         memcpy(sth->magic,STORAGE_magic,8);
394         memset(sth->unknown1,0,sizeof(sth->unknown1));
395         memset(sth->unknown2,0,sizeof(sth->unknown2));
396         memset(sth->unknown3,0,sizeof(sth->unknown3));
397         sth->num_of_bbd_blocks  = 1;
398         sth->root_startblock    = 1;
399         sth->sbd_startblock     = 0xffffffff;
400         memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
401         sth->bbd_list[0]        = 0;
402         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
403         /* block 0 is the big block directory */
404         bbs=(LPDWORD)block;
405         memset(block,0xff,sizeof(block)); /* mark all blocks as free */
406         bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
407         bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
408         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
409         /* block 1 is the root directory entry */
410         memset(block,0x00,sizeof(block));
411         stde = (struct storage_pps_entry*)block;
412         MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
413                              sizeof(stde->pps_rawname)/sizeof(WCHAR));
414         stde->pps_sizeofname    = (lstrlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
415         stde->pps_type          = 5;
416         stde->pps_dir           = -1;
417         stde->pps_next          = -1;
418         stde->pps_prev          = -1;
419         stde->pps_sb            = 0xffffffff;
420         stde->pps_size          = 0;
421         assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
422         return TRUE;
423 }
424
425 /******************************************************************************
426  *              STORAGE_set_big_chain   [Internal]
427  */
428 static BOOL
429 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
430         BYTE    block[BIGSIZE];
431         LPINT   bbd = (LPINT)block;
432         int     nextblocknr,bigblocknr;
433         struct storage_header sth;
434
435         READ_HEADER;
436         assert(blocknr!=type);
437         while (blocknr>=0) {
438                 bigblocknr = sth.bbd_list[blocknr/128];
439                 assert(bigblocknr>=0);
440                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
441
442                 nextblocknr = bbd[blocknr&(128-1)];
443                 bbd[blocknr&(128-1)] = type;
444                 if (type>=0)
445                         return TRUE;
446                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
447                 type = STORAGE_CHAINENTRY_FREE;
448                 blocknr = nextblocknr;
449         }
450         return TRUE;
451 }
452
453 /******************************************************************************
454  * STORAGE_set_small_chain [Internal]
455  */
456 static BOOL
457 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
458         BYTE    block[BIGSIZE];
459         LPINT   sbd = (LPINT)block;
460         int     lastblocknr,nextsmallblocknr,bigblocknr;
461         struct storage_header sth;
462
463         READ_HEADER;
464
465         assert(blocknr!=type);
466         lastblocknr=-129;bigblocknr=-2;
467         while (blocknr>=0) {
468                 /* cache block ... */
469                 if (lastblocknr/128!=blocknr/128) {
470                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
471                         assert(bigblocknr>=0);
472                         assert(STORAGE_get_big_block(hf,bigblocknr,block));
473                 }
474                 lastblocknr = blocknr;
475                 nextsmallblocknr = sbd[blocknr&(128-1)];
476                 sbd[blocknr&(128-1)] = type;
477                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
478                 if (type>=0)
479                         return TRUE;
480                 type = STORAGE_CHAINENTRY_FREE;
481                 blocknr = nextsmallblocknr;
482         }
483         return TRUE;
484 }
485
486 /******************************************************************************
487  *              STORAGE_get_free_big_blocknr    [Internal]
488  */
489 static int 
490 STORAGE_get_free_big_blocknr(HFILE hf) {
491         BYTE    block[BIGSIZE];
492         LPINT   sbd = (LPINT)block;
493         int     lastbigblocknr,i,curblock,bigblocknr;
494         struct storage_header sth;
495
496         READ_HEADER;
497         curblock        = 0;
498         lastbigblocknr  = -1;
499         bigblocknr      = sth.bbd_list[curblock];
500         while (curblock<sth.num_of_bbd_blocks) {
501                 assert(bigblocknr>=0);
502                 assert(STORAGE_get_big_block(hf,bigblocknr,block));
503                 for (i=0;i<128;i++)
504                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
505                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
506                                 assert(STORAGE_put_big_block(hf,bigblocknr,block));
507                                 memset(block,0x42,sizeof(block));
508                                 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
509                                 return i+curblock*128;
510                         }
511                 lastbigblocknr = bigblocknr;
512                 bigblocknr = sth.bbd_list[++curblock];
513         }
514         bigblocknr = curblock*128;
515         /* since we have marked all blocks from 0 up to curblock*128-1 
516          * the next free one is curblock*128, where we happily put our 
517          * next large block depot.
518          */
519         memset(block,0xff,sizeof(block));
520         /* mark the block allocated and returned by this function */
521         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
522         assert(STORAGE_put_big_block(hf,bigblocknr,block));
523
524         /* if we had a bbd block already (mostlikely) we need
525          * to link the new one into the chain 
526          */
527         if (lastbigblocknr!=-1)
528                 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
529         sth.bbd_list[curblock]=bigblocknr;
530         sth.num_of_bbd_blocks++;
531         assert(sth.num_of_bbd_blocks==curblock+1);
532         assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
533
534         /* Set the end of the chain for the bigblockdepots */
535         assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
536         /* add 1, for the first entry is used for the additional big block 
537          * depot. (means we already used bigblocknr) */
538         memset(block,0x42,sizeof(block));
539         /* allocate this block (filled with 0x42) */
540         assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
541         return bigblocknr+1;
542 }
543
544
545 /******************************************************************************
546  *              STORAGE_get_free_small_blocknr  [Internal]
547  */
548 static int 
549 STORAGE_get_free_small_blocknr(HFILE hf) {
550         BYTE    block[BIGSIZE];
551         LPINT   sbd = (LPINT)block;
552         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
553         struct storage_pps_entry        root;
554         struct storage_header sth;
555
556         READ_HEADER;
557         bigblocknr      = sth.sbd_startblock;
558         curblock        = 0;
559         lastbigblocknr  = -1;
560         newblocknr      = -1;
561         while (bigblocknr>=0) {
562                 if (!STORAGE_get_big_block(hf,bigblocknr,block))
563                         return -1;
564                 for (i=0;i<128;i++)
565                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
566                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
567                                 newblocknr = i+curblock*128;
568                                 break;
569                         }
570                 if (i!=128)
571                         break;
572                 lastbigblocknr = bigblocknr;
573                 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
574                 curblock++;
575         }
576         if (newblocknr==-1) {
577                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
578                 if (bigblocknr<0)
579                         return -1;
580                 READ_HEADER;
581                 memset(block,0xff,sizeof(block));
582                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
583                 if (!STORAGE_put_big_block(hf,bigblocknr,block))
584                         return -1;
585                 if (lastbigblocknr==-1) {
586                         sth.sbd_startblock = bigblocknr;
587                         if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
588                                 return -1;
589                 } else {
590                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
591                                 return -1;
592                 }
593                 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
594                         return -1;
595                 newblocknr = curblock*128;
596         }
597         /* allocate enough big blocks for storing the allocated small block */
598         if (!STORAGE_get_root_pps_entry(hf,&root))
599                 return -1;
600         if (root.pps_sb==-1)
601                 lastbigblocknr  = -1;
602         else
603                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
604         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
605                 /* we need to allocate more stuff */
606                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
607                 if (bigblocknr<0)
608                         return -1;
609                 READ_HEADER;
610                 if (root.pps_sb==-1) {
611                         root.pps_sb      = bigblocknr;
612                         root.pps_size   += BIGSIZE;
613                 } else {
614                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
615                                 return -1;
616                         root.pps_size   += BIGSIZE;
617                 }
618                 lastbigblocknr = bigblocknr;
619         }
620         if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
621                 return -1;
622         if (!STORAGE_put_pps_entry(hf,0,&root))
623                 return -1;
624         return newblocknr;
625 }
626
627 /******************************************************************************
628  *              STORAGE_get_free_pps_entry      [Internal]
629  */
630 static int
631 STORAGE_get_free_pps_entry(HFILE hf) {
632         int     blocknr,i,curblock,lastblocknr;
633         BYTE    block[BIGSIZE];
634         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
635         struct storage_header sth;
636
637         READ_HEADER;
638         blocknr = sth.root_startblock;
639         assert(blocknr>=0);
640         curblock=0;
641         while (blocknr>=0) {
642                 if (!STORAGE_get_big_block(hf,blocknr,block))
643                         return -1;
644                 for (i=0;i<4;i++) 
645                         if (stde[i].pps_sizeofname==0) /* free */
646                                 return curblock*4+i;
647                 lastblocknr = blocknr;
648                 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
649                 curblock++;
650         }
651         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
652         blocknr = STORAGE_get_free_big_blocknr(hf);
653         /* sth invalidated */
654         if (blocknr<0)
655                 return -1;
656         
657         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
658                 return -1;
659         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
660                 return -1;
661         memset(block,0,sizeof(block));
662         STORAGE_put_big_block(hf,blocknr,block);
663         return curblock*4;
664 }
665
666 /* --- IStream32 implementation */
667
668 typedef struct
669 {
670         /* IUnknown fields */
671         ICOM_VFIELD(IStream);
672         DWORD                           ref;
673         /* IStream32 fields */
674         struct storage_pps_entry        stde;
675         int                             ppsent;
676         HFILE                         hf;
677         ULARGE_INTEGER                  offset;
678 } IStream32Impl;
679
680 /*****************************************************************************
681  *              IStream32_QueryInterface        [VTABLE]
682  */
683 HRESULT WINAPI IStream_fnQueryInterface(
684         IStream* iface,REFIID refiid,LPVOID *obj
685 ) {
686         ICOM_THIS(IStream32Impl,iface);
687
688         Print(MAX_TRACE, ("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj));
689         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
690                 *obj = This;
691                 return 0;
692         }
693         return OLE_E_ENUM_NOMORE;
694         
695 }
696
697 /******************************************************************************
698  * IStream32_AddRef [VTABLE]
699  */
700 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
701         ICOM_THIS(IStream32Impl,iface);
702         return ++(This->ref);
703 }
704
705 /******************************************************************************
706  * IStream32_Release [VTABLE]
707  */
708 ULONG WINAPI IStream_fnRelease(IStream* iface) {
709 #if 0
710         ICOM_THIS(IStream32Impl,iface);
711         FlushFileBuffers(This->hf);
712         This->ref--;
713         if (!This->ref) {
714                 CloseHandle(This->hf);
715                 SEGPTR_FREE(This);
716                 return 0;
717         }
718         return This->ref;
719 #else
720   UNIMPLEMENTED;
721   return 0;
722 #endif
723 }
724
725
726 /******************************************************************************
727  *      Storage API functions
728  */
729
730 /******************************************************************************
731  *              StgCreateDocFile16      [STORAGE.1]
732  */
733 HRESULT WINAPI StgCreateDocFile16(
734         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
735 ) {
736   UNIMPLEMENTED;
737   return S_OK;
738 }
739
740 /******************************************************************************
741  * StgIsStorageFile16 [STORAGE.5]
742  */
743 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
744   UNIMPLEMENTED;
745   return S_OK;
746 }
747
748 /******************************************************************************
749  * StgIsStorageFile [OLE32.146]
750  */
751 HRESULT WINAPI 
752 StgIsStorageFile(LPCOLESTR fn) 
753 {
754 #if 0
755         LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
756         HRESULT ret = StgIsStorageFile16(xfn);
757
758         HeapFree(GetProcessHeap(),0,xfn);
759         return ret;
760 #else
761   UNIMPLEMENTED;
762   return S_OK;
763 #endif
764 }
765
766
767 /******************************************************************************
768  * StgOpenStorage16 [STORAGE.3]
769  */
770 HRESULT WINAPI StgOpenStorage16(
771         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
772         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
773 ) {
774   UNIMPLEMENTED;
775   return S_OK;
776 }
777
778