Allow specification of "DLLMODE=native" for native dlls.
[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 ICOM_VTABLE(IStorage16) stvt16;
94 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
95 static ICOM_VTABLE(IStream16) strvt16;
96 static ICOM_VTABLE(IStream16) *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,curblock,bigblocknr;
770         struct storage_header sth;
771         BOOL ret;
772
773         READ_HEADER;
774         curblock        = 0;
775         lastbigblocknr  = -1;
776         bigblocknr      = sth.bbd_list[curblock];
777         while (curblock<sth.num_of_bbd_blocks) {
778                 assert(bigblocknr>=0);
779                 ret = STORAGE_get_big_block(hf,bigblocknr,block);
780                 assert(ret);
781                 for (i=0;i<128;i++)
782                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
783                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
784                                 ret = STORAGE_put_big_block(hf,bigblocknr,block);
785                                 assert(ret);
786                                 memset(block,0x42,sizeof(block));
787                                 ret = STORAGE_put_big_block(hf,i+curblock*128,block);
788                                 assert(ret);
789                                 return i+curblock*128;
790                         }
791                 lastbigblocknr = bigblocknr;
792                 bigblocknr = sth.bbd_list[++curblock];
793         }
794         bigblocknr = curblock*128;
795         /* since we have marked all blocks from 0 up to curblock*128-1
796          * the next free one is curblock*128, where we happily put our
797          * next large block depot.
798          */
799         memset(block,0xff,sizeof(block));
800         /* mark the block allocated and returned by this function */
801         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
802         ret = STORAGE_put_big_block(hf,bigblocknr,block);
803         assert(ret);
804
805         /* if we had a bbd block already (mostlikely) we need
806          * to link the new one into the chain
807          */
808         if (lastbigblocknr!=-1) {
809                 ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr);
810                 assert(ret);
811         }
812         sth.bbd_list[curblock]=bigblocknr;
813         sth.num_of_bbd_blocks++;
814         assert(sth.num_of_bbd_blocks==curblock+1);
815         ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth);
816         assert(ret);
817
818         /* Set the end of the chain for the bigblockdepots */
819         ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
820         assert(ret);
821         /* add 1, for the first entry is used for the additional big block
822          * depot. (means we already used bigblocknr) */
823         memset(block,0x42,sizeof(block));
824         /* allocate this block (filled with 0x42) */
825         ret = STORAGE_put_big_block(hf,bigblocknr+1,block);
826         assert(ret);
827         return bigblocknr+1;
828 }
829
830
831 /******************************************************************************
832  *              STORAGE_get_free_small_blocknr  [Internal]
833  */
834 static int
835 STORAGE_get_free_small_blocknr(HANDLE hf) {
836         BYTE    block[BIGSIZE];
837         LPINT   sbd = (LPINT)block;
838         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
839         struct storage_pps_entry        root;
840         struct storage_header sth;
841
842         READ_HEADER;
843         bigblocknr      = sth.sbd_startblock;
844         curblock        = 0;
845         lastbigblocknr  = -1;
846         newblocknr      = -1;
847         while (bigblocknr>=0) {
848                 if (!STORAGE_get_big_block(hf,bigblocknr,block))
849                         return -1;
850                 for (i=0;i<128;i++)
851                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
852                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
853                                 newblocknr = i+curblock*128;
854                                 break;
855                         }
856                 if (i!=128)
857                         break;
858                 lastbigblocknr = bigblocknr;
859                 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
860                 curblock++;
861         }
862         if (newblocknr==-1) {
863                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
864                 if (bigblocknr<0)
865                         return -1;
866                 READ_HEADER;
867                 memset(block,0xff,sizeof(block));
868                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
869                 if (!STORAGE_put_big_block(hf,bigblocknr,block))
870                         return -1;
871                 if (lastbigblocknr==-1) {
872                         sth.sbd_startblock = bigblocknr;
873                         if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
874                                 return -1;
875                 } else {
876                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
877                                 return -1;
878                 }
879                 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
880                         return -1;
881                 newblocknr = curblock*128;
882         }
883         /* allocate enough big blocks for storing the allocated small block */
884         if (!STORAGE_get_root_pps_entry(hf,&root))
885                 return -1;
886         if (root.pps_sb==-1)
887                 lastbigblocknr  = -1;
888         else
889                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
890         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
891                 /* we need to allocate more stuff */
892                 bigblocknr = STORAGE_get_free_big_blocknr(hf);
893                 if (bigblocknr<0)
894                         return -1;
895                 READ_HEADER;
896                 if (root.pps_sb==-1) {
897                         root.pps_sb      = bigblocknr;
898                         root.pps_size   += BIGSIZE;
899                 } else {
900                         if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
901                                 return -1;
902                         root.pps_size   += BIGSIZE;
903                 }
904                 lastbigblocknr = bigblocknr;
905         }
906         if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
907                 return -1;
908         if (!STORAGE_put_pps_entry(hf,0,&root))
909                 return -1;
910         return newblocknr;
911 }
912
913 /******************************************************************************
914  *              STORAGE_get_free_pps_entry      [Internal]
915  */
916 static int
917 STORAGE_get_free_pps_entry(HANDLE hf) {
918         int     blocknr, i, curblock, lastblocknr=-1;
919         BYTE    block[BIGSIZE];
920         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
921         struct storage_header sth;
922
923         READ_HEADER;
924         blocknr = sth.root_startblock;
925         assert(blocknr>=0);
926         curblock=0;
927         while (blocknr>=0) {
928                 if (!STORAGE_get_big_block(hf,blocknr,block))
929                         return -1;
930                 for (i=0;i<4;i++)
931                         if (stde[i].pps_sizeofname==0) /* free */
932                                 return curblock*4+i;
933                 lastblocknr = blocknr;
934                 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
935                 curblock++;
936         }
937         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
938         blocknr = STORAGE_get_free_big_blocknr(hf);
939         /* sth invalidated */
940         if (blocknr<0)
941                 return -1;
942
943         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
944                 return -1;
945         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
946                 return -1;
947         memset(block,0,sizeof(block));
948         STORAGE_put_big_block(hf,blocknr,block);
949         return curblock*4;
950 }
951
952 /* --- IStream16 implementation */
953
954 typedef struct
955 {
956         /* IUnknown fields */
957         ICOM_VFIELD(IStream16);
958         DWORD                           ref;
959         /* IStream16 fields */
960         SEGPTR                          thisptr; /* pointer to this struct as segmented */
961         struct storage_pps_entry        stde;
962         int                             ppsent;
963         HANDLE                         hf;
964         ULARGE_INTEGER                  offset;
965 } IStream16Impl;
966
967 /******************************************************************************
968  *              IStream16_QueryInterface        [STORAGE.518]
969  */
970 HRESULT WINAPI IStream16_fnQueryInterface(
971         IStream16* iface,REFIID refiid,LPVOID *obj
972 ) {
973         ICOM_THIS(IStream16Impl,iface);
974         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
975         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
976                 *obj = This;
977                 return 0;
978         }
979         return OLE_E_ENUM_NOMORE;
980
981 }
982
983 /******************************************************************************
984  * IStream16_AddRef [STORAGE.519]
985  */
986 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
987         ICOM_THIS(IStream16Impl,iface);
988         return ++(This->ref);
989 }
990
991 /******************************************************************************
992  * IStream16_Release [STORAGE.520]
993  */
994 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
995         ICOM_THIS(IStream16Impl,iface);
996         FlushFileBuffers(This->hf);
997         This->ref--;
998         if (!This->ref) {
999                 CloseHandle(This->hf);
1000                 UnMapLS( This->thisptr );
1001                 HeapFree( GetProcessHeap(), 0, This );
1002                 return 0;
1003         }
1004         return This->ref;
1005 }
1006
1007 /******************************************************************************
1008  *              IStream16_Seek  [STORAGE.523]
1009  *
1010  * FIXME
1011  *    Does not handle 64 bits
1012  */
1013 HRESULT WINAPI IStream16_fnSeek(
1014         IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
1015 ) {
1016         ICOM_THIS(IStream16Impl,iface);
1017         TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
1018
1019         switch (whence) {
1020         /* unix SEEK_xx should be the same as win95 ones */
1021         case SEEK_SET:
1022                 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
1023                  * right now.
1024                  */
1025                 assert(offset.u.HighPart==0);
1026                 This->offset.u.HighPart = offset.u.HighPart;
1027                 This->offset.u.LowPart = offset.u.LowPart;
1028                 break;
1029         case SEEK_CUR:
1030                 if (offset.u.HighPart < 0) {
1031                         /* FIXME: is this negation correct ? */
1032                         offset.u.HighPart = -offset.u.HighPart;
1033                         offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
1034
1035                         assert(offset.u.HighPart==0);
1036                         assert(This->offset.u.LowPart >= offset.u.LowPart);
1037                         This->offset.u.LowPart -= offset.u.LowPart;
1038                 } else {
1039                         assert(offset.u.HighPart==0);
1040                         This->offset.u.LowPart+= offset.u.LowPart;
1041                 }
1042                 break;
1043         case SEEK_END:
1044                 assert(offset.u.HighPart==0);
1045                 This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
1046                 break;
1047         }
1048         if (This->offset.u.LowPart>This->stde.pps_size)
1049                 This->offset.u.LowPart=This->stde.pps_size;
1050         if (newpos) *newpos = This->offset;
1051         return S_OK;
1052 }
1053
1054 /******************************************************************************
1055  *              IStream16_Read  [STORAGE.521]
1056  */
1057 HRESULT WINAPI IStream16_fnRead(
1058         IStream16* iface,void  *pv,ULONG cb,ULONG  *pcbRead
1059 ) {
1060         ICOM_THIS(IStream16Impl,iface);
1061         BYTE    block[BIGSIZE];
1062         ULONG   *bytesread=pcbRead,xxread;
1063         int     blocknr;
1064
1065         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
1066         if (!pcbRead) bytesread=&xxread;
1067         *bytesread = 0;
1068
1069         if (cb>This->stde.pps_size-This->offset.u.LowPart)
1070                 cb=This->stde.pps_size-This->offset.u.LowPart;
1071         if (This->stde.pps_size < 0x1000) {
1072                 /* use small block reader */
1073                 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1074                 while (cb) {
1075                         int     cc;
1076
1077                         if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
1078                            WARN("small block read failed!!!\n");
1079                                 return E_FAIL;
1080                         }
1081                         cc = cb;
1082                         if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1083                                 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1084                         memcpy((LPBYTE)pv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1085                         This->offset.u.LowPart+=cc;
1086                         (LPBYTE)pv+=cc;
1087                         *bytesread+=cc;
1088                         cb-=cc;
1089                         blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
1090                 }
1091         } else {
1092                 /* use big block reader */
1093                 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1094                 while (cb) {
1095                         int     cc;
1096
1097                         if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
1098                                 WARN("big block read failed!!!\n");
1099                                 return E_FAIL;
1100                         }
1101                         cc = cb;
1102                         if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1103                                 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1104                         memcpy((LPBYTE)pv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1105                         This->offset.u.LowPart+=cc;
1106                         (LPBYTE)pv+=cc;
1107                         *bytesread+=cc;
1108                         cb-=cc;
1109                         blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
1110                 }
1111         }
1112         return S_OK;
1113 }
1114
1115 /******************************************************************************
1116  *              IStream16_Write [STORAGE.522]
1117  */
1118 HRESULT WINAPI IStream16_fnWrite(
1119         IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
1120 ) {
1121         ICOM_THIS(IStream16Impl,iface);
1122         BYTE    block[BIGSIZE];
1123         ULONG   *byteswritten=pcbWrite,xxwritten;
1124         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1125         HANDLE  hf = This->hf;
1126
1127         if (!pcbWrite) byteswritten=&xxwritten;
1128         *byteswritten = 0;
1129
1130         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
1131         /* do we need to junk some blocks? */
1132         newsize = This->offset.u.LowPart+cb;
1133         oldsize = This->stde.pps_size;
1134         if (newsize < oldsize) {
1135                 if (oldsize < 0x1000) {
1136                         /* only small blocks */
1137                         blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
1138
1139                         assert(blocknr>=0);
1140
1141                         /* will set the rest of the chain to 'free' */
1142                         if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1143                                 return E_FAIL;
1144                 } else {
1145                         if (newsize >= 0x1000) {
1146                                 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
1147                                 assert(blocknr>=0);
1148
1149                                 /* will set the rest of the chain to 'free' */
1150                                 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1151                                         return E_FAIL;
1152                         } else {
1153                                 /* Migrate large blocks to small blocks
1154                                  * (we just migrate newsize bytes)
1155                                  */
1156                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1157                                 HRESULT r = E_FAIL;
1158
1159                                 cc      = newsize;
1160                                 blocknr = This->stde.pps_sb;
1161                                 curdata = data;
1162                                 while (cc>0) {
1163                                         if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
1164                                                 HeapFree(GetProcessHeap(),0,data);
1165                                                 return E_FAIL;
1166                                         }
1167                                         curdata += BIGSIZE;
1168                                         cc      -= BIGSIZE;
1169                                         blocknr  = STORAGE_get_next_big_blocknr(hf,blocknr);
1170                                 }
1171                                 /* frees complete chain for this stream */
1172                                 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1173                                         goto err;
1174                                 curdata = data;
1175                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
1176                                 if (blocknr<0)
1177                                         goto err;
1178                                 cc      = newsize;
1179                                 while (cc>0) {
1180                                         if (!STORAGE_put_small_block(hf,blocknr,curdata))
1181                                                 goto err;
1182                                         cc      -= SMALLSIZE;
1183                                         if (cc<=0) {
1184                                                 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1185                                                         goto err;
1186                                                 break;
1187                                         } else {
1188                                                 int newblocknr = STORAGE_get_free_small_blocknr(hf);
1189                                                 if (newblocknr<0)
1190                                                         goto err;
1191                                                 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
1192                                                         goto err;
1193                                                 blocknr = newblocknr;
1194                                         }
1195                                         curdata += SMALLSIZE;
1196                                 }
1197                                 r = S_OK;
1198                         err:
1199                                 HeapFree(GetProcessHeap(),0,data);
1200                                 if(r != S_OK)
1201                                         return r;
1202                         }
1203                 }
1204                 This->stde.pps_size = newsize;
1205         }
1206
1207         if (newsize > oldsize) {
1208                 if (oldsize >= 0x1000) {
1209                         /* should return the block right before the 'endofchain' */
1210                         blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1211                         assert(blocknr>=0);
1212                         lastblocknr     = blocknr;
1213                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1214                                 blocknr = STORAGE_get_free_big_blocknr(hf);
1215                                 if (blocknr<0)
1216                                         return E_FAIL;
1217                                 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1218                                         return E_FAIL;
1219                                 lastblocknr = blocknr;
1220                         }
1221                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1222                                 return E_FAIL;
1223                 } else {
1224                         if (newsize < 0x1000) {
1225                                 /* find startblock */
1226                                 if (!oldsize)
1227                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1228                                 else
1229                                         blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1230                                 if (blocknr<0)
1231                                         return E_FAIL;
1232
1233                                 /* allocate required new small blocks */
1234                                 lastblocknr = blocknr;
1235                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1236                                         blocknr = STORAGE_get_free_small_blocknr(hf);
1237                                         if (blocknr<0)
1238                                                 return E_FAIL;
1239                                         if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1240                                                 return E_FAIL;
1241                                         lastblocknr = blocknr;
1242                                 }
1243                                 /* and terminate the chain */
1244                                 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1245                                         return E_FAIL;
1246                         } else {
1247                                 if (!oldsize) {
1248                                         /* no single block allocated yet */
1249                                         blocknr=STORAGE_get_free_big_blocknr(hf);
1250                                         if (blocknr<0)
1251                                                 return E_FAIL;
1252                                         This->stde.pps_sb = blocknr;
1253                                 } else {
1254                                         /* Migrate small blocks to big blocks */
1255                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1256                                         HRESULT r = E_FAIL;
1257
1258                                         cc      = oldsize;
1259                                         blocknr = This->stde.pps_sb;
1260                                         curdata = data;
1261                                         /* slurp in */
1262                                         while (cc>0) {
1263                                                 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1264                                                         goto err2;
1265                                                 curdata += SMALLSIZE;
1266                                                 cc      -= SMALLSIZE;
1267                                                 blocknr  = STORAGE_get_next_small_blocknr(hf,blocknr);
1268                                         }
1269                                         /* free small block chain */
1270                                         if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1271                                                 goto err2;
1272                                         curdata = data;
1273                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1274                                         if (blocknr<0)
1275                                                 goto err2;
1276                                         /* put the data into the big blocks */
1277                                         cc      = This->stde.pps_size;
1278                                         while (cc>0) {
1279                                                 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1280                                                         goto err2;
1281                                                 cc      -= BIGSIZE;
1282                                                 if (cc<=0) {
1283                                                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1284                                                                 goto err2;
1285                                                         break;
1286                                                 } else {
1287                                                         int newblocknr = STORAGE_get_free_big_blocknr(hf);
1288                                                         if (newblocknr<0)
1289                                                                 goto err2;
1290                                                         if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1291                                                                 goto err2;
1292                                                         blocknr = newblocknr;
1293                                                 }
1294                                                 curdata += BIGSIZE;
1295                                         }
1296                                         r = S_OK;
1297                                 err2:
1298                                         HeapFree(GetProcessHeap(),0,data);
1299                                         if(r != S_OK)
1300                                                 return r;
1301                                 }
1302                                 /* generate big blocks to fit the new data */
1303                                 lastblocknr     = blocknr;
1304                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1305                                         blocknr = STORAGE_get_free_big_blocknr(hf);
1306                                         if (blocknr<0)
1307                                                 return E_FAIL;
1308                                         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1309                                                 return E_FAIL;
1310                                         lastblocknr = blocknr;
1311                                 }
1312                                 /* terminate chain */
1313                                 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1314                                         return E_FAIL;
1315                         }
1316                 }
1317                 This->stde.pps_size = newsize;
1318         }
1319
1320         /* There are just some cases where we didn't modify it, we write it out
1321          * everytime
1322          */
1323         if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1324                 return E_FAIL;
1325
1326         /* finally the write pass */
1327         if (This->stde.pps_size < 0x1000) {
1328                 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1329                 assert(blocknr>=0);
1330                 while (cb>0) {
1331                         /* we ensured that it is allocated above */
1332                         assert(blocknr>=0);
1333                         /* Read old block everytime, since we can have
1334                          * overlapping data at START and END of the write
1335                          */
1336                         if (!STORAGE_get_small_block(hf,blocknr,block))
1337                                 return E_FAIL;
1338
1339                         cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1340                         if (cc>cb)
1341                                 cc=cb;
1342                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1343                                 (LPBYTE)((char *) pv+curoffset),
1344                                 cc
1345                         );
1346                         if (!STORAGE_put_small_block(hf,blocknr,block))
1347                                 return E_FAIL;
1348                         cb                      -= cc;
1349                         curoffset               += cc;
1350                         (LPBYTE)pv              += cc;
1351                         This->offset.u.LowPart  += cc;
1352                         *byteswritten           += cc;
1353                         blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1354                 }
1355         } else {
1356                 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1357                 assert(blocknr>=0);
1358                 while (cb>0) {
1359                         /* we ensured that it is allocated above, so it better is */
1360                         assert(blocknr>=0);
1361                         /* read old block everytime, since we can have
1362                          * overlapping data at START and END of the write
1363                          */
1364                         if (!STORAGE_get_big_block(hf,blocknr,block))
1365                                 return E_FAIL;
1366
1367                         cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1368                         if (cc>cb)
1369                                 cc=cb;
1370                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1371                                 (LPBYTE)((char *) pv+curoffset),
1372                                 cc
1373                         );
1374                         if (!STORAGE_put_big_block(hf,blocknr,block))
1375                                 return E_FAIL;
1376                         cb                      -= cc;
1377                         curoffset               += cc;
1378                         (LPBYTE)pv              += cc;
1379                         This->offset.u.LowPart  += cc;
1380                         *byteswritten           += cc;
1381                         blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1382                 }
1383         }
1384         return S_OK;
1385 }
1386
1387 /******************************************************************************
1388  *              _create_istream16       [Internal]
1389  */
1390 static void _create_istream16(LPSTREAM16 *str) {
1391         IStream16Impl*  lpst;
1392
1393         if (!strvt16.QueryInterface) {
1394                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1395                 if (wp>=32) {
1396                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1397 #define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1398                         VTENT(QueryInterface);
1399                         VTENT(AddRef);
1400                         VTENT(Release);
1401                         VTENT(Read);
1402                         VTENT(Write);
1403                         VTENT(Seek);
1404                         VTENT(SetSize);
1405                         VTENT(CopyTo);
1406                         VTENT(Commit);
1407                         VTENT(Revert);
1408                         VTENT(LockRegion);
1409                         VTENT(UnlockRegion);
1410                         VTENT(Stat);
1411                         VTENT(Clone);
1412 #undef VTENT
1413                         segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1414                 } else {
1415 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1416                         VTENT(QueryInterface);
1417                         VTENT(AddRef);
1418                         VTENT(Release);
1419                         VTENT(Read);
1420                         VTENT(Write);
1421                         VTENT(Seek);
1422         /*
1423                         VTENT(CopyTo);
1424                         VTENT(Commit);
1425                         VTENT(SetSize);
1426                         VTENT(Revert);
1427                         VTENT(LockRegion);
1428                         VTENT(UnlockRegion);
1429                         VTENT(Stat);
1430                         VTENT(Clone);
1431         */
1432 #undef VTENT
1433                         segstrvt16 = &strvt16;
1434                 }
1435         }
1436         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1437         lpst->lpVtbl    = segstrvt16;
1438         lpst->ref       = 1;
1439         lpst->thisptr   = MapLS( lpst );
1440         *str = (void*)lpst->thisptr;
1441 }
1442
1443
1444 /* --- IStream32 implementation */
1445
1446 typedef struct
1447 {
1448         /* IUnknown fields */
1449         ICOM_VFIELD(IStream);
1450         DWORD                           ref;
1451         /* IStream32 fields */
1452         struct storage_pps_entry        stde;
1453         int                             ppsent;
1454         HANDLE                         hf;
1455         ULARGE_INTEGER                  offset;
1456 } IStream32Impl;
1457
1458 /*****************************************************************************
1459  *              IStream32_QueryInterface        [VTABLE]
1460  */
1461 HRESULT WINAPI IStream_fnQueryInterface(
1462         IStream* iface,REFIID refiid,LPVOID *obj
1463 ) {
1464         ICOM_THIS(IStream32Impl,iface);
1465
1466         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1467         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1468                 *obj = This;
1469                 return 0;
1470         }
1471         return OLE_E_ENUM_NOMORE;
1472
1473 }
1474
1475 /******************************************************************************
1476  * IStream32_AddRef [VTABLE]
1477  */
1478 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1479         ICOM_THIS(IStream32Impl,iface);
1480         return ++(This->ref);
1481 }
1482
1483 /******************************************************************************
1484  * IStream32_Release [VTABLE]
1485  */
1486 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1487         ICOM_THIS(IStream32Impl,iface);
1488         FlushFileBuffers(This->hf);
1489         This->ref--;
1490         if (!This->ref) {
1491                 CloseHandle(This->hf);
1492                 HeapFree( GetProcessHeap(), 0, This );
1493                 return 0;
1494         }
1495         return This->ref;
1496 }
1497
1498 /* --- IStorage16 implementation */
1499
1500 typedef struct
1501 {
1502         /* IUnknown fields */
1503         ICOM_VFIELD(IStorage16);
1504         DWORD                           ref;
1505         /* IStorage16 fields */
1506         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1507         struct storage_pps_entry        stde;
1508         int                             ppsent;
1509         HANDLE                         hf;
1510 } IStorage16Impl;
1511
1512 /******************************************************************************
1513  *              IStorage16_QueryInterface       [STORAGE.500]
1514  */
1515 HRESULT WINAPI IStorage16_fnQueryInterface(
1516         IStorage16* iface,REFIID refiid,LPVOID *obj
1517 ) {
1518         ICOM_THIS(IStorage16Impl,iface);
1519
1520         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1521
1522         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1523                 *obj = This;
1524                 return 0;
1525         }
1526         return OLE_E_ENUM_NOMORE;
1527 }
1528
1529 /******************************************************************************
1530  * IStorage16_AddRef [STORAGE.501]
1531  */
1532 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1533         ICOM_THIS(IStorage16Impl,iface);
1534         return ++(This->ref);
1535 }
1536
1537 /******************************************************************************
1538  * IStorage16_Release [STORAGE.502]
1539  */
1540 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1541         ICOM_THIS(IStorage16Impl,iface);
1542         This->ref--;
1543         if (This->ref)
1544                 return This->ref;
1545         UnMapLS( This->thisptr );
1546         HeapFree( GetProcessHeap(), 0, This );
1547         return 0;
1548 }
1549
1550 /******************************************************************************
1551  * IStorage16_Stat [STORAGE.517]
1552  */
1553 HRESULT WINAPI IStorage16_fnStat(
1554         LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1555 ) {
1556         ICOM_THIS(IStorage16Impl,iface);
1557         DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1558         LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1559
1560         TRACE("(%p)->(%p,0x%08lx)\n",
1561                 This,pstatstg,grfStatFlag
1562         );
1563         WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1564         pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1565         pstatstg->type = This->stde.pps_type;
1566         pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1567         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1568         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1569         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1570         pstatstg->grfMode       = 0; /* FIXME */
1571         pstatstg->grfLocksSupported = 0; /* FIXME */
1572         pstatstg->clsid         = This->stde.pps_guid;
1573         pstatstg->grfStateBits  = 0; /* FIXME */
1574         pstatstg->reserved      = 0;
1575         return S_OK;
1576 }
1577
1578 /******************************************************************************
1579  *              IStorage16_Commit       [STORAGE.509]
1580  */
1581 HRESULT WINAPI IStorage16_fnCommit(
1582         LPSTORAGE16 iface,DWORD commitflags
1583 ) {
1584         ICOM_THIS(IStorage16Impl,iface);
1585         FIXME("(%p)->(0x%08lx),STUB!\n",
1586                 This,commitflags
1587         );
1588         return S_OK;
1589 }
1590
1591 /******************************************************************************
1592  * IStorage16_CopyTo [STORAGE.507]
1593  */
1594 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1595         ICOM_THIS(IStorage16Impl,iface);
1596         FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1597                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1598         );
1599         return S_OK;
1600 }
1601
1602
1603 /******************************************************************************
1604  * IStorage16_CreateStorage [STORAGE.505]
1605  */
1606 HRESULT WINAPI IStorage16_fnCreateStorage(
1607         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1608 ) {
1609         ICOM_THIS(IStorage16Impl,iface);
1610         IStorage16Impl* lpstg;
1611         int             ppsent,x;
1612         struct storage_pps_entry        stde;
1613         struct storage_header sth;
1614         HANDLE          hf=This->hf;
1615         BOOL ret;
1616         int      nPPSEntries;
1617
1618         READ_HEADER;
1619
1620         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1621                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1622         );
1623         if (grfMode & STGM_TRANSACTED)
1624                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1625         _create_istorage16(ppstg);
1626         lpstg = MapSL((SEGPTR)*ppstg);
1627         lpstg->hf               = This->hf;
1628
1629         ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1630         if (ppsent<0)
1631                 return E_FAIL;
1632         stde=This->stde;
1633         if (stde.pps_dir==-1) {
1634                 stde.pps_dir = ppsent;
1635                 x = This->ppsent;
1636         } else {
1637                 FIXME(" use prev chain too ?\n");
1638                 x=stde.pps_dir;
1639                 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1640                         return E_FAIL;
1641                 while (stde.pps_next!=-1) {
1642                         x=stde.pps_next;
1643                         if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1644                                 return E_FAIL;
1645                 }
1646                 stde.pps_next = ppsent;
1647         }
1648         ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1649         assert(ret);
1650         nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1651         assert(nPPSEntries == 1);
1652         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1653                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1654         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1655         lpstg->stde.pps_next    = -1;
1656         lpstg->stde.pps_prev    = -1;
1657         lpstg->stde.pps_dir     = -1;
1658         lpstg->stde.pps_sb      = -1;
1659         lpstg->stde.pps_size    =  0;
1660         lpstg->stde.pps_type    =  1;
1661         lpstg->ppsent           = ppsent;
1662         /* FIXME: timestamps? */
1663         if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1664                 return E_FAIL;
1665         return S_OK;
1666 }
1667
1668 /******************************************************************************
1669  *              IStorage16_CreateStream [STORAGE.503]
1670  */
1671 HRESULT WINAPI IStorage16_fnCreateStream(
1672         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1673 ) {
1674         ICOM_THIS(IStorage16Impl,iface);
1675         IStream16Impl*  lpstr;
1676         int             ppsent,x;
1677         struct storage_pps_entry        stde;
1678         BOOL ret;
1679         int      nPPSEntries;
1680
1681         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1682                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1683         );
1684         if (grfMode & STGM_TRANSACTED)
1685                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1686         _create_istream16(ppstm);
1687         lpstr = MapSL((SEGPTR)*ppstm);
1688         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1689                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1690         lpstr->offset.u.LowPart = 0;
1691         lpstr->offset.u.HighPart        = 0;
1692
1693         ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1694         if (ppsent<0)
1695                 return E_FAIL;
1696         stde=This->stde;
1697         if (stde.pps_next==-1)
1698                 x=This->ppsent;
1699         else
1700                 while (stde.pps_next!=-1) {
1701                         x=stde.pps_next;
1702                         if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1703                                 return E_FAIL;
1704                 }
1705         stde.pps_next = ppsent;
1706         ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1707         assert(ret);
1708         nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1709         assert(nPPSEntries == 1);
1710         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1711                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1712         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1713         lpstr->stde.pps_next    = -1;
1714         lpstr->stde.pps_prev    = -1;
1715         lpstr->stde.pps_dir     = -1;
1716         lpstr->stde.pps_sb      = -1;
1717         lpstr->stde.pps_size    =  0;
1718         lpstr->stde.pps_type    =  2;
1719         lpstr->ppsent           = ppsent;
1720         /* FIXME: timestamps? */
1721         if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1722                 return E_FAIL;
1723         return S_OK;
1724 }
1725
1726 /******************************************************************************
1727  *              IStorage16_OpenStorage  [STORAGE.506]
1728  */
1729 HRESULT WINAPI IStorage16_fnOpenStorage(
1730         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1731 ) {
1732         ICOM_THIS(IStorage16Impl,iface);
1733         IStream16Impl*  lpstg;
1734         WCHAR           name[33];
1735         int             newpps;
1736
1737         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1738                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1739         );
1740         if (grfMode & STGM_TRANSACTED)
1741                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1742         _create_istorage16(ppstg);
1743         lpstg = MapSL((SEGPTR)*ppstg);
1744         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1745                          &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1746         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1747         newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1748         if (newpps==-1) {
1749                 IStream16_fnRelease((IStream16*)lpstg);
1750                 return E_FAIL;
1751         }
1752
1753         if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1754                 IStream16_fnRelease((IStream16*)lpstg);
1755                 return E_FAIL;
1756         }
1757         lpstg->ppsent           = newpps;
1758         return S_OK;
1759 }
1760
1761 /******************************************************************************
1762  * IStorage16_OpenStream [STORAGE.504]
1763  */
1764 HRESULT WINAPI IStorage16_fnOpenStream(
1765         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1766 ) {
1767         ICOM_THIS(IStorage16Impl,iface);
1768         IStream16Impl*  lpstr;
1769         WCHAR           name[33];
1770         int             newpps;
1771
1772         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1773                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1774         );
1775         if (grfMode & STGM_TRANSACTED)
1776                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1777         _create_istream16(ppstm);
1778         lpstr = MapSL((SEGPTR)*ppstm);
1779         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1780                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1781         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1782         newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1783         if (newpps==-1) {
1784                 IStream16_fnRelease((IStream16*)lpstr);
1785                 return E_FAIL;
1786         }
1787
1788         if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1789                 IStream16_fnRelease((IStream16*)lpstr);
1790                 return E_FAIL;
1791         }
1792         lpstr->offset.u.LowPart = 0;
1793         lpstr->offset.u.HighPart        = 0;
1794         lpstr->ppsent           = newpps;
1795         return S_OK;
1796 }
1797
1798 /******************************************************************************
1799  * _create_istorage16 [INTERNAL]
1800  */
1801 static void _create_istorage16(LPSTORAGE16 *stg) {
1802         IStorage16Impl* lpst;
1803
1804         if (!stvt16.QueryInterface) {
1805                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1806                 if (wp>=32) {
1807 #define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1808                         VTENT(QueryInterface)
1809                         VTENT(AddRef)
1810                         VTENT(Release)
1811                         VTENT(CreateStream)
1812                         VTENT(OpenStream)
1813                         VTENT(CreateStorage)
1814                         VTENT(OpenStorage)
1815                         VTENT(CopyTo)
1816                         VTENT(MoveElementTo)
1817                         VTENT(Commit)
1818                         VTENT(Revert)
1819                         VTENT(EnumElements)
1820                         VTENT(DestroyElement)
1821                         VTENT(RenameElement)
1822                         VTENT(SetElementTimes)
1823                         VTENT(SetClass)
1824                         VTENT(SetStateBits)
1825                         VTENT(Stat)
1826 #undef VTENT
1827                         segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1828                 } else {
1829 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1830                         VTENT(QueryInterface)
1831                         VTENT(AddRef)
1832                         VTENT(Release)
1833                         VTENT(CreateStream)
1834                         VTENT(OpenStream)
1835                         VTENT(CreateStorage)
1836                         VTENT(OpenStorage)
1837                         VTENT(CopyTo)
1838                         VTENT(Commit)
1839         /*  not (yet) implemented ...
1840                         VTENT(MoveElementTo)
1841                         VTENT(Revert)
1842                         VTENT(EnumElements)
1843                         VTENT(DestroyElement)
1844                         VTENT(RenameElement)
1845                         VTENT(SetElementTimes)
1846                         VTENT(SetClass)
1847                         VTENT(SetStateBits)
1848                         VTENT(Stat)
1849         */
1850 #undef VTENT
1851                         segstvt16 = &stvt16;
1852                 }
1853         }
1854         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1855         lpst->lpVtbl    = segstvt16;
1856         lpst->ref       = 1;
1857         lpst->thisptr   = MapLS(lpst);
1858         *stg = (void*)lpst->thisptr;
1859 }
1860
1861 /******************************************************************************
1862  *      Storage API functions
1863  */
1864
1865 /******************************************************************************
1866  *              StgCreateDocFileA       [STORAGE.1]
1867  */
1868 HRESULT WINAPI StgCreateDocFile16(
1869         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1870 ) {
1871         HANDLE          hf;
1872         int             i,ret;
1873         IStorage16Impl* lpstg;
1874         struct storage_pps_entry        stde;
1875
1876         TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1877                 pwcsName,grfMode,reserved,ppstgOpen
1878         );
1879         _create_istorage16(ppstgOpen);
1880         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1881         if (hf==INVALID_HANDLE_VALUE) {
1882                 WARN("couldn't open file for storage:%ld\n",GetLastError());
1883                 return E_FAIL;
1884         }
1885         lpstg = MapSL((SEGPTR)*ppstgOpen);
1886         lpstg->hf = hf;
1887         /* FIXME: check for existence before overwriting? */
1888         if (!STORAGE_init_storage(hf)) {
1889                 CloseHandle(hf);
1890                 return E_FAIL;
1891         }
1892         i=0;ret=0;
1893         while (!ret) { /* neither 1 nor <0 */
1894                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1895                 if ((ret==1) && (stde.pps_type==5)) {
1896                         lpstg->stde     = stde;
1897                         lpstg->ppsent   = i;
1898                         break;
1899                 }
1900                 i++;
1901         }
1902         if (ret!=1) {
1903                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1904                 return E_FAIL;
1905         }
1906
1907         return S_OK;
1908 }
1909
1910 /******************************************************************************
1911  * StgIsStorageFile [STORAGE.5]
1912  */
1913 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1914         UNICODE_STRING strW;
1915         HRESULT ret;
1916
1917         RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1918         ret = StgIsStorageFile( strW.Buffer );
1919         RtlFreeUnicodeString( &strW );
1920
1921         return ret;
1922 }
1923
1924 /******************************************************************************
1925  * StgOpenStorage [STORAGE.3]
1926  */
1927 HRESULT WINAPI StgOpenStorage16(
1928         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1929         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1930 ) {
1931         HANDLE          hf;
1932         int             ret,i;
1933         IStorage16Impl* lpstg;
1934         struct storage_pps_entry        stde;
1935
1936         TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1937               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1938         );
1939         _create_istorage16(ppstgOpen);
1940         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1941         if (hf==INVALID_HANDLE_VALUE) {
1942                 WARN("Couldn't open file for storage\n");
1943                 return E_FAIL;
1944         }
1945         lpstg = MapSL((SEGPTR)*ppstgOpen);
1946         lpstg->hf = hf;
1947
1948         i=0;ret=0;
1949         while (!ret) { /* neither 1 nor <0 */
1950                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1951                 if ((ret==1) && (stde.pps_type==5)) {
1952                         lpstg->stde=stde;
1953                         break;
1954                 }
1955                 i++;
1956         }
1957         if (ret!=1) {
1958                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1959                 return E_FAIL;
1960         }
1961         return S_OK;
1962
1963 }
1964
1965 /******************************************************************************
1966  *              StgIsStorageILockBytes        [STORAGE.6]
1967  *
1968  * Determines if the ILockBytes contains a storage object.
1969  */
1970 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1971 {
1972   DWORD args[6];
1973   HRESULT hres;
1974   HANDLE16 hsig;
1975   
1976   args[0] = (DWORD)plkbyt;      /* iface */
1977   args[1] = args[2] = 0;        /* ULARGE_INTEGER offset */
1978   args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1979   args[4] = 8;
1980   args[5] = 0;
1981
1982   if (!K32WOWCallback16Ex(
1983       (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1984                   (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1985       )->ReadAt,
1986       WCB16_PASCAL,
1987       6*sizeof(DWORD),
1988       (LPVOID)args,
1989       (LPDWORD)&hres
1990   )) {
1991       ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1992       return hres;
1993   }
1994   if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1995     K32WOWGlobalUnlockFree16(args[3]);
1996     return S_OK;
1997   }
1998   K32WOWGlobalUnlockFree16(args[3]);
1999   return S_FALSE;
2000 }
2001
2002 /******************************************************************************
2003  *    StgOpenStorageOnILockBytes    [STORAGE.4]
2004  */
2005 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2006       ILockBytes16 *plkbyt,
2007       IStorage16 *pstgPriority,
2008       DWORD grfMode,
2009       SNB16 snbExclude,
2010       DWORD reserved,
2011       IStorage16 **ppstgOpen)
2012 {
2013   IStorage16Impl*       lpstg;
2014
2015   if ((plkbyt == 0) || (ppstgOpen == 0))
2016     return STG_E_INVALIDPOINTER;
2017
2018   *ppstgOpen = 0;
2019
2020   _create_istorage16(ppstgOpen);
2021   lpstg = MapSL((SEGPTR)*ppstgOpen);
2022
2023   /* just teach it to use HANDLE instead of ilockbytes :/ */
2024
2025   return S_OK;
2026 }