Get rid of the non-standard ICOM_VFIELD macro.
[wine/multimedia.git] / dlls / ole32 / storage.c
blobabed7bd5b0da74adaca7f22713b32c1afe8d7547
1 /* Compound Storage
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>)
7 * Copyright 1998 Marcus Meissner
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.
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.
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
24 #include "config.h"
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
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"
48 #include "ifs.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(ole);
51 WINE_DECLARE_DEBUG_CHANNEL(relay);
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)*/
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 */
80 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
81 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
82 #define STORAGE_CHAINENTRY_FREE 0xffffffff
85 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
87 #define BIGSIZE 512
88 #define SMALLSIZE 64
90 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
92 #define READ_HEADER STORAGE_get_big_block(hf,-1,(LPBYTE)&sth);assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
93 static ICOM_VTABLE(IStorage16) stvt16;
94 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
95 static ICOM_VTABLE(IStream16) strvt16;
96 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
98 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
99 static void _create_istorage16(LPSTORAGE16 *stg);
100 static void _create_istream16(LPSTREAM16 *str);
102 #define IMPLEMENTED 1
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.
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
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
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
130 * A DocFile is divided into blocks of 512 bytes.
131 * The first block contains the header.
133 * The file header contains The first 109 entries in the VTOC of VTOCs.
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:
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.
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.
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.
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.
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!!!!
165 * So, to review:
167 * 1. If you are using a FAT file system, the location of
168 * your file's blocks is stored in chains.
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).
174 * 3. The VTOC of VTOCs contains descriptions of three file level
175 * streams:
177 * a. The Directory stream
178 * b. The Data stream
179 * c. The Data VTOC stream
181 * These are, of course, represented as chains.
183 * 4. The Data VTOC contains data describing the chains of blocks
184 * within the Data stream.
186 * That's right - we have a total of four levels of block chains!
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.
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.
202 * #define TOTAL_SIMPLE_VTOCS 109
204 * struct DocFile_Header
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 * };
227 * struct DocFile_VTOC
229 * df_int4 aiBlocks[DF_VTOC_SIZE];
230 * };
233 * The meaning of the magic numbers
235 * 0xd0cf11e0 is DocFile with a zero on the end (sort of)
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".
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.
248 * struct DocFile_DirEnt
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 * };
268 * Siblings
269 * ========
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.
275 * A red-black tree can always be balanced very easily. The rules
276 * for a red-black tree are as follows:
278 * 1. The root node is always black.
279 * 2. The parent of a red node is always black.
281 * There is a Java demo of red-black trees at:
283 * http://langevin.usc.edu/BST/RedBlackTree-Example.html
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.
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.
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.
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).
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.
323 /******************************************************************************
324 * STORAGE_get_big_block [Internal]
326 * Reading OLE compound storage
328 static BOOL
329 STORAGE_get_big_block(HANDLE hf,int n,BYTE *block)
331 DWORD result;
333 assert(n>=-1);
334 if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
335 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
337 WARN(" seek failed (%ld)\n",GetLastError());
338 return FALSE;
340 if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
342 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
343 return FALSE;
345 return TRUE;
348 /******************************************************************************
349 * STORAGE_put_big_block [INTERNAL]
351 static BOOL
352 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
354 DWORD result;
356 assert(n>=-1);
357 if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
358 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
360 WARN("seek failed (%ld)\n",GetLastError());
361 return FALSE;
363 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
365 WARN(" write failed (%ld)\n",GetLastError());
366 return FALSE;
368 return TRUE;
371 /******************************************************************************
372 * STORAGE_get_next_big_blocknr [INTERNAL]
374 static int
375 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
376 INT bbs[BIGSIZE/sizeof(INT)];
377 struct storage_header sth;
379 READ_HEADER;
381 assert(blocknr>>7<sth.num_of_bbd_blocks);
382 if (sth.bbd_list[blocknr>>7]==0xffffffff)
383 return -5;
384 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
385 return -5;
386 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
387 return bbs[blocknr&0x7f];
390 /******************************************************************************
391 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
393 static int
394 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
395 INT bbs[BIGSIZE/sizeof(INT)];
396 int lastblock = -1;
397 struct storage_header sth;
399 READ_HEADER;
401 assert(blocknr>=0);
402 while (nr--) {
403 assert((blocknr>>7)<sth.num_of_bbd_blocks);
404 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
406 /* simple caching... */
407 if (lastblock!=sth.bbd_list[blocknr>>7]) {
408 BOOL ret = STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
409 assert(ret);
410 lastblock = sth.bbd_list[blocknr>>7];
412 blocknr = bbs[blocknr&0x7f];
414 return blocknr;
417 /******************************************************************************
418 * STORAGE_get_root_pps_entry [Internal]
420 static BOOL
421 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
422 int blocknr,i;
423 BYTE block[BIGSIZE];
424 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
425 struct storage_header sth;
427 READ_HEADER;
428 blocknr = sth.root_startblock;
429 while (blocknr>=0) {
430 BOOL ret = STORAGE_get_big_block(hf,blocknr,block);
431 assert(ret);
432 for (i=0;i<4;i++) {
433 if (!stde[i].pps_sizeofname)
434 continue;
435 if (stde[i].pps_type==5) {
436 *pstde=stde[i];
437 return TRUE;
440 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
442 return FALSE;
445 /******************************************************************************
446 * STORAGE_get_small_block [INTERNAL]
448 static BOOL
449 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
450 BYTE block[BIGSIZE];
451 int bigblocknr;
452 struct storage_pps_entry root;
453 BOOL ret;
455 assert(blocknr>=0);
456 ret = STORAGE_get_root_pps_entry(hf,&root);
457 assert(ret);
458 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
459 assert(bigblocknr>=0);
460 ret = STORAGE_get_big_block(hf,bigblocknr,block);
461 assert(ret);
463 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
464 return TRUE;
467 /******************************************************************************
468 * STORAGE_put_small_block [INTERNAL]
470 static BOOL
471 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
472 BYTE block[BIGSIZE];
473 int bigblocknr;
474 struct storage_pps_entry root;
475 BOOL ret;
477 assert(blocknr>=0);
479 ret = STORAGE_get_root_pps_entry(hf,&root);
480 assert(ret);
481 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
482 assert(bigblocknr>=0);
483 ret = STORAGE_get_big_block(hf,bigblocknr,block);
484 assert(ret);
486 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
487 ret = STORAGE_put_big_block(hf,bigblocknr,block);
488 assert(ret);
489 return TRUE;
492 /******************************************************************************
493 * STORAGE_get_next_small_blocknr [INTERNAL]
495 static int
496 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
497 BYTE block[BIGSIZE];
498 LPINT sbd = (LPINT)block;
499 int bigblocknr;
500 struct storage_header sth;
501 BOOL ret;
503 READ_HEADER;
504 assert(blocknr>=0);
505 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
506 assert(bigblocknr>=0);
507 ret = STORAGE_get_big_block(hf,bigblocknr,block);
508 assert(ret);
509 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
510 return sbd[blocknr & (128-1)];
513 /******************************************************************************
514 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
516 static int
517 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
518 int lastblocknr=-1;
519 BYTE block[BIGSIZE];
520 LPINT sbd = (LPINT)block;
521 struct storage_header sth;
522 BOOL ret;
524 READ_HEADER;
525 assert(blocknr>=0);
526 while ((nr--) && (blocknr>=0)) {
527 if (lastblocknr/128!=blocknr/128) {
528 int bigblocknr;
529 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
530 assert(bigblocknr>=0);
531 ret = STORAGE_get_big_block(hf,bigblocknr,block);
532 assert(ret);
533 lastblocknr = blocknr;
535 assert(lastblocknr>=0);
536 lastblocknr=blocknr;
537 blocknr=sbd[blocknr & (128-1)];
538 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
540 return blocknr;
543 /******************************************************************************
544 * STORAGE_get_pps_entry [INTERNAL]
546 static int
547 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
548 int blocknr;
549 BYTE block[BIGSIZE];
550 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
551 struct storage_header sth;
552 BOOL ret;
554 READ_HEADER;
555 /* we have 4 pps entries per big block */
556 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
557 assert(blocknr>=0);
558 ret = STORAGE_get_big_block(hf,blocknr,block);
559 assert(ret);
561 *pstde=*stde;
562 return 1;
565 /******************************************************************************
566 * STORAGE_put_pps_entry [Internal]
568 static int
569 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
570 int blocknr;
571 BYTE block[BIGSIZE];
572 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
573 struct storage_header sth;
574 BOOL ret;
576 READ_HEADER;
578 /* we have 4 pps entries per big block */
579 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
580 assert(blocknr>=0);
581 ret = STORAGE_get_big_block(hf,blocknr,block);
582 assert(ret);
583 *stde=*pstde;
584 ret = STORAGE_put_big_block(hf,blocknr,block);
585 assert(ret);
586 return 1;
589 /******************************************************************************
590 * STORAGE_look_for_named_pps [Internal]
592 static int
593 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
594 struct storage_pps_entry stde;
595 int ret;
597 if (n==-1)
598 return -1;
599 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
600 return -1;
602 if (!lstrcmpW(name,stde.pps_rawname))
603 return n;
604 if (stde.pps_prev != -1) {
605 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
606 if (ret!=-1)
607 return ret;
609 if (stde.pps_next != -1) {
610 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
611 if (ret!=-1)
612 return ret;
614 return -1;
617 /******************************************************************************
618 * STORAGE_dump_pps_entry [Internal]
620 * FIXME
621 * Function is unused
623 void
624 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
625 char name[33];
627 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
628 if (!stde->pps_sizeofname)
629 return;
630 DPRINTF("name: %s\n",name);
631 DPRINTF("type: %d\n",stde->pps_type);
632 DPRINTF("prev pps: %ld\n",stde->pps_prev);
633 DPRINTF("next pps: %ld\n",stde->pps_next);
634 DPRINTF("dir pps: %ld\n",stde->pps_dir);
635 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
636 if (stde->pps_type !=2) {
637 time_t t;
638 DWORD dw;
639 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
640 t = dw;
641 DPRINTF("ts1: %s\n",ctime(&t));
642 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
643 t = dw;
644 DPRINTF("ts2: %s\n",ctime(&t));
646 DPRINTF("startblock: %ld\n",stde->pps_sb);
647 DPRINTF("size: %ld\n",stde->pps_size);
650 /******************************************************************************
651 * STORAGE_init_storage [INTERNAL]
653 static BOOL
654 STORAGE_init_storage(HANDLE hf) {
655 BYTE block[BIGSIZE];
656 LPDWORD bbs;
657 struct storage_header *sth;
658 struct storage_pps_entry *stde;
659 DWORD result;
661 SetFilePointer( hf, 0, NULL, SEEK_SET );
662 /* block -1 is the storage header */
663 sth = (struct storage_header*)block;
664 memcpy(sth->magic,STORAGE_magic,8);
665 memset(sth->unknown1,0,sizeof(sth->unknown1));
666 memset(sth->unknown2,0,sizeof(sth->unknown2));
667 memset(sth->unknown3,0,sizeof(sth->unknown3));
668 sth->num_of_bbd_blocks = 1;
669 sth->root_startblock = 1;
670 sth->sbd_startblock = 0xffffffff;
671 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
672 sth->bbd_list[0] = 0;
673 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
674 /* block 0 is the big block directory */
675 bbs=(LPDWORD)block;
676 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
677 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
678 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
679 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
680 /* block 1 is the root directory entry */
681 memset(block,0x00,sizeof(block));
682 stde = (struct storage_pps_entry*)block;
683 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
684 sizeof(stde->pps_rawname)/sizeof(WCHAR));
685 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
686 stde->pps_type = 5;
687 stde->pps_dir = -1;
688 stde->pps_next = -1;
689 stde->pps_prev = -1;
690 stde->pps_sb = 0xffffffff;
691 stde->pps_size = 0;
692 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
695 /******************************************************************************
696 * STORAGE_set_big_chain [Internal]
698 static BOOL
699 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
700 BYTE block[BIGSIZE];
701 LPINT bbd = (LPINT)block;
702 int nextblocknr,bigblocknr;
703 struct storage_header sth;
704 BOOL ret;
706 READ_HEADER;
707 assert(blocknr!=type);
708 while (blocknr>=0) {
709 bigblocknr = sth.bbd_list[blocknr/128];
710 assert(bigblocknr>=0);
711 ret = STORAGE_get_big_block(hf,bigblocknr,block);
712 assert(ret);
714 nextblocknr = bbd[blocknr&(128-1)];
715 bbd[blocknr&(128-1)] = type;
716 if (type>=0)
717 return TRUE;
718 ret = STORAGE_put_big_block(hf,bigblocknr,block);
719 assert(ret);
720 type = STORAGE_CHAINENTRY_FREE;
721 blocknr = nextblocknr;
723 return TRUE;
726 /******************************************************************************
727 * STORAGE_set_small_chain [Internal]
729 static BOOL
730 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
731 BYTE block[BIGSIZE];
732 LPINT sbd = (LPINT)block;
733 int lastblocknr,nextsmallblocknr,bigblocknr;
734 struct storage_header sth;
735 BOOL ret;
737 READ_HEADER;
739 assert(blocknr!=type);
740 lastblocknr=-129;bigblocknr=-2;
741 while (blocknr>=0) {
742 /* cache block ... */
743 if (lastblocknr/128!=blocknr/128) {
744 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
745 assert(bigblocknr>=0);
746 ret = STORAGE_get_big_block(hf,bigblocknr,block);
747 assert(ret);
749 lastblocknr = blocknr;
750 nextsmallblocknr = sbd[blocknr&(128-1)];
751 sbd[blocknr&(128-1)] = type;
752 ret = STORAGE_put_big_block(hf,bigblocknr,block);
753 assert(ret);
754 if (type>=0)
755 return TRUE;
756 type = STORAGE_CHAINENTRY_FREE;
757 blocknr = nextsmallblocknr;
759 return TRUE;
762 /******************************************************************************
763 * STORAGE_get_free_big_blocknr [Internal]
765 static int
766 STORAGE_get_free_big_blocknr(HANDLE hf) {
767 BYTE block[BIGSIZE];
768 LPINT sbd = (LPINT)block;
769 int lastbigblocknr,i,curblock,bigblocknr;
770 struct storage_header sth;
771 BOOL ret;
773 READ_HEADER;
774 curblock = 0;
775 lastbigblocknr = -1;
776 bigblocknr = sth.bbd_list[curblock];
777 while (curblock<sth.num_of_bbd_blocks) {
778 assert(bigblocknr>=0);
779 ret = STORAGE_get_big_block(hf,bigblocknr,block);
780 assert(ret);
781 for (i=0;i<128;i++)
782 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
783 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
784 ret = STORAGE_put_big_block(hf,bigblocknr,block);
785 assert(ret);
786 memset(block,0x42,sizeof(block));
787 ret = STORAGE_put_big_block(hf,i+curblock*128,block);
788 assert(ret);
789 return i+curblock*128;
791 lastbigblocknr = bigblocknr;
792 bigblocknr = sth.bbd_list[++curblock];
794 bigblocknr = curblock*128;
795 /* since we have marked all blocks from 0 up to curblock*128-1
796 * the next free one is curblock*128, where we happily put our
797 * next large block depot.
799 memset(block,0xff,sizeof(block));
800 /* mark the block allocated and returned by this function */
801 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
802 ret = STORAGE_put_big_block(hf,bigblocknr,block);
803 assert(ret);
805 /* if we had a bbd block already (mostlikely) we need
806 * to link the new one into the chain
808 if (lastbigblocknr!=-1) {
809 ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr);
810 assert(ret);
812 sth.bbd_list[curblock]=bigblocknr;
813 sth.num_of_bbd_blocks++;
814 assert(sth.num_of_bbd_blocks==curblock+1);
815 ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth);
816 assert(ret);
818 /* Set the end of the chain for the bigblockdepots */
819 ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
820 assert(ret);
821 /* add 1, for the first entry is used for the additional big block
822 * depot. (means we already used bigblocknr) */
823 memset(block,0x42,sizeof(block));
824 /* allocate this block (filled with 0x42) */
825 ret = STORAGE_put_big_block(hf,bigblocknr+1,block);
826 assert(ret);
827 return bigblocknr+1;
831 /******************************************************************************
832 * STORAGE_get_free_small_blocknr [Internal]
834 static int
835 STORAGE_get_free_small_blocknr(HANDLE hf) {
836 BYTE block[BIGSIZE];
837 LPINT sbd = (LPINT)block;
838 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
839 struct storage_pps_entry root;
840 struct storage_header sth;
842 READ_HEADER;
843 bigblocknr = sth.sbd_startblock;
844 curblock = 0;
845 lastbigblocknr = -1;
846 newblocknr = -1;
847 while (bigblocknr>=0) {
848 if (!STORAGE_get_big_block(hf,bigblocknr,block))
849 return -1;
850 for (i=0;i<128;i++)
851 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
852 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
853 newblocknr = i+curblock*128;
854 break;
856 if (i!=128)
857 break;
858 lastbigblocknr = bigblocknr;
859 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
860 curblock++;
862 if (newblocknr==-1) {
863 bigblocknr = STORAGE_get_free_big_blocknr(hf);
864 if (bigblocknr<0)
865 return -1;
866 READ_HEADER;
867 memset(block,0xff,sizeof(block));
868 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
869 if (!STORAGE_put_big_block(hf,bigblocknr,block))
870 return -1;
871 if (lastbigblocknr==-1) {
872 sth.sbd_startblock = bigblocknr;
873 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
874 return -1;
875 } else {
876 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
877 return -1;
879 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
880 return -1;
881 newblocknr = curblock*128;
883 /* allocate enough big blocks for storing the allocated small block */
884 if (!STORAGE_get_root_pps_entry(hf,&root))
885 return -1;
886 if (root.pps_sb==-1)
887 lastbigblocknr = -1;
888 else
889 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
890 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
891 /* we need to allocate more stuff */
892 bigblocknr = STORAGE_get_free_big_blocknr(hf);
893 if (bigblocknr<0)
894 return -1;
895 READ_HEADER;
896 if (root.pps_sb==-1) {
897 root.pps_sb = bigblocknr;
898 root.pps_size += BIGSIZE;
899 } else {
900 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
901 return -1;
902 root.pps_size += BIGSIZE;
904 lastbigblocknr = bigblocknr;
906 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
907 return -1;
908 if (!STORAGE_put_pps_entry(hf,0,&root))
909 return -1;
910 return newblocknr;
913 /******************************************************************************
914 * STORAGE_get_free_pps_entry [Internal]
916 static int
917 STORAGE_get_free_pps_entry(HANDLE hf) {
918 int blocknr, i, curblock, lastblocknr=-1;
919 BYTE block[BIGSIZE];
920 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
921 struct storage_header sth;
923 READ_HEADER;
924 blocknr = sth.root_startblock;
925 assert(blocknr>=0);
926 curblock=0;
927 while (blocknr>=0) {
928 if (!STORAGE_get_big_block(hf,blocknr,block))
929 return -1;
930 for (i=0;i<4;i++)
931 if (stde[i].pps_sizeofname==0) /* free */
932 return curblock*4+i;
933 lastblocknr = blocknr;
934 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
935 curblock++;
937 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
938 blocknr = STORAGE_get_free_big_blocknr(hf);
939 /* sth invalidated */
940 if (blocknr<0)
941 return -1;
943 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
944 return -1;
945 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
946 return -1;
947 memset(block,0,sizeof(block));
948 STORAGE_put_big_block(hf,blocknr,block);
949 return curblock*4;
952 /* --- IStream16 implementation */
954 typedef struct
956 /* IUnknown fields */
957 IStream16Vtbl *lpVtbl;
958 DWORD ref;
959 /* IStream16 fields */
960 SEGPTR thisptr; /* pointer to this struct as segmented */
961 struct storage_pps_entry stde;
962 int ppsent;
963 HANDLE hf;
964 ULARGE_INTEGER offset;
965 } IStream16Impl;
967 /******************************************************************************
968 * IStream16_QueryInterface [STORAGE.518]
970 HRESULT WINAPI IStream16_fnQueryInterface(
971 IStream16* iface,REFIID refiid,LPVOID *obj
973 ICOM_THIS(IStream16Impl,iface);
974 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
975 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
976 *obj = This;
977 return 0;
979 return OLE_E_ENUM_NOMORE;
983 /******************************************************************************
984 * IStream16_AddRef [STORAGE.519]
986 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
987 ICOM_THIS(IStream16Impl,iface);
988 return ++(This->ref);
991 /******************************************************************************
992 * IStream16_Release [STORAGE.520]
994 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
995 ICOM_THIS(IStream16Impl,iface);
996 FlushFileBuffers(This->hf);
997 This->ref--;
998 if (!This->ref) {
999 CloseHandle(This->hf);
1000 UnMapLS( This->thisptr );
1001 HeapFree( GetProcessHeap(), 0, This );
1002 return 0;
1004 return This->ref;
1007 /******************************************************************************
1008 * IStream16_Seek [STORAGE.523]
1010 * FIXME
1011 * Does not handle 64 bits
1013 HRESULT WINAPI IStream16_fnSeek(
1014 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
1016 ICOM_THIS(IStream16Impl,iface);
1017 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
1019 switch (whence) {
1020 /* unix SEEK_xx should be the same as win95 ones */
1021 case SEEK_SET:
1022 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
1023 * right now.
1025 assert(offset.u.HighPart==0);
1026 This->offset.u.HighPart = offset.u.HighPart;
1027 This->offset.u.LowPart = offset.u.LowPart;
1028 break;
1029 case SEEK_CUR:
1030 if (offset.u.HighPart < 0) {
1031 /* FIXME: is this negation correct ? */
1032 offset.u.HighPart = -offset.u.HighPart;
1033 offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
1035 assert(offset.u.HighPart==0);
1036 assert(This->offset.u.LowPart >= offset.u.LowPart);
1037 This->offset.u.LowPart -= offset.u.LowPart;
1038 } else {
1039 assert(offset.u.HighPart==0);
1040 This->offset.u.LowPart+= offset.u.LowPart;
1042 break;
1043 case SEEK_END:
1044 assert(offset.u.HighPart==0);
1045 This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
1046 break;
1048 if (This->offset.u.LowPart>This->stde.pps_size)
1049 This->offset.u.LowPart=This->stde.pps_size;
1050 if (newpos) *newpos = This->offset;
1051 return S_OK;
1054 /******************************************************************************
1055 * IStream16_Read [STORAGE.521]
1057 HRESULT WINAPI IStream16_fnRead(
1058 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
1060 ICOM_THIS(IStream16Impl,iface);
1061 BYTE block[BIGSIZE];
1062 ULONG *bytesread=pcbRead,xxread;
1063 int blocknr;
1064 LPBYTE pbv = pv;
1066 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
1067 if (!pcbRead) bytesread=&xxread;
1068 *bytesread = 0;
1070 if (cb>This->stde.pps_size-This->offset.u.LowPart)
1071 cb=This->stde.pps_size-This->offset.u.LowPart;
1072 if (This->stde.pps_size < 0x1000) {
1073 /* use small block reader */
1074 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1075 while (cb) {
1076 int cc;
1078 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
1079 WARN("small block read failed!!!\n");
1080 return E_FAIL;
1082 cc = cb;
1083 if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1084 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1085 memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1086 This->offset.u.LowPart+=cc;
1087 pbv+=cc;
1088 *bytesread+=cc;
1089 cb-=cc;
1090 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
1092 } else {
1093 /* use big block reader */
1094 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1095 while (cb) {
1096 int cc;
1098 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
1099 WARN("big block read failed!!!\n");
1100 return E_FAIL;
1102 cc = cb;
1103 if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1104 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1105 memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1106 This->offset.u.LowPart+=cc;
1107 pbv+=cc;
1108 *bytesread+=cc;
1109 cb-=cc;
1110 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
1113 return S_OK;
1116 /******************************************************************************
1117 * IStream16_Write [STORAGE.522]
1119 HRESULT WINAPI IStream16_fnWrite(
1120 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
1122 ICOM_THIS(IStream16Impl,iface);
1123 BYTE block[BIGSIZE];
1124 ULONG *byteswritten=pcbWrite,xxwritten;
1125 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1126 HANDLE hf = This->hf;
1127 LPBYTE pbv = (LPBYTE)pv;
1129 if (!pcbWrite) byteswritten=&xxwritten;
1130 *byteswritten = 0;
1132 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
1133 /* do we need to junk some blocks? */
1134 newsize = This->offset.u.LowPart+cb;
1135 oldsize = This->stde.pps_size;
1136 if (newsize < oldsize) {
1137 if (oldsize < 0x1000) {
1138 /* only small blocks */
1139 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
1141 assert(blocknr>=0);
1143 /* will set the rest of the chain to 'free' */
1144 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1145 return E_FAIL;
1146 } else {
1147 if (newsize >= 0x1000) {
1148 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
1149 assert(blocknr>=0);
1151 /* will set the rest of the chain to 'free' */
1152 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1153 return E_FAIL;
1154 } else {
1155 /* Migrate large blocks to small blocks
1156 * (we just migrate newsize bytes)
1158 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1159 HRESULT r = E_FAIL;
1161 cc = newsize;
1162 blocknr = This->stde.pps_sb;
1163 curdata = data;
1164 while (cc>0) {
1165 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
1166 HeapFree(GetProcessHeap(),0,data);
1167 return E_FAIL;
1169 curdata += BIGSIZE;
1170 cc -= BIGSIZE;
1171 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1173 /* frees complete chain for this stream */
1174 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1175 goto err;
1176 curdata = data;
1177 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
1178 if (blocknr<0)
1179 goto err;
1180 cc = newsize;
1181 while (cc>0) {
1182 if (!STORAGE_put_small_block(hf,blocknr,curdata))
1183 goto err;
1184 cc -= SMALLSIZE;
1185 if (cc<=0) {
1186 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1187 goto err;
1188 break;
1189 } else {
1190 int newblocknr = STORAGE_get_free_small_blocknr(hf);
1191 if (newblocknr<0)
1192 goto err;
1193 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
1194 goto err;
1195 blocknr = newblocknr;
1197 curdata += SMALLSIZE;
1199 r = S_OK;
1200 err:
1201 HeapFree(GetProcessHeap(),0,data);
1202 if(r != S_OK)
1203 return r;
1206 This->stde.pps_size = newsize;
1209 if (newsize > oldsize) {
1210 if (oldsize >= 0x1000) {
1211 /* should return the block right before the 'endofchain' */
1212 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1213 assert(blocknr>=0);
1214 lastblocknr = blocknr;
1215 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1216 blocknr = STORAGE_get_free_big_blocknr(hf);
1217 if (blocknr<0)
1218 return E_FAIL;
1219 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1220 return E_FAIL;
1221 lastblocknr = blocknr;
1223 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1224 return E_FAIL;
1225 } else {
1226 if (newsize < 0x1000) {
1227 /* find startblock */
1228 if (!oldsize)
1229 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1230 else
1231 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1232 if (blocknr<0)
1233 return E_FAIL;
1235 /* allocate required new small blocks */
1236 lastblocknr = blocknr;
1237 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1238 blocknr = STORAGE_get_free_small_blocknr(hf);
1239 if (blocknr<0)
1240 return E_FAIL;
1241 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1242 return E_FAIL;
1243 lastblocknr = blocknr;
1245 /* and terminate the chain */
1246 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1247 return E_FAIL;
1248 } else {
1249 if (!oldsize) {
1250 /* no single block allocated yet */
1251 blocknr=STORAGE_get_free_big_blocknr(hf);
1252 if (blocknr<0)
1253 return E_FAIL;
1254 This->stde.pps_sb = blocknr;
1255 } else {
1256 /* Migrate small blocks to big blocks */
1257 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1258 HRESULT r = E_FAIL;
1260 cc = oldsize;
1261 blocknr = This->stde.pps_sb;
1262 curdata = data;
1263 /* slurp in */
1264 while (cc>0) {
1265 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1266 goto err2;
1267 curdata += SMALLSIZE;
1268 cc -= SMALLSIZE;
1269 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1271 /* free small block chain */
1272 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1273 goto err2;
1274 curdata = data;
1275 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1276 if (blocknr<0)
1277 goto err2;
1278 /* put the data into the big blocks */
1279 cc = This->stde.pps_size;
1280 while (cc>0) {
1281 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1282 goto err2;
1283 cc -= BIGSIZE;
1284 if (cc<=0) {
1285 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1286 goto err2;
1287 break;
1288 } else {
1289 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1290 if (newblocknr<0)
1291 goto err2;
1292 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1293 goto err2;
1294 blocknr = newblocknr;
1296 curdata += BIGSIZE;
1298 r = S_OK;
1299 err2:
1300 HeapFree(GetProcessHeap(),0,data);
1301 if(r != S_OK)
1302 return r;
1304 /* generate big blocks to fit the new data */
1305 lastblocknr = blocknr;
1306 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1307 blocknr = STORAGE_get_free_big_blocknr(hf);
1308 if (blocknr<0)
1309 return E_FAIL;
1310 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1311 return E_FAIL;
1312 lastblocknr = blocknr;
1314 /* terminate chain */
1315 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1316 return E_FAIL;
1319 This->stde.pps_size = newsize;
1322 /* There are just some cases where we didn't modify it, we write it out
1323 * everytime
1325 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1326 return E_FAIL;
1328 /* finally the write pass */
1329 if (This->stde.pps_size < 0x1000) {
1330 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1331 assert(blocknr>=0);
1332 while (cb>0) {
1333 /* we ensured that it is allocated above */
1334 assert(blocknr>=0);
1335 /* Read old block everytime, since we can have
1336 * overlapping data at START and END of the write
1338 if (!STORAGE_get_small_block(hf,blocknr,block))
1339 return E_FAIL;
1341 cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1342 if (cc>cb)
1343 cc=cb;
1344 memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1345 pbv+curoffset,
1348 if (!STORAGE_put_small_block(hf,blocknr,block))
1349 return E_FAIL;
1350 cb -= cc;
1351 curoffset += cc;
1352 pbv += cc;
1353 This->offset.u.LowPart += cc;
1354 *byteswritten += cc;
1355 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1357 } else {
1358 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1359 assert(blocknr>=0);
1360 while (cb>0) {
1361 /* we ensured that it is allocated above, so it better is */
1362 assert(blocknr>=0);
1363 /* read old block everytime, since we can have
1364 * overlapping data at START and END of the write
1366 if (!STORAGE_get_big_block(hf,blocknr,block))
1367 return E_FAIL;
1369 cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1370 if (cc>cb)
1371 cc=cb;
1372 memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1373 pbv+curoffset,
1376 if (!STORAGE_put_big_block(hf,blocknr,block))
1377 return E_FAIL;
1378 cb -= cc;
1379 curoffset += cc;
1380 pbv += cc;
1381 This->offset.u.LowPart += cc;
1382 *byteswritten += cc;
1383 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1386 return S_OK;
1389 /******************************************************************************
1390 * _create_istream16 [Internal]
1392 static void _create_istream16(LPSTREAM16 *str) {
1393 IStream16Impl* lpst;
1395 if (!strvt16.QueryInterface) {
1396 HMODULE16 wp = GetModuleHandle16("STORAGE");
1397 if (wp>=32) {
1398 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1399 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1400 VTENT(QueryInterface);
1401 VTENT(AddRef);
1402 VTENT(Release);
1403 VTENT(Read);
1404 VTENT(Write);
1405 VTENT(Seek);
1406 VTENT(SetSize);
1407 VTENT(CopyTo);
1408 VTENT(Commit);
1409 VTENT(Revert);
1410 VTENT(LockRegion);
1411 VTENT(UnlockRegion);
1412 VTENT(Stat);
1413 VTENT(Clone);
1414 #undef VTENT
1415 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1416 } else {
1417 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1418 VTENT(QueryInterface);
1419 VTENT(AddRef);
1420 VTENT(Release);
1421 VTENT(Read);
1422 VTENT(Write);
1423 VTENT(Seek);
1425 VTENT(CopyTo);
1426 VTENT(Commit);
1427 VTENT(SetSize);
1428 VTENT(Revert);
1429 VTENT(LockRegion);
1430 VTENT(UnlockRegion);
1431 VTENT(Stat);
1432 VTENT(Clone);
1434 #undef VTENT
1435 segstrvt16 = &strvt16;
1438 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1439 lpst->lpVtbl = segstrvt16;
1440 lpst->ref = 1;
1441 lpst->thisptr = MapLS( lpst );
1442 *str = (void*)lpst->thisptr;
1446 /* --- IStream32 implementation */
1448 typedef struct
1450 /* IUnknown fields */
1451 IStreamVtbl *lpVtbl;
1452 DWORD ref;
1453 /* IStream32 fields */
1454 struct storage_pps_entry stde;
1455 int ppsent;
1456 HANDLE hf;
1457 ULARGE_INTEGER offset;
1458 } IStream32Impl;
1460 /*****************************************************************************
1461 * IStream32_QueryInterface [VTABLE]
1463 HRESULT WINAPI IStream_fnQueryInterface(
1464 IStream* iface,REFIID refiid,LPVOID *obj
1466 ICOM_THIS(IStream32Impl,iface);
1468 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1469 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1470 *obj = This;
1471 return 0;
1473 return OLE_E_ENUM_NOMORE;
1477 /******************************************************************************
1478 * IStream32_AddRef [VTABLE]
1480 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1481 ICOM_THIS(IStream32Impl,iface);
1482 return ++(This->ref);
1485 /******************************************************************************
1486 * IStream32_Release [VTABLE]
1488 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1489 ICOM_THIS(IStream32Impl,iface);
1490 FlushFileBuffers(This->hf);
1491 This->ref--;
1492 if (!This->ref) {
1493 CloseHandle(This->hf);
1494 HeapFree( GetProcessHeap(), 0, This );
1495 return 0;
1497 return This->ref;
1500 /* --- IStorage16 implementation */
1502 typedef struct
1504 /* IUnknown fields */
1505 IStorage16Vtbl *lpVtbl;
1506 DWORD ref;
1507 /* IStorage16 fields */
1508 SEGPTR thisptr; /* pointer to this struct as segmented */
1509 struct storage_pps_entry stde;
1510 int ppsent;
1511 HANDLE hf;
1512 } IStorage16Impl;
1514 /******************************************************************************
1515 * IStorage16_QueryInterface [STORAGE.500]
1517 HRESULT WINAPI IStorage16_fnQueryInterface(
1518 IStorage16* iface,REFIID refiid,LPVOID *obj
1520 ICOM_THIS(IStorage16Impl,iface);
1522 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1524 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1525 *obj = This;
1526 return 0;
1528 return OLE_E_ENUM_NOMORE;
1531 /******************************************************************************
1532 * IStorage16_AddRef [STORAGE.501]
1534 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1535 ICOM_THIS(IStorage16Impl,iface);
1536 return ++(This->ref);
1539 /******************************************************************************
1540 * IStorage16_Release [STORAGE.502]
1542 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1543 ICOM_THIS(IStorage16Impl,iface);
1544 This->ref--;
1545 if (This->ref)
1546 return This->ref;
1547 UnMapLS( This->thisptr );
1548 HeapFree( GetProcessHeap(), 0, This );
1549 return 0;
1552 /******************************************************************************
1553 * IStorage16_Stat [STORAGE.517]
1555 HRESULT WINAPI IStorage16_fnStat(
1556 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1558 ICOM_THIS(IStorage16Impl,iface);
1559 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1560 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1562 TRACE("(%p)->(%p,0x%08lx)\n",
1563 This,pstatstg,grfStatFlag
1565 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1566 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1567 pstatstg->type = This->stde.pps_type;
1568 pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1569 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1570 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1571 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1572 pstatstg->grfMode = 0; /* FIXME */
1573 pstatstg->grfLocksSupported = 0; /* FIXME */
1574 pstatstg->clsid = This->stde.pps_guid;
1575 pstatstg->grfStateBits = 0; /* FIXME */
1576 pstatstg->reserved = 0;
1577 return S_OK;
1580 /******************************************************************************
1581 * IStorage16_Commit [STORAGE.509]
1583 HRESULT WINAPI IStorage16_fnCommit(
1584 LPSTORAGE16 iface,DWORD commitflags
1586 ICOM_THIS(IStorage16Impl,iface);
1587 FIXME("(%p)->(0x%08lx),STUB!\n",
1588 This,commitflags
1590 return S_OK;
1593 /******************************************************************************
1594 * IStorage16_CopyTo [STORAGE.507]
1596 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1597 ICOM_THIS(IStorage16Impl,iface);
1598 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1599 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1601 return S_OK;
1605 /******************************************************************************
1606 * IStorage16_CreateStorage [STORAGE.505]
1608 HRESULT WINAPI IStorage16_fnCreateStorage(
1609 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1611 ICOM_THIS(IStorage16Impl,iface);
1612 IStorage16Impl* lpstg;
1613 int ppsent,x;
1614 struct storage_pps_entry stde;
1615 struct storage_header sth;
1616 HANDLE hf=This->hf;
1617 BOOL ret;
1618 int nPPSEntries;
1620 READ_HEADER;
1622 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1623 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1625 if (grfMode & STGM_TRANSACTED)
1626 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1627 _create_istorage16(ppstg);
1628 lpstg = MapSL((SEGPTR)*ppstg);
1629 lpstg->hf = This->hf;
1631 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1632 if (ppsent<0)
1633 return E_FAIL;
1634 stde=This->stde;
1635 if (stde.pps_dir==-1) {
1636 stde.pps_dir = ppsent;
1637 x = This->ppsent;
1638 } else {
1639 FIXME(" use prev chain too ?\n");
1640 x=stde.pps_dir;
1641 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1642 return E_FAIL;
1643 while (stde.pps_next!=-1) {
1644 x=stde.pps_next;
1645 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1646 return E_FAIL;
1648 stde.pps_next = ppsent;
1650 ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1651 assert(ret);
1652 nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1653 assert(nPPSEntries == 1);
1654 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1655 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1656 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1657 lpstg->stde.pps_next = -1;
1658 lpstg->stde.pps_prev = -1;
1659 lpstg->stde.pps_dir = -1;
1660 lpstg->stde.pps_sb = -1;
1661 lpstg->stde.pps_size = 0;
1662 lpstg->stde.pps_type = 1;
1663 lpstg->ppsent = ppsent;
1664 /* FIXME: timestamps? */
1665 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1666 return E_FAIL;
1667 return S_OK;
1670 /******************************************************************************
1671 * IStorage16_CreateStream [STORAGE.503]
1673 HRESULT WINAPI IStorage16_fnCreateStream(
1674 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1676 ICOM_THIS(IStorage16Impl,iface);
1677 IStream16Impl* lpstr;
1678 int ppsent,x;
1679 struct storage_pps_entry stde;
1680 BOOL ret;
1681 int nPPSEntries;
1683 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1684 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1686 if (grfMode & STGM_TRANSACTED)
1687 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1688 _create_istream16(ppstm);
1689 lpstr = MapSL((SEGPTR)*ppstm);
1690 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1691 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1692 lpstr->offset.u.LowPart = 0;
1693 lpstr->offset.u.HighPart = 0;
1695 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1696 if (ppsent<0)
1697 return E_FAIL;
1698 stde=This->stde;
1699 if (stde.pps_next==-1)
1700 x=This->ppsent;
1701 else
1702 while (stde.pps_next!=-1) {
1703 x=stde.pps_next;
1704 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1705 return E_FAIL;
1707 stde.pps_next = ppsent;
1708 ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1709 assert(ret);
1710 nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1711 assert(nPPSEntries == 1);
1712 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1713 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1714 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1715 lpstr->stde.pps_next = -1;
1716 lpstr->stde.pps_prev = -1;
1717 lpstr->stde.pps_dir = -1;
1718 lpstr->stde.pps_sb = -1;
1719 lpstr->stde.pps_size = 0;
1720 lpstr->stde.pps_type = 2;
1721 lpstr->ppsent = ppsent;
1722 /* FIXME: timestamps? */
1723 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1724 return E_FAIL;
1725 return S_OK;
1728 /******************************************************************************
1729 * IStorage16_OpenStorage [STORAGE.506]
1731 HRESULT WINAPI IStorage16_fnOpenStorage(
1732 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1734 ICOM_THIS(IStorage16Impl,iface);
1735 IStream16Impl* lpstg;
1736 WCHAR name[33];
1737 int newpps;
1739 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1740 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1742 if (grfMode & STGM_TRANSACTED)
1743 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1744 _create_istorage16(ppstg);
1745 lpstg = MapSL((SEGPTR)*ppstg);
1746 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1747 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1748 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1749 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1750 if (newpps==-1) {
1751 IStream16_fnRelease((IStream16*)lpstg);
1752 return E_FAIL;
1755 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1756 IStream16_fnRelease((IStream16*)lpstg);
1757 return E_FAIL;
1759 lpstg->ppsent = newpps;
1760 return S_OK;
1763 /******************************************************************************
1764 * IStorage16_OpenStream [STORAGE.504]
1766 HRESULT WINAPI IStorage16_fnOpenStream(
1767 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1769 ICOM_THIS(IStorage16Impl,iface);
1770 IStream16Impl* lpstr;
1771 WCHAR name[33];
1772 int newpps;
1774 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1775 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1777 if (grfMode & STGM_TRANSACTED)
1778 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1779 _create_istream16(ppstm);
1780 lpstr = MapSL((SEGPTR)*ppstm);
1781 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1782 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1783 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1784 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1785 if (newpps==-1) {
1786 IStream16_fnRelease((IStream16*)lpstr);
1787 return E_FAIL;
1790 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1791 IStream16_fnRelease((IStream16*)lpstr);
1792 return E_FAIL;
1794 lpstr->offset.u.LowPart = 0;
1795 lpstr->offset.u.HighPart = 0;
1796 lpstr->ppsent = newpps;
1797 return S_OK;
1800 /******************************************************************************
1801 * _create_istorage16 [INTERNAL]
1803 static void _create_istorage16(LPSTORAGE16 *stg) {
1804 IStorage16Impl* lpst;
1806 if (!stvt16.QueryInterface) {
1807 HMODULE16 wp = GetModuleHandle16("STORAGE");
1808 if (wp>=32) {
1809 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1810 VTENT(QueryInterface)
1811 VTENT(AddRef)
1812 VTENT(Release)
1813 VTENT(CreateStream)
1814 VTENT(OpenStream)
1815 VTENT(CreateStorage)
1816 VTENT(OpenStorage)
1817 VTENT(CopyTo)
1818 VTENT(MoveElementTo)
1819 VTENT(Commit)
1820 VTENT(Revert)
1821 VTENT(EnumElements)
1822 VTENT(DestroyElement)
1823 VTENT(RenameElement)
1824 VTENT(SetElementTimes)
1825 VTENT(SetClass)
1826 VTENT(SetStateBits)
1827 VTENT(Stat)
1828 #undef VTENT
1829 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1830 } else {
1831 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1832 VTENT(QueryInterface)
1833 VTENT(AddRef)
1834 VTENT(Release)
1835 VTENT(CreateStream)
1836 VTENT(OpenStream)
1837 VTENT(CreateStorage)
1838 VTENT(OpenStorage)
1839 VTENT(CopyTo)
1840 VTENT(Commit)
1841 /* not (yet) implemented ...
1842 VTENT(MoveElementTo)
1843 VTENT(Revert)
1844 VTENT(EnumElements)
1845 VTENT(DestroyElement)
1846 VTENT(RenameElement)
1847 VTENT(SetElementTimes)
1848 VTENT(SetClass)
1849 VTENT(SetStateBits)
1850 VTENT(Stat)
1852 #undef VTENT
1853 segstvt16 = &stvt16;
1856 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1857 lpst->lpVtbl = segstvt16;
1858 lpst->ref = 1;
1859 lpst->thisptr = MapLS(lpst);
1860 *stg = (void*)lpst->thisptr;
1863 /******************************************************************************
1864 * Storage API functions
1867 /******************************************************************************
1868 * StgCreateDocFileA [STORAGE.1]
1870 HRESULT WINAPI StgCreateDocFile16(
1871 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1873 HANDLE hf;
1874 int i,ret;
1875 IStorage16Impl* lpstg;
1876 struct storage_pps_entry stde;
1878 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1879 pwcsName,grfMode,reserved,ppstgOpen
1881 _create_istorage16(ppstgOpen);
1882 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1883 if (hf==INVALID_HANDLE_VALUE) {
1884 WARN("couldn't open file for storage:%ld\n",GetLastError());
1885 return E_FAIL;
1887 lpstg = MapSL((SEGPTR)*ppstgOpen);
1888 lpstg->hf = hf;
1889 /* FIXME: check for existence before overwriting? */
1890 if (!STORAGE_init_storage(hf)) {
1891 CloseHandle(hf);
1892 return E_FAIL;
1894 i=0;ret=0;
1895 while (!ret) { /* neither 1 nor <0 */
1896 ret=STORAGE_get_pps_entry(hf,i,&stde);
1897 if ((ret==1) && (stde.pps_type==5)) {
1898 lpstg->stde = stde;
1899 lpstg->ppsent = i;
1900 break;
1902 i++;
1904 if (ret!=1) {
1905 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1906 return E_FAIL;
1909 return S_OK;
1912 /******************************************************************************
1913 * StgIsStorageFile [STORAGE.5]
1915 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1916 UNICODE_STRING strW;
1917 HRESULT ret;
1919 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1920 ret = StgIsStorageFile( strW.Buffer );
1921 RtlFreeUnicodeString( &strW );
1923 return ret;
1926 /******************************************************************************
1927 * StgOpenStorage [STORAGE.3]
1929 HRESULT WINAPI StgOpenStorage16(
1930 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1931 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1933 HANDLE hf;
1934 int ret,i;
1935 IStorage16Impl* lpstg;
1936 struct storage_pps_entry stde;
1938 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1939 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1941 _create_istorage16(ppstgOpen);
1942 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1943 if (hf==INVALID_HANDLE_VALUE) {
1944 WARN("Couldn't open file for storage\n");
1945 return E_FAIL;
1947 lpstg = MapSL((SEGPTR)*ppstgOpen);
1948 lpstg->hf = hf;
1950 i=0;ret=0;
1951 while (!ret) { /* neither 1 nor <0 */
1952 ret=STORAGE_get_pps_entry(hf,i,&stde);
1953 if ((ret==1) && (stde.pps_type==5)) {
1954 lpstg->stde=stde;
1955 break;
1957 i++;
1959 if (ret!=1) {
1960 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1961 return E_FAIL;
1963 return S_OK;
1967 /******************************************************************************
1968 * StgIsStorageILockBytes [STORAGE.6]
1970 * Determines if the ILockBytes contains a storage object.
1972 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1974 DWORD args[6];
1975 HRESULT hres;
1976 HANDLE16 hsig;
1978 args[0] = (DWORD)plkbyt; /* iface */
1979 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1980 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1981 args[4] = 8;
1982 args[5] = 0;
1984 if (!K32WOWCallback16Ex(
1985 (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1986 (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1987 )->ReadAt,
1988 WCB16_PASCAL,
1989 6*sizeof(DWORD),
1990 (LPVOID)args,
1991 (LPDWORD)&hres
1992 )) {
1993 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1994 return hres;
1996 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1997 K32WOWGlobalUnlockFree16(args[3]);
1998 return S_OK;
2000 K32WOWGlobalUnlockFree16(args[3]);
2001 return S_FALSE;
2004 /******************************************************************************
2005 * StgOpenStorageOnILockBytes [STORAGE.4]
2007 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2008 ILockBytes16 *plkbyt,
2009 IStorage16 *pstgPriority,
2010 DWORD grfMode,
2011 SNB16 snbExclude,
2012 DWORD reserved,
2013 IStorage16 **ppstgOpen)
2015 IStorage16Impl* lpstg;
2017 if ((plkbyt == 0) || (ppstgOpen == 0))
2018 return STG_E_INVALIDPOINTER;
2020 *ppstgOpen = 0;
2022 _create_istorage16(ppstgOpen);
2023 lpstg = MapSL((SEGPTR)*ppstgOpen);
2025 /* just teach it to use HANDLE instead of ilockbytes :/ */
2027 return S_OK;