po: Update French translation.
[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         IStorage16                      IStorage16_iface;
330         LONG                            ref;
331         /* IStorage16 fields */
332         SEGPTR                          thisptr; /* pointer to this struct as segmented */
333         struct storage_pps_entry        stde;
334         int                             ppsent;
335         stream_access16                 str;
336 } IStorage16Impl;
337
338
339 /******************************************************************************
340  *              STORAGE_get_big_block   [Internal]
341  *
342  * Reading OLE compound storage
343  */
344 static BOOL
345 STORAGE_get_big_block(stream_access16 *str,int n,BYTE *block)
346 {
347     DWORD result;
348
349     assert(n>=-1);
350     if (str->hf) {
351         if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL,
352                              SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
353         {
354             WARN("(%p,%d,%p), seek failed (%d)\n",str->hf, n, block, GetLastError());
355             return FALSE;
356         }
357         if (!ReadFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
358         {
359             WARN("(hf=%p, block size %d): read didn't read (%d)\n",str->hf,n,GetLastError());
360             return FALSE;
361         }
362     } else {
363         DWORD args[6];
364         HRESULT hres;
365         HANDLE16 hsig;
366
367         args[0] = (DWORD)str->lockbytes;        /* iface */
368         args[1] = (n+1)*BIGSIZE;
369         args[2] = 0;    /* ULARGE_INTEGER offset */
370         args[3] = WOWGlobalAllocLock16( 0, BIGSIZE, &hsig ); /* sig */
371         args[4] = BIGSIZE;
372         args[5] = 0;
373
374         if (!WOWCallback16Ex(
375             (DWORD)((const ILockBytes16Vtbl*)MapSL(
376                         (SEGPTR)((LPLOCKBYTES16)MapSL(str->lockbytes))->lpVtbl)
377             )->ReadAt,
378             WCB16_PASCAL,
379             6*sizeof(DWORD),
380             (LPVOID)args,
381             (LPDWORD)&hres
382         )) {
383             ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %x\n",hres);
384             return FALSE;
385         }
386         memcpy(block, MapSL(args[3]), BIGSIZE);
387         WOWGlobalUnlockFree16(args[3]);
388     }
389     return TRUE;
390 }
391
392 static BOOL
393 _ilockbytes16_writeat(SEGPTR lockbytes, DWORD offset, DWORD length, void *buffer) {
394     DWORD args[6];
395     HRESULT hres;
396
397     args[0] = (DWORD)lockbytes; /* iface */
398     args[1] = offset;
399     args[2] = 0;        /* ULARGE_INTEGER offset */
400     args[3] = (DWORD)MapLS( buffer );
401     args[4] = length;
402     args[5] = 0;
403
404     /* THIS_ ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, ULONG *pcbWritten); */
405
406     if (!WOWCallback16Ex(
407         (DWORD)((const ILockBytes16Vtbl*)MapSL(
408                     (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
409         )->WriteAt,
410         WCB16_PASCAL,
411         6*sizeof(DWORD),
412         (LPVOID)args,
413         (LPDWORD)&hres
414     )) {
415         ERR("CallTo16 ILockBytes16::WriteAt() failed, hres %x\n",hres);
416         return FALSE;
417     }
418     UnMapLS(args[3]);
419     return TRUE;
420 }
421
422 /******************************************************************************
423  * STORAGE_put_big_block [INTERNAL]
424  */
425 static BOOL
426 STORAGE_put_big_block(stream_access16 *str,int n,BYTE *block)
427 {
428     DWORD result;
429
430     assert(n>=-1);
431     if (str->hf) {
432         if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL,
433                              SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
434         {
435             WARN("seek failed (%d)\n",GetLastError());
436             return FALSE;
437         }
438         if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
439         {
440             WARN(" write failed (%d)\n",GetLastError());
441             return FALSE;
442         }
443         return TRUE;
444     } else {
445         _ilockbytes16_writeat(str->lockbytes, (n+1)*BIGSIZE, BIGSIZE, block);
446         return TRUE;
447     }
448 }
449
450 /******************************************************************************
451  * STORAGE_get_next_big_blocknr [INTERNAL]
452  */
453 static int
454 STORAGE_get_next_big_blocknr(stream_access16 *str,int blocknr) {
455         INT     bbs[BIGSIZE/sizeof(INT)];
456         struct  storage_header  sth;
457
458         READ_HEADER(str);
459
460         assert(blocknr>>7<sth.num_of_bbd_blocks);
461         if (sth.bbd_list[blocknr>>7]==0xffffffff)
462                 return -5;
463         if (!STORAGE_get_big_block(str,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
464                 return -5;
465         assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
466         return bbs[blocknr&0x7f];
467 }
468
469 /******************************************************************************
470  * STORAGE_get_nth_next_big_blocknr [INTERNAL]
471  */
472 static int
473 STORAGE_get_nth_next_big_blocknr(stream_access16 *str,int blocknr,int nr) {
474         INT     bbs[BIGSIZE/sizeof(INT)];
475         int     lastblock = -1;
476         struct storage_header sth;
477
478         TRACE("(blocknr=%d, nr=%d)\n", blocknr, nr);
479         READ_HEADER(str);
480
481         assert(blocknr>=0);
482         while (nr--) {
483                 assert((blocknr>>7)<sth.num_of_bbd_blocks);
484                 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
485
486                 /* simple caching... */
487                 if (lastblock!=sth.bbd_list[blocknr>>7]) {
488                         BOOL ret = STORAGE_get_big_block(str,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
489                         assert(ret);
490                         lastblock = sth.bbd_list[blocknr>>7];
491                 }
492                 blocknr = bbs[blocknr&0x7f];
493         }
494         return blocknr;
495 }
496
497 /******************************************************************************
498  *              STORAGE_get_root_pps_entry      [Internal]
499  */
500 static BOOL
501 STORAGE_get_root_pps_entry(stream_access16* str,struct storage_pps_entry *pstde) {
502         int     blocknr,i;
503         BYTE    block[BIGSIZE];
504         struct storage_pps_entry        *stde=(struct storage_pps_entry*)block;
505         struct storage_header sth;
506
507         READ_HEADER(str);
508         blocknr = sth.root_startblock;
509         TRACE("startblock is %d\n", blocknr);
510         while (blocknr>=0) {
511                 BOOL ret = STORAGE_get_big_block(str,blocknr,block);
512                 assert(ret);
513                 for (i=0;i<4;i++) {
514                         if (!stde[i].pps_sizeofname)
515                                 continue;
516                         if (stde[i].pps_type==5) {
517                                 *pstde=stde[i];
518                                 return TRUE;
519                         }
520                 }
521                 blocknr=STORAGE_get_next_big_blocknr(str,blocknr);
522                 TRACE("next block is %d\n", blocknr);
523         }
524         return FALSE;
525 }
526
527 /******************************************************************************
528  * STORAGE_get_small_block [INTERNAL]
529  */
530 static BOOL
531 STORAGE_get_small_block(stream_access16 *str,int blocknr,BYTE *sblock) {
532         BYTE                            block[BIGSIZE];
533         int                             bigblocknr;
534         struct storage_pps_entry        root;
535         BOOL ret;
536
537         TRACE("(blocknr=%d)\n", blocknr);
538         assert(blocknr>=0);
539         ret = STORAGE_get_root_pps_entry(str,&root);
540         assert(ret);
541         bigblocknr = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
542         assert(bigblocknr>=0);
543         ret = STORAGE_get_big_block(str,bigblocknr,block);
544         assert(ret);
545
546         memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
547         return TRUE;
548 }
549
550 /******************************************************************************
551  * STORAGE_put_small_block [INTERNAL]
552  */
553 static BOOL
554 STORAGE_put_small_block(stream_access16 *str,int blocknr,const BYTE *sblock) {
555         BYTE                            block[BIGSIZE];
556         int                             bigblocknr;
557         struct storage_pps_entry        root;
558         BOOL ret;
559
560         assert(blocknr>=0);
561         TRACE("(blocknr=%d)\n", blocknr);
562
563         ret = STORAGE_get_root_pps_entry(str,&root);
564         assert(ret);
565         bigblocknr = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
566         assert(bigblocknr>=0);
567         ret = STORAGE_get_big_block(str,bigblocknr,block);
568         assert(ret);
569
570         memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
571         ret = STORAGE_put_big_block(str,bigblocknr,block);
572         assert(ret);
573         return TRUE;
574 }
575
576 /******************************************************************************
577  * STORAGE_get_next_small_blocknr [INTERNAL]
578  */
579 static int
580 STORAGE_get_next_small_blocknr(stream_access16 *str,int blocknr) {
581         BYTE                            block[BIGSIZE];
582         LPINT                           sbd = (LPINT)block;
583         int                             bigblocknr;
584         struct storage_header           sth;
585         BOOL ret;
586
587         TRACE("(blocknr=%d)\n", blocknr);
588         READ_HEADER(str);
589         assert(blocknr>=0);
590         bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
591         assert(bigblocknr>=0);
592         ret = STORAGE_get_big_block(str,bigblocknr,block);
593         assert(ret);
594         assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
595         return sbd[blocknr & (128-1)];
596 }
597
598 /******************************************************************************
599  * STORAGE_get_nth_next_small_blocknr [INTERNAL]
600  */
601 static int
602 STORAGE_get_nth_next_small_blocknr(stream_access16*str,int blocknr,int nr) {
603         int     lastblocknr=-1;
604         BYTE    block[BIGSIZE];
605         LPINT   sbd = (LPINT)block;
606         struct storage_header sth;
607         BOOL ret;
608
609         TRACE("(blocknr=%d, nr=%d)\n", blocknr, nr);
610         READ_HEADER(str);
611         assert(blocknr>=0);
612         while ((nr--) && (blocknr>=0)) {
613                 if (lastblocknr/128!=blocknr/128) {
614                         int     bigblocknr;
615                         bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
616                         assert(bigblocknr>=0);
617                         ret = STORAGE_get_big_block(str,bigblocknr,block);
618                         assert(ret);
619                         lastblocknr = blocknr;
620                 }
621                 assert(lastblocknr>=0);
622                 lastblocknr=blocknr;
623                 blocknr=sbd[blocknr & (128-1)];
624                 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
625         }
626         return blocknr;
627 }
628
629 /******************************************************************************
630  * STORAGE_get_pps_entry [INTERNAL]
631  */
632 static int
633 STORAGE_get_pps_entry(stream_access16*str,int n,struct storage_pps_entry *pstde) {
634         int     blocknr;
635         BYTE    block[BIGSIZE];
636         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
637         struct storage_header sth;
638         BOOL ret;
639
640         TRACE("(n=%d)\n", n);
641         READ_HEADER(str);
642         /* we have 4 pps entries per big block */
643         blocknr = STORAGE_get_nth_next_big_blocknr(str,sth.root_startblock,n/4);
644         assert(blocknr>=0);
645         ret = STORAGE_get_big_block(str,blocknr,block);
646         assert(ret);
647
648         *pstde=*stde;
649         return 1;
650 }
651
652 /******************************************************************************
653  *              STORAGE_put_pps_entry   [Internal]
654  */
655 static int
656 STORAGE_put_pps_entry(stream_access16*str,int n,const struct storage_pps_entry *pstde) {
657         int     blocknr;
658         BYTE    block[BIGSIZE];
659         struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
660         struct storage_header sth;
661         BOOL ret;
662
663         TRACE("(n=%d)\n", n);
664         READ_HEADER(str);
665         /* we have 4 pps entries per big block */
666         blocknr = STORAGE_get_nth_next_big_blocknr(str,sth.root_startblock,n/4);
667         assert(blocknr>=0);
668         ret = STORAGE_get_big_block(str,blocknr,block);
669         assert(ret);
670         *stde=*pstde;
671         ret = STORAGE_put_big_block(str,blocknr,block);
672         assert(ret);
673         return 1;
674 }
675
676 /******************************************************************************
677  *              STORAGE_look_for_named_pps      [Internal]
678  */
679 static int
680 STORAGE_look_for_named_pps(stream_access16*str,int n,LPOLESTR name) {
681         struct storage_pps_entry        stde;
682         int                             ret;
683
684         TRACE("(n=%d,name=%s)\n", n, debugstr_w(name));
685         if (n==-1)
686                 return -1;
687         if (1!=STORAGE_get_pps_entry(str,n,&stde))
688                 return -1;
689
690         if (!lstrcmpW(name,stde.pps_rawname))
691                 return n;
692         if (stde.pps_prev != -1) {
693                 ret=STORAGE_look_for_named_pps(str,stde.pps_prev,name);
694                 if (ret!=-1)
695                         return ret;
696         }
697         if (stde.pps_next != -1) {
698                 ret=STORAGE_look_for_named_pps(str,stde.pps_next,name);
699                 if (ret!=-1)
700                         return ret;
701         }
702         return -1;
703 }
704
705 /******************************************************************************
706  *              STORAGE_dump_pps_entry  [Internal]
707  *
708  * This function is there to simplify debugging. It is otherwise unused.
709  */
710 void
711 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
712     char        name[33];
713
714     WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
715         if (!stde->pps_sizeofname)
716                 return;
717         TRACE("name: %s\n",name);
718         TRACE("type: %d\n",stde->pps_type);
719         TRACE("prev pps: %d\n",stde->pps_prev);
720         TRACE("next pps: %d\n",stde->pps_next);
721         TRACE("dir pps: %d\n",stde->pps_dir);
722         TRACE("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
723         if (stde->pps_type !=2) {
724                 time_t  t;
725                 DWORD dw;
726                 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
727                 t = dw;
728                 TRACE("ts1: %s\n",ctime(&t));
729                 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
730                 t = dw;
731                 TRACE("ts2: %s\n",ctime(&t));
732         }
733         TRACE("startblock: %d\n",stde->pps_sb);
734         TRACE("size: %d\n",stde->pps_size);
735 }
736
737 /******************************************************************************
738  * STORAGE_init_storage [INTERNAL]
739  */
740 static BOOL
741 STORAGE_init_storage(stream_access16 *str) {
742         BYTE    block[BIGSIZE];
743         LPDWORD bbs;
744         struct storage_header *sth;
745         struct storage_pps_entry *stde;
746         DWORD result;
747
748         if (str->hf)
749             SetFilePointer( str->hf, 0, NULL, SEEK_SET );
750         /* block -1 is the storage header */
751         sth = (struct storage_header*)block;
752         memcpy(sth->magic,STORAGE_magic,8);
753         memset(sth->unknown1,0,sizeof(sth->unknown1));
754         memset(sth->unknown2,0,sizeof(sth->unknown2));
755         memset(sth->unknown3,0,sizeof(sth->unknown3));
756         sth->num_of_bbd_blocks  = 1;
757         sth->root_startblock    = 1;
758         sth->sbd_startblock     = 0xffffffff;
759         memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
760         sth->bbd_list[0]        = 0;
761         if (str->hf) {
762             if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
763         } else {
764             if (!_ilockbytes16_writeat(str->lockbytes, 0, BIGSIZE, block)) return FALSE;
765         }
766         /* block 0 is the big block directory */
767         bbs=(LPDWORD)block;
768         memset(block,0xff,sizeof(block)); /* mark all blocks as free */
769         bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
770         bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
771         if (str->hf) {
772             if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
773         } else {
774             if (!_ilockbytes16_writeat(str->lockbytes, BIGSIZE, BIGSIZE, block)) return FALSE;
775         }
776         /* block 1 is the root directory entry */
777         memset(block,0x00,sizeof(block));
778         stde = (struct storage_pps_entry*)block;
779         MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
780                              sizeof(stde->pps_rawname)/sizeof(WCHAR));
781         stde->pps_sizeofname    = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
782         stde->pps_type          = 5;
783         stde->pps_dir           = -1;
784         stde->pps_next          = -1;
785         stde->pps_prev          = -1;
786         stde->pps_sb            = 0xffffffff;
787         stde->pps_size          = 0;
788         if (str->hf) {
789             return (WriteFile( str->hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
790         } else {
791             return _ilockbytes16_writeat(str->lockbytes, BIGSIZE, BIGSIZE, block);
792         }
793 }
794
795 /******************************************************************************
796  *              STORAGE_set_big_chain   [Internal]
797  */
798 static BOOL
799 STORAGE_set_big_chain(stream_access16*str,int blocknr,INT type) {
800         BYTE    block[BIGSIZE];
801         LPINT   bbd = (LPINT)block;
802         int     nextblocknr,bigblocknr;
803         struct storage_header sth;
804         BOOL ret;
805
806         READ_HEADER(str);
807         assert(blocknr!=type);
808         while (blocknr>=0) {
809                 bigblocknr = sth.bbd_list[blocknr/128];
810                 assert(bigblocknr>=0);
811                 ret = STORAGE_get_big_block(str,bigblocknr,block);
812                 assert(ret);
813
814                 nextblocknr = bbd[blocknr&(128-1)];
815                 bbd[blocknr&(128-1)] = type;
816                 if (type>=0)
817                         return TRUE;
818                 ret = STORAGE_put_big_block(str,bigblocknr,block);
819                 assert(ret);
820                 type = STORAGE_CHAINENTRY_FREE;
821                 blocknr = nextblocknr;
822         }
823         return TRUE;
824 }
825
826 /******************************************************************************
827  * STORAGE_set_small_chain [Internal]
828  */
829 static BOOL
830 STORAGE_set_small_chain(stream_access16*str,int blocknr,INT type) {
831         BYTE    block[BIGSIZE];
832         LPINT   sbd = (LPINT)block;
833         int     lastblocknr,nextsmallblocknr,bigblocknr;
834         struct storage_header sth;
835         BOOL ret;
836
837         READ_HEADER(str);
838
839         assert(blocknr!=type);
840         lastblocknr=-129;bigblocknr=-2;
841         while (blocknr>=0) {
842                 /* cache block ... */
843                 if (lastblocknr/128!=blocknr/128) {
844                         bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
845                         assert(bigblocknr>=0);
846                         ret = STORAGE_get_big_block(str,bigblocknr,block);
847                         assert(ret);
848                 }
849                 lastblocknr = blocknr;
850                 nextsmallblocknr = sbd[blocknr&(128-1)];
851                 sbd[blocknr&(128-1)] = type;
852                 ret = STORAGE_put_big_block(str,bigblocknr,block);
853                 assert(ret);
854                 if (type>=0)
855                         return TRUE;
856                 type = STORAGE_CHAINENTRY_FREE;
857                 blocknr = nextsmallblocknr;
858         }
859         return TRUE;
860 }
861
862 /******************************************************************************
863  *              STORAGE_get_free_big_blocknr    [Internal]
864  */
865 static int
866 STORAGE_get_free_big_blocknr(stream_access16 *str) {
867         BYTE    block[BIGSIZE];
868         LPINT   sbd = (LPINT)block;
869         int     lastbigblocknr,i,bigblocknr;
870         unsigned int curblock;
871         struct storage_header sth;
872         BOOL ret;
873
874         READ_HEADER(str);
875         curblock        = 0;
876         lastbigblocknr  = -1;
877         bigblocknr      = sth.bbd_list[curblock];
878         while (curblock<sth.num_of_bbd_blocks) {
879                 assert(bigblocknr>=0);
880                 ret = STORAGE_get_big_block(str,bigblocknr,block);
881                 assert(ret);
882                 for (i=0;i<128;i++)
883                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
884                                 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
885                                 ret = STORAGE_put_big_block(str,bigblocknr,block);
886                                 assert(ret);
887                                 memset(block,0x42,sizeof(block));
888                                 ret = STORAGE_put_big_block(str,i+curblock*128,block);
889                                 assert(ret);
890                                 return i+curblock*128;
891                         }
892                 lastbigblocknr = bigblocknr;
893                 bigblocknr = sth.bbd_list[++curblock];
894         }
895         bigblocknr = curblock*128;
896         /* since we have marked all blocks from 0 up to curblock*128-1
897          * the next free one is curblock*128, where we happily put our
898          * next large block depot.
899          */
900         memset(block,0xff,sizeof(block));
901         /* mark the block allocated and returned by this function */
902         sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
903         ret = STORAGE_put_big_block(str,bigblocknr,block);
904         assert(ret);
905
906         /* if we had a bbd block already (most likely) we need
907          * to link the new one into the chain
908          */
909         if (lastbigblocknr!=-1) {
910                 ret = STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr);
911                 assert(ret);
912         }
913         sth.bbd_list[curblock]=bigblocknr;
914         sth.num_of_bbd_blocks++;
915         assert(sth.num_of_bbd_blocks==curblock+1);
916         ret = STORAGE_put_big_block(str,-1,(LPBYTE)&sth);
917         assert(ret);
918
919         /* Set the end of the chain for the bigblockdepots */
920         ret = STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
921         assert(ret);
922         /* add 1, for the first entry is used for the additional big block
923          * depot. (means we already used bigblocknr) */
924         memset(block,0x42,sizeof(block));
925         /* allocate this block (filled with 0x42) */
926         ret = STORAGE_put_big_block(str,bigblocknr+1,block);
927         assert(ret);
928         return bigblocknr+1;
929 }
930
931
932 /******************************************************************************
933  *              STORAGE_get_free_small_blocknr  [Internal]
934  */
935 static int
936 STORAGE_get_free_small_blocknr(stream_access16 *str) {
937         BYTE    block[BIGSIZE];
938         LPINT   sbd = (LPINT)block;
939         int     lastbigblocknr,newblocknr,i,curblock,bigblocknr;
940         struct storage_pps_entry        root;
941         struct storage_header sth;
942
943         READ_HEADER(str);
944         bigblocknr      = sth.sbd_startblock;
945         curblock        = 0;
946         lastbigblocknr  = -1;
947         newblocknr      = -1;
948         while (bigblocknr>=0) {
949                 if (!STORAGE_get_big_block(str,bigblocknr,block))
950                         return -1;
951                 for (i=0;i<128;i++)
952                         if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
953                                 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
954                                 newblocknr = i+curblock*128;
955                                 break;
956                         }
957                 if (i!=128)
958                         break;
959                 lastbigblocknr = bigblocknr;
960                 bigblocknr = STORAGE_get_next_big_blocknr(str,bigblocknr);
961                 curblock++;
962         }
963         if (newblocknr==-1) {
964                 bigblocknr = STORAGE_get_free_big_blocknr(str);
965                 if (bigblocknr<0)
966                         return -1;
967                 READ_HEADER(str);
968                 memset(block,0xff,sizeof(block));
969                 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
970                 if (!STORAGE_put_big_block(str,bigblocknr,block))
971                         return -1;
972                 if (lastbigblocknr==-1) {
973                         sth.sbd_startblock = bigblocknr;
974                         if (!STORAGE_put_big_block(str,-1,(LPBYTE)&sth)) /* need to write it */
975                                 return -1;
976                 } else {
977                         if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
978                                 return -1;
979                 }
980                 if (!STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
981                         return -1;
982                 newblocknr = curblock*128;
983         }
984         /* allocate enough big blocks for storing the allocated small block */
985         if (!STORAGE_get_root_pps_entry(str,&root))
986                 return -1;
987         if (root.pps_sb==-1)
988                 lastbigblocknr  = -1;
989         else
990                 lastbigblocknr  = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,(root.pps_size-1)/BIGSIZE);
991         while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
992                 /* we need to allocate more stuff */
993                 bigblocknr = STORAGE_get_free_big_blocknr(str);
994                 if (bigblocknr<0)
995                         return -1;
996                 READ_HEADER(str);
997                 if (root.pps_sb==-1) {
998                         root.pps_sb      = bigblocknr;
999                         root.pps_size   += BIGSIZE;
1000                 } else {
1001                         if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
1002                                 return -1;
1003                         root.pps_size   += BIGSIZE;
1004                 }
1005                 lastbigblocknr = bigblocknr;
1006         }
1007         if (!STORAGE_set_big_chain(str,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1008                 return -1;
1009         if (!STORAGE_put_pps_entry(str,0,&root))
1010                 return -1;
1011         return newblocknr;
1012 }
1013
1014 /******************************************************************************
1015  *              STORAGE_get_free_pps_entry      [Internal]
1016  */
1017 static int
1018 STORAGE_get_free_pps_entry(stream_access16*str) {
1019         int     blocknr, i, curblock, lastblocknr=-1;
1020         BYTE    block[BIGSIZE];
1021         struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
1022         struct storage_header sth;
1023
1024         READ_HEADER(str);
1025         blocknr = sth.root_startblock;
1026         assert(blocknr>=0);
1027         curblock=0;
1028         while (blocknr>=0) {
1029                 if (!STORAGE_get_big_block(str,blocknr,block))
1030                         return -1;
1031                 for (i=0;i<4;i++)
1032                         if (stde[i].pps_sizeofname==0) /* free */
1033                                 return curblock*4+i;
1034                 lastblocknr = blocknr;
1035                 blocknr = STORAGE_get_next_big_blocknr(str,blocknr);
1036                 curblock++;
1037         }
1038         assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
1039         blocknr = STORAGE_get_free_big_blocknr(str);
1040         /* sth invalidated */
1041         if (blocknr<0)
1042                 return -1;
1043
1044         if (!STORAGE_set_big_chain(str,lastblocknr,blocknr))
1045                 return -1;
1046         if (!STORAGE_set_big_chain(str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1047                 return -1;
1048         memset(block,0,sizeof(block));
1049         STORAGE_put_big_block(str,blocknr,block);
1050         return curblock*4;
1051 }
1052
1053 /* --- IStream16 implementation */
1054
1055 typedef struct
1056 {
1057         IStream16                       IStream16_iface;
1058         LONG                            ref;
1059         /* IStream16 fields */
1060         SEGPTR                          thisptr; /* pointer to this struct as segmented */
1061         struct storage_pps_entry        stde;
1062         int                             ppsent;
1063         ULARGE_INTEGER                  offset;
1064         stream_access16                 str;
1065 } IStream16Impl;
1066
1067 static inline IStream16Impl *impl_from_IStream16(IStream16 *iface)
1068 {
1069         return CONTAINING_RECORD(iface, IStream16Impl, IStream16_iface);
1070 }
1071
1072 /******************************************************************************
1073  *              IStream16_QueryInterface        [STORAGE.518]
1074  */
1075 HRESULT CDECL IStream16_fnQueryInterface(IStream16 *iface, REFIID refiid, void **obj)
1076 {
1077         IStream16Impl *This = impl_from_IStream16(iface);
1078         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1079         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1080                 *obj = This;
1081                 return 0;
1082         }
1083         return OLE_E_ENUM_NOMORE;
1084
1085 }
1086
1087 /******************************************************************************
1088  * IStream16_AddRef [STORAGE.519]
1089  */
1090 ULONG CDECL IStream16_fnAddRef(IStream16 *iface)
1091 {
1092         IStream16Impl *This = impl_from_IStream16(iface);
1093         return InterlockedIncrement(&This->ref);
1094 }
1095
1096 static void
1097 _ilockbytes16_addref(SEGPTR lockbytes) {
1098     DWORD args[1];
1099     HRESULT hres;
1100
1101     args[0] = (DWORD)lockbytes; /* iface */
1102     if (!WOWCallback16Ex(
1103         (DWORD)((const ILockBytes16Vtbl*)MapSL(
1104                     (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
1105         )->AddRef,
1106         WCB16_PASCAL,
1107         1*sizeof(DWORD),
1108         (LPVOID)args,
1109         (LPDWORD)&hres
1110     ))
1111         ERR("CallTo16 ILockBytes16::AddRef() failed, hres %x\n",hres);
1112 }
1113
1114 static void
1115 _ilockbytes16_release(SEGPTR lockbytes) {
1116     DWORD args[1];
1117     HRESULT hres;
1118
1119     args[0] = (DWORD)lockbytes; /* iface */
1120     if (!WOWCallback16Ex(
1121         (DWORD)((const ILockBytes16Vtbl*)MapSL(
1122                     (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
1123         )->Release,
1124         WCB16_PASCAL,
1125         1*sizeof(DWORD),
1126         (LPVOID)args,
1127         (LPDWORD)&hres
1128     ))
1129         ERR("CallTo16 ILockBytes16::Release() failed, hres %x\n",hres);
1130 }
1131
1132 static void
1133 _ilockbytes16_flush(SEGPTR lockbytes) {
1134     DWORD args[1];
1135     HRESULT hres;
1136
1137     args[0] = (DWORD)lockbytes; /* iface */
1138     if (!WOWCallback16Ex(
1139         (DWORD)((const ILockBytes16Vtbl*)MapSL(
1140                     (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
1141         )->Flush,
1142         WCB16_PASCAL,
1143         1*sizeof(DWORD),
1144         (LPVOID)args,
1145         (LPDWORD)&hres
1146     ))
1147         ERR("CallTo16 ILockBytes16::Flush() failed, hres %x\n",hres);
1148 }
1149
1150 /******************************************************************************
1151  * IStream16_Release [STORAGE.520]
1152  */
1153 ULONG CDECL IStream16_fnRelease(IStream16 *iface)
1154 {
1155         IStream16Impl *This = impl_from_IStream16(iface);
1156         ULONG ref;
1157
1158         if (This->str.hf)
1159             FlushFileBuffers(This->str.hf);
1160         else
1161             _ilockbytes16_flush(This->str.lockbytes);
1162         ref = InterlockedDecrement(&This->ref);
1163         if (ref)
1164             return ref;
1165
1166         if (This->str.hf)
1167             CloseHandle(This->str.hf);
1168         else
1169             _ilockbytes16_release(This->str.lockbytes);
1170         UnMapLS( This->thisptr );
1171         HeapFree( GetProcessHeap(), 0, This );
1172         return 0;
1173 }
1174
1175 /******************************************************************************
1176  *              IStream16_Seek  [STORAGE.523]
1177  *
1178  * FIXME
1179  *    Does not handle 64 bits
1180  */
1181 HRESULT CDECL IStream16_fnSeek(IStream16 *iface, LARGE_INTEGER offset, DWORD whence,
1182         ULARGE_INTEGER *newpos)
1183 {
1184         IStream16Impl *This = impl_from_IStream16(iface);
1185         TRACE_(relay)("(%p)->([%d.%d],%d,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
1186
1187         switch (whence) {
1188         /* unix SEEK_xx should be the same as win95 ones */
1189         case SEEK_SET:
1190                 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
1191                  * right now.
1192                  */
1193                 assert(offset.u.HighPart==0);
1194                 This->offset.u.HighPart = offset.u.HighPart;
1195                 This->offset.u.LowPart = offset.u.LowPart;
1196                 break;
1197         case SEEK_CUR:
1198                 if (offset.u.HighPart < 0) {
1199                         /* FIXME: is this negation correct ? */
1200                         offset.u.HighPart = -offset.u.HighPart;
1201                         offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
1202
1203                         assert(offset.u.HighPart==0);
1204                         assert(This->offset.u.LowPart >= offset.u.LowPart);
1205                         This->offset.u.LowPart -= offset.u.LowPart;
1206                 } else {
1207                         assert(offset.u.HighPart==0);
1208                         This->offset.u.LowPart+= offset.u.LowPart;
1209                 }
1210                 break;
1211         case SEEK_END:
1212                 assert(offset.u.HighPart==0);
1213                 This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
1214                 break;
1215         }
1216         if (This->offset.u.LowPart>This->stde.pps_size)
1217                 This->offset.u.LowPart=This->stde.pps_size;
1218         if (newpos) *newpos = This->offset;
1219         return S_OK;
1220 }
1221
1222 /******************************************************************************
1223  *              IStream16_Read  [STORAGE.521]
1224  */
1225 HRESULT CDECL IStream16_fnRead(IStream16 *iface, void *pv, ULONG cb, ULONG *pcbRead)
1226 {
1227         IStream16Impl *This = impl_from_IStream16(iface);
1228         BYTE    block[BIGSIZE];
1229         ULONG   *bytesread=pcbRead,xxread;
1230         int     blocknr;
1231         LPBYTE  pbv = pv;
1232
1233         TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbRead);
1234         if (!pcbRead) bytesread=&xxread;
1235         *bytesread = 0;
1236
1237         if (cb>This->stde.pps_size-This->offset.u.LowPart)
1238                 cb=This->stde.pps_size-This->offset.u.LowPart;
1239         if (This->stde.pps_size < 0x1000) {
1240                 /* use small block reader */
1241                 blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1242                 while (cb) {
1243                         unsigned int cc;
1244
1245                         if (!STORAGE_get_small_block(&This->str,blocknr,block)) {
1246                            WARN("small block read failed!!!\n");
1247                                 return E_FAIL;
1248                         }
1249                         cc = cb;
1250                         if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1251                                 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1252                         memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1253                         This->offset.u.LowPart+=cc;
1254                         pbv+=cc;
1255                         *bytesread+=cc;
1256                         cb-=cc;
1257                         blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
1258                 }
1259         } else {
1260                 /* use big block reader */
1261                 blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1262                 while (cb) {
1263                         unsigned int cc;
1264
1265                         if (!STORAGE_get_big_block(&This->str,blocknr,block)) {
1266                                 WARN("big block read failed!!!\n");
1267                                 return E_FAIL;
1268                         }
1269                         cc = cb;
1270                         if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1271                                 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1272                         memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1273                         This->offset.u.LowPart+=cc;
1274                         pbv+=cc;
1275                         *bytesread+=cc;
1276                         cb-=cc;
1277                         blocknr=STORAGE_get_next_big_blocknr(&This->str,blocknr);
1278                 }
1279         }
1280         return S_OK;
1281 }
1282
1283 /******************************************************************************
1284  *              IStream16_Write [STORAGE.522]
1285  */
1286 HRESULT CDECL IStream16_fnWrite(IStream16 *iface, const void *pv, ULONG cb, ULONG *pcbWrite)
1287 {
1288         IStream16Impl *This = impl_from_IStream16(iface);
1289         BYTE    block[BIGSIZE];
1290         ULONG   *byteswritten=pcbWrite,xxwritten;
1291         int     oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1292         const BYTE* pbv = pv;
1293
1294         if (!pcbWrite) byteswritten=&xxwritten;
1295         *byteswritten = 0;
1296
1297         TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbWrite);
1298         /* do we need to junk some blocks? */
1299         newsize = This->offset.u.LowPart+cb;
1300         oldsize = This->stde.pps_size;
1301         if (newsize < oldsize) {
1302                 if (oldsize < 0x1000) {
1303                         /* only small blocks */
1304                         blocknr=STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,newsize/SMALLSIZE);
1305
1306                         assert(blocknr>=0);
1307
1308                         /* will set the rest of the chain to 'free' */
1309                         if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1310                                 return E_FAIL;
1311                 } else {
1312                         if (newsize >= 0x1000) {
1313                                 blocknr=STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,newsize/BIGSIZE);
1314                                 assert(blocknr>=0);
1315
1316                                 /* will set the rest of the chain to 'free' */
1317                                 if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1318                                         return E_FAIL;
1319                         } else {
1320                                 /* Migrate large blocks to small blocks
1321                                  * (we just migrate newsize bytes)
1322                                  */
1323                                 LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1324                                 HRESULT r = E_FAIL;
1325
1326                                 cc      = newsize;
1327                                 blocknr = This->stde.pps_sb;
1328                                 curdata = data;
1329                                 while (cc>0) {
1330                                         if (!STORAGE_get_big_block(&This->str,blocknr,curdata)) {
1331                                                 HeapFree(GetProcessHeap(),0,data);
1332                                                 return E_FAIL;
1333                                         }
1334                                         curdata += BIGSIZE;
1335                                         cc      -= BIGSIZE;
1336                                         blocknr  = STORAGE_get_next_big_blocknr(&This->str,blocknr);
1337                                 }
1338                                 /* frees complete chain for this stream */
1339                                 if (!STORAGE_set_big_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1340                                         goto err;
1341                                 curdata = data;
1342                                 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(&This->str);
1343                                 if (blocknr<0)
1344                                         goto err;
1345                                 cc      = newsize;
1346                                 while (cc>0) {
1347                                         if (!STORAGE_put_small_block(&This->str,blocknr,curdata))
1348                                                 goto err;
1349                                         cc      -= SMALLSIZE;
1350                                         if (cc<=0) {
1351                                                 if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1352                                                         goto err;
1353                                                 break;
1354                                         } else {
1355                                                 int newblocknr = STORAGE_get_free_small_blocknr(&This->str);
1356                                                 if (newblocknr<0)
1357                                                         goto err;
1358                                                 if (!STORAGE_set_small_chain(&This->str,blocknr,newblocknr))
1359                                                         goto err;
1360                                                 blocknr = newblocknr;
1361                                         }
1362                                         curdata += SMALLSIZE;
1363                                 }
1364                                 r = S_OK;
1365                         err:
1366                                 HeapFree(GetProcessHeap(),0,data);
1367                                 if(r != S_OK)
1368                                         return r;
1369                         }
1370                 }
1371                 This->stde.pps_size = newsize;
1372         }
1373
1374         if (newsize > oldsize) {
1375                 if (oldsize >= 0x1000) {
1376                         /* should return the block right before the 'endofchain' */
1377                         blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1378                         assert(blocknr>=0);
1379                         lastblocknr     = blocknr;
1380                         for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1381                                 blocknr = STORAGE_get_free_big_blocknr(&This->str);
1382                                 if (blocknr<0)
1383                                         return E_FAIL;
1384                                 if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
1385                                         return E_FAIL;
1386                                 lastblocknr = blocknr;
1387                         }
1388                         if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1389                                 return E_FAIL;
1390                 } else {
1391                         if (newsize < 0x1000) {
1392                                 /* find startblock */
1393                                 if (!oldsize)
1394                                         This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(&This->str);
1395                                 else
1396                                         blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1397                                 if (blocknr<0)
1398                                         return E_FAIL;
1399
1400                                 /* allocate required new small blocks */
1401                                 lastblocknr = blocknr;
1402                                 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1403                                         blocknr = STORAGE_get_free_small_blocknr(&This->str);
1404                                         if (blocknr<0)
1405                                                 return E_FAIL;
1406                                         if (!STORAGE_set_small_chain(&This->str,lastblocknr,blocknr))
1407                                                 return E_FAIL;
1408                                         lastblocknr = blocknr;
1409                                 }
1410                                 /* and terminate the chain */
1411                                 if (!STORAGE_set_small_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1412                                         return E_FAIL;
1413                         } else {
1414                                 if (!oldsize) {
1415                                         /* no single block allocated yet */
1416                                         blocknr=STORAGE_get_free_big_blocknr(&This->str);
1417                                         if (blocknr<0)
1418                                                 return E_FAIL;
1419                                         This->stde.pps_sb = blocknr;
1420                                 } else {
1421                                         /* Migrate small blocks to big blocks */
1422                                         LPBYTE  curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1423                                         HRESULT r = E_FAIL;
1424
1425                                         cc      = oldsize;
1426                                         blocknr = This->stde.pps_sb;
1427                                         curdata = data;
1428                                         /* slurp in */
1429                                         while (cc>0) {
1430                                                 if (!STORAGE_get_small_block(&This->str,blocknr,curdata))
1431                                                         goto err2;
1432                                                 curdata += SMALLSIZE;
1433                                                 cc      -= SMALLSIZE;
1434                                                 blocknr  = STORAGE_get_next_small_blocknr(&This->str,blocknr);
1435                                         }
1436                                         /* free small block chain */
1437                                         if (!STORAGE_set_small_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1438                                                 goto err2;
1439                                         curdata = data;
1440                                         blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(&This->str);
1441                                         if (blocknr<0)
1442                                                 goto err2;
1443                                         /* put the data into the big blocks */
1444                                         cc      = This->stde.pps_size;
1445                                         while (cc>0) {
1446                                                 if (!STORAGE_put_big_block(&This->str,blocknr,curdata))
1447                                                         goto err2;
1448                                                 cc      -= BIGSIZE;
1449                                                 if (cc<=0) {
1450                                                         if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1451                                                                 goto err2;
1452                                                         break;
1453                                                 } else {
1454                                                         int newblocknr = STORAGE_get_free_big_blocknr(&This->str);
1455                                                         if (newblocknr<0)
1456                                                                 goto err2;
1457                                                         if (!STORAGE_set_big_chain(&This->str,blocknr,newblocknr))
1458                                                                 goto err2;
1459                                                         blocknr = newblocknr;
1460                                                 }
1461                                                 curdata += BIGSIZE;
1462                                         }
1463                                         r = S_OK;
1464                                 err2:
1465                                         HeapFree(GetProcessHeap(),0,data);
1466                                         if(r != S_OK)
1467                                                 return r;
1468                                 }
1469                                 /* generate big blocks to fit the new data */
1470                                 lastblocknr     = blocknr;
1471                                 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1472                                         blocknr = STORAGE_get_free_big_blocknr(&This->str);
1473                                         if (blocknr<0)
1474                                                 return E_FAIL;
1475                                         if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
1476                                                 return E_FAIL;
1477                                         lastblocknr = blocknr;
1478                                 }
1479                                 /* terminate chain */
1480                                 if (!STORAGE_set_big_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1481                                         return E_FAIL;
1482                         }
1483                 }
1484                 This->stde.pps_size = newsize;
1485         }
1486
1487         /* There are just some cases where we didn't modify it, we write it out
1488          * every time
1489          */
1490         if (!STORAGE_put_pps_entry(&This->str,This->ppsent,&(This->stde)))
1491                 return E_FAIL;
1492
1493         /* finally the write pass */
1494         if (This->stde.pps_size < 0x1000) {
1495                 blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1496                 assert(blocknr>=0);
1497                 while (cb>0) {
1498                         /* we ensured that it is allocated above */
1499                         assert(blocknr>=0);
1500                         /* Read old block every time, since we can have
1501                          * overlapping data at START and END of the write
1502                          */
1503                         if (!STORAGE_get_small_block(&This->str,blocknr,block))
1504                                 return E_FAIL;
1505
1506                         cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1507                         if (cc>cb)
1508                                 cc=cb;
1509                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1510                                 pbv+curoffset,
1511                                 cc
1512                         );
1513                         if (!STORAGE_put_small_block(&This->str,blocknr,block))
1514                                 return E_FAIL;
1515                         cb                      -= cc;
1516                         curoffset               += cc;
1517                         pbv                     += cc;
1518                         This->offset.u.LowPart  += cc;
1519                         *byteswritten           += cc;
1520                         blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
1521                 }
1522         } else {
1523                 blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1524                 assert(blocknr>=0);
1525                 while (cb>0) {
1526                         /* we ensured that it is allocated above, so it better is */
1527                         assert(blocknr>=0);
1528                         /* read old block every time, since we can have
1529                          * overlapping data at START and END of the write
1530                          */
1531                         if (!STORAGE_get_big_block(&This->str,blocknr,block))
1532                                 return E_FAIL;
1533
1534                         cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1535                         if (cc>cb)
1536                                 cc=cb;
1537                         memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1538                                 pbv+curoffset,
1539                                 cc
1540                         );
1541                         if (!STORAGE_put_big_block(&This->str,blocknr,block))
1542                                 return E_FAIL;
1543                         cb                      -= cc;
1544                         curoffset               += cc;
1545                         pbv                     += cc;
1546                         This->offset.u.LowPart  += cc;
1547                         *byteswritten           += cc;
1548                         blocknr = STORAGE_get_next_big_blocknr(&This->str,blocknr);
1549                 }
1550         }
1551         return S_OK;
1552 }
1553
1554 /******************************************************************************
1555  *              _create_istream16       [Internal]
1556  */
1557 static void _create_istream16(LPSTREAM16 *str) {
1558         IStream16Impl*  lpst;
1559
1560         if (!strvt16.QueryInterface) {
1561                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1562                 if (wp>=32) {
1563                   /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1564 #define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1565                         VTENT(QueryInterface);
1566                         VTENT(AddRef);
1567                         VTENT(Release);
1568                         VTENT(Read);
1569                         VTENT(Write);
1570                         VTENT(Seek);
1571                         VTENT(SetSize);
1572                         VTENT(CopyTo);
1573                         VTENT(Commit);
1574                         VTENT(Revert);
1575                         VTENT(LockRegion);
1576                         VTENT(UnlockRegion);
1577                         VTENT(Stat);
1578                         VTENT(Clone);
1579 #undef VTENT
1580                         segstrvt16 = (const IStream16Vtbl*)MapLS( &strvt16 );
1581                 } else {
1582 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1583                         VTENT(QueryInterface);
1584                         VTENT(AddRef);
1585                         VTENT(Release);
1586                         VTENT(Read);
1587                         VTENT(Write);
1588                         VTENT(Seek);
1589         /*
1590                         VTENT(CopyTo);
1591                         VTENT(Commit);
1592                         VTENT(SetSize);
1593                         VTENT(Revert);
1594                         VTENT(LockRegion);
1595                         VTENT(UnlockRegion);
1596                         VTENT(Stat);
1597                         VTENT(Clone);
1598         */
1599 #undef VTENT
1600                         segstrvt16 = &strvt16;
1601                 }
1602         }
1603         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1604         lpst->IStream16_iface.lpVtbl = segstrvt16;
1605         lpst->ref       = 1;
1606         lpst->thisptr   = MapLS( lpst );
1607         lpst->str.hf    = NULL;
1608         lpst->str.lockbytes     = 0;
1609         *str = (void*)lpst->thisptr;
1610 }
1611
1612 static inline IStorage16Impl *impl_from_IStorage16(IStorage16 *iface)
1613 {
1614         return CONTAINING_RECORD(iface, IStorage16Impl, IStorage16_iface);
1615 }
1616
1617 /******************************************************************************
1618  *              IStorage16_QueryInterface       [STORAGE.500]
1619  */
1620 HRESULT CDECL IStorage16_fnQueryInterface(IStorage16 *iface, REFIID refiid, void **obj)
1621 {
1622         IStorage16Impl *This = impl_from_IStorage16(iface);
1623
1624         TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1625
1626         if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1627                 *obj = This;
1628                 return 0;
1629         }
1630         return OLE_E_ENUM_NOMORE;
1631 }
1632
1633 /******************************************************************************
1634  * IStorage16_AddRef [STORAGE.501]
1635  */
1636 ULONG CDECL IStorage16_fnAddRef(IStorage16 *iface)
1637 {
1638         IStorage16Impl *This = impl_from_IStorage16(iface);
1639         return InterlockedIncrement(&This->ref);
1640 }
1641
1642 /******************************************************************************
1643  * IStorage16_Release [STORAGE.502]
1644  */
1645 ULONG CDECL IStorage16_fnRelease(IStorage16 *iface)
1646 {
1647         IStorage16Impl *This = impl_from_IStorage16(iface);
1648         ULONG ref;
1649         ref = InterlockedDecrement(&This->ref);
1650         if (!ref)
1651         {
1652             UnMapLS( This->thisptr );
1653             HeapFree( GetProcessHeap(), 0, This );
1654         }
1655         return ref;
1656 }
1657
1658 /******************************************************************************
1659  * IStorage16_Stat [STORAGE.517]
1660  */
1661 HRESULT CDECL IStorage16_fnStat(IStorage16 *iface, STATSTG16 *pstatstg, DWORD grfStatFlag)
1662 {
1663         IStorage16Impl *This = impl_from_IStorage16(iface);
1664         DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1665         LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1666
1667         TRACE("(%p)->(%p,0x%08x)\n",
1668                 This,pstatstg,grfStatFlag
1669         );
1670         WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1671         pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1672         pstatstg->type = This->stde.pps_type;
1673         pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1674         pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1675         pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1676         pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1677         pstatstg->grfMode       = 0; /* FIXME */
1678         pstatstg->grfLocksSupported = 0; /* FIXME */
1679         pstatstg->clsid         = This->stde.pps_guid;
1680         pstatstg->grfStateBits  = 0; /* FIXME */
1681         pstatstg->reserved      = 0;
1682         return S_OK;
1683 }
1684
1685 /******************************************************************************
1686  *              IStorage16_Commit       [STORAGE.509]
1687  */
1688 HRESULT CDECL IStorage16_fnCommit(IStorage16 *iface, DWORD commitflags)
1689 {
1690         IStorage16Impl *This = impl_from_IStorage16(iface);
1691         FIXME("(%p)->(0x%08x),STUB!\n",
1692                 This,commitflags
1693         );
1694         return S_OK;
1695 }
1696
1697 /******************************************************************************
1698  * IStorage16_CopyTo [STORAGE.507]
1699  */
1700 HRESULT CDECL IStorage16_fnCopyTo(IStorage16 *iface, DWORD ciidExclude, const IID *rgiidExclude,
1701         SNB16 SNB16Exclude, IStorage16 *pstgDest)
1702 {
1703         IStorage16Impl *This = impl_from_IStorage16(iface);
1704         FIXME("IStorage16(%p)->(0x%08x,%s,%p,%p),stub!\n",
1705                 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1706         );
1707         return S_OK;
1708 }
1709
1710
1711 /******************************************************************************
1712  * IStorage16_CreateStorage [STORAGE.505]
1713  */
1714 HRESULT CDECL IStorage16_fnCreateStorage(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
1715         DWORD dwStgFormat, DWORD reserved2, IStorage16 **ppstg)
1716 {
1717         IStorage16Impl *This = impl_from_IStorage16(iface);
1718         IStorage16Impl* lpstg;
1719         int             ppsent,x;
1720         struct storage_pps_entry        stde;
1721         struct storage_header sth;
1722         BOOL ret;
1723         int      nPPSEntries;
1724
1725         READ_HEADER(&This->str);
1726         TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1727                 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1728         );
1729         if (grfMode & STGM_TRANSACTED)
1730                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1731         _create_istorage16(ppstg);
1732         lpstg = MapSL((SEGPTR)*ppstg);
1733         if (This->str.hf) {
1734             DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
1735                              &lpstg->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1736         } else {
1737             lpstg->str.lockbytes = This->str.lockbytes;
1738             _ilockbytes16_addref(This->str.lockbytes);
1739         }
1740
1741         ppsent=STORAGE_get_free_pps_entry(&lpstg->str);
1742         if (ppsent<0)
1743                 return E_FAIL;
1744         stde=This->stde;
1745         if (stde.pps_dir==-1) {
1746                 stde.pps_dir = ppsent;
1747                 x = This->ppsent;
1748         } else {
1749                 FIXME(" use prev chain too ?\n");
1750                 x=stde.pps_dir;
1751                 if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
1752                         return E_FAIL;
1753                 while (stde.pps_next!=-1) {
1754                         x=stde.pps_next;
1755                         if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
1756                                 return E_FAIL;
1757                 }
1758                 stde.pps_next = ppsent;
1759         }
1760         ret = STORAGE_put_pps_entry(&lpstg->str,x,&stde);
1761         assert(ret);
1762         nPPSEntries = STORAGE_get_pps_entry(&lpstg->str,ppsent,&(lpstg->stde));
1763         assert(nPPSEntries == 1);
1764         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1765                              sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1766         lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1767         lpstg->stde.pps_next    = -1;
1768         lpstg->stde.pps_prev    = -1;
1769         lpstg->stde.pps_dir     = -1;
1770         lpstg->stde.pps_sb      = -1;
1771         lpstg->stde.pps_size    =  0;
1772         lpstg->stde.pps_type    =  1;
1773         lpstg->ppsent           = ppsent;
1774         /* FIXME: timestamps? */
1775         if (!STORAGE_put_pps_entry(&lpstg->str,ppsent,&(lpstg->stde)))
1776                 return E_FAIL;
1777         return S_OK;
1778 }
1779
1780 /******************************************************************************
1781  *              IStorage16_CreateStream [STORAGE.503]
1782  */
1783 HRESULT CDECL IStorage16_fnCreateStream(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
1784         DWORD reserved1, DWORD reserved2, IStream16 **ppstm)
1785 {
1786         IStorage16Impl *This = impl_from_IStorage16(iface);
1787         IStream16Impl*  lpstr;
1788         int             ppsent,x;
1789         struct storage_pps_entry        stde;
1790         BOOL ret;
1791         int      nPPSEntries;
1792
1793         TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1794                 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1795         );
1796         if (grfMode & STGM_TRANSACTED)
1797                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1798         _create_istream16(ppstm);
1799         lpstr = MapSL((SEGPTR)*ppstm);
1800         if (This->str.hf) {
1801             DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
1802                              &lpstr->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1803         } else {
1804             lpstr->str.lockbytes = This->str.lockbytes;
1805             _ilockbytes16_addref(This->str.lockbytes);
1806         }
1807         lpstr->offset.u.LowPart = 0;
1808         lpstr->offset.u.HighPart= 0;
1809
1810         ppsent=STORAGE_get_free_pps_entry(&lpstr->str);
1811         if (ppsent<0)
1812                 return E_FAIL;
1813         stde=This->stde;
1814         if (stde.pps_next==-1)
1815                 x=This->ppsent;
1816         else
1817                 while (stde.pps_next!=-1) {
1818                         x=stde.pps_next;
1819                         if (1!=STORAGE_get_pps_entry(&lpstr->str,x,&stde))
1820                                 return E_FAIL;
1821                 }
1822         stde.pps_next = ppsent;
1823         ret = STORAGE_put_pps_entry(&lpstr->str,x,&stde);
1824         assert(ret);
1825         nPPSEntries = STORAGE_get_pps_entry(&lpstr->str,ppsent,&(lpstr->stde));
1826         assert(nPPSEntries == 1);
1827         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1828                              sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1829         lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1830         lpstr->stde.pps_next    = -1;
1831         lpstr->stde.pps_prev    = -1;
1832         lpstr->stde.pps_dir     = -1;
1833         lpstr->stde.pps_sb      = -1;
1834         lpstr->stde.pps_size    =  0;
1835         lpstr->stde.pps_type    =  2;
1836         lpstr->ppsent           = ppsent;
1837
1838         /* FIXME: timestamps? */
1839         if (!STORAGE_put_pps_entry(&lpstr->str,ppsent,&(lpstr->stde)))
1840                 return E_FAIL;
1841         return S_OK;
1842 }
1843
1844 /******************************************************************************
1845  *              IStorage16_OpenStorage  [STORAGE.506]
1846  */
1847 HRESULT CDECL IStorage16_fnOpenStorage(IStorage16 *iface, LPCOLESTR16 pwcsName,
1848         IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg)
1849 {
1850         IStorage16Impl *This = impl_from_IStorage16(iface);
1851         IStream16Impl*  lpstg;
1852         WCHAR           name[33];
1853         int             newpps;
1854
1855         TRACE("(%p)->(%s,%p,0x%08x,%p,0x%08x,%p)\n",
1856                 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1857         );
1858         if (grfMode & STGM_TRANSACTED)
1859                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1860         _create_istorage16(ppstg);
1861         lpstg = MapSL((SEGPTR)*ppstg);
1862         if (This->str.hf) {
1863             DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
1864                              &lpstg->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1865         } else {
1866             lpstg->str.lockbytes = This->str.lockbytes;
1867             _ilockbytes16_addref(This->str.lockbytes);
1868         }
1869         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1870         newpps = STORAGE_look_for_named_pps(&lpstg->str,This->stde.pps_dir,name);
1871         if (newpps==-1) {
1872                 IStream16_fnRelease(&lpstg->IStream16_iface);
1873                 return E_FAIL;
1874         }
1875
1876         if (1!=STORAGE_get_pps_entry(&lpstg->str,newpps,&(lpstg->stde))) {
1877                 IStream16_fnRelease(&lpstg->IStream16_iface);
1878                 return E_FAIL;
1879         }
1880         lpstg->ppsent           = newpps;
1881         return S_OK;
1882 }
1883
1884 /******************************************************************************
1885  * IStorage16_OpenStream [STORAGE.504]
1886  */
1887 HRESULT CDECL IStorage16_fnOpenStream(IStorage16 *iface, LPCOLESTR16 pwcsName, void *reserved1,
1888         DWORD grfMode, DWORD reserved2, IStream16 **ppstm)
1889 {
1890         IStorage16Impl *This = impl_from_IStorage16(iface);
1891         IStream16Impl*  lpstr;
1892         WCHAR           name[33];
1893         int             newpps;
1894
1895         TRACE("(%p)->(%s,%p,0x%08x,0x%08x,%p)\n",
1896                 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1897         );
1898         if (grfMode & STGM_TRANSACTED)
1899                 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1900         _create_istream16(ppstm);
1901         lpstr = MapSL((SEGPTR)*ppstm);
1902         if (This->str.hf) {
1903             DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
1904                              &lpstr->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1905         } else {
1906             lpstr->str.lockbytes = This->str.lockbytes;
1907             _ilockbytes16_addref(This->str.lockbytes);
1908         }
1909         MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1910         newpps = STORAGE_look_for_named_pps(&lpstr->str,This->stde.pps_dir,name);
1911         if (newpps==-1) {
1912                 IStream16_fnRelease(&lpstr->IStream16_iface);
1913                 return E_FAIL;
1914         }
1915
1916         if (1!=STORAGE_get_pps_entry(&lpstr->str,newpps,&(lpstr->stde))) {
1917                 IStream16_fnRelease(&lpstr->IStream16_iface);
1918                 return E_FAIL;
1919         }
1920         lpstr->offset.u.LowPart         = 0;
1921         lpstr->offset.u.HighPart        = 0;
1922         lpstr->ppsent                   = newpps;
1923         return S_OK;
1924 }
1925
1926 /******************************************************************************
1927  * _create_istorage16 [INTERNAL]
1928  */
1929 static void _create_istorage16(LPSTORAGE16 *stg) {
1930         IStorage16Impl* lpst;
1931
1932         if (!stvt16.QueryInterface) {
1933                 HMODULE16       wp = GetModuleHandle16("STORAGE");
1934                 if (wp>=32) {
1935 #define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1936                         VTENT(QueryInterface)
1937                         VTENT(AddRef)
1938                         VTENT(Release)
1939                         VTENT(CreateStream)
1940                         VTENT(OpenStream)
1941                         VTENT(CreateStorage)
1942                         VTENT(OpenStorage)
1943                         VTENT(CopyTo)
1944                         VTENT(MoveElementTo)
1945                         VTENT(Commit)
1946                         VTENT(Revert)
1947                         VTENT(EnumElements)
1948                         VTENT(DestroyElement)
1949                         VTENT(RenameElement)
1950                         VTENT(SetElementTimes)
1951                         VTENT(SetClass)
1952                         VTENT(SetStateBits)
1953                         VTENT(Stat)
1954 #undef VTENT
1955                         segstvt16 = (const IStorage16Vtbl*)MapLS( &stvt16 );
1956                 } else {
1957 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1958                         VTENT(QueryInterface)
1959                         VTENT(AddRef)
1960                         VTENT(Release)
1961                         VTENT(CreateStream)
1962                         VTENT(OpenStream)
1963                         VTENT(CreateStorage)
1964                         VTENT(OpenStorage)
1965                         VTENT(CopyTo)
1966                         VTENT(Commit)
1967         /*  not (yet) implemented ...
1968                         VTENT(MoveElementTo)
1969                         VTENT(Revert)
1970                         VTENT(EnumElements)
1971                         VTENT(DestroyElement)
1972                         VTENT(RenameElement)
1973                         VTENT(SetElementTimes)
1974                         VTENT(SetClass)
1975                         VTENT(SetStateBits)
1976                         VTENT(Stat)
1977         */
1978 #undef VTENT
1979                         segstvt16 = &stvt16;
1980                 }
1981         }
1982         lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1983         lpst->IStorage16_iface.lpVtbl = segstvt16;
1984         lpst->str.hf    = NULL;
1985         lpst->str.lockbytes     = 0;
1986         lpst->ref       = 1;
1987         lpst->thisptr   = MapLS(lpst);
1988         *stg = (void*)lpst->thisptr;
1989 }
1990
1991 /******************************************************************************
1992  *      Storage API functions
1993  */
1994
1995 /******************************************************************************
1996  *              StgCreateDocFileA       [STORAGE.1]
1997  */
1998 HRESULT WINAPI StgCreateDocFile16(
1999         LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
2000 ) {
2001         HANDLE          hf;
2002         int             i,ret;
2003         IStorage16Impl* lpstg;
2004         struct storage_pps_entry        stde;
2005
2006         TRACE("(%s,0x%08x,0x%08x,%p)\n",
2007                 pwcsName,grfMode,reserved,ppstgOpen
2008         );
2009         _create_istorage16(ppstgOpen);
2010         hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
2011         if (hf==INVALID_HANDLE_VALUE) {
2012                 WARN("couldn't open file for storage:%d\n",GetLastError());
2013                 return E_FAIL;
2014         }
2015         lpstg = MapSL((SEGPTR)*ppstgOpen);
2016         lpstg->str.hf = hf;
2017         lpstg->str.lockbytes = 0;
2018         /* FIXME: check for existence before overwriting? */
2019         if (!STORAGE_init_storage(&lpstg->str)) {
2020                 CloseHandle(hf);
2021                 return E_FAIL;
2022         }
2023         i=0;ret=0;
2024         while (!ret) { /* neither 1 nor <0 */
2025                 ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
2026                 if ((ret==1) && (stde.pps_type==5)) {
2027                         lpstg->stde     = stde;
2028                         lpstg->ppsent   = i;
2029                         break;
2030                 }
2031                 i++;
2032         }
2033         if (ret!=1) {
2034                 IStorage16_fnRelease(&lpstg->IStorage16_iface);
2035                 return E_FAIL;
2036         }
2037
2038         return S_OK;
2039 }
2040
2041 /******************************************************************************
2042  * StgIsStorageFile [STORAGE.5]
2043  */
2044 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
2045         UNICODE_STRING strW;
2046         HRESULT ret;
2047
2048         RtlCreateUnicodeStringFromAsciiz(&strW, fn);
2049         ret = StgIsStorageFile( strW.Buffer );
2050         RtlFreeUnicodeString( &strW );
2051
2052         return ret;
2053 }
2054
2055 /******************************************************************************
2056  * StgOpenStorage [STORAGE.3]
2057  */
2058 HRESULT WINAPI StgOpenStorage16(
2059         LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
2060         SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
2061 ) {
2062         HANDLE          hf;
2063         int             ret,i;
2064         IStorage16Impl* lpstg;
2065         struct storage_pps_entry        stde;
2066
2067         TRACE("(%s,%p,0x%08x,%p,%d,%p)\n",
2068               pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
2069         );
2070         _create_istorage16(ppstgOpen);
2071         hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
2072         if (hf==INVALID_HANDLE_VALUE) {
2073                 WARN("Couldn't open file for storage\n");
2074                 return E_FAIL;
2075         }
2076         lpstg = MapSL((SEGPTR)*ppstgOpen);
2077         lpstg->str.hf = hf;
2078
2079         i=0;ret=0;
2080         while (!ret) { /* neither 1 nor <0 */
2081                 ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
2082                 if ((ret==1) && (stde.pps_type==5)) {
2083                         lpstg->stde=stde;
2084                         break;
2085                 }
2086                 i++;
2087         }
2088         if (ret!=1) {
2089                 IStorage16_fnRelease(&lpstg->IStorage16_iface);
2090                 return E_FAIL;
2091         }
2092         return S_OK;
2093
2094 }
2095
2096 /******************************************************************************
2097  *              StgIsStorageILockBytes        [STORAGE.6]
2098  *
2099  * Determines if the ILockBytes contains a storage object.
2100  */
2101 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
2102 {
2103   DWORD args[6];
2104   HRESULT hres;
2105   HANDLE16 hsig;
2106
2107   args[0] = (DWORD)plkbyt;      /* iface */
2108   args[1] = args[2] = 0;        /* ULARGE_INTEGER offset */
2109   args[3] = WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
2110   args[4] = 8;
2111   args[5] = 0;
2112
2113   if (!WOWCallback16Ex(
2114       (DWORD)((const ILockBytes16Vtbl*)MapSL(
2115                   (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
2116       )->ReadAt,
2117       WCB16_PASCAL,
2118       6*sizeof(DWORD),
2119       (LPVOID)args,
2120       (LPDWORD)&hres
2121   )) {
2122       ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %x\n",hres);
2123       return hres;
2124   }
2125   if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
2126     WOWGlobalUnlockFree16(args[3]);
2127     return S_OK;
2128   }
2129   WOWGlobalUnlockFree16(args[3]);
2130   return S_FALSE;
2131 }
2132
2133 /******************************************************************************
2134  *    StgOpenStorageOnILockBytes    [STORAGE.4]
2135  *
2136  * PARAMS
2137  *  plkbyt  FIXME: Should probably be an ILockBytes16 *.
2138  */
2139 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2140         SEGPTR plkbyt,
2141         IStorage16 *pstgPriority,
2142         DWORD grfMode,
2143         SNB16 snbExclude,
2144         DWORD reserved,
2145         IStorage16 **ppstgOpen)
2146 {
2147         IStorage16Impl* lpstg;
2148         int i,ret;
2149         struct storage_pps_entry        stde;
2150
2151         FIXME("(%x, %p, 0x%08x, %d, %x, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen);
2152         if ((plkbyt == 0) || (ppstgOpen == 0))
2153                 return STG_E_INVALIDPOINTER;
2154
2155         *ppstgOpen = 0;
2156
2157         _create_istorage16(ppstgOpen);
2158         lpstg = MapSL((SEGPTR)*ppstgOpen);
2159         lpstg->str.hf = NULL;
2160         lpstg->str.lockbytes = plkbyt;
2161         i=0;ret=0;
2162         while (!ret) { /* neither 1 nor <0 */
2163                 ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
2164                 if ((ret==1) && (stde.pps_type==5)) {
2165                         lpstg->stde=stde;
2166                         break;
2167                 }
2168                 i++;
2169         }
2170         if (ret!=1) {
2171                 IStorage16_fnRelease(&lpstg->IStorage16_iface);
2172                 return E_FAIL;
2173         }
2174         return S_OK;
2175 }