Remove unnecessary function prototypes.
[wine] / dlls / ole32 / storage.c
1 /* Compound Storage
2  *
3  * Implemented using the documentation of the LAOLA project at
4  * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5  * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
6  *
7  * Copyright 1998 Marcus Meissner
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25
26 #include <assert.h>
27 #include <time.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winreg.h"
40 #include "winternl.h"
41 #include "winerror.h"
42 #include "wine/winbase16.h"
43 #include "wownt32.h"
44 #include "wine/unicode.h"
45 #include "objbase.h"
46 #include "wine/debug.h"
47
48 #include "ifs.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(ole);
51 WINE_DECLARE_DEBUG_CHANNEL(relay);
52
53 struct storage_header {
54         BYTE    magic[8];       /* 00: magic */
55         BYTE    unknown1[36];   /* 08: unknown */
56         DWORD   num_of_bbd_blocks;/* 2C: length of big datablocks */
57         DWORD   root_startblock;/* 30: root storage first big block */
58         DWORD   unknown2[2];    /* 34: unknown */
59         DWORD   sbd_startblock; /* 3C: small block depot first big block */
60         DWORD   unknown3[3];    /* 40: unknown */
61         DWORD   bbd_list[109];  /* 4C: big data block list (up to end of sector)*/
62 };
63 struct storage_pps_entry {
64         WCHAR   pps_rawname[32];/* 00: \0 terminated widechar name */
65         WORD    pps_sizeofname; /* 40: namelength in bytes */
66         BYTE    pps_type;       /* 42: flags, 1 storage/dir, 2 stream, 5 root */
67         BYTE    pps_unknown0;   /* 43: unknown */
68         DWORD   pps_prev;       /* 44: previous pps */
69         DWORD   pps_next;       /* 48: next pps */
70         DWORD   pps_dir;        /* 4C: directory pps */
71         GUID    pps_guid;       /* 50: class ID */
72         DWORD   pps_unknown1;   /* 60: unknown */
73         FILETIME pps_ft1;       /* 64: filetime1 */
74         FILETIME pps_ft2;       /* 70: filetime2 */
75         DWORD   pps_sb;         /* 74: data startblock */
76         DWORD   pps_size;       /* 78: datalength. (<0x1000)?small:big blocks*/
77         DWORD   pps_unknown2;   /* 7C: unknown */
78 };
79
80 #define STORAGE_CHAINENTRY_FAT          0xfffffffd
81 #define STORAGE_CHAINENTRY_ENDOFCHAIN   0xfffffffe
82 #define STORAGE_CHAINENTRY_FREE         0xffffffff
83
84
85 static const BYTE STORAGE_magic[8]   ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
86
87 #define BIGSIZE         512
88 #define SMALLSIZE               64
89
90 #define SMALLBLOCKS_PER_BIGBLOCK        (BIGSIZE/SMALLSIZE)
91
92 #define READ_HEADER     STORAGE_get_big_block(hf,-1,(LPBYTE)&sth);assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
93 static IStorage16Vtbl stvt16;
94 static IStorage16Vtbl *segstvt16 = NULL;
95 static IStream16Vtbl strvt16;
96 static IStream16Vtbl *segstrvt16 = NULL;
97
98 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
99 static void _create_istorage16(LPSTORAGE16 *stg);
100 static void _create_istream16(LPSTREAM16 *str);
101
102 #define IMPLEMENTED 1
103
104 /* The following is taken from the CorVu implementation of docfiles, and
105  * documents things about the file format that are not implemented here, and
106  * not documented by the LAOLA project. The CorVu implementation was posted
107  * to wine-devel in February 2004, and released under the LGPL at the same
108  * time. Because that implementation is in C++, it's not directly usable in
109  * Wine, but does have documentation value.
110  *
111  *
112  * #define DF_EXT_VTOC          -4
113  * #define DF_VTOC_VTOC         -3
114  * #define DF_VTOC_EOF          -2
115  * #define DF_VTOC_FREE         -1
116  * #define DF_NAMELEN   0x20    // Maximum entry name length - 31 characters plus
117  *                              // a NUL terminator
118  * 
119  * #define DF_FT_STORAGE        1
120  * #define DF_FT_STREAM         2
121  * #define DF_FT_LOCKBYTES      3       // Not used -- How the bloody hell did I manage
122  * #define DF_FT_PROPERTY       4       // Not Used -- to figure these two out?
123  * #define DF_FT_ROOT           5
124  * 
125  * #define DF_BLOCK_SIZE        0x200
126  * #define DF_VTOC_SIZE         0x80
127  * #define DF_DE_PER_BLOCK      4
128  * #define DF_STREAM_BLOCK_SIZE 0x40
129  * 
130  * A DocFile is divided into blocks of 512 bytes.
131  * The first block contains the header.
132  *
133  * The file header contains The first 109 entries in the VTOC of VTOCs.
134  *
135  * Each block pointed to by a VTOC of VTOCs contains a VTOC, which
136  * includes block chains - just like FAT. This is a somewhat poor
137  * design for the following reasons:
138  *
139  *      1. FAT was a poor file system design to begin with, and
140  *         has long been known to be horrendously inefficient
141  *         for day to day operations.
142  *
143  *      2. The problem is compounded here, since the file
144  *         level streams are generally *not* read sequentially.
145  *         This means that a significant percentage of reads
146  *         require seeking from the start of the chain.
147  *
148  * Data chains also contain an internal VTOC. The block size for
149  * the standard VTOC is 512. The block size for the internal VTOC
150  * is 64.
151  *
152  * Now, the 109 blocks in the VTOC of VTOCs allows for files of
153  * up to around 7MB. So what do you think happens if that's
154  * exceeded? Well, there's an entry in the header block which
155  * points to the first block used as additional storage for
156  * the VTOC of VTOCs.
157  *
158  * Now we can get up to around 15MB. Now, guess how the file
159  * format adds in another block to the VTOC of VTOCs. Come on,
160  * it's no big surprise. That's right - the last entry in each
161  * block extending the VTOC of VTOCs is, you guessed it, the
162  * block number of the next block containing an extension to
163  * the VTOC of VTOCs. The VTOC of VTOCs is chained!!!!
164  *
165  * So, to review:
166  *
167  * 1. If you are using a FAT file system, the location of
168  *    your file's blocks is stored in chains.
169  *
170  * 2. At the abstract level, the file contains a VTOC of VTOCs,
171  *    which is stored in the most inefficient possible format for
172  *    random access - a chain (AKA list).
173  *
174  * 3. The VTOC of VTOCs contains descriptions of three file level
175  *    streams:
176  *
177  *    a. The Directory stream
178  *    b. The Data stream
179  *    c. The Data VTOC stream
180  *
181  *    These are, of course, represented as chains.
182  *
183  * 4. The Data VTOC contains data describing the chains of blocks
184  *    within the Data stream.
185  *
186  * That's right - we have a total of four levels of block chains!
187  *
188  * Now, is that complicated enough for you? No? OK, there's another
189  * complication. If an individual stream (ie. an IStream) reaches
190  * 4096 bytes in size, it gets moved from the Data Stream to
191  * a new file level stream. Now, if the stream then gets truncated
192  * back to less than 4096 bytes, it returns to the data stream.
193  *
194  * The effect of using this format can be seen very easily. Pick
195  * an arbitrary application with a grid data representation that
196  * can export to both Lotus 123 and Excel 5 or higher. Export
197  * a large file to Lotus 123 and time it. Export the same thing
198  * to Excel 5 and time that. The difference is the inefficiency
199  * of the Microsoft DocFile format.
200  *
201  *
202  * #define TOTAL_SIMPLE_VTOCS   109
203  * 
204  * struct       DocFile_Header
205  * {
206  *      df_byte iMagic1;        // 0xd0 
207  *      df_byte iMagic2;        // 0xcf 
208  *      df_byte iMagic3;        // 0x11 
209  *      df_byte iMagic4;        // 0xe0 - Spells D0CF11E0, or DocFile 
210  *      df_byte iMagic5;        // 161  (igi upside down) 
211  *      df_byte iMagic6;        // 177  (lli upside down - see below 
212  *      df_byte iMagic7;        // 26 (gz upside down) 
213  *      df_byte iMagic8;        // 225 (szz upside down) - see below 
214  *      df_int4 aiUnknown1[4];
215  *      df_int4 iVersion;       // DocFile Version - 0x03003E   
216  *      df_int4 aiUnknown2[4];
217  *      df_int4 nVTOCs;         // Number of VTOCs 
218  *      df_int4 iFirstDirBlock; // First Directory Block 
219  *      df_int4 aiUnknown3[2];
220  *      df_int4 iFirstDataVTOC; // First data VTOC block 
221  *      df_int4 iHasData;       // 1 if there is data in the file - yes, this is important
222  *      df_int4 iExtendedVTOC;  // Extended VTOC location 
223  *      df_int4 iExtendedVTOCSize; // Size of extended VTOC (+1?) 
224  *      df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS];
225  * };
226  * 
227  * struct       DocFile_VTOC
228  * {
229  *      df_int4 aiBlocks[DF_VTOC_SIZE];
230  * };
231  * 
232  * 
233  * The meaning of the magic numbers
234  *
235  * 0xd0cf11e0 is DocFile with a zero on the end (sort of)
236  *
237  * If you key 177161 into a calculator, then turn the calculator
238  * upside down, you get igilli, which may be a reference to
239  * somebody's name, or to the Hebrew word for "angel".
240  *
241  * If you key 26225 into a calculator, then turn it upside down, you
242  * get szzgz. Microsoft has a tradition of creating nonsense words
243  * using the letters s, g, z and y. We think szzgz may be one of the
244  * Microsoft placeholder variables, along the lines of foo, bar and baz.
245  * Alternatively, it could be 22526, which would be gzszz.
246  *
247  * 
248  * struct       DocFile_DirEnt
249  * {
250  *      df_char achEntryName[DF_NAMELEN];       // Entry Name 
251  *      df_int2 iNameLen;                       // Name length in bytes, including NUL terminator 
252  *      df_byte iFileType;                      // Entry type 
253  *      df_byte iColour;                        // 1 = Black, 0 = Red 
254  *      df_int4 iLeftSibling;                   // Next Left Sibling Entry - See below 
255  *      df_int4 iRightSibling;                  // Next Right Sibling Entry 
256  *      df_int4 iFirstChild;                    // First Child Entry 
257  *      df_byte achClassID[16];                 // Class ID 
258  *      df_int4 iStateBits;                     // [GS]etStateBits value 
259  *      df_int4 iCreatedLow;                    // Low DWORD of creation time 
260  *      df_int4 iCreatedHigh;                   // High DWORD of creation time 
261  *      df_int4 iModifiedLow;                   // Low DWORD of modification time 
262  *      df_int4 iModifiedHigh;                  // High DWORD of modification time 
263  *      df_int4 iVTOCPosition;                  // VTOC Position 
264  *      df_int4 iFileSize;                      // Size of the stream 
265  *      df_int4 iZero;                          // We think this is part of the 64 bit stream size - must be 0 
266  * };
267  * 
268  * Siblings
269  * ========
270  *
271  * Siblings are stored in an obscure but incredibly elegant
272  * data structure called a red-black tree. This is generally
273  * defined as a 2-3-4 tree stored in a binary tree.
274  *
275  * A red-black tree can always be balanced very easily. The rules
276  * for a red-black tree are as follows:
277  *
278  *      1. The root node is always black.
279  *      2. The parent of a red node is always black.
280  *
281  * There is a Java demo of red-black trees at:
282  *
283  *      http://langevin.usc.edu/BST/RedBlackTree-Example.html
284  *
285  * This demo is an excellent tool for learning how red-black
286  * trees work, without having to go through the process of
287  * learning how they were derived.
288  *
289  * Within the tree, elements are ordered by the length of the
290  * name and within that, ASCII order by name. This causes the
291  * apparently bizarre reordering you see when you use dfview.
292  *
293  * This is a somewhat bizarre choice. It suggests that the
294  * designer of the DocFile format was trying to optimise
295  * searching through the directory entries. However searching
296  * through directory entries is a relatively rare operation.
297  * Reading and seeking within a stream are much more common
298  * operations, especially within the file level streams, yet
299  * these use the horrendously inefficient FAT chains.
300  *
301  * This suggests that the designer was probably somebody
302  * fresh out of university, who had some basic knowledge of
303  * basic data structures, but little knowledge of anything
304  * more practical. It is bizarre to attempt to optimise
305  * directory searches while not using a more efficient file
306  * block locating system than FAT (seedling/sapling/tree
307  * would result in a massive improvement - in fact we have
308  * an alternative to DocFiles that we use internally that
309  * uses seedling/sapling/tree and *is* far more efficient).
310  *
311  * It is worth noting that the MS implementation of red-black
312  * trees is incorrect (I can tell you're surprised) and
313  * actually causes more operations to occur than are really
314  * needed. Fortunately the fact that our implementation is
315  * correct will not cause any problems - the MS implementation
316  * still appears to cause the tree to satisfy the rules, albeit
317  * a sequence of the same insertions in the different
318  * implementations may result in a different, and possibly
319  * deeper (but never shallower) tree.
320  */
321
322
323 /******************************************************************************
324  *              STORAGE_get_big_block   [Internal]
325  *
326  * Reading OLE compound storage
327  */
328 static BOOL
329 STORAGE_get_big_block(HANDLE hf,int n,BYTE *block)
330 {
331     DWORD result;
332
333     assert(n>=-1);
334     if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
335                          SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
336     {
337         WARN(" seek failed (%ld)\n",GetLastError());
338         return FALSE;
339     }
340     if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
341     {
342         WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
343         return FALSE;
344     }
345     return TRUE;
346 }
347
348 /******************************************************************************
349  * STORAGE_put_big_block [INTERNAL]
350  */
351 static BOOL
352 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
353 {
354     DWORD result;
355
356     assert(n>=-1);
357     if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
358                          SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
359     {
360         WARN("seek failed (%ld)\n",GetLastError());
361         return FALSE;
362     }
363     if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
364     {
365         WARN(" write failed (%ld)\n",GetLastError());
366         return FALSE;
367     }
368     return TRUE;
369 }
370
371 /******************************************************************************
372  * STORAGE_get_next_big_blocknr [INTERNAL]
373  */
374 static int
375 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
376         INT     bbs[BIGSIZE/sizeof(INT)];
377         struct  storage_header  sth;
378
379         READ_HEADER;
380
381         assert(blocknr>>7<sth.num_of_bbd_blocks);
382         if (sth.bbd_list[blocknr>>7]==0xffffffff)
383                 return -5;
384         if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
385                 return -5;
386         assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
387         return bbs[blocknr&0x7f];
388 }
389
390 /******************************************************************************
391  * STORAGE_get_nth_next_big_blocknr [INTERNAL]
392  */
393 static int
394 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
395         INT     bbs[BIGSIZE/sizeof(INT)];
396         int     lastblock = -1;
397         struct storage_header sth;
398
399         READ_HEADER;
400
401         assert(blocknr>=0);
402         while (nr--) {
403                 assert((blocknr>>7)<sth.num_of_bbd_blocks);
404                 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
405
406                 /* simple caching... */
407                 if (lastblock!=sth.bbd_list[blocknr>>7]) {
408                         BOOL ret = STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
409                         assert(ret);
410                         lastblock = sth.bbd_list[blocknr>>7];
411                 }
412                 blocknr = bbs[blocknr&0x7f];
413         }
414         return blocknr;
415 }
416
417 /******************************************************************************
418  *              STORAGE_get_root_pps_entry      [Internal]
419  */
420 static BOOL
421 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
422         int     blocknr,i;
423         BYTE    block[BIGSIZE];
424         struct storage_pps_entry        *stde=(struct storage_pps_entry*)block;
425         struct storage_header sth;
426
427         READ_HEADER;
428         blocknr = sth.root_startblock;
429         while (blocknr>=0) {
430                 BOOL ret = STORAGE_get_big_block(hf,blocknr,block);
431                 assert(ret);
432                 for (i=0;i<4;i++) {
433                         if (!stde[i].pps_sizeofname)
434                                 continue;
435                         if (stde[i].pps_type==5) {
436                                 *pstde=stde[i];
437                                 return TRUE;
438                         }
439                 }
440                 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
441         }
442         return FALSE;
443 }
444
445 /******************************************************************************
446  * STORAGE_get_small_block [INTERNAL]
447  */
448 static BOOL
449 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
450         BYTE                            block[BIGSIZE];
451         int                             bigblocknr;
452         struct storage_pps_entry        root;
453         BOOL ret;
454
455         assert(blocknr>=0);
456         ret = STORAGE_get_root_pps_entry(hf,&root);
457         assert(ret);
458         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
459         assert(bigblocknr>=0);
460         ret = STORAGE_get_big_block(hf,bigblocknr,block);
461         assert(ret);
462
463         memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
464         return TRUE;
465 }
466
467 /******************************************************************************
468  * STORAGE_put_small_block [INTERNAL]
469  */
470 static BOOL
471 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
472         BYTE                            block[BIGSIZE];
473         int                             bigblocknr;
474         struct storage_pps_entry        root;
475         BOOL ret;
476
477         assert(blocknr>=0);
478
479         ret = STORAGE_get_root_pps_entry(hf,&root);
480         assert(ret);
481         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
482         assert(bigblocknr>=0);
483         ret = STORAGE_get_big_block(hf,bigblocknr,block);
484         assert(ret);
485
486         memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
487         ret = STORAGE_put_big_block(hf,bigblocknr,block);
488         assert(ret);
489         return TRUE;
490 }
491
492 /******************************************************************************
493  * STORAGE_get_next_small_blocknr [INTERNAL]
494  */
495 static int
496 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
497         BYTE                            block[BIGSIZE];
498         LPINT                           sbd = (LPINT)block;
499         int                             bigblocknr;
500         struct storage_header           sth;
501         BOOL ret;
502
503         READ_HEADER;
504         assert(blocknr>=0);
505         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
506         assert(bigblocknr>=0);
507         ret = STORAGE_get_big_block(hf,bigblocknr,block);
508         assert(ret);
509         assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
510         return sbd[blocknr & (128-1)];
511 }
512
513 /******************************************************************************
514  * STORAGE_get_nth_next_small_blocknr [INTERNAL]
515  */
516 static int
517 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
518         int     lastblocknr=-1;
519         BYTE    block[BIGSIZE];
520         LPINT   sbd = (LPINT)block;
521         struct storage_header sth;
522         BOOL ret;
523
524         READ_HEADER;
525         assert(blocknr>=0);
526         while ((nr--) && (blocknr>=0)) {
527                 if (lastblocknr/128!=blocknr/128) {
528                         int     bigblocknr;
529                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
530                         assert(bigblocknr>=0);
531                         ret = STORAGE_get_big_block(hf,bigblocknr,block);
532                         assert(ret);
533                         lastblocknr = blocknr;
534                 }
535                 assert(lastblocknr>=0);
536                 lastblocknr=blocknr;
537                 blocknr=sbd[blocknr & (128-1)];
538                 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
539         }
540         return blocknr;
541 }
542
543 /******************************************************************************
544  * STORAGE_get_pps_entry [INTERNAL]
545  */
546 static int
547 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
548         int     blocknr;
549         BYTE    block[BIGSIZE];
550         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
551         struct storage_header sth;
552         BOOL ret;
553
554         READ_HEADER;
555         /* we have 4 pps entries per big block */
556         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
557         assert(blocknr>=0);
558         ret = STORAGE_get_big_block(hf,blocknr,block);
559         assert(ret);
560
561         *pstde=*stde;
562         return 1;
563 }
564
565 /******************************************************************************
566  *              STORAGE_put_pps_entry   [Internal]
567  */
568 static int
569 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
570         int     blocknr;
571         BYTE    block[BIGSIZE];
572         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
573         struct storage_header sth;
574         BOOL ret;
575
576         READ_HEADER;
577
578         /* we have 4 pps entries per big block */
579         blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
580         assert(blocknr>=0);
581         ret = STORAGE_get_big_block(hf,blocknr,block);
582         assert(ret);
583         *stde=*pstde;
584         ret = STORAGE_put_big_block(hf,blocknr,block);
585         assert(ret);
586         return 1;
587 }
588
589 /******************************************************************************
590  *              STORAGE_look_for_named_pps      [Internal]
591  */
592 static int
593 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
594         struct storage_pps_entry        stde;
595         int                             ret;
596
597         if (n==-1)
598                 return -1;
599         if (1!=STORAGE_get_pps_entry(hf,n,&stde))
600                 return -1;
601
602         if (!lstrcmpW(name,stde.pps_rawname))
603                 return n;
604         if (stde.pps_prev != -1) {
605                 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
606                 if (ret!=-1)
607                         return ret;
608         }
609         if (stde.pps_next != -1) {
610                 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
611                 if (ret!=-1)
612                         return ret;
613         }
614         return -1;
615 }
616
617 /******************************************************************************
618  *              STORAGE_dump_pps_entry  [Internal]
619  *
620  * FIXME
621  *    Function is unused
622  */
623 void
624 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
625     char        name[33];
626
627     WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
628         if (!stde->pps_sizeofname)
629                 return;
630         DPRINTF("name: %s\n",name);
631         DPRINTF("type: %d\n",stde->pps_type);
632         DPRINTF("prev pps: %ld\n",stde->pps_prev);
633         DPRINTF("next pps: %ld\n",stde->pps_next);
634         DPRINTF("dir pps: %ld\n",stde->pps_dir);
635         DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
636         if (stde->pps_type !=2) {
637                 time_t  t;
638                 DWORD dw;
639                 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
640                 t = dw;
641                 DPRINTF("ts1: %s\n",ctime(&t));
642                 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
643                 t = dw;
644                 DPRINTF("ts2: %s\n",ctime(&t));
645         }
646         DPRINTF("startblock: %ld\n",stde->pps_sb);
647         DPRINTF("size: %ld\n",stde->pps_size);
648 }
649
650 /******************************************************************************
651  * STORAGE_init_storage [INTERNAL]
652  */
653 static BOOL
654 STORAGE_init_storage(HANDLE hf) {
655         BYTE    block[BIGSIZE];
656         LPDWORD bbs;
657         struct storage_header *sth;
658         struct storage_pps_entry *stde;
659         DWORD result;
660
661         SetFilePointer( hf, 0, NULL, SEEK_SET );
662         /* block -1 is the storage header */
663         sth = (struct storage_header*)block;
664         memcpy(sth->magic,STORAGE_magic,8);
665         memset(sth->unknown1,0,sizeof(sth->unknown1));
666         memset(sth->unknown2,0,sizeof(sth->unknown2));
667         memset(sth->unknown3,0,sizeof(sth->unknown3));
668         sth->num_of_bbd_blocks  = 1;
669         sth->root_startblock    = 1;
670         sth->sbd_startblock     = 0xffffffff;
671         memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
672         sth->bbd_list[0]        = 0;
673         if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
674         /* block 0 is the big block directory */
675         bbs=(LPDWORD)block;
676         memset(block,0xff,sizeof(block)); /* mark all blocks as free */
677         bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
678         bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
679         if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
680         /* block 1 is the root directory entry */
681         memset(block,0x00,sizeof(block));
682         stde = (struct storage_pps_entry*)block;
683         MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
684                              sizeof(stde->pps_rawname)/sizeof(WCHAR));
685         stde->pps_sizeofname    = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
686         stde->pps_type          = 5;
687         stde->pps_dir           = -1;
688         stde->pps_next          = -1;
689         stde->pps_prev          = -1;
690         stde->pps_sb            = 0xffffffff;
691         stde->pps_size          = 0;
692         return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
693 }
694
695 /******************************************************************************
696  *              STORAGE_set_big_chain   [Internal]
697  */
698 static BOOL
699 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
700         BYTE    block[BIGSIZE];
701         LPINT   bbd = (LPINT)block;
702         int     nextblocknr,bigblocknr;
703         struct storage_header sth;
704         BOOL ret;
705
706         READ_HEADER;
707         assert(blocknr!=type);
708         while (blocknr>=0) {
709                 bigblocknr = sth.bbd_list[blocknr/128];
710                 assert(bigblocknr>=0);
711                 ret = STORAGE_get_big_block(hf,bigblocknr,block);
712                 assert(ret);
713
714                 nextblocknr = bbd[blocknr&(128-1)];
715                 bbd[blocknr&(128-1)] = type;
716                 if (type>=0)
717                         return TRUE;
718                 ret = STORAGE_put_big_block(hf,bigblocknr,block);
719                 assert(ret);
720                 type = STORAGE_CHAINENTRY_FREE;
721                 blocknr = nextblocknr;
722         }
723         return TRUE;
724 }
725
726 /******************************************************************************
727  * STORAGE_set_small_chain [Internal]
728  */
729 static BOOL
730 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
731         BYTE    block[BIGSIZE];
732         LPINT   sbd = (LPINT)block;
733         int     lastblocknr,nextsmallblocknr,bigblocknr;
734         struct storage_header sth;
735         BOOL ret;
736
737         READ_HEADER;
738
739         assert(blocknr!=type);
740         lastblocknr=-129;bigblocknr=-2;
741         while (blocknr>=0) {
742                 /* cache block ... */
743                 if (lastblocknr/128!=blocknr/128) {
744                         bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
745                         assert(bigblocknr>=0);
746                         ret = STORAGE_get_big_block(hf,bigblocknr,block);
747                         assert(ret);
748                 }
749                 lastblocknr = blocknr;
750                 nextsmallblocknr = sbd[blocknr&(128-1)];
751                 sbd[blocknr&(128-1)] = type;
752                 ret = STORAGE_put_big_block(hf,bigblocknr,block);
753                 assert(ret);
754                 if (type>=0)
755                         return TRUE;
756                 type = STORAGE_CHAINENTRY_FREE;
757                 blocknr = nextsmallblocknr;
758         }
759         return TRUE;
760 }
761
762 /******************************************************************************
763  *              STORAGE_get_free_big_blocknr    [Internal]
764  */
765 static int
766 STORAGE_get_free_big_blocknr(HANDLE hf) {
767         BYTE    block[BIGSIZE];
768         LPINT   sbd = (LPINT)block;
769         int     lastbigblocknr,i,bigblocknr;
770         unsigned int curblock;
771         struct storage_header sth;
772         BOOL ret;
773
774         READ_HEADER;
775         curblock        = 0;
776         lastbigblocknr  = -1;
777         bigblocknr      = sth.bbd_list[curblock];
778         while (curblock<sth.num_of_bbd_blocks) {
779                 assert(bigblocknr>=0);
780                 ret = STORAGE_get_big_block(hf,bigblocknr,block);
781                 assert(ret);
782                 for (i=0;i<128;i++)
783                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
784                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
785                                 ret = STORAGE_put_big_block(hf,bigblocknr,block);
786                                 assert(ret);
787                                 memset(block,0x42,sizeof(block));
788                                 ret = STORAGE_put_big_block(hf,i+curblock*128,block);
789                                 assert(ret);
790                                 return i+curblock*128;
791                         }
792                 lastbigblocknr = bigblocknr;
793                 bigblocknr = sth.bbd_list[++curblock];
794         }
795         bigblocknr = curblock*128;
796         /* since we have marked all blocks from 0 up to curblock*128-1
797          * the next free one is curblock*128, where we happily put our
798          * next large block depot.
799          */
800         memset(block,0xff,sizeof(block));
801         /* mark the block allocated and returned by this function */
802         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
803         ret = STORAGE_put_big_block(hf,bigblocknr,block);
804         assert(ret);
805
806         /* if we had a bbd block already (mostlikely) we need
807          * to link the new one into the chain
808          */
809         if (lastbigblocknr!=-1) {
810                 ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr);
811                 assert(ret);
812         }
813         sth.bbd_list[curblock]=bigblocknr;
814         sth.num_of_bbd_blocks++;
815         assert(sth.num_of_bbd_blocks==curblock+1);
816         ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth);
817         assert(ret);
818
819         /* Set the end of the chain for the bigblockdepots */
820         ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
821         assert(ret);
822         /* add 1, for the first entry is used for the additional big block
823          * depot. (means we already used bigblocknr) */
824         memset(block,0x42,sizeof(block));
825         /* allocate this block (filled with 0x42) */
826         ret = STORAGE_put_big_block(hf,bigblocknr+1,block);
827         assert(ret);
828         return bigblocknr+1;
829 }
830
831
832 /******************************************************************************
833  *              STORAGE_get_free_small_blocknr  [Internal]
834  */
835 static int
836 STORAGE_get_free_small_blocknr(HANDLE hf) {
837         BYTE    block[BIGSIZE];
838         LPINT   sbd = (LPINT)block;
839         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
840         struct storage_pps_entry        root;
841         struct storage_header sth;
842
843         READ_HEADER;
844         bigblocknr      = sth.sbd_startblock;
845         curblock        = 0;
846         lastbigblocknr  = -1;
847         newblocknr      = -1;
848         while (bigblocknr>=0) {
849                 if (!STORAGE_get_big_block(hf,bigblocknr,block))
850                         return -1;
851                 for (i=0;i<128;i++)
852                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
853                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
854                                 newblocknr = i+curblock*128;
855                                 break;
856                         }
857                 if (i!=128)
858                         break;
859                 lastbigblocknr = bigblocknr;
860                 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
861                 curblock++;
862         }
863         if (newblocknr==-1) {
864                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
865                 if (bigblocknr<0)
866                         return -1;
867                 READ_HEADER;
868                 memset(block,0xff,sizeof(block));
869                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
870                 if (!STORAGE_put_big_block(hf,bigblocknr,block))
871                         return -1;
872                 if (lastbigblocknr==-1) {
873                         sth.sbd_startblock = bigblocknr;
874                         if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
875                                 return -1;
876                 } else {
877                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
878                                 return -1;
879                 }
880                 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
881                         return -1;
882                 newblocknr = curblock*128;
883         }
884         /* allocate enough big blocks for storing the allocated small block */
885         if (!STORAGE_get_root_pps_entry(hf,&root))
886                 return -1;
887         if (root.pps_sb==-1)
888                 lastbigblocknr  = -1;
889         else
890                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
891         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
892                 /* we need to allocate more stuff */
893                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
894                 if (bigblocknr<0)
895                         return -1;
896                 READ_HEADER;
897                 if (root.pps_sb==-1) {
898                         root.pps_sb      = bigblocknr;
899                         root.pps_size   += BIGSIZE;
900                 } else {
901                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
902                                 return -1;
903                         root.pps_size   += BIGSIZE;
904                 }
905                 lastbigblocknr = bigblocknr;
906         }
907         if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
908                 return -1;
909         if (!STORAGE_put_pps_entry(hf,0,&root))
910                 return -1;
911         return newblocknr;
912 }
913
914 /******************************************************************************
915  *              STORAGE_get_free_pps_entry      [Internal]
916  */
917 static int
918 STORAGE_get_free_pps_entry(HANDLE hf) {
919         int     blocknr, i, curblock, lastblocknr=-1;
920         BYTE    block[BIGSIZE];
921         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
922         struct storage_header sth;
923
924         READ_HEADER;
925         blocknr = sth.root_startblock;
926         assert(blocknr>=0);
927         curblock=0;
928         while (blocknr>=0) {
929                 if (!STORAGE_get_big_block(hf,blocknr,block))
930                         return -1;
931                 for (i=0;i<4;i++)
932                         if (stde[i].pps_sizeofname==0) /* free */
933                                 return curblock*4+i;
934                 lastblocknr = blocknr;
935                 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
936                 curblock++;
937         }
938         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
939         blocknr = STORAGE_get_free_big_blocknr(hf);
940         /* sth invalidated */
941         if (blocknr<0)
942                 return -1;
943
944         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
945                 return -1;
946         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
947                 return -1;
948         memset(block,0,sizeof(block));
949         STORAGE_put_big_block(hf,blocknr,block);
950         return curblock*4;
951 }
952
953 /* --- IStream16 implementation */
954
955 typedef struct
956 {
957         /* IUnknown fields */
958         IStream16Vtbl                  *lpVtbl;
959         DWORD                           ref;
960         /* IStream16 fields */
961         SEGPTR                          thisptr; /* pointer to this struct as segmented */
962         struct storage_pps_entry        stde;
963         int                             ppsent;
964         HANDLE                         hf;
965         ULARGE_INTEGER                  offset;
966 } IStream16Impl;
967
968 /******************************************************************************
969  *              IStream16_QueryInterface        [STORAGE.518]
970  */
971 HRESULT WINAPI IStream16_fnQueryInterface(
972         IStream16* iface,REFIID refiid,LPVOID *obj
973 ) {
974         IStream16Impl *This = (IStream16Impl *)iface;
975         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
976         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
977                 *obj = This;
978                 return 0;
979         }
980         return OLE_E_ENUM_NOMORE;
981
982 }
983
984 /******************************************************************************
985  * IStream16_AddRef [STORAGE.519]
986  */
987 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
988         IStream16Impl *This = (IStream16Impl *)iface;
989         return InterlockedIncrement(&This->ref);
990 }
991
992 /******************************************************************************
993  * IStream16_Release [STORAGE.520]
994  */
995 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
996         IStream16Impl *This = (IStream16Impl *)iface;
997         ULONG ref;
998         FlushFileBuffers(This->hf);
999         ref = InterlockedDecrement(&This->ref);
1000         if (!ref) {
1001                 CloseHandle(This->hf);
1002                 UnMapLS( This->thisptr );
1003                 HeapFree( GetProcessHeap(), 0, This );
1004         }
1005         return ref;
1006 }
1007
1008 /******************************************************************************
1009  *              IStream16_Seek  [STORAGE.523]
1010  *
1011  * FIXME
1012  *    Does not handle 64 bits
1013  */
1014 HRESULT WINAPI IStream16_fnSeek(
1015         IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
1016 ) {
1017         IStream16Impl *This = (IStream16Impl *)iface;
1018         TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
1019
1020         switch (whence) {
1021         /* unix SEEK_xx should be the same as win95 ones */
1022         case SEEK_SET:
1023                 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
1024                  * right now.
1025                  */
1026                 assert(offset.u.HighPart==0);
1027                 This->offset.u.HighPart = offset.u.HighPart;
1028                 This->offset.u.LowPart = offset.u.LowPart;
1029                 break;
1030         case SEEK_CUR:
1031                 if (offset.u.HighPart < 0) {
1032                         /* FIXME: is this negation correct ? */
1033                         offset.u.HighPart = -offset.u.HighPart;
1034                         offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
1035
1036                         assert(offset.u.HighPart==0);
1037                         assert(This->offset.u.LowPart >= offset.u.LowPart);
1038                         This->offset.u.LowPart -= offset.u.LowPart;
1039                 } else {
1040                         assert(offset.u.HighPart==0);
1041                         This->offset.u.LowPart+= offset.u.LowPart;
1042                 }
1043                 break;
1044         case SEEK_END:
1045                 assert(offset.u.HighPart==0);
1046                 This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
1047                 break;
1048         }
1049         if (This->offset.u.LowPart>This->stde.pps_size)
1050                 This->offset.u.LowPart=This->stde.pps_size;
1051         if (newpos) *newpos = This->offset;
1052         return S_OK;
1053 }
1054
1055 /******************************************************************************
1056  *              IStream16_Read  [STORAGE.521]
1057  */
1058 HRESULT WINAPI IStream16_fnRead(
1059         IStream16* iface,void  *pv,ULONG cb,ULONG  *pcbRead
1060 ) {
1061         IStream16Impl *This = (IStream16Impl *)iface;
1062         BYTE    block[BIGSIZE];
1063         ULONG   *bytesread=pcbRead,xxread;
1064         int     blocknr;
1065         LPBYTE  pbv = pv;
1066
1067         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
1068         if (!pcbRead) bytesread=&xxread;
1069         *bytesread = 0;
1070
1071         if (cb>This->stde.pps_size-This->offset.u.LowPart)
1072                 cb=This->stde.pps_size-This->offset.u.LowPart;
1073         if (This->stde.pps_size < 0x1000) {
1074                 /* use small block reader */
1075                 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1076                 while (cb) {
1077                         unsigned int cc;
1078
1079                         if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
1080                            WARN("small block read failed!!!\n");
1081                                 return E_FAIL;
1082                         }
1083                         cc = cb;
1084                         if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1085                                 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1086                         memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1087                         This->offset.u.LowPart+=cc;
1088                         pbv+=cc;
1089                         *bytesread+=cc;
1090                         cb-=cc;
1091                         blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
1092                 }
1093         } else {
1094                 /* use big block reader */
1095                 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1096                 while (cb) {
1097                         unsigned int cc;
1098
1099                         if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
1100                                 WARN("big block read failed!!!\n");
1101                                 return E_FAIL;
1102                         }
1103                         cc = cb;
1104                         if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1105                                 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1106                         memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1107                         This->offset.u.LowPart+=cc;
1108                         pbv+=cc;
1109                         *bytesread+=cc;
1110                         cb-=cc;
1111                         blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
1112                 }
1113         }
1114         return S_OK;
1115 }
1116
1117 /******************************************************************************
1118  *              IStream16_Write [STORAGE.522]
1119  */
1120 HRESULT WINAPI IStream16_fnWrite(
1121         IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
1122 ) {
1123         IStream16Impl *This = (IStream16Impl *)iface;
1124         BYTE    block[BIGSIZE];
1125         ULONG   *byteswritten=pcbWrite,xxwritten;
1126         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1127         HANDLE  hf = This->hf;
1128         const BYTE*     pbv = (const BYTE*)pv;
1129
1130         if (!pcbWrite) byteswritten=&xxwritten;
1131         *byteswritten = 0;
1132
1133         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
1134         /* do we need to junk some blocks? */
1135         newsize = This->offset.u.LowPart+cb;
1136         oldsize = This->stde.pps_size;
1137         if (newsize < oldsize) {
1138                 if (oldsize < 0x1000) {
1139                         /* only small blocks */
1140                         blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
1141
1142                         assert(blocknr>=0);
1143
1144                         /* will set the rest of the chain to 'free' */
1145                         if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1146                                 return E_FAIL;
1147                 } else {
1148                         if (newsize >= 0x1000) {
1149                                 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
1150                                 assert(blocknr>=0);
1151
1152                                 /* will set the rest of the chain to 'free' */
1153                                 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1154                                         return E_FAIL;
1155                         } else {
1156                                 /* Migrate large blocks to small blocks
1157                                  * (we just migrate newsize bytes)
1158                                  */
1159                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1160                                 HRESULT r = E_FAIL;
1161
1162                                 cc      = newsize;
1163                                 blocknr = This->stde.pps_sb;
1164                                 curdata = data;
1165                                 while (cc>0) {
1166                                         if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
1167                                                 HeapFree(GetProcessHeap(),0,data);
1168                                                 return E_FAIL;
1169                                         }
1170                                         curdata += BIGSIZE;
1171                                         cc      -= BIGSIZE;
1172                                         blocknr  = STORAGE_get_next_big_blocknr(hf,blocknr);
1173                                 }
1174                                 /* frees complete chain for this stream */
1175                                 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1176                                         goto err;
1177                                 curdata = data;
1178                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
1179                                 if (blocknr<0)
1180                                         goto err;
1181                                 cc      = newsize;
1182                                 while (cc>0) {
1183                                         if (!STORAGE_put_small_block(hf,blocknr,curdata))
1184                                                 goto err;
1185                                         cc      -= SMALLSIZE;
1186                                         if (cc<=0) {
1187                                                 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1188                                                         goto err;
1189                                                 break;
1190                                         } else {
1191                                                 int newblocknr = STORAGE_get_free_small_blocknr(hf);
1192                                                 if (newblocknr<0)
1193                                                         goto err;
1194                                                 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
1195                                                         goto err;
1196                                                 blocknr = newblocknr;
1197                                         }
1198                                         curdata += SMALLSIZE;
1199                                 }
1200                                 r = S_OK;
1201                         err:
1202                                 HeapFree(GetProcessHeap(),0,data);
1203                                 if(r != S_OK)
1204                                         return r;
1205                         }
1206                 }
1207                 This->stde.pps_size = newsize;
1208         }
1209
1210         if (newsize > oldsize) {
1211                 if (oldsize >= 0x1000) {
1212                         /* should return the block right before the 'endofchain' */
1213                         blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1214                         assert(blocknr>=0);
1215                         lastblocknr     = blocknr;
1216                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1217                                 blocknr = STORAGE_get_free_big_blocknr(hf);
1218                                 if (blocknr<0)
1219                                         return E_FAIL;
1220                                 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1221                                         return E_FAIL;
1222                                 lastblocknr = blocknr;
1223                         }
1224                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1225                                 return E_FAIL;
1226                 } else {
1227                         if (newsize < 0x1000) {
1228                                 /* find startblock */
1229                                 if (!oldsize)
1230                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1231                                 else
1232                                         blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1233                                 if (blocknr<0)
1234                                         return E_FAIL;
1235
1236                                 /* allocate required new small blocks */
1237                                 lastblocknr = blocknr;
1238                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1239                                         blocknr = STORAGE_get_free_small_blocknr(hf);
1240                                         if (blocknr<0)
1241                                                 return E_FAIL;
1242                                         if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1243                                                 return E_FAIL;
1244                                         lastblocknr = blocknr;
1245                                 }
1246                                 /* and terminate the chain */
1247                                 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1248                                         return E_FAIL;
1249                         } else {
1250                                 if (!oldsize) {
1251                                         /* no single block allocated yet */
1252                                         blocknr=STORAGE_get_free_big_blocknr(hf);
1253                                         if (blocknr<0)
1254                                                 return E_FAIL;
1255                                         This->stde.pps_sb = blocknr;
1256                                 } else {
1257                                         /* Migrate small blocks to big blocks */
1258                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1259                                         HRESULT r = E_FAIL;
1260
1261                                         cc      = oldsize;
1262                                         blocknr = This->stde.pps_sb;
1263                                         curdata = data;
1264                                         /* slurp in */
1265                                         while (cc>0) {
1266                                                 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1267                                                         goto err2;
1268                                                 curdata += SMALLSIZE;
1269                                                 cc      -= SMALLSIZE;
1270                                                 blocknr  = STORAGE_get_next_small_blocknr(hf,blocknr);
1271                                         }
1272                                         /* free small block chain */
1273                                         if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1274                                                 goto err2;
1275                                         curdata = data;
1276                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1277                                         if (blocknr<0)
1278                                                 goto err2;
1279                                         /* put the data into the big blocks */
1280                                         cc      = This->stde.pps_size;
1281                                         while (cc>0) {
1282                                                 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1283                                                         goto err2;
1284                                                 cc      -= BIGSIZE;
1285                                                 if (cc<=0) {
1286                                                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1287                                                                 goto err2;
1288                                                         break;
1289                                                 } else {
1290                                                         int newblocknr = STORAGE_get_free_big_blocknr(hf);
1291                                                         if (newblocknr<0)
1292                                                                 goto err2;
1293                                                         if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1294                                                                 goto err2;
1295                                                         blocknr = newblocknr;
1296                                                 }
1297                                                 curdata += BIGSIZE;
1298                                         }
1299                                         r = S_OK;
1300                                 err2:
1301                                         HeapFree(GetProcessHeap(),0,data);
1302                                         if(r != S_OK)
1303                                                 return r;
1304                                 }
1305                                 /* generate big blocks to fit the new data */
1306                                 lastblocknr     = blocknr;
1307                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1308                                         blocknr = STORAGE_get_free_big_blocknr(hf);
1309                                         if (blocknr<0)
1310                                                 return E_FAIL;
1311                                         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1312                                                 return E_FAIL;
1313                                         lastblocknr = blocknr;
1314                                 }
1315                                 /* terminate chain */
1316                                 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1317                                         return E_FAIL;
1318                         }
1319                 }
1320                 This->stde.pps_size = newsize;
1321         }
1322
1323         /* There are just some cases where we didn't modify it, we write it out
1324          * everytime
1325          */
1326         if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1327                 return E_FAIL;
1328
1329         /* finally the write pass */
1330         if (This->stde.pps_size < 0x1000) {
1331                 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1332                 assert(blocknr>=0);
1333                 while (cb>0) {
1334                         /* we ensured that it is allocated above */
1335                         assert(blocknr>=0);
1336                         /* Read old block everytime, since we can have
1337                          * overlapping data at START and END of the write
1338                          */
1339                         if (!STORAGE_get_small_block(hf,blocknr,block))
1340                                 return E_FAIL;
1341
1342                         cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1343                         if (cc>cb)
1344                                 cc=cb;
1345                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1346                                 pbv+curoffset,
1347                                 cc
1348                         );
1349                         if (!STORAGE_put_small_block(hf,blocknr,block))
1350                                 return E_FAIL;
1351                         cb                      -= cc;
1352                         curoffset               += cc;
1353                         pbv                     += cc;
1354                         This->offset.u.LowPart  += cc;
1355                         *byteswritten           += cc;
1356                         blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1357                 }
1358         } else {
1359                 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1360                 assert(blocknr>=0);
1361                 while (cb>0) {
1362                         /* we ensured that it is allocated above, so it better is */
1363                         assert(blocknr>=0);
1364                         /* read old block everytime, since we can have
1365                          * overlapping data at START and END of the write
1366                          */
1367                         if (!STORAGE_get_big_block(hf,blocknr,block))
1368                                 return E_FAIL;
1369
1370                         cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1371                         if (cc>cb)
1372                                 cc=cb;
1373                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1374                                 pbv+curoffset,
1375                                 cc
1376                         );
1377                         if (!STORAGE_put_big_block(hf,blocknr,block))
1378                                 return E_FAIL;
1379                         cb                      -= cc;
1380                         curoffset               += cc;
1381                         pbv                     += cc;
1382                         This->offset.u.LowPart  += cc;
1383                         *byteswritten           += cc;
1384                         blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1385                 }
1386         }
1387         return S_OK;
1388 }
1389
1390 /******************************************************************************
1391  *              _create_istream16       [Internal]
1392  */
1393 static void _create_istream16(LPSTREAM16 *str) {
1394         IStream16Impl*  lpst;
1395
1396         if (!strvt16.QueryInterface) {
1397                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1398                 if (wp>=32) {
1399                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1400 #define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1401                         VTENT(QueryInterface);
1402                         VTENT(AddRef);
1403                         VTENT(Release);
1404                         VTENT(Read);
1405                         VTENT(Write);
1406                         VTENT(Seek);
1407                         VTENT(SetSize);
1408                         VTENT(CopyTo);
1409                         VTENT(Commit);
1410                         VTENT(Revert);
1411                         VTENT(LockRegion);
1412                         VTENT(UnlockRegion);
1413                         VTENT(Stat);
1414                         VTENT(Clone);
1415 #undef VTENT
1416                         segstrvt16 = (IStream16Vtbl*)MapLS( &strvt16 );
1417                 } else {
1418 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1419                         VTENT(QueryInterface);
1420                         VTENT(AddRef);
1421                         VTENT(Release);
1422                         VTENT(Read);
1423                         VTENT(Write);
1424                         VTENT(Seek);
1425         /*
1426                         VTENT(CopyTo);
1427                         VTENT(Commit);
1428                         VTENT(SetSize);
1429                         VTENT(Revert);
1430                         VTENT(LockRegion);
1431                         VTENT(UnlockRegion);
1432                         VTENT(Stat);
1433                         VTENT(Clone);
1434         */
1435 #undef VTENT
1436                         segstrvt16 = &strvt16;
1437                 }
1438         }
1439         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1440         lpst->lpVtbl    = segstrvt16;
1441         lpst->ref       = 1;
1442         lpst->thisptr   = MapLS( lpst );
1443         *str = (void*)lpst->thisptr;
1444 }
1445
1446
1447 /* --- IStream32 implementation */
1448
1449 typedef struct
1450 {
1451         /* IUnknown fields */
1452         IStreamVtbl                    *lpVtbl;
1453         DWORD                           ref;
1454         /* IStream32 fields */
1455         struct storage_pps_entry        stde;
1456         int                             ppsent;
1457         HANDLE                         hf;
1458         ULARGE_INTEGER                  offset;
1459 } IStream32Impl;
1460
1461 /*****************************************************************************
1462  *              IStream32_QueryInterface        [VTABLE]
1463  */
1464 HRESULT WINAPI IStream_fnQueryInterface(
1465         IStream* iface,REFIID refiid,LPVOID *obj
1466 ) {
1467         IStream32Impl *This = (IStream32Impl *)iface;
1468
1469         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1470         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1471                 *obj = This;
1472                 return 0;
1473         }
1474         return OLE_E_ENUM_NOMORE;
1475
1476 }
1477
1478 /******************************************************************************
1479  * IStream32_AddRef [VTABLE]
1480  */
1481 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1482         IStream32Impl *This = (IStream32Impl *)iface;
1483         return InterlockedIncrement(&This->ref);
1484 }
1485
1486 /******************************************************************************
1487  * IStream32_Release [VTABLE]
1488  */
1489 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1490         IStream32Impl *This = (IStream32Impl *)iface;
1491         ULONG ref;
1492         FlushFileBuffers(This->hf);
1493         ref = InterlockedDecrement(&This->ref);
1494         if (!ref) {
1495                 CloseHandle(This->hf);
1496                 HeapFree( GetProcessHeap(), 0, This );
1497         }
1498         return ref;
1499 }
1500
1501 /* --- IStorage16 implementation */
1502
1503 typedef struct
1504 {
1505         /* IUnknown fields */
1506         IStorage16Vtbl                 *lpVtbl;
1507         DWORD                           ref;
1508         /* IStorage16 fields */
1509         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1510         struct storage_pps_entry        stde;
1511         int                             ppsent;
1512         HANDLE                         hf;
1513 } IStorage16Impl;
1514
1515 /******************************************************************************
1516  *              IStorage16_QueryInterface       [STORAGE.500]
1517  */
1518 HRESULT WINAPI IStorage16_fnQueryInterface(
1519         IStorage16* iface,REFIID refiid,LPVOID *obj
1520 ) {
1521         IStorage16Impl *This = (IStorage16Impl *)iface;
1522
1523         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1524
1525         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1526                 *obj = This;
1527                 return 0;
1528         }
1529         return OLE_E_ENUM_NOMORE;
1530 }
1531
1532 /******************************************************************************
1533  * IStorage16_AddRef [STORAGE.501]
1534  */
1535 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1536         IStorage16Impl *This = (IStorage16Impl *)iface;
1537         return InterlockedIncrement(&This->ref);
1538 }
1539
1540 /******************************************************************************
1541  * IStorage16_Release [STORAGE.502]
1542  */
1543 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1544         IStorage16Impl *This = (IStorage16Impl *)iface;
1545         ULONG ref;
1546         ref = InterlockedDecrement(&This->ref);
1547         if (!ref)
1548         {
1549             UnMapLS( This->thisptr );
1550             HeapFree( GetProcessHeap(), 0, This );
1551         }
1552         return ref;
1553 }
1554
1555 /******************************************************************************
1556  * IStorage16_Stat [STORAGE.517]
1557  */
1558 HRESULT WINAPI IStorage16_fnStat(
1559         LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1560 ) {
1561         IStorage16Impl *This = (IStorage16Impl *)iface;
1562         DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1563         LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1564
1565         TRACE("(%p)->(%p,0x%08lx)\n",
1566                 This,pstatstg,grfStatFlag
1567         );
1568         WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1569         pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1570         pstatstg->type = This->stde.pps_type;
1571         pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1572         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1573         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1574         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1575         pstatstg->grfMode       = 0; /* FIXME */
1576         pstatstg->grfLocksSupported = 0; /* FIXME */
1577         pstatstg->clsid         = This->stde.pps_guid;
1578         pstatstg->grfStateBits  = 0; /* FIXME */
1579         pstatstg->reserved      = 0;
1580         return S_OK;
1581 }
1582
1583 /******************************************************************************
1584  *              IStorage16_Commit       [STORAGE.509]
1585  */
1586 HRESULT WINAPI IStorage16_fnCommit(
1587         LPSTORAGE16 iface,DWORD commitflags
1588 ) {
1589         IStorage16Impl *This = (IStorage16Impl *)iface;
1590         FIXME("(%p)->(0x%08lx),STUB!\n",
1591                 This,commitflags
1592         );
1593         return S_OK;
1594 }
1595
1596 /******************************************************************************
1597  * IStorage16_CopyTo [STORAGE.507]
1598  */
1599 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1600         IStorage16Impl *This = (IStorage16Impl *)iface;
1601         FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1602                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1603         );
1604         return S_OK;
1605 }
1606
1607
1608 /******************************************************************************
1609  * IStorage16_CreateStorage [STORAGE.505]
1610  */
1611 HRESULT WINAPI IStorage16_fnCreateStorage(
1612         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1613 ) {
1614         IStorage16Impl *This = (IStorage16Impl *)iface;
1615         IStorage16Impl* lpstg;
1616         int             ppsent,x;
1617         struct storage_pps_entry        stde;
1618         struct storage_header sth;
1619         HANDLE          hf=This->hf;
1620         BOOL ret;
1621         int      nPPSEntries;
1622
1623         READ_HEADER;
1624
1625         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1626                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1627         );
1628         if (grfMode & STGM_TRANSACTED)
1629                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1630         _create_istorage16(ppstg);
1631         lpstg = MapSL((SEGPTR)*ppstg);
1632         lpstg->hf               = This->hf;
1633
1634         ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1635         if (ppsent<0)
1636                 return E_FAIL;
1637         stde=This->stde;
1638         if (stde.pps_dir==-1) {
1639                 stde.pps_dir = ppsent;
1640                 x = This->ppsent;
1641         } else {
1642                 FIXME(" use prev chain too ?\n");
1643                 x=stde.pps_dir;
1644                 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1645                         return E_FAIL;
1646                 while (stde.pps_next!=-1) {
1647                         x=stde.pps_next;
1648                         if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1649                                 return E_FAIL;
1650                 }
1651                 stde.pps_next = ppsent;
1652         }
1653         ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1654         assert(ret);
1655         nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1656         assert(nPPSEntries == 1);
1657         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1658                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1659         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1660         lpstg->stde.pps_next    = -1;
1661         lpstg->stde.pps_prev    = -1;
1662         lpstg->stde.pps_dir     = -1;
1663         lpstg->stde.pps_sb      = -1;
1664         lpstg->stde.pps_size    =  0;
1665         lpstg->stde.pps_type    =  1;
1666         lpstg->ppsent           = ppsent;
1667         /* FIXME: timestamps? */
1668         if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1669                 return E_FAIL;
1670         return S_OK;
1671 }
1672
1673 /******************************************************************************
1674  *              IStorage16_CreateStream [STORAGE.503]
1675  */
1676 HRESULT WINAPI IStorage16_fnCreateStream(
1677         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1678 ) {
1679         IStorage16Impl *This = (IStorage16Impl *)iface;
1680         IStream16Impl*  lpstr;
1681         int             ppsent,x;
1682         struct storage_pps_entry        stde;
1683         BOOL ret;
1684         int      nPPSEntries;
1685
1686         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1687                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1688         );
1689         if (grfMode & STGM_TRANSACTED)
1690                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1691         _create_istream16(ppstm);
1692         lpstr = MapSL((SEGPTR)*ppstm);
1693         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1694                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1695         lpstr->offset.u.LowPart = 0;
1696         lpstr->offset.u.HighPart        = 0;
1697
1698         ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1699         if (ppsent<0)
1700                 return E_FAIL;
1701         stde=This->stde;
1702         if (stde.pps_next==-1)
1703                 x=This->ppsent;
1704         else
1705                 while (stde.pps_next!=-1) {
1706                         x=stde.pps_next;
1707                         if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1708                                 return E_FAIL;
1709                 }
1710         stde.pps_next = ppsent;
1711         ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1712         assert(ret);
1713         nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1714         assert(nPPSEntries == 1);
1715         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1716                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1717         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1718         lpstr->stde.pps_next    = -1;
1719         lpstr->stde.pps_prev    = -1;
1720         lpstr->stde.pps_dir     = -1;
1721         lpstr->stde.pps_sb      = -1;
1722         lpstr->stde.pps_size    =  0;
1723         lpstr->stde.pps_type    =  2;
1724         lpstr->ppsent           = ppsent;
1725         /* FIXME: timestamps? */
1726         if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1727                 return E_FAIL;
1728         return S_OK;
1729 }
1730
1731 /******************************************************************************
1732  *              IStorage16_OpenStorage  [STORAGE.506]
1733  */
1734 HRESULT WINAPI IStorage16_fnOpenStorage(
1735         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1736 ) {
1737         IStorage16Impl *This = (IStorage16Impl *)iface;
1738         IStream16Impl*  lpstg;
1739         WCHAR           name[33];
1740         int             newpps;
1741
1742         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1743                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1744         );
1745         if (grfMode & STGM_TRANSACTED)
1746                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1747         _create_istorage16(ppstg);
1748         lpstg = MapSL((SEGPTR)*ppstg);
1749         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1750                          &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1751         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1752         newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1753         if (newpps==-1) {
1754                 IStream16_fnRelease((IStream16*)lpstg);
1755                 return E_FAIL;
1756         }
1757
1758         if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1759                 IStream16_fnRelease((IStream16*)lpstg);
1760                 return E_FAIL;
1761         }
1762         lpstg->ppsent           = newpps;
1763         return S_OK;
1764 }
1765
1766 /******************************************************************************
1767  * IStorage16_OpenStream [STORAGE.504]
1768  */
1769 HRESULT WINAPI IStorage16_fnOpenStream(
1770         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1771 ) {
1772         IStorage16Impl *This = (IStorage16Impl *)iface;
1773         IStream16Impl*  lpstr;
1774         WCHAR           name[33];
1775         int             newpps;
1776
1777         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1778                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1779         );
1780         if (grfMode & STGM_TRANSACTED)
1781                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1782         _create_istream16(ppstm);
1783         lpstr = MapSL((SEGPTR)*ppstm);
1784         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1785                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1786         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1787         newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1788         if (newpps==-1) {
1789                 IStream16_fnRelease((IStream16*)lpstr);
1790                 return E_FAIL;
1791         }
1792
1793         if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1794                 IStream16_fnRelease((IStream16*)lpstr);
1795                 return E_FAIL;
1796         }
1797         lpstr->offset.u.LowPart = 0;
1798         lpstr->offset.u.HighPart        = 0;
1799         lpstr->ppsent           = newpps;
1800         return S_OK;
1801 }
1802
1803 /******************************************************************************
1804  * _create_istorage16 [INTERNAL]
1805  */
1806 static void _create_istorage16(LPSTORAGE16 *stg) {
1807         IStorage16Impl* lpst;
1808
1809         if (!stvt16.QueryInterface) {
1810                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1811                 if (wp>=32) {
1812 #define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1813                         VTENT(QueryInterface)
1814                         VTENT(AddRef)
1815                         VTENT(Release)
1816                         VTENT(CreateStream)
1817                         VTENT(OpenStream)
1818                         VTENT(CreateStorage)
1819                         VTENT(OpenStorage)
1820                         VTENT(CopyTo)
1821                         VTENT(MoveElementTo)
1822                         VTENT(Commit)
1823                         VTENT(Revert)
1824                         VTENT(EnumElements)
1825                         VTENT(DestroyElement)
1826                         VTENT(RenameElement)
1827                         VTENT(SetElementTimes)
1828                         VTENT(SetClass)
1829                         VTENT(SetStateBits)
1830                         VTENT(Stat)
1831 #undef VTENT
1832                         segstvt16 = (IStorage16Vtbl*)MapLS( &stvt16 );
1833                 } else {
1834 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1835                         VTENT(QueryInterface)
1836                         VTENT(AddRef)
1837                         VTENT(Release)
1838                         VTENT(CreateStream)
1839                         VTENT(OpenStream)
1840                         VTENT(CreateStorage)
1841                         VTENT(OpenStorage)
1842                         VTENT(CopyTo)
1843                         VTENT(Commit)
1844         /*  not (yet) implemented ...
1845                         VTENT(MoveElementTo)
1846                         VTENT(Revert)
1847                         VTENT(EnumElements)
1848                         VTENT(DestroyElement)
1849                         VTENT(RenameElement)
1850                         VTENT(SetElementTimes)
1851                         VTENT(SetClass)
1852                         VTENT(SetStateBits)
1853                         VTENT(Stat)
1854         */
1855 #undef VTENT
1856                         segstvt16 = &stvt16;
1857                 }
1858         }
1859         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1860         lpst->lpVtbl    = segstvt16;
1861         lpst->ref       = 1;
1862         lpst->thisptr   = MapLS(lpst);
1863         *stg = (void*)lpst->thisptr;
1864 }
1865
1866 /******************************************************************************
1867  *      Storage API functions
1868  */
1869
1870 /******************************************************************************
1871  *              StgCreateDocFileA       [STORAGE.1]
1872  */
1873 HRESULT WINAPI StgCreateDocFile16(
1874         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1875 ) {
1876         HANDLE          hf;
1877         int             i,ret;
1878         IStorage16Impl* lpstg;
1879         struct storage_pps_entry        stde;
1880
1881         TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1882                 pwcsName,grfMode,reserved,ppstgOpen
1883         );
1884         _create_istorage16(ppstgOpen);
1885         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1886         if (hf==INVALID_HANDLE_VALUE) {
1887                 WARN("couldn't open file for storage:%ld\n",GetLastError());
1888                 return E_FAIL;
1889         }
1890         lpstg = MapSL((SEGPTR)*ppstgOpen);
1891         lpstg->hf = hf;
1892         /* FIXME: check for existence before overwriting? */
1893         if (!STORAGE_init_storage(hf)) {
1894                 CloseHandle(hf);
1895                 return E_FAIL;
1896         }
1897         i=0;ret=0;
1898         while (!ret) { /* neither 1 nor <0 */
1899                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1900                 if ((ret==1) && (stde.pps_type==5)) {
1901                         lpstg->stde     = stde;
1902                         lpstg->ppsent   = i;
1903                         break;
1904                 }
1905                 i++;
1906         }
1907         if (ret!=1) {
1908                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1909                 return E_FAIL;
1910         }
1911
1912         return S_OK;
1913 }
1914
1915 /******************************************************************************
1916  * StgIsStorageFile [STORAGE.5]
1917  */
1918 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1919         UNICODE_STRING strW;
1920         HRESULT ret;
1921
1922         RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1923         ret = StgIsStorageFile( strW.Buffer );
1924         RtlFreeUnicodeString( &strW );
1925
1926         return ret;
1927 }
1928
1929 /******************************************************************************
1930  * StgOpenStorage [STORAGE.3]
1931  */
1932 HRESULT WINAPI StgOpenStorage16(
1933         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1934         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1935 ) {
1936         HANDLE          hf;
1937         int             ret,i;
1938         IStorage16Impl* lpstg;
1939         struct storage_pps_entry        stde;
1940
1941         TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1942               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1943         );
1944         _create_istorage16(ppstgOpen);
1945         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1946         if (hf==INVALID_HANDLE_VALUE) {
1947                 WARN("Couldn't open file for storage\n");
1948                 return E_FAIL;
1949         }
1950         lpstg = MapSL((SEGPTR)*ppstgOpen);
1951         lpstg->hf = hf;
1952
1953         i=0;ret=0;
1954         while (!ret) { /* neither 1 nor <0 */
1955                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1956                 if ((ret==1) && (stde.pps_type==5)) {
1957                         lpstg->stde=stde;
1958                         break;
1959                 }
1960                 i++;
1961         }
1962         if (ret!=1) {
1963                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1964                 return E_FAIL;
1965         }
1966         return S_OK;
1967
1968 }
1969
1970 /******************************************************************************
1971  *              StgIsStorageILockBytes        [STORAGE.6]
1972  *
1973  * Determines if the ILockBytes contains a storage object.
1974  */
1975 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1976 {
1977   DWORD args[6];
1978   HRESULT hres;
1979   HANDLE16 hsig;
1980   
1981   args[0] = (DWORD)plkbyt;      /* iface */
1982   args[1] = args[2] = 0;        /* ULARGE_INTEGER offset */
1983   args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1984   args[4] = 8;
1985   args[5] = 0;
1986
1987   if (!K32WOWCallback16Ex(
1988       (DWORD)((ILockBytes16Vtbl*)MapSL(
1989                   (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1990       )->ReadAt,
1991       WCB16_PASCAL,
1992       6*sizeof(DWORD),
1993       (LPVOID)args,
1994       (LPDWORD)&hres
1995   )) {
1996       ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1997       return hres;
1998   }
1999   if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
2000     K32WOWGlobalUnlockFree16(args[3]);
2001     return S_OK;
2002   }
2003   K32WOWGlobalUnlockFree16(args[3]);
2004   return S_FALSE;
2005 }
2006
2007 /******************************************************************************
2008  *    StgOpenStorageOnILockBytes    [STORAGE.4]
2009  */
2010 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2011       ILockBytes16 *plkbyt,
2012       IStorage16 *pstgPriority,
2013       DWORD grfMode,
2014       SNB16 snbExclude,
2015       DWORD reserved,
2016       IStorage16 **ppstgOpen)
2017 {
2018   IStorage16Impl*       lpstg;
2019
2020   if ((plkbyt == 0) || (ppstgOpen == 0))
2021     return STG_E_INVALIDPOINTER;
2022
2023   *ppstgOpen = 0;
2024
2025   _create_istorage16(ppstgOpen);
2026   lpstg = MapSL((SEGPTR)*ppstgOpen);
2027
2028   /* just teach it to use HANDLE instead of ilockbytes :/ */
2029
2030   return S_OK;
2031 }