Implement A->W call for GetNamedSecurityInfo.
[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         LPBYTE  pbv = pv;
1065
1066         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
1067         if (!pcbRead) bytesread=&xxread;
1068         *bytesread = 0;
1069
1070         if (cb>This->stde.pps_size-This->offset.u.LowPart)
1071                 cb=This->stde.pps_size-This->offset.u.LowPart;
1072         if (This->stde.pps_size < 0x1000) {
1073                 /* use small block reader */
1074                 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1075                 while (cb) {
1076                         int     cc;
1077
1078                         if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
1079                            WARN("small block read failed!!!\n");
1080                                 return E_FAIL;
1081                         }
1082                         cc = cb;
1083                         if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1084                                 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1085                         memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1086                         This->offset.u.LowPart+=cc;
1087                         pbv+=cc;
1088                         *bytesread+=cc;
1089                         cb-=cc;
1090                         blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
1091                 }
1092         } else {
1093                 /* use big block reader */
1094                 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1095                 while (cb) {
1096                         int     cc;
1097
1098                         if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
1099                                 WARN("big block read failed!!!\n");
1100                                 return E_FAIL;
1101                         }
1102                         cc = cb;
1103                         if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1104                                 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1105                         memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1106                         This->offset.u.LowPart+=cc;
1107                         pbv+=cc;
1108                         *bytesread+=cc;
1109                         cb-=cc;
1110                         blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
1111                 }
1112         }
1113         return S_OK;
1114 }
1115
1116 /******************************************************************************
1117  *              IStream16_Write [STORAGE.522]
1118  */
1119 HRESULT WINAPI IStream16_fnWrite(
1120         IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
1121 ) {
1122         ICOM_THIS(IStream16Impl,iface);
1123         BYTE    block[BIGSIZE];
1124         ULONG   *byteswritten=pcbWrite,xxwritten;
1125         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1126         HANDLE  hf = This->hf;
1127         LPBYTE  pbv = (LPBYTE)pv;
1128
1129         if (!pcbWrite) byteswritten=&xxwritten;
1130         *byteswritten = 0;
1131
1132         TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
1133         /* do we need to junk some blocks? */
1134         newsize = This->offset.u.LowPart+cb;
1135         oldsize = This->stde.pps_size;
1136         if (newsize < oldsize) {
1137                 if (oldsize < 0x1000) {
1138                         /* only small blocks */
1139                         blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
1140
1141                         assert(blocknr>=0);
1142
1143                         /* will set the rest of the chain to 'free' */
1144                         if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1145                                 return E_FAIL;
1146                 } else {
1147                         if (newsize >= 0x1000) {
1148                                 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
1149                                 assert(blocknr>=0);
1150
1151                                 /* will set the rest of the chain to 'free' */
1152                                 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1153                                         return E_FAIL;
1154                         } else {
1155                                 /* Migrate large blocks to small blocks
1156                                  * (we just migrate newsize bytes)
1157                                  */
1158                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1159                                 HRESULT r = E_FAIL;
1160
1161                                 cc      = newsize;
1162                                 blocknr = This->stde.pps_sb;
1163                                 curdata = data;
1164                                 while (cc>0) {
1165                                         if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
1166                                                 HeapFree(GetProcessHeap(),0,data);
1167                                                 return E_FAIL;
1168                                         }
1169                                         curdata += BIGSIZE;
1170                                         cc      -= BIGSIZE;
1171                                         blocknr  = STORAGE_get_next_big_blocknr(hf,blocknr);
1172                                 }
1173                                 /* frees complete chain for this stream */
1174                                 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1175                                         goto err;
1176                                 curdata = data;
1177                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
1178                                 if (blocknr<0)
1179                                         goto err;
1180                                 cc      = newsize;
1181                                 while (cc>0) {
1182                                         if (!STORAGE_put_small_block(hf,blocknr,curdata))
1183                                                 goto err;
1184                                         cc      -= SMALLSIZE;
1185                                         if (cc<=0) {
1186                                                 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1187                                                         goto err;
1188                                                 break;
1189                                         } else {
1190                                                 int newblocknr = STORAGE_get_free_small_blocknr(hf);
1191                                                 if (newblocknr<0)
1192                                                         goto err;
1193                                                 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
1194                                                         goto err;
1195                                                 blocknr = newblocknr;
1196                                         }
1197                                         curdata += SMALLSIZE;
1198                                 }
1199                                 r = S_OK;
1200                         err:
1201                                 HeapFree(GetProcessHeap(),0,data);
1202                                 if(r != S_OK)
1203                                         return r;
1204                         }
1205                 }
1206                 This->stde.pps_size = newsize;
1207         }
1208
1209         if (newsize > oldsize) {
1210                 if (oldsize >= 0x1000) {
1211                         /* should return the block right before the 'endofchain' */
1212                         blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1213                         assert(blocknr>=0);
1214                         lastblocknr     = blocknr;
1215                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1216                                 blocknr = STORAGE_get_free_big_blocknr(hf);
1217                                 if (blocknr<0)
1218                                         return E_FAIL;
1219                                 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1220                                         return E_FAIL;
1221                                 lastblocknr = blocknr;
1222                         }
1223                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1224                                 return E_FAIL;
1225                 } else {
1226                         if (newsize < 0x1000) {
1227                                 /* find startblock */
1228                                 if (!oldsize)
1229                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1230                                 else
1231                                         blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1232                                 if (blocknr<0)
1233                                         return E_FAIL;
1234
1235                                 /* allocate required new small blocks */
1236                                 lastblocknr = blocknr;
1237                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1238                                         blocknr = STORAGE_get_free_small_blocknr(hf);
1239                                         if (blocknr<0)
1240                                                 return E_FAIL;
1241                                         if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1242                                                 return E_FAIL;
1243                                         lastblocknr = blocknr;
1244                                 }
1245                                 /* and terminate the chain */
1246                                 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1247                                         return E_FAIL;
1248                         } else {
1249                                 if (!oldsize) {
1250                                         /* no single block allocated yet */
1251                                         blocknr=STORAGE_get_free_big_blocknr(hf);
1252                                         if (blocknr<0)
1253                                                 return E_FAIL;
1254                                         This->stde.pps_sb = blocknr;
1255                                 } else {
1256                                         /* Migrate small blocks to big blocks */
1257                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1258                                         HRESULT r = E_FAIL;
1259
1260                                         cc      = oldsize;
1261                                         blocknr = This->stde.pps_sb;
1262                                         curdata = data;
1263                                         /* slurp in */
1264                                         while (cc>0) {
1265                                                 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1266                                                         goto err2;
1267                                                 curdata += SMALLSIZE;
1268                                                 cc      -= SMALLSIZE;
1269                                                 blocknr  = STORAGE_get_next_small_blocknr(hf,blocknr);
1270                                         }
1271                                         /* free small block chain */
1272                                         if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1273                                                 goto err2;
1274                                         curdata = data;
1275                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1276                                         if (blocknr<0)
1277                                                 goto err2;
1278                                         /* put the data into the big blocks */
1279                                         cc      = This->stde.pps_size;
1280                                         while (cc>0) {
1281                                                 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1282                                                         goto err2;
1283                                                 cc      -= BIGSIZE;
1284                                                 if (cc<=0) {
1285                                                         if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1286                                                                 goto err2;
1287                                                         break;
1288                                                 } else {
1289                                                         int newblocknr = STORAGE_get_free_big_blocknr(hf);
1290                                                         if (newblocknr<0)
1291                                                                 goto err2;
1292                                                         if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1293                                                                 goto err2;
1294                                                         blocknr = newblocknr;
1295                                                 }
1296                                                 curdata += BIGSIZE;
1297                                         }
1298                                         r = S_OK;
1299                                 err2:
1300                                         HeapFree(GetProcessHeap(),0,data);
1301                                         if(r != S_OK)
1302                                                 return r;
1303                                 }
1304                                 /* generate big blocks to fit the new data */
1305                                 lastblocknr     = blocknr;
1306                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1307                                         blocknr = STORAGE_get_free_big_blocknr(hf);
1308                                         if (blocknr<0)
1309                                                 return E_FAIL;
1310                                         if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1311                                                 return E_FAIL;
1312                                         lastblocknr = blocknr;
1313                                 }
1314                                 /* terminate chain */
1315                                 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1316                                         return E_FAIL;
1317                         }
1318                 }
1319                 This->stde.pps_size = newsize;
1320         }
1321
1322         /* There are just some cases where we didn't modify it, we write it out
1323          * everytime
1324          */
1325         if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1326                 return E_FAIL;
1327
1328         /* finally the write pass */
1329         if (This->stde.pps_size < 0x1000) {
1330                 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1331                 assert(blocknr>=0);
1332                 while (cb>0) {
1333                         /* we ensured that it is allocated above */
1334                         assert(blocknr>=0);
1335                         /* Read old block everytime, since we can have
1336                          * overlapping data at START and END of the write
1337                          */
1338                         if (!STORAGE_get_small_block(hf,blocknr,block))
1339                                 return E_FAIL;
1340
1341                         cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1342                         if (cc>cb)
1343                                 cc=cb;
1344                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1345                                 pbv+curoffset,
1346                                 cc
1347                         );
1348                         if (!STORAGE_put_small_block(hf,blocknr,block))
1349                                 return E_FAIL;
1350                         cb                      -= cc;
1351                         curoffset               += cc;
1352                         pbv                     += cc;
1353                         This->offset.u.LowPart  += cc;
1354                         *byteswritten           += cc;
1355                         blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1356                 }
1357         } else {
1358                 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1359                 assert(blocknr>=0);
1360                 while (cb>0) {
1361                         /* we ensured that it is allocated above, so it better is */
1362                         assert(blocknr>=0);
1363                         /* read old block everytime, since we can have
1364                          * overlapping data at START and END of the write
1365                          */
1366                         if (!STORAGE_get_big_block(hf,blocknr,block))
1367                                 return E_FAIL;
1368
1369                         cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1370                         if (cc>cb)
1371                                 cc=cb;
1372                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1373                                 pbv+curoffset,
1374                                 cc
1375                         );
1376                         if (!STORAGE_put_big_block(hf,blocknr,block))
1377                                 return E_FAIL;
1378                         cb                      -= cc;
1379                         curoffset               += cc;
1380                         pbv                     += cc;
1381                         This->offset.u.LowPart  += cc;
1382                         *byteswritten           += cc;
1383                         blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1384                 }
1385         }
1386         return S_OK;
1387 }
1388
1389 /******************************************************************************
1390  *              _create_istream16       [Internal]
1391  */
1392 static void _create_istream16(LPSTREAM16 *str) {
1393         IStream16Impl*  lpst;
1394
1395         if (!strvt16.QueryInterface) {
1396                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1397                 if (wp>=32) {
1398                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1399 #define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1400                         VTENT(QueryInterface);
1401                         VTENT(AddRef);
1402                         VTENT(Release);
1403                         VTENT(Read);
1404                         VTENT(Write);
1405                         VTENT(Seek);
1406                         VTENT(SetSize);
1407                         VTENT(CopyTo);
1408                         VTENT(Commit);
1409                         VTENT(Revert);
1410                         VTENT(LockRegion);
1411                         VTENT(UnlockRegion);
1412                         VTENT(Stat);
1413                         VTENT(Clone);
1414 #undef VTENT
1415                         segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1416                 } else {
1417 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1418                         VTENT(QueryInterface);
1419                         VTENT(AddRef);
1420                         VTENT(Release);
1421                         VTENT(Read);
1422                         VTENT(Write);
1423                         VTENT(Seek);
1424         /*
1425                         VTENT(CopyTo);
1426                         VTENT(Commit);
1427                         VTENT(SetSize);
1428                         VTENT(Revert);
1429                         VTENT(LockRegion);
1430                         VTENT(UnlockRegion);
1431                         VTENT(Stat);
1432                         VTENT(Clone);
1433         */
1434 #undef VTENT
1435                         segstrvt16 = &strvt16;
1436                 }
1437         }
1438         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1439         lpst->lpVtbl    = segstrvt16;
1440         lpst->ref       = 1;
1441         lpst->thisptr   = MapLS( lpst );
1442         *str = (void*)lpst->thisptr;
1443 }
1444
1445
1446 /* --- IStream32 implementation */
1447
1448 typedef struct
1449 {
1450         /* IUnknown fields */
1451         ICOM_VFIELD(IStream);
1452         DWORD                           ref;
1453         /* IStream32 fields */
1454         struct storage_pps_entry        stde;
1455         int                             ppsent;
1456         HANDLE                         hf;
1457         ULARGE_INTEGER                  offset;
1458 } IStream32Impl;
1459
1460 /*****************************************************************************
1461  *              IStream32_QueryInterface        [VTABLE]
1462  */
1463 HRESULT WINAPI IStream_fnQueryInterface(
1464         IStream* iface,REFIID refiid,LPVOID *obj
1465 ) {
1466         ICOM_THIS(IStream32Impl,iface);
1467
1468         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1469         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1470                 *obj = This;
1471                 return 0;
1472         }
1473         return OLE_E_ENUM_NOMORE;
1474
1475 }
1476
1477 /******************************************************************************
1478  * IStream32_AddRef [VTABLE]
1479  */
1480 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1481         ICOM_THIS(IStream32Impl,iface);
1482         return ++(This->ref);
1483 }
1484
1485 /******************************************************************************
1486  * IStream32_Release [VTABLE]
1487  */
1488 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1489         ICOM_THIS(IStream32Impl,iface);
1490         FlushFileBuffers(This->hf);
1491         This->ref--;
1492         if (!This->ref) {
1493                 CloseHandle(This->hf);
1494                 HeapFree( GetProcessHeap(), 0, This );
1495                 return 0;
1496         }
1497         return This->ref;
1498 }
1499
1500 /* --- IStorage16 implementation */
1501
1502 typedef struct
1503 {
1504         /* IUnknown fields */
1505         ICOM_VFIELD(IStorage16);
1506         DWORD                           ref;
1507         /* IStorage16 fields */
1508         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1509         struct storage_pps_entry        stde;
1510         int                             ppsent;
1511         HANDLE                         hf;
1512 } IStorage16Impl;
1513
1514 /******************************************************************************
1515  *              IStorage16_QueryInterface       [STORAGE.500]
1516  */
1517 HRESULT WINAPI IStorage16_fnQueryInterface(
1518         IStorage16* iface,REFIID refiid,LPVOID *obj
1519 ) {
1520         ICOM_THIS(IStorage16Impl,iface);
1521
1522         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1523
1524         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1525                 *obj = This;
1526                 return 0;
1527         }
1528         return OLE_E_ENUM_NOMORE;
1529 }
1530
1531 /******************************************************************************
1532  * IStorage16_AddRef [STORAGE.501]
1533  */
1534 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1535         ICOM_THIS(IStorage16Impl,iface);
1536         return ++(This->ref);
1537 }
1538
1539 /******************************************************************************
1540  * IStorage16_Release [STORAGE.502]
1541  */
1542 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1543         ICOM_THIS(IStorage16Impl,iface);
1544         This->ref--;
1545         if (This->ref)
1546                 return This->ref;
1547         UnMapLS( This->thisptr );
1548         HeapFree( GetProcessHeap(), 0, This );
1549         return 0;
1550 }
1551
1552 /******************************************************************************
1553  * IStorage16_Stat [STORAGE.517]
1554  */
1555 HRESULT WINAPI IStorage16_fnStat(
1556         LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1557 ) {
1558         ICOM_THIS(IStorage16Impl,iface);
1559         DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1560         LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1561
1562         TRACE("(%p)->(%p,0x%08lx)\n",
1563                 This,pstatstg,grfStatFlag
1564         );
1565         WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1566         pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1567         pstatstg->type = This->stde.pps_type;
1568         pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1569         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1570         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1571         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1572         pstatstg->grfMode       = 0; /* FIXME */
1573         pstatstg->grfLocksSupported = 0; /* FIXME */
1574         pstatstg->clsid         = This->stde.pps_guid;
1575         pstatstg->grfStateBits  = 0; /* FIXME */
1576         pstatstg->reserved      = 0;
1577         return S_OK;
1578 }
1579
1580 /******************************************************************************
1581  *              IStorage16_Commit       [STORAGE.509]
1582  */
1583 HRESULT WINAPI IStorage16_fnCommit(
1584         LPSTORAGE16 iface,DWORD commitflags
1585 ) {
1586         ICOM_THIS(IStorage16Impl,iface);
1587         FIXME("(%p)->(0x%08lx),STUB!\n",
1588                 This,commitflags
1589         );
1590         return S_OK;
1591 }
1592
1593 /******************************************************************************
1594  * IStorage16_CopyTo [STORAGE.507]
1595  */
1596 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1597         ICOM_THIS(IStorage16Impl,iface);
1598         FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1599                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1600         );
1601         return S_OK;
1602 }
1603
1604
1605 /******************************************************************************
1606  * IStorage16_CreateStorage [STORAGE.505]
1607  */
1608 HRESULT WINAPI IStorage16_fnCreateStorage(
1609         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1610 ) {
1611         ICOM_THIS(IStorage16Impl,iface);
1612         IStorage16Impl* lpstg;
1613         int             ppsent,x;
1614         struct storage_pps_entry        stde;
1615         struct storage_header sth;
1616         HANDLE          hf=This->hf;
1617         BOOL ret;
1618         int      nPPSEntries;
1619
1620         READ_HEADER;
1621
1622         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1623                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1624         );
1625         if (grfMode & STGM_TRANSACTED)
1626                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1627         _create_istorage16(ppstg);
1628         lpstg = MapSL((SEGPTR)*ppstg);
1629         lpstg->hf               = This->hf;
1630
1631         ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1632         if (ppsent<0)
1633                 return E_FAIL;
1634         stde=This->stde;
1635         if (stde.pps_dir==-1) {
1636                 stde.pps_dir = ppsent;
1637                 x = This->ppsent;
1638         } else {
1639                 FIXME(" use prev chain too ?\n");
1640                 x=stde.pps_dir;
1641                 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1642                         return E_FAIL;
1643                 while (stde.pps_next!=-1) {
1644                         x=stde.pps_next;
1645                         if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1646                                 return E_FAIL;
1647                 }
1648                 stde.pps_next = ppsent;
1649         }
1650         ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1651         assert(ret);
1652         nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1653         assert(nPPSEntries == 1);
1654         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1655                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1656         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1657         lpstg->stde.pps_next    = -1;
1658         lpstg->stde.pps_prev    = -1;
1659         lpstg->stde.pps_dir     = -1;
1660         lpstg->stde.pps_sb      = -1;
1661         lpstg->stde.pps_size    =  0;
1662         lpstg->stde.pps_type    =  1;
1663         lpstg->ppsent           = ppsent;
1664         /* FIXME: timestamps? */
1665         if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1666                 return E_FAIL;
1667         return S_OK;
1668 }
1669
1670 /******************************************************************************
1671  *              IStorage16_CreateStream [STORAGE.503]
1672  */
1673 HRESULT WINAPI IStorage16_fnCreateStream(
1674         LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1675 ) {
1676         ICOM_THIS(IStorage16Impl,iface);
1677         IStream16Impl*  lpstr;
1678         int             ppsent,x;
1679         struct storage_pps_entry        stde;
1680         BOOL ret;
1681         int      nPPSEntries;
1682
1683         TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1684                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1685         );
1686         if (grfMode & STGM_TRANSACTED)
1687                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1688         _create_istream16(ppstm);
1689         lpstr = MapSL((SEGPTR)*ppstm);
1690         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1691                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1692         lpstr->offset.u.LowPart = 0;
1693         lpstr->offset.u.HighPart        = 0;
1694
1695         ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1696         if (ppsent<0)
1697                 return E_FAIL;
1698         stde=This->stde;
1699         if (stde.pps_next==-1)
1700                 x=This->ppsent;
1701         else
1702                 while (stde.pps_next!=-1) {
1703                         x=stde.pps_next;
1704                         if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1705                                 return E_FAIL;
1706                 }
1707         stde.pps_next = ppsent;
1708         ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1709         assert(ret);
1710         nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1711         assert(nPPSEntries == 1);
1712         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1713                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1714         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1715         lpstr->stde.pps_next    = -1;
1716         lpstr->stde.pps_prev    = -1;
1717         lpstr->stde.pps_dir     = -1;
1718         lpstr->stde.pps_sb      = -1;
1719         lpstr->stde.pps_size    =  0;
1720         lpstr->stde.pps_type    =  2;
1721         lpstr->ppsent           = ppsent;
1722         /* FIXME: timestamps? */
1723         if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1724                 return E_FAIL;
1725         return S_OK;
1726 }
1727
1728 /******************************************************************************
1729  *              IStorage16_OpenStorage  [STORAGE.506]
1730  */
1731 HRESULT WINAPI IStorage16_fnOpenStorage(
1732         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1733 ) {
1734         ICOM_THIS(IStorage16Impl,iface);
1735         IStream16Impl*  lpstg;
1736         WCHAR           name[33];
1737         int             newpps;
1738
1739         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1740                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1741         );
1742         if (grfMode & STGM_TRANSACTED)
1743                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1744         _create_istorage16(ppstg);
1745         lpstg = MapSL((SEGPTR)*ppstg);
1746         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1747                          &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1748         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1749         newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1750         if (newpps==-1) {
1751                 IStream16_fnRelease((IStream16*)lpstg);
1752                 return E_FAIL;
1753         }
1754
1755         if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1756                 IStream16_fnRelease((IStream16*)lpstg);
1757                 return E_FAIL;
1758         }
1759         lpstg->ppsent           = newpps;
1760         return S_OK;
1761 }
1762
1763 /******************************************************************************
1764  * IStorage16_OpenStream [STORAGE.504]
1765  */
1766 HRESULT WINAPI IStorage16_fnOpenStream(
1767         LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1768 ) {
1769         ICOM_THIS(IStorage16Impl,iface);
1770         IStream16Impl*  lpstr;
1771         WCHAR           name[33];
1772         int             newpps;
1773
1774         TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1775                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1776         );
1777         if (grfMode & STGM_TRANSACTED)
1778                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1779         _create_istream16(ppstm);
1780         lpstr = MapSL((SEGPTR)*ppstm);
1781         DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1782                          &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1783         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1784         newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1785         if (newpps==-1) {
1786                 IStream16_fnRelease((IStream16*)lpstr);
1787                 return E_FAIL;
1788         }
1789
1790         if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1791                 IStream16_fnRelease((IStream16*)lpstr);
1792                 return E_FAIL;
1793         }
1794         lpstr->offset.u.LowPart = 0;
1795         lpstr->offset.u.HighPart        = 0;
1796         lpstr->ppsent           = newpps;
1797         return S_OK;
1798 }
1799
1800 /******************************************************************************
1801  * _create_istorage16 [INTERNAL]
1802  */
1803 static void _create_istorage16(LPSTORAGE16 *stg) {
1804         IStorage16Impl* lpst;
1805
1806         if (!stvt16.QueryInterface) {
1807                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1808                 if (wp>=32) {
1809 #define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1810                         VTENT(QueryInterface)
1811                         VTENT(AddRef)
1812                         VTENT(Release)
1813                         VTENT(CreateStream)
1814                         VTENT(OpenStream)
1815                         VTENT(CreateStorage)
1816                         VTENT(OpenStorage)
1817                         VTENT(CopyTo)
1818                         VTENT(MoveElementTo)
1819                         VTENT(Commit)
1820                         VTENT(Revert)
1821                         VTENT(EnumElements)
1822                         VTENT(DestroyElement)
1823                         VTENT(RenameElement)
1824                         VTENT(SetElementTimes)
1825                         VTENT(SetClass)
1826                         VTENT(SetStateBits)
1827                         VTENT(Stat)
1828 #undef VTENT
1829                         segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1830                 } else {
1831 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1832                         VTENT(QueryInterface)
1833                         VTENT(AddRef)
1834                         VTENT(Release)
1835                         VTENT(CreateStream)
1836                         VTENT(OpenStream)
1837                         VTENT(CreateStorage)
1838                         VTENT(OpenStorage)
1839                         VTENT(CopyTo)
1840                         VTENT(Commit)
1841         /*  not (yet) implemented ...
1842                         VTENT(MoveElementTo)
1843                         VTENT(Revert)
1844                         VTENT(EnumElements)
1845                         VTENT(DestroyElement)
1846                         VTENT(RenameElement)
1847                         VTENT(SetElementTimes)
1848                         VTENT(SetClass)
1849                         VTENT(SetStateBits)
1850                         VTENT(Stat)
1851         */
1852 #undef VTENT
1853                         segstvt16 = &stvt16;
1854                 }
1855         }
1856         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1857         lpst->lpVtbl    = segstvt16;
1858         lpst->ref       = 1;
1859         lpst->thisptr   = MapLS(lpst);
1860         *stg = (void*)lpst->thisptr;
1861 }
1862
1863 /******************************************************************************
1864  *      Storage API functions
1865  */
1866
1867 /******************************************************************************
1868  *              StgCreateDocFileA       [STORAGE.1]
1869  */
1870 HRESULT WINAPI StgCreateDocFile16(
1871         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1872 ) {
1873         HANDLE          hf;
1874         int             i,ret;
1875         IStorage16Impl* lpstg;
1876         struct storage_pps_entry        stde;
1877
1878         TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1879                 pwcsName,grfMode,reserved,ppstgOpen
1880         );
1881         _create_istorage16(ppstgOpen);
1882         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1883         if (hf==INVALID_HANDLE_VALUE) {
1884                 WARN("couldn't open file for storage:%ld\n",GetLastError());
1885                 return E_FAIL;
1886         }
1887         lpstg = MapSL((SEGPTR)*ppstgOpen);
1888         lpstg->hf = hf;
1889         /* FIXME: check for existence before overwriting? */
1890         if (!STORAGE_init_storage(hf)) {
1891                 CloseHandle(hf);
1892                 return E_FAIL;
1893         }
1894         i=0;ret=0;
1895         while (!ret) { /* neither 1 nor <0 */
1896                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1897                 if ((ret==1) && (stde.pps_type==5)) {
1898                         lpstg->stde     = stde;
1899                         lpstg->ppsent   = i;
1900                         break;
1901                 }
1902                 i++;
1903         }
1904         if (ret!=1) {
1905                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1906                 return E_FAIL;
1907         }
1908
1909         return S_OK;
1910 }
1911
1912 /******************************************************************************
1913  * StgIsStorageFile [STORAGE.5]
1914  */
1915 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1916         UNICODE_STRING strW;
1917         HRESULT ret;
1918
1919         RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1920         ret = StgIsStorageFile( strW.Buffer );
1921         RtlFreeUnicodeString( &strW );
1922
1923         return ret;
1924 }
1925
1926 /******************************************************************************
1927  * StgOpenStorage [STORAGE.3]
1928  */
1929 HRESULT WINAPI StgOpenStorage16(
1930         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1931         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1932 ) {
1933         HANDLE          hf;
1934         int             ret,i;
1935         IStorage16Impl* lpstg;
1936         struct storage_pps_entry        stde;
1937
1938         TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1939               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1940         );
1941         _create_istorage16(ppstgOpen);
1942         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1943         if (hf==INVALID_HANDLE_VALUE) {
1944                 WARN("Couldn't open file for storage\n");
1945                 return E_FAIL;
1946         }
1947         lpstg = MapSL((SEGPTR)*ppstgOpen);
1948         lpstg->hf = hf;
1949
1950         i=0;ret=0;
1951         while (!ret) { /* neither 1 nor <0 */
1952                 ret=STORAGE_get_pps_entry(hf,i,&stde);
1953                 if ((ret==1) && (stde.pps_type==5)) {
1954                         lpstg->stde=stde;
1955                         break;
1956                 }
1957                 i++;
1958         }
1959         if (ret!=1) {
1960                 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1961                 return E_FAIL;
1962         }
1963         return S_OK;
1964
1965 }
1966
1967 /******************************************************************************
1968  *              StgIsStorageILockBytes        [STORAGE.6]
1969  *
1970  * Determines if the ILockBytes contains a storage object.
1971  */
1972 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1973 {
1974   DWORD args[6];
1975   HRESULT hres;
1976   HANDLE16 hsig;
1977   
1978   args[0] = (DWORD)plkbyt;      /* iface */
1979   args[1] = args[2] = 0;        /* ULARGE_INTEGER offset */
1980   args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1981   args[4] = 8;
1982   args[5] = 0;
1983
1984   if (!K32WOWCallback16Ex(
1985       (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1986                   (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1987       )->ReadAt,
1988       WCB16_PASCAL,
1989       6*sizeof(DWORD),
1990       (LPVOID)args,
1991       (LPDWORD)&hres
1992   )) {
1993       ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1994       return hres;
1995   }
1996   if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1997     K32WOWGlobalUnlockFree16(args[3]);
1998     return S_OK;
1999   }
2000   K32WOWGlobalUnlockFree16(args[3]);
2001   return S_FALSE;
2002 }
2003
2004 /******************************************************************************
2005  *    StgOpenStorageOnILockBytes    [STORAGE.4]
2006  */
2007 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2008       ILockBytes16 *plkbyt,
2009       IStorage16 *pstgPriority,
2010       DWORD grfMode,
2011       SNB16 snbExclude,
2012       DWORD reserved,
2013       IStorage16 **ppstgOpen)
2014 {
2015   IStorage16Impl*       lpstg;
2016
2017   if ((plkbyt == 0) || (ppstgOpen == 0))
2018     return STG_E_INVALIDPOINTER;
2019
2020   *ppstgOpen = 0;
2021
2022   _create_istorage16(ppstgOpen);
2023   lpstg = MapSL((SEGPTR)*ppstgOpen);
2024
2025   /* just teach it to use HANDLE instead of ilockbytes :/ */
2026
2027   return S_OK;
2028 }