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