Added YUV routines needed for v4l driver, and in the future possibly
[wine/gsoc-2012-control.git] / dlls / ole32 / storage.c
blob0e0b4858e009938a67409acd3dec2346f46c8b4e
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 IStorage16Vtbl stvt16;
94 static IStorage16Vtbl *segstvt16 = NULL;
95 static IStream16Vtbl strvt16;
96 static IStream16Vtbl *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,bigblocknr;
770 unsigned int curblock;
771 struct storage_header sth;
772 BOOL ret;
774 READ_HEADER;
775 curblock = 0;
776 lastbigblocknr = -1;
777 bigblocknr = sth.bbd_list[curblock];
778 while (curblock<sth.num_of_bbd_blocks) {
779 assert(bigblocknr>=0);
780 ret = STORAGE_get_big_block(hf,bigblocknr,block);
781 assert(ret);
782 for (i=0;i<128;i++)
783 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
784 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
785 ret = STORAGE_put_big_block(hf,bigblocknr,block);
786 assert(ret);
787 memset(block,0x42,sizeof(block));
788 ret = STORAGE_put_big_block(hf,i+curblock*128,block);
789 assert(ret);
790 return i+curblock*128;
792 lastbigblocknr = bigblocknr;
793 bigblocknr = sth.bbd_list[++curblock];
795 bigblocknr = curblock*128;
796 /* since we have marked all blocks from 0 up to curblock*128-1
797 * the next free one is curblock*128, where we happily put our
798 * next large block depot.
800 memset(block,0xff,sizeof(block));
801 /* mark the block allocated and returned by this function */
802 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
803 ret = STORAGE_put_big_block(hf,bigblocknr,block);
804 assert(ret);
806 /* if we had a bbd block already (mostlikely) we need
807 * to link the new one into the chain
809 if (lastbigblocknr!=-1) {
810 ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr);
811 assert(ret);
813 sth.bbd_list[curblock]=bigblocknr;
814 sth.num_of_bbd_blocks++;
815 assert(sth.num_of_bbd_blocks==curblock+1);
816 ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth);
817 assert(ret);
819 /* Set the end of the chain for the bigblockdepots */
820 ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
821 assert(ret);
822 /* add 1, for the first entry is used for the additional big block
823 * depot. (means we already used bigblocknr) */
824 memset(block,0x42,sizeof(block));
825 /* allocate this block (filled with 0x42) */
826 ret = STORAGE_put_big_block(hf,bigblocknr+1,block);
827 assert(ret);
828 return bigblocknr+1;
832 /******************************************************************************
833 * STORAGE_get_free_small_blocknr [Internal]
835 static int
836 STORAGE_get_free_small_blocknr(HANDLE hf) {
837 BYTE block[BIGSIZE];
838 LPINT sbd = (LPINT)block;
839 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
840 struct storage_pps_entry root;
841 struct storage_header sth;
843 READ_HEADER;
844 bigblocknr = sth.sbd_startblock;
845 curblock = 0;
846 lastbigblocknr = -1;
847 newblocknr = -1;
848 while (bigblocknr>=0) {
849 if (!STORAGE_get_big_block(hf,bigblocknr,block))
850 return -1;
851 for (i=0;i<128;i++)
852 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
853 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
854 newblocknr = i+curblock*128;
855 break;
857 if (i!=128)
858 break;
859 lastbigblocknr = bigblocknr;
860 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
861 curblock++;
863 if (newblocknr==-1) {
864 bigblocknr = STORAGE_get_free_big_blocknr(hf);
865 if (bigblocknr<0)
866 return -1;
867 READ_HEADER;
868 memset(block,0xff,sizeof(block));
869 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
870 if (!STORAGE_put_big_block(hf,bigblocknr,block))
871 return -1;
872 if (lastbigblocknr==-1) {
873 sth.sbd_startblock = bigblocknr;
874 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
875 return -1;
876 } else {
877 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
878 return -1;
880 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
881 return -1;
882 newblocknr = curblock*128;
884 /* allocate enough big blocks for storing the allocated small block */
885 if (!STORAGE_get_root_pps_entry(hf,&root))
886 return -1;
887 if (root.pps_sb==-1)
888 lastbigblocknr = -1;
889 else
890 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
891 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
892 /* we need to allocate more stuff */
893 bigblocknr = STORAGE_get_free_big_blocknr(hf);
894 if (bigblocknr<0)
895 return -1;
896 READ_HEADER;
897 if (root.pps_sb==-1) {
898 root.pps_sb = bigblocknr;
899 root.pps_size += BIGSIZE;
900 } else {
901 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
902 return -1;
903 root.pps_size += BIGSIZE;
905 lastbigblocknr = bigblocknr;
907 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
908 return -1;
909 if (!STORAGE_put_pps_entry(hf,0,&root))
910 return -1;
911 return newblocknr;
914 /******************************************************************************
915 * STORAGE_get_free_pps_entry [Internal]
917 static int
918 STORAGE_get_free_pps_entry(HANDLE hf) {
919 int blocknr, i, curblock, lastblocknr=-1;
920 BYTE block[BIGSIZE];
921 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
922 struct storage_header sth;
924 READ_HEADER;
925 blocknr = sth.root_startblock;
926 assert(blocknr>=0);
927 curblock=0;
928 while (blocknr>=0) {
929 if (!STORAGE_get_big_block(hf,blocknr,block))
930 return -1;
931 for (i=0;i<4;i++)
932 if (stde[i].pps_sizeofname==0) /* free */
933 return curblock*4+i;
934 lastblocknr = blocknr;
935 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
936 curblock++;
938 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
939 blocknr = STORAGE_get_free_big_blocknr(hf);
940 /* sth invalidated */
941 if (blocknr<0)
942 return -1;
944 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
945 return -1;
946 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
947 return -1;
948 memset(block,0,sizeof(block));
949 STORAGE_put_big_block(hf,blocknr,block);
950 return curblock*4;
953 /* --- IStream16 implementation */
955 typedef struct
957 /* IUnknown fields */
958 IStream16Vtbl *lpVtbl;
959 DWORD ref;
960 /* IStream16 fields */
961 SEGPTR thisptr; /* pointer to this struct as segmented */
962 struct storage_pps_entry stde;
963 int ppsent;
964 HANDLE hf;
965 ULARGE_INTEGER offset;
966 } IStream16Impl;
968 /******************************************************************************
969 * IStream16_QueryInterface [STORAGE.518]
971 HRESULT WINAPI IStream16_fnQueryInterface(
972 IStream16* iface,REFIID refiid,LPVOID *obj
974 IStream16Impl *This = (IStream16Impl *)iface;
975 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
976 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
977 *obj = This;
978 return 0;
980 return OLE_E_ENUM_NOMORE;
984 /******************************************************************************
985 * IStream16_AddRef [STORAGE.519]
987 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
988 IStream16Impl *This = (IStream16Impl *)iface;
989 return InterlockedIncrement(&This->ref);
992 /******************************************************************************
993 * IStream16_Release [STORAGE.520]
995 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
996 IStream16Impl *This = (IStream16Impl *)iface;
997 ULONG ref;
998 FlushFileBuffers(This->hf);
999 ref = InterlockedDecrement(&This->ref);
1000 if (!ref) {
1001 CloseHandle(This->hf);
1002 UnMapLS( This->thisptr );
1003 HeapFree( GetProcessHeap(), 0, This );
1005 return ref;
1008 /******************************************************************************
1009 * IStream16_Seek [STORAGE.523]
1011 * FIXME
1012 * Does not handle 64 bits
1014 HRESULT WINAPI IStream16_fnSeek(
1015 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
1017 IStream16Impl *This = (IStream16Impl *)iface;
1018 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
1020 switch (whence) {
1021 /* unix SEEK_xx should be the same as win95 ones */
1022 case SEEK_SET:
1023 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
1024 * right now.
1026 assert(offset.u.HighPart==0);
1027 This->offset.u.HighPart = offset.u.HighPart;
1028 This->offset.u.LowPart = offset.u.LowPart;
1029 break;
1030 case SEEK_CUR:
1031 if (offset.u.HighPart < 0) {
1032 /* FIXME: is this negation correct ? */
1033 offset.u.HighPart = -offset.u.HighPart;
1034 offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
1036 assert(offset.u.HighPart==0);
1037 assert(This->offset.u.LowPart >= offset.u.LowPart);
1038 This->offset.u.LowPart -= offset.u.LowPart;
1039 } else {
1040 assert(offset.u.HighPart==0);
1041 This->offset.u.LowPart+= offset.u.LowPart;
1043 break;
1044 case SEEK_END:
1045 assert(offset.u.HighPart==0);
1046 This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
1047 break;
1049 if (This->offset.u.LowPart>This->stde.pps_size)
1050 This->offset.u.LowPart=This->stde.pps_size;
1051 if (newpos) *newpos = This->offset;
1052 return S_OK;
1055 /******************************************************************************
1056 * IStream16_Read [STORAGE.521]
1058 HRESULT WINAPI IStream16_fnRead(
1059 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
1061 IStream16Impl *This = (IStream16Impl *)iface;
1062 BYTE block[BIGSIZE];
1063 ULONG *bytesread=pcbRead,xxread;
1064 int blocknr;
1065 LPBYTE pbv = pv;
1067 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
1068 if (!pcbRead) bytesread=&xxread;
1069 *bytesread = 0;
1071 if (cb>This->stde.pps_size-This->offset.u.LowPart)
1072 cb=This->stde.pps_size-This->offset.u.LowPart;
1073 if (This->stde.pps_size < 0x1000) {
1074 /* use small block reader */
1075 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1076 while (cb) {
1077 unsigned int cc;
1079 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
1080 WARN("small block read failed!!!\n");
1081 return E_FAIL;
1083 cc = cb;
1084 if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
1085 cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1086 memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1087 This->offset.u.LowPart+=cc;
1088 pbv+=cc;
1089 *bytesread+=cc;
1090 cb-=cc;
1091 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
1093 } else {
1094 /* use big block reader */
1095 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1096 while (cb) {
1097 unsigned int cc;
1099 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
1100 WARN("big block read failed!!!\n");
1101 return E_FAIL;
1103 cc = cb;
1104 if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
1105 cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1106 memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1107 This->offset.u.LowPart+=cc;
1108 pbv+=cc;
1109 *bytesread+=cc;
1110 cb-=cc;
1111 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
1114 return S_OK;
1117 /******************************************************************************
1118 * IStream16_Write [STORAGE.522]
1120 HRESULT WINAPI IStream16_fnWrite(
1121 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
1123 IStream16Impl *This = (IStream16Impl *)iface;
1124 BYTE block[BIGSIZE];
1125 ULONG *byteswritten=pcbWrite,xxwritten;
1126 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1127 HANDLE hf = This->hf;
1128 const BYTE* pbv = (const BYTE*)pv;
1130 if (!pcbWrite) byteswritten=&xxwritten;
1131 *byteswritten = 0;
1133 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
1134 /* do we need to junk some blocks? */
1135 newsize = This->offset.u.LowPart+cb;
1136 oldsize = This->stde.pps_size;
1137 if (newsize < oldsize) {
1138 if (oldsize < 0x1000) {
1139 /* only small blocks */
1140 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
1142 assert(blocknr>=0);
1144 /* will set the rest of the chain to 'free' */
1145 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1146 return E_FAIL;
1147 } else {
1148 if (newsize >= 0x1000) {
1149 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
1150 assert(blocknr>=0);
1152 /* will set the rest of the chain to 'free' */
1153 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1154 return E_FAIL;
1155 } else {
1156 /* Migrate large blocks to small blocks
1157 * (we just migrate newsize bytes)
1159 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1160 HRESULT r = E_FAIL;
1162 cc = newsize;
1163 blocknr = This->stde.pps_sb;
1164 curdata = data;
1165 while (cc>0) {
1166 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
1167 HeapFree(GetProcessHeap(),0,data);
1168 return E_FAIL;
1170 curdata += BIGSIZE;
1171 cc -= BIGSIZE;
1172 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1174 /* frees complete chain for this stream */
1175 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1176 goto err;
1177 curdata = data;
1178 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
1179 if (blocknr<0)
1180 goto err;
1181 cc = newsize;
1182 while (cc>0) {
1183 if (!STORAGE_put_small_block(hf,blocknr,curdata))
1184 goto err;
1185 cc -= SMALLSIZE;
1186 if (cc<=0) {
1187 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1188 goto err;
1189 break;
1190 } else {
1191 int newblocknr = STORAGE_get_free_small_blocknr(hf);
1192 if (newblocknr<0)
1193 goto err;
1194 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
1195 goto err;
1196 blocknr = newblocknr;
1198 curdata += SMALLSIZE;
1200 r = S_OK;
1201 err:
1202 HeapFree(GetProcessHeap(),0,data);
1203 if(r != S_OK)
1204 return r;
1207 This->stde.pps_size = newsize;
1210 if (newsize > oldsize) {
1211 if (oldsize >= 0x1000) {
1212 /* should return the block right before the 'endofchain' */
1213 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
1214 assert(blocknr>=0);
1215 lastblocknr = blocknr;
1216 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1217 blocknr = STORAGE_get_free_big_blocknr(hf);
1218 if (blocknr<0)
1219 return E_FAIL;
1220 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1221 return E_FAIL;
1222 lastblocknr = blocknr;
1224 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1225 return E_FAIL;
1226 } else {
1227 if (newsize < 0x1000) {
1228 /* find startblock */
1229 if (!oldsize)
1230 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1231 else
1232 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1233 if (blocknr<0)
1234 return E_FAIL;
1236 /* allocate required new small blocks */
1237 lastblocknr = blocknr;
1238 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1239 blocknr = STORAGE_get_free_small_blocknr(hf);
1240 if (blocknr<0)
1241 return E_FAIL;
1242 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1243 return E_FAIL;
1244 lastblocknr = blocknr;
1246 /* and terminate the chain */
1247 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1248 return E_FAIL;
1249 } else {
1250 if (!oldsize) {
1251 /* no single block allocated yet */
1252 blocknr=STORAGE_get_free_big_blocknr(hf);
1253 if (blocknr<0)
1254 return E_FAIL;
1255 This->stde.pps_sb = blocknr;
1256 } else {
1257 /* Migrate small blocks to big blocks */
1258 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1259 HRESULT r = E_FAIL;
1261 cc = oldsize;
1262 blocknr = This->stde.pps_sb;
1263 curdata = data;
1264 /* slurp in */
1265 while (cc>0) {
1266 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1267 goto err2;
1268 curdata += SMALLSIZE;
1269 cc -= SMALLSIZE;
1270 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1272 /* free small block chain */
1273 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1274 goto err2;
1275 curdata = data;
1276 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1277 if (blocknr<0)
1278 goto err2;
1279 /* put the data into the big blocks */
1280 cc = This->stde.pps_size;
1281 while (cc>0) {
1282 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1283 goto err2;
1284 cc -= BIGSIZE;
1285 if (cc<=0) {
1286 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1287 goto err2;
1288 break;
1289 } else {
1290 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1291 if (newblocknr<0)
1292 goto err2;
1293 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1294 goto err2;
1295 blocknr = newblocknr;
1297 curdata += BIGSIZE;
1299 r = S_OK;
1300 err2:
1301 HeapFree(GetProcessHeap(),0,data);
1302 if(r != S_OK)
1303 return r;
1305 /* generate big blocks to fit the new data */
1306 lastblocknr = blocknr;
1307 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1308 blocknr = STORAGE_get_free_big_blocknr(hf);
1309 if (blocknr<0)
1310 return E_FAIL;
1311 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1312 return E_FAIL;
1313 lastblocknr = blocknr;
1315 /* terminate chain */
1316 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1317 return E_FAIL;
1320 This->stde.pps_size = newsize;
1323 /* There are just some cases where we didn't modify it, we write it out
1324 * everytime
1326 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1327 return E_FAIL;
1329 /* finally the write pass */
1330 if (This->stde.pps_size < 0x1000) {
1331 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
1332 assert(blocknr>=0);
1333 while (cb>0) {
1334 /* we ensured that it is allocated above */
1335 assert(blocknr>=0);
1336 /* Read old block everytime, since we can have
1337 * overlapping data at START and END of the write
1339 if (!STORAGE_get_small_block(hf,blocknr,block))
1340 return E_FAIL;
1342 cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
1343 if (cc>cb)
1344 cc=cb;
1345 memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
1346 pbv+curoffset,
1349 if (!STORAGE_put_small_block(hf,blocknr,block))
1350 return E_FAIL;
1351 cb -= cc;
1352 curoffset += cc;
1353 pbv += cc;
1354 This->offset.u.LowPart += cc;
1355 *byteswritten += cc;
1356 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1358 } else {
1359 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
1360 assert(blocknr>=0);
1361 while (cb>0) {
1362 /* we ensured that it is allocated above, so it better is */
1363 assert(blocknr>=0);
1364 /* read old block everytime, since we can have
1365 * overlapping data at START and END of the write
1367 if (!STORAGE_get_big_block(hf,blocknr,block))
1368 return E_FAIL;
1370 cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
1371 if (cc>cb)
1372 cc=cb;
1373 memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
1374 pbv+curoffset,
1377 if (!STORAGE_put_big_block(hf,blocknr,block))
1378 return E_FAIL;
1379 cb -= cc;
1380 curoffset += cc;
1381 pbv += cc;
1382 This->offset.u.LowPart += cc;
1383 *byteswritten += cc;
1384 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1387 return S_OK;
1390 /******************************************************************************
1391 * _create_istream16 [Internal]
1393 static void _create_istream16(LPSTREAM16 *str) {
1394 IStream16Impl* lpst;
1396 if (!strvt16.QueryInterface) {
1397 HMODULE16 wp = GetModuleHandle16("STORAGE");
1398 if (wp>=32) {
1399 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1400 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1401 VTENT(QueryInterface);
1402 VTENT(AddRef);
1403 VTENT(Release);
1404 VTENT(Read);
1405 VTENT(Write);
1406 VTENT(Seek);
1407 VTENT(SetSize);
1408 VTENT(CopyTo);
1409 VTENT(Commit);
1410 VTENT(Revert);
1411 VTENT(LockRegion);
1412 VTENT(UnlockRegion);
1413 VTENT(Stat);
1414 VTENT(Clone);
1415 #undef VTENT
1416 segstrvt16 = (IStream16Vtbl*)MapLS( &strvt16 );
1417 } else {
1418 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1419 VTENT(QueryInterface);
1420 VTENT(AddRef);
1421 VTENT(Release);
1422 VTENT(Read);
1423 VTENT(Write);
1424 VTENT(Seek);
1426 VTENT(CopyTo);
1427 VTENT(Commit);
1428 VTENT(SetSize);
1429 VTENT(Revert);
1430 VTENT(LockRegion);
1431 VTENT(UnlockRegion);
1432 VTENT(Stat);
1433 VTENT(Clone);
1435 #undef VTENT
1436 segstrvt16 = &strvt16;
1439 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1440 lpst->lpVtbl = segstrvt16;
1441 lpst->ref = 1;
1442 lpst->thisptr = MapLS( lpst );
1443 *str = (void*)lpst->thisptr;
1447 /* --- IStream32 implementation */
1449 typedef struct
1451 /* IUnknown fields */
1452 IStreamVtbl *lpVtbl;
1453 DWORD ref;
1454 /* IStream32 fields */
1455 struct storage_pps_entry stde;
1456 int ppsent;
1457 HANDLE hf;
1458 ULARGE_INTEGER offset;
1459 } IStream32Impl;
1461 /*****************************************************************************
1462 * IStream32_QueryInterface [VTABLE]
1464 HRESULT WINAPI IStream_fnQueryInterface(
1465 IStream* iface,REFIID refiid,LPVOID *obj
1467 IStream32Impl *This = (IStream32Impl *)iface;
1469 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1470 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1471 *obj = This;
1472 return 0;
1474 return OLE_E_ENUM_NOMORE;
1478 /******************************************************************************
1479 * IStream32_AddRef [VTABLE]
1481 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1482 IStream32Impl *This = (IStream32Impl *)iface;
1483 return InterlockedIncrement(&This->ref);
1486 /******************************************************************************
1487 * IStream32_Release [VTABLE]
1489 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1490 IStream32Impl *This = (IStream32Impl *)iface;
1491 ULONG ref;
1492 FlushFileBuffers(This->hf);
1493 ref = InterlockedDecrement(&This->ref);
1494 if (!ref) {
1495 CloseHandle(This->hf);
1496 HeapFree( GetProcessHeap(), 0, This );
1498 return ref;
1501 /* --- IStorage16 implementation */
1503 typedef struct
1505 /* IUnknown fields */
1506 IStorage16Vtbl *lpVtbl;
1507 DWORD ref;
1508 /* IStorage16 fields */
1509 SEGPTR thisptr; /* pointer to this struct as segmented */
1510 struct storage_pps_entry stde;
1511 int ppsent;
1512 HANDLE hf;
1513 } IStorage16Impl;
1515 /******************************************************************************
1516 * IStorage16_QueryInterface [STORAGE.500]
1518 HRESULT WINAPI IStorage16_fnQueryInterface(
1519 IStorage16* iface,REFIID refiid,LPVOID *obj
1521 IStorage16Impl *This = (IStorage16Impl *)iface;
1523 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1525 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1526 *obj = This;
1527 return 0;
1529 return OLE_E_ENUM_NOMORE;
1532 /******************************************************************************
1533 * IStorage16_AddRef [STORAGE.501]
1535 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1536 IStorage16Impl *This = (IStorage16Impl *)iface;
1537 return InterlockedIncrement(&This->ref);
1540 /******************************************************************************
1541 * IStorage16_Release [STORAGE.502]
1543 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1544 IStorage16Impl *This = (IStorage16Impl *)iface;
1545 ULONG ref;
1546 ref = InterlockedDecrement(&This->ref);
1547 if (!ref)
1549 UnMapLS( This->thisptr );
1550 HeapFree( GetProcessHeap(), 0, This );
1552 return ref;
1555 /******************************************************************************
1556 * IStorage16_Stat [STORAGE.517]
1558 HRESULT WINAPI IStorage16_fnStat(
1559 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1561 IStorage16Impl *This = (IStorage16Impl *)iface;
1562 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1563 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1565 TRACE("(%p)->(%p,0x%08lx)\n",
1566 This,pstatstg,grfStatFlag
1568 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1569 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1570 pstatstg->type = This->stde.pps_type;
1571 pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1572 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1573 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1574 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1575 pstatstg->grfMode = 0; /* FIXME */
1576 pstatstg->grfLocksSupported = 0; /* FIXME */
1577 pstatstg->clsid = This->stde.pps_guid;
1578 pstatstg->grfStateBits = 0; /* FIXME */
1579 pstatstg->reserved = 0;
1580 return S_OK;
1583 /******************************************************************************
1584 * IStorage16_Commit [STORAGE.509]
1586 HRESULT WINAPI IStorage16_fnCommit(
1587 LPSTORAGE16 iface,DWORD commitflags
1589 IStorage16Impl *This = (IStorage16Impl *)iface;
1590 FIXME("(%p)->(0x%08lx),STUB!\n",
1591 This,commitflags
1593 return S_OK;
1596 /******************************************************************************
1597 * IStorage16_CopyTo [STORAGE.507]
1599 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1600 IStorage16Impl *This = (IStorage16Impl *)iface;
1601 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1602 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1604 return S_OK;
1608 /******************************************************************************
1609 * IStorage16_CreateStorage [STORAGE.505]
1611 HRESULT WINAPI IStorage16_fnCreateStorage(
1612 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1614 IStorage16Impl *This = (IStorage16Impl *)iface;
1615 IStorage16Impl* lpstg;
1616 int ppsent,x;
1617 struct storage_pps_entry stde;
1618 struct storage_header sth;
1619 HANDLE hf=This->hf;
1620 BOOL ret;
1621 int nPPSEntries;
1623 READ_HEADER;
1625 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1626 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1628 if (grfMode & STGM_TRANSACTED)
1629 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1630 _create_istorage16(ppstg);
1631 lpstg = MapSL((SEGPTR)*ppstg);
1632 lpstg->hf = This->hf;
1634 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1635 if (ppsent<0)
1636 return E_FAIL;
1637 stde=This->stde;
1638 if (stde.pps_dir==-1) {
1639 stde.pps_dir = ppsent;
1640 x = This->ppsent;
1641 } else {
1642 FIXME(" use prev chain too ?\n");
1643 x=stde.pps_dir;
1644 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1645 return E_FAIL;
1646 while (stde.pps_next!=-1) {
1647 x=stde.pps_next;
1648 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1649 return E_FAIL;
1651 stde.pps_next = ppsent;
1653 ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1654 assert(ret);
1655 nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1656 assert(nPPSEntries == 1);
1657 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1658 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1659 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1660 lpstg->stde.pps_next = -1;
1661 lpstg->stde.pps_prev = -1;
1662 lpstg->stde.pps_dir = -1;
1663 lpstg->stde.pps_sb = -1;
1664 lpstg->stde.pps_size = 0;
1665 lpstg->stde.pps_type = 1;
1666 lpstg->ppsent = ppsent;
1667 /* FIXME: timestamps? */
1668 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1669 return E_FAIL;
1670 return S_OK;
1673 /******************************************************************************
1674 * IStorage16_CreateStream [STORAGE.503]
1676 HRESULT WINAPI IStorage16_fnCreateStream(
1677 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1679 IStorage16Impl *This = (IStorage16Impl *)iface;
1680 IStream16Impl* lpstr;
1681 int ppsent,x;
1682 struct storage_pps_entry stde;
1683 BOOL ret;
1684 int nPPSEntries;
1686 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1687 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1689 if (grfMode & STGM_TRANSACTED)
1690 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1691 _create_istream16(ppstm);
1692 lpstr = MapSL((SEGPTR)*ppstm);
1693 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1694 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1695 lpstr->offset.u.LowPart = 0;
1696 lpstr->offset.u.HighPart = 0;
1698 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1699 if (ppsent<0)
1700 return E_FAIL;
1701 stde=This->stde;
1702 if (stde.pps_next==-1)
1703 x=This->ppsent;
1704 else
1705 while (stde.pps_next!=-1) {
1706 x=stde.pps_next;
1707 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1708 return E_FAIL;
1710 stde.pps_next = ppsent;
1711 ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1712 assert(ret);
1713 nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1714 assert(nPPSEntries == 1);
1715 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1716 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1717 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1718 lpstr->stde.pps_next = -1;
1719 lpstr->stde.pps_prev = -1;
1720 lpstr->stde.pps_dir = -1;
1721 lpstr->stde.pps_sb = -1;
1722 lpstr->stde.pps_size = 0;
1723 lpstr->stde.pps_type = 2;
1724 lpstr->ppsent = ppsent;
1725 /* FIXME: timestamps? */
1726 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1727 return E_FAIL;
1728 return S_OK;
1731 /******************************************************************************
1732 * IStorage16_OpenStorage [STORAGE.506]
1734 HRESULT WINAPI IStorage16_fnOpenStorage(
1735 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1737 IStorage16Impl *This = (IStorage16Impl *)iface;
1738 IStream16Impl* lpstg;
1739 WCHAR name[33];
1740 int newpps;
1742 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1743 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1745 if (grfMode & STGM_TRANSACTED)
1746 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1747 _create_istorage16(ppstg);
1748 lpstg = MapSL((SEGPTR)*ppstg);
1749 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1750 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1751 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1752 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1753 if (newpps==-1) {
1754 IStream16_fnRelease((IStream16*)lpstg);
1755 return E_FAIL;
1758 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1759 IStream16_fnRelease((IStream16*)lpstg);
1760 return E_FAIL;
1762 lpstg->ppsent = newpps;
1763 return S_OK;
1766 /******************************************************************************
1767 * IStorage16_OpenStream [STORAGE.504]
1769 HRESULT WINAPI IStorage16_fnOpenStream(
1770 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1772 IStorage16Impl *This = (IStorage16Impl *)iface;
1773 IStream16Impl* lpstr;
1774 WCHAR name[33];
1775 int newpps;
1777 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1778 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1780 if (grfMode & STGM_TRANSACTED)
1781 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1782 _create_istream16(ppstm);
1783 lpstr = MapSL((SEGPTR)*ppstm);
1784 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1785 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1786 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1787 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1788 if (newpps==-1) {
1789 IStream16_fnRelease((IStream16*)lpstr);
1790 return E_FAIL;
1793 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1794 IStream16_fnRelease((IStream16*)lpstr);
1795 return E_FAIL;
1797 lpstr->offset.u.LowPart = 0;
1798 lpstr->offset.u.HighPart = 0;
1799 lpstr->ppsent = newpps;
1800 return S_OK;
1803 /******************************************************************************
1804 * _create_istorage16 [INTERNAL]
1806 static void _create_istorage16(LPSTORAGE16 *stg) {
1807 IStorage16Impl* lpst;
1809 if (!stvt16.QueryInterface) {
1810 HMODULE16 wp = GetModuleHandle16("STORAGE");
1811 if (wp>=32) {
1812 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1813 VTENT(QueryInterface)
1814 VTENT(AddRef)
1815 VTENT(Release)
1816 VTENT(CreateStream)
1817 VTENT(OpenStream)
1818 VTENT(CreateStorage)
1819 VTENT(OpenStorage)
1820 VTENT(CopyTo)
1821 VTENT(MoveElementTo)
1822 VTENT(Commit)
1823 VTENT(Revert)
1824 VTENT(EnumElements)
1825 VTENT(DestroyElement)
1826 VTENT(RenameElement)
1827 VTENT(SetElementTimes)
1828 VTENT(SetClass)
1829 VTENT(SetStateBits)
1830 VTENT(Stat)
1831 #undef VTENT
1832 segstvt16 = (IStorage16Vtbl*)MapLS( &stvt16 );
1833 } else {
1834 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1835 VTENT(QueryInterface)
1836 VTENT(AddRef)
1837 VTENT(Release)
1838 VTENT(CreateStream)
1839 VTENT(OpenStream)
1840 VTENT(CreateStorage)
1841 VTENT(OpenStorage)
1842 VTENT(CopyTo)
1843 VTENT(Commit)
1844 /* not (yet) implemented ...
1845 VTENT(MoveElementTo)
1846 VTENT(Revert)
1847 VTENT(EnumElements)
1848 VTENT(DestroyElement)
1849 VTENT(RenameElement)
1850 VTENT(SetElementTimes)
1851 VTENT(SetClass)
1852 VTENT(SetStateBits)
1853 VTENT(Stat)
1855 #undef VTENT
1856 segstvt16 = &stvt16;
1859 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1860 lpst->lpVtbl = segstvt16;
1861 lpst->ref = 1;
1862 lpst->thisptr = MapLS(lpst);
1863 *stg = (void*)lpst->thisptr;
1866 /******************************************************************************
1867 * Storage API functions
1870 /******************************************************************************
1871 * StgCreateDocFileA [STORAGE.1]
1873 HRESULT WINAPI StgCreateDocFile16(
1874 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1876 HANDLE hf;
1877 int i,ret;
1878 IStorage16Impl* lpstg;
1879 struct storage_pps_entry stde;
1881 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1882 pwcsName,grfMode,reserved,ppstgOpen
1884 _create_istorage16(ppstgOpen);
1885 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1886 if (hf==INVALID_HANDLE_VALUE) {
1887 WARN("couldn't open file for storage:%ld\n",GetLastError());
1888 return E_FAIL;
1890 lpstg = MapSL((SEGPTR)*ppstgOpen);
1891 lpstg->hf = hf;
1892 /* FIXME: check for existence before overwriting? */
1893 if (!STORAGE_init_storage(hf)) {
1894 CloseHandle(hf);
1895 return E_FAIL;
1897 i=0;ret=0;
1898 while (!ret) { /* neither 1 nor <0 */
1899 ret=STORAGE_get_pps_entry(hf,i,&stde);
1900 if ((ret==1) && (stde.pps_type==5)) {
1901 lpstg->stde = stde;
1902 lpstg->ppsent = i;
1903 break;
1905 i++;
1907 if (ret!=1) {
1908 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1909 return E_FAIL;
1912 return S_OK;
1915 /******************************************************************************
1916 * StgIsStorageFile [STORAGE.5]
1918 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1919 UNICODE_STRING strW;
1920 HRESULT ret;
1922 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1923 ret = StgIsStorageFile( strW.Buffer );
1924 RtlFreeUnicodeString( &strW );
1926 return ret;
1929 /******************************************************************************
1930 * StgOpenStorage [STORAGE.3]
1932 HRESULT WINAPI StgOpenStorage16(
1933 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1934 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1936 HANDLE hf;
1937 int ret,i;
1938 IStorage16Impl* lpstg;
1939 struct storage_pps_entry stde;
1941 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1942 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1944 _create_istorage16(ppstgOpen);
1945 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1946 if (hf==INVALID_HANDLE_VALUE) {
1947 WARN("Couldn't open file for storage\n");
1948 return E_FAIL;
1950 lpstg = MapSL((SEGPTR)*ppstgOpen);
1951 lpstg->hf = hf;
1953 i=0;ret=0;
1954 while (!ret) { /* neither 1 nor <0 */
1955 ret=STORAGE_get_pps_entry(hf,i,&stde);
1956 if ((ret==1) && (stde.pps_type==5)) {
1957 lpstg->stde=stde;
1958 break;
1960 i++;
1962 if (ret!=1) {
1963 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1964 return E_FAIL;
1966 return S_OK;
1970 /******************************************************************************
1971 * StgIsStorageILockBytes [STORAGE.6]
1973 * Determines if the ILockBytes contains a storage object.
1975 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1977 DWORD args[6];
1978 HRESULT hres;
1979 HANDLE16 hsig;
1981 args[0] = (DWORD)plkbyt; /* iface */
1982 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1983 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1984 args[4] = 8;
1985 args[5] = 0;
1987 if (!K32WOWCallback16Ex(
1988 (DWORD)((ILockBytes16Vtbl*)MapSL(
1989 (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1990 )->ReadAt,
1991 WCB16_PASCAL,
1992 6*sizeof(DWORD),
1993 (LPVOID)args,
1994 (LPDWORD)&hres
1995 )) {
1996 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1997 return hres;
1999 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
2000 K32WOWGlobalUnlockFree16(args[3]);
2001 return S_OK;
2003 K32WOWGlobalUnlockFree16(args[3]);
2004 return S_FALSE;
2007 /******************************************************************************
2008 * StgOpenStorageOnILockBytes [STORAGE.4]
2010 HRESULT WINAPI StgOpenStorageOnILockBytes16(
2011 ILockBytes16 *plkbyt,
2012 IStorage16 *pstgPriority,
2013 DWORD grfMode,
2014 SNB16 snbExclude,
2015 DWORD reserved,
2016 IStorage16 **ppstgOpen)
2018 IStorage16Impl* lpstg;
2020 if ((plkbyt == 0) || (ppstgOpen == 0))
2021 return STG_E_INVALIDPOINTER;
2023 *ppstgOpen = 0;
2025 _create_istorage16(ppstgOpen);
2026 lpstg = MapSL((SEGPTR)*ppstgOpen);
2028 /* just teach it to use HANDLE instead of ilockbytes :/ */
2030 return S_OK;