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