Authors: Warren Baird <warren.baird@cimmetry.com>, Dave Belanger <dave.belanger@cimme...
[wine/multimedia.git] / dlls / ole32 / storage.c
blob804f4ce74da6248755f4fc4e606844483bbf06ef
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
105 /******************************************************************************
106 * STORAGE_get_big_block [Internal]
108 * Reading OLE compound storage
110 static BOOL
111 STORAGE_get_big_block(HANDLE hf,int n,BYTE *block)
113 DWORD result;
115 assert(n>=-1);
116 if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
117 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
119 WARN(" seek failed (%ld)\n",GetLastError());
120 return FALSE;
122 if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
124 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
125 return FALSE;
127 return TRUE;
130 /******************************************************************************
131 * STORAGE_put_big_block [INTERNAL]
133 static BOOL
134 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
136 DWORD result;
138 assert(n>=-1);
139 if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
140 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
142 WARN("seek failed (%ld)\n",GetLastError());
143 return FALSE;
145 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
147 WARN(" write failed (%ld)\n",GetLastError());
148 return FALSE;
150 return TRUE;
153 /******************************************************************************
154 * STORAGE_get_next_big_blocknr [INTERNAL]
156 static int
157 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
158 INT bbs[BIGSIZE/sizeof(INT)];
159 struct storage_header sth;
161 READ_HEADER;
163 assert(blocknr>>7<sth.num_of_bbd_blocks);
164 if (sth.bbd_list[blocknr>>7]==0xffffffff)
165 return -5;
166 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
167 return -5;
168 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
169 return bbs[blocknr&0x7f];
172 /******************************************************************************
173 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
175 static int
176 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
177 INT bbs[BIGSIZE/sizeof(INT)];
178 int lastblock = -1;
179 struct storage_header sth;
181 READ_HEADER;
183 assert(blocknr>=0);
184 while (nr--) {
185 assert((blocknr>>7)<sth.num_of_bbd_blocks);
186 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
188 /* simple caching... */
189 if (lastblock!=sth.bbd_list[blocknr>>7]) {
190 BOOL ret = STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
191 assert(ret);
192 lastblock = sth.bbd_list[blocknr>>7];
194 blocknr = bbs[blocknr&0x7f];
196 return blocknr;
199 /******************************************************************************
200 * STORAGE_get_root_pps_entry [Internal]
202 static BOOL
203 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
204 int blocknr,i;
205 BYTE block[BIGSIZE];
206 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
207 struct storage_header sth;
209 READ_HEADER;
210 blocknr = sth.root_startblock;
211 while (blocknr>=0) {
212 BOOL ret = STORAGE_get_big_block(hf,blocknr,block);
213 assert(ret);
214 for (i=0;i<4;i++) {
215 if (!stde[i].pps_sizeofname)
216 continue;
217 if (stde[i].pps_type==5) {
218 *pstde=stde[i];
219 return TRUE;
222 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
224 return FALSE;
227 /******************************************************************************
228 * STORAGE_get_small_block [INTERNAL]
230 static BOOL
231 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
232 BYTE block[BIGSIZE];
233 int bigblocknr;
234 struct storage_pps_entry root;
235 BOOL ret;
237 assert(blocknr>=0);
238 ret = STORAGE_get_root_pps_entry(hf,&root);
239 assert(ret);
240 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
241 assert(bigblocknr>=0);
242 ret = STORAGE_get_big_block(hf,bigblocknr,block);
243 assert(ret);
245 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
246 return TRUE;
249 /******************************************************************************
250 * STORAGE_put_small_block [INTERNAL]
252 static BOOL
253 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
254 BYTE block[BIGSIZE];
255 int bigblocknr;
256 struct storage_pps_entry root;
257 BOOL ret;
259 assert(blocknr>=0);
261 ret = STORAGE_get_root_pps_entry(hf,&root);
262 assert(ret);
263 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
264 assert(bigblocknr>=0);
265 ret = STORAGE_get_big_block(hf,bigblocknr,block);
266 assert(ret);
268 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
269 ret = STORAGE_put_big_block(hf,bigblocknr,block);
270 assert(ret);
271 return TRUE;
274 /******************************************************************************
275 * STORAGE_get_next_small_blocknr [INTERNAL]
277 static int
278 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
279 BYTE block[BIGSIZE];
280 LPINT sbd = (LPINT)block;
281 int bigblocknr;
282 struct storage_header sth;
283 BOOL ret;
285 READ_HEADER;
286 assert(blocknr>=0);
287 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
288 assert(bigblocknr>=0);
289 ret = STORAGE_get_big_block(hf,bigblocknr,block);
290 assert(ret);
291 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
292 return sbd[blocknr & (128-1)];
295 /******************************************************************************
296 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
298 static int
299 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
300 int lastblocknr=-1;
301 BYTE block[BIGSIZE];
302 LPINT sbd = (LPINT)block;
303 struct storage_header sth;
304 BOOL ret;
306 READ_HEADER;
307 assert(blocknr>=0);
308 while ((nr--) && (blocknr>=0)) {
309 if (lastblocknr/128!=blocknr/128) {
310 int bigblocknr;
311 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
312 assert(bigblocknr>=0);
313 ret = STORAGE_get_big_block(hf,bigblocknr,block);
314 assert(ret);
315 lastblocknr = blocknr;
317 assert(lastblocknr>=0);
318 lastblocknr=blocknr;
319 blocknr=sbd[blocknr & (128-1)];
320 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
322 return blocknr;
325 /******************************************************************************
326 * STORAGE_get_pps_entry [INTERNAL]
328 static int
329 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
330 int blocknr;
331 BYTE block[BIGSIZE];
332 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
333 struct storage_header sth;
334 BOOL ret;
336 READ_HEADER;
337 /* we have 4 pps entries per big block */
338 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
339 assert(blocknr>=0);
340 ret = STORAGE_get_big_block(hf,blocknr,block);
341 assert(ret);
343 *pstde=*stde;
344 return 1;
347 /******************************************************************************
348 * STORAGE_put_pps_entry [Internal]
350 static int
351 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
352 int blocknr;
353 BYTE block[BIGSIZE];
354 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
355 struct storage_header sth;
356 BOOL ret;
358 READ_HEADER;
360 /* we have 4 pps entries per big block */
361 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
362 assert(blocknr>=0);
363 ret = STORAGE_get_big_block(hf,blocknr,block);
364 assert(ret);
365 *stde=*pstde;
366 ret = STORAGE_put_big_block(hf,blocknr,block);
367 assert(ret);
368 return 1;
371 /******************************************************************************
372 * STORAGE_look_for_named_pps [Internal]
374 static int
375 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
376 struct storage_pps_entry stde;
377 int ret;
379 if (n==-1)
380 return -1;
381 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
382 return -1;
384 if (!lstrcmpW(name,stde.pps_rawname))
385 return n;
386 if (stde.pps_prev != -1) {
387 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
388 if (ret!=-1)
389 return ret;
391 if (stde.pps_next != -1) {
392 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
393 if (ret!=-1)
394 return ret;
396 return -1;
399 /******************************************************************************
400 * STORAGE_dump_pps_entry [Internal]
402 * FIXME
403 * Function is unused
405 void
406 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
407 char name[33];
409 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
410 if (!stde->pps_sizeofname)
411 return;
412 DPRINTF("name: %s\n",name);
413 DPRINTF("type: %d\n",stde->pps_type);
414 DPRINTF("prev pps: %ld\n",stde->pps_prev);
415 DPRINTF("next pps: %ld\n",stde->pps_next);
416 DPRINTF("dir pps: %ld\n",stde->pps_dir);
417 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
418 if (stde->pps_type !=2) {
419 time_t t;
420 DWORD dw;
421 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
422 t = dw;
423 DPRINTF("ts1: %s\n",ctime(&t));
424 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
425 t = dw;
426 DPRINTF("ts2: %s\n",ctime(&t));
428 DPRINTF("startblock: %ld\n",stde->pps_sb);
429 DPRINTF("size: %ld\n",stde->pps_size);
432 /******************************************************************************
433 * STORAGE_init_storage [INTERNAL]
435 static BOOL
436 STORAGE_init_storage(HANDLE hf) {
437 BYTE block[BIGSIZE];
438 LPDWORD bbs;
439 struct storage_header *sth;
440 struct storage_pps_entry *stde;
441 DWORD result;
443 SetFilePointer( hf, 0, NULL, SEEK_SET );
444 /* block -1 is the storage header */
445 sth = (struct storage_header*)block;
446 memcpy(sth->magic,STORAGE_magic,8);
447 memset(sth->unknown1,0,sizeof(sth->unknown1));
448 memset(sth->unknown2,0,sizeof(sth->unknown2));
449 memset(sth->unknown3,0,sizeof(sth->unknown3));
450 sth->num_of_bbd_blocks = 1;
451 sth->root_startblock = 1;
452 sth->sbd_startblock = 0xffffffff;
453 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
454 sth->bbd_list[0] = 0;
455 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
456 /* block 0 is the big block directory */
457 bbs=(LPDWORD)block;
458 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
459 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
460 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
461 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
462 /* block 1 is the root directory entry */
463 memset(block,0x00,sizeof(block));
464 stde = (struct storage_pps_entry*)block;
465 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
466 sizeof(stde->pps_rawname)/sizeof(WCHAR));
467 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
468 stde->pps_type = 5;
469 stde->pps_dir = -1;
470 stde->pps_next = -1;
471 stde->pps_prev = -1;
472 stde->pps_sb = 0xffffffff;
473 stde->pps_size = 0;
474 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
477 /******************************************************************************
478 * STORAGE_set_big_chain [Internal]
480 static BOOL
481 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
482 BYTE block[BIGSIZE];
483 LPINT bbd = (LPINT)block;
484 int nextblocknr,bigblocknr;
485 struct storage_header sth;
486 BOOL ret;
488 READ_HEADER;
489 assert(blocknr!=type);
490 while (blocknr>=0) {
491 bigblocknr = sth.bbd_list[blocknr/128];
492 assert(bigblocknr>=0);
493 ret = STORAGE_get_big_block(hf,bigblocknr,block);
494 assert(ret);
496 nextblocknr = bbd[blocknr&(128-1)];
497 bbd[blocknr&(128-1)] = type;
498 if (type>=0)
499 return TRUE;
500 ret = STORAGE_put_big_block(hf,bigblocknr,block);
501 assert(ret);
502 type = STORAGE_CHAINENTRY_FREE;
503 blocknr = nextblocknr;
505 return TRUE;
508 /******************************************************************************
509 * STORAGE_set_small_chain [Internal]
511 static BOOL
512 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
513 BYTE block[BIGSIZE];
514 LPINT sbd = (LPINT)block;
515 int lastblocknr,nextsmallblocknr,bigblocknr;
516 struct storage_header sth;
517 BOOL ret;
519 READ_HEADER;
521 assert(blocknr!=type);
522 lastblocknr=-129;bigblocknr=-2;
523 while (blocknr>=0) {
524 /* cache block ... */
525 if (lastblocknr/128!=blocknr/128) {
526 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
527 assert(bigblocknr>=0);
528 ret = STORAGE_get_big_block(hf,bigblocknr,block);
529 assert(ret);
531 lastblocknr = blocknr;
532 nextsmallblocknr = sbd[blocknr&(128-1)];
533 sbd[blocknr&(128-1)] = type;
534 ret = STORAGE_put_big_block(hf,bigblocknr,block);
535 assert(ret);
536 if (type>=0)
537 return TRUE;
538 type = STORAGE_CHAINENTRY_FREE;
539 blocknr = nextsmallblocknr;
541 return TRUE;
544 /******************************************************************************
545 * STORAGE_get_free_big_blocknr [Internal]
547 static int
548 STORAGE_get_free_big_blocknr(HANDLE hf) {
549 BYTE block[BIGSIZE];
550 LPINT sbd = (LPINT)block;
551 int lastbigblocknr,i,curblock,bigblocknr;
552 struct storage_header sth;
553 BOOL ret;
555 READ_HEADER;
556 curblock = 0;
557 lastbigblocknr = -1;
558 bigblocknr = sth.bbd_list[curblock];
559 while (curblock<sth.num_of_bbd_blocks) {
560 assert(bigblocknr>=0);
561 ret = STORAGE_get_big_block(hf,bigblocknr,block);
562 assert(ret);
563 for (i=0;i<128;i++)
564 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
565 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
566 ret = STORAGE_put_big_block(hf,bigblocknr,block);
567 assert(ret);
568 memset(block,0x42,sizeof(block));
569 ret = STORAGE_put_big_block(hf,i+curblock*128,block);
570 assert(ret);
571 return i+curblock*128;
573 lastbigblocknr = bigblocknr;
574 bigblocknr = sth.bbd_list[++curblock];
576 bigblocknr = curblock*128;
577 /* since we have marked all blocks from 0 up to curblock*128-1
578 * the next free one is curblock*128, where we happily put our
579 * next large block depot.
581 memset(block,0xff,sizeof(block));
582 /* mark the block allocated and returned by this function */
583 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
584 ret = STORAGE_put_big_block(hf,bigblocknr,block);
585 assert(ret);
587 /* if we had a bbd block already (mostlikely) we need
588 * to link the new one into the chain
590 if (lastbigblocknr!=-1) {
591 ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr);
592 assert(ret);
594 sth.bbd_list[curblock]=bigblocknr;
595 sth.num_of_bbd_blocks++;
596 assert(sth.num_of_bbd_blocks==curblock+1);
597 ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth);
598 assert(ret);
600 /* Set the end of the chain for the bigblockdepots */
601 ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
602 assert(ret);
603 /* add 1, for the first entry is used for the additional big block
604 * depot. (means we already used bigblocknr) */
605 memset(block,0x42,sizeof(block));
606 /* allocate this block (filled with 0x42) */
607 ret = STORAGE_put_big_block(hf,bigblocknr+1,block);
608 assert(ret);
609 return bigblocknr+1;
613 /******************************************************************************
614 * STORAGE_get_free_small_blocknr [Internal]
616 static int
617 STORAGE_get_free_small_blocknr(HANDLE hf) {
618 BYTE block[BIGSIZE];
619 LPINT sbd = (LPINT)block;
620 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
621 struct storage_pps_entry root;
622 struct storage_header sth;
624 READ_HEADER;
625 bigblocknr = sth.sbd_startblock;
626 curblock = 0;
627 lastbigblocknr = -1;
628 newblocknr = -1;
629 while (bigblocknr>=0) {
630 if (!STORAGE_get_big_block(hf,bigblocknr,block))
631 return -1;
632 for (i=0;i<128;i++)
633 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
634 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
635 newblocknr = i+curblock*128;
636 break;
638 if (i!=128)
639 break;
640 lastbigblocknr = bigblocknr;
641 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
642 curblock++;
644 if (newblocknr==-1) {
645 bigblocknr = STORAGE_get_free_big_blocknr(hf);
646 if (bigblocknr<0)
647 return -1;
648 READ_HEADER;
649 memset(block,0xff,sizeof(block));
650 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
651 if (!STORAGE_put_big_block(hf,bigblocknr,block))
652 return -1;
653 if (lastbigblocknr==-1) {
654 sth.sbd_startblock = bigblocknr;
655 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
656 return -1;
657 } else {
658 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
659 return -1;
661 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
662 return -1;
663 newblocknr = curblock*128;
665 /* allocate enough big blocks for storing the allocated small block */
666 if (!STORAGE_get_root_pps_entry(hf,&root))
667 return -1;
668 if (root.pps_sb==-1)
669 lastbigblocknr = -1;
670 else
671 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
672 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
673 /* we need to allocate more stuff */
674 bigblocknr = STORAGE_get_free_big_blocknr(hf);
675 if (bigblocknr<0)
676 return -1;
677 READ_HEADER;
678 if (root.pps_sb==-1) {
679 root.pps_sb = bigblocknr;
680 root.pps_size += BIGSIZE;
681 } else {
682 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
683 return -1;
684 root.pps_size += BIGSIZE;
686 lastbigblocknr = bigblocknr;
688 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
689 return -1;
690 if (!STORAGE_put_pps_entry(hf,0,&root))
691 return -1;
692 return newblocknr;
695 /******************************************************************************
696 * STORAGE_get_free_pps_entry [Internal]
698 static int
699 STORAGE_get_free_pps_entry(HANDLE hf) {
700 int blocknr, i, curblock, lastblocknr=-1;
701 BYTE block[BIGSIZE];
702 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
703 struct storage_header sth;
705 READ_HEADER;
706 blocknr = sth.root_startblock;
707 assert(blocknr>=0);
708 curblock=0;
709 while (blocknr>=0) {
710 if (!STORAGE_get_big_block(hf,blocknr,block))
711 return -1;
712 for (i=0;i<4;i++)
713 if (stde[i].pps_sizeofname==0) /* free */
714 return curblock*4+i;
715 lastblocknr = blocknr;
716 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
717 curblock++;
719 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
720 blocknr = STORAGE_get_free_big_blocknr(hf);
721 /* sth invalidated */
722 if (blocknr<0)
723 return -1;
725 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
726 return -1;
727 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
728 return -1;
729 memset(block,0,sizeof(block));
730 STORAGE_put_big_block(hf,blocknr,block);
731 return curblock*4;
734 /* --- IStream16 implementation */
736 typedef struct
738 /* IUnknown fields */
739 ICOM_VFIELD(IStream16);
740 DWORD ref;
741 /* IStream16 fields */
742 SEGPTR thisptr; /* pointer to this struct as segmented */
743 struct storage_pps_entry stde;
744 int ppsent;
745 HANDLE hf;
746 ULARGE_INTEGER offset;
747 } IStream16Impl;
749 /******************************************************************************
750 * IStream16_QueryInterface [STORAGE.518]
752 HRESULT WINAPI IStream16_fnQueryInterface(
753 IStream16* iface,REFIID refiid,LPVOID *obj
755 ICOM_THIS(IStream16Impl,iface);
756 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
757 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
758 *obj = This;
759 return 0;
761 return OLE_E_ENUM_NOMORE;
765 /******************************************************************************
766 * IStream16_AddRef [STORAGE.519]
768 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
769 ICOM_THIS(IStream16Impl,iface);
770 return ++(This->ref);
773 /******************************************************************************
774 * IStream16_Release [STORAGE.520]
776 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
777 ICOM_THIS(IStream16Impl,iface);
778 FlushFileBuffers(This->hf);
779 This->ref--;
780 if (!This->ref) {
781 CloseHandle(This->hf);
782 UnMapLS( This->thisptr );
783 HeapFree( GetProcessHeap(), 0, This );
784 return 0;
786 return This->ref;
789 /******************************************************************************
790 * IStream16_Seek [STORAGE.523]
792 * FIXME
793 * Does not handle 64 bits
795 HRESULT WINAPI IStream16_fnSeek(
796 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
798 ICOM_THIS(IStream16Impl,iface);
799 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
801 switch (whence) {
802 /* unix SEEK_xx should be the same as win95 ones */
803 case SEEK_SET:
804 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
805 * right now.
807 assert(offset.s.HighPart==0);
808 This->offset.s.HighPart = offset.s.HighPart;
809 This->offset.s.LowPart = offset.s.LowPart;
810 break;
811 case SEEK_CUR:
812 if (offset.s.HighPart < 0) {
813 /* FIXME: is this negation correct ? */
814 offset.s.HighPart = -offset.s.HighPart;
815 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
817 assert(offset.s.HighPart==0);
818 assert(This->offset.s.LowPart >= offset.s.LowPart);
819 This->offset.s.LowPart -= offset.s.LowPart;
820 } else {
821 assert(offset.s.HighPart==0);
822 This->offset.s.LowPart+= offset.s.LowPart;
824 break;
825 case SEEK_END:
826 assert(offset.s.HighPart==0);
827 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
828 break;
830 if (This->offset.s.LowPart>This->stde.pps_size)
831 This->offset.s.LowPart=This->stde.pps_size;
832 if (newpos) *newpos = This->offset;
833 return S_OK;
836 /******************************************************************************
837 * IStream16_Read [STORAGE.521]
839 HRESULT WINAPI IStream16_fnRead(
840 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
842 ICOM_THIS(IStream16Impl,iface);
843 BYTE block[BIGSIZE];
844 ULONG *bytesread=pcbRead,xxread;
845 int blocknr;
847 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
848 if (!pcbRead) bytesread=&xxread;
849 *bytesread = 0;
851 if (cb>This->stde.pps_size-This->offset.s.LowPart)
852 cb=This->stde.pps_size-This->offset.s.LowPart;
853 if (This->stde.pps_size < 0x1000) {
854 /* use small block reader */
855 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
856 while (cb) {
857 int cc;
859 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
860 WARN("small block read failed!!!\n");
861 return E_FAIL;
863 cc = cb;
864 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
865 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
866 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
867 This->offset.s.LowPart+=cc;
868 (LPBYTE)pv+=cc;
869 *bytesread+=cc;
870 cb-=cc;
871 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
873 } else {
874 /* use big block reader */
875 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
876 while (cb) {
877 int cc;
879 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
880 WARN("big block read failed!!!\n");
881 return E_FAIL;
883 cc = cb;
884 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
885 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
886 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
887 This->offset.s.LowPart+=cc;
888 (LPBYTE)pv+=cc;
889 *bytesread+=cc;
890 cb-=cc;
891 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
894 return S_OK;
897 /******************************************************************************
898 * IStream16_Write [STORAGE.522]
900 HRESULT WINAPI IStream16_fnWrite(
901 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
903 ICOM_THIS(IStream16Impl,iface);
904 BYTE block[BIGSIZE];
905 ULONG *byteswritten=pcbWrite,xxwritten;
906 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
907 HANDLE hf = This->hf;
909 if (!pcbWrite) byteswritten=&xxwritten;
910 *byteswritten = 0;
912 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
913 /* do we need to junk some blocks? */
914 newsize = This->offset.s.LowPart+cb;
915 oldsize = This->stde.pps_size;
916 if (newsize < oldsize) {
917 if (oldsize < 0x1000) {
918 /* only small blocks */
919 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
921 assert(blocknr>=0);
923 /* will set the rest of the chain to 'free' */
924 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
925 return E_FAIL;
926 } else {
927 if (newsize >= 0x1000) {
928 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
929 assert(blocknr>=0);
931 /* will set the rest of the chain to 'free' */
932 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933 return E_FAIL;
934 } else {
935 /* Migrate large blocks to small blocks
936 * (we just migrate newsize bytes)
938 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
939 HRESULT r = E_FAIL;
941 cc = newsize;
942 blocknr = This->stde.pps_sb;
943 curdata = data;
944 while (cc>0) {
945 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
946 HeapFree(GetProcessHeap(),0,data);
947 return E_FAIL;
949 curdata += BIGSIZE;
950 cc -= BIGSIZE;
951 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
953 /* frees complete chain for this stream */
954 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
955 goto err;
956 curdata = data;
957 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
958 if (blocknr<0)
959 goto err;
960 cc = newsize;
961 while (cc>0) {
962 if (!STORAGE_put_small_block(hf,blocknr,curdata))
963 goto err;
964 cc -= SMALLSIZE;
965 if (cc<=0) {
966 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
967 goto err;
968 break;
969 } else {
970 int newblocknr = STORAGE_get_free_small_blocknr(hf);
971 if (newblocknr<0)
972 goto err;
973 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
974 goto err;
975 blocknr = newblocknr;
977 curdata += SMALLSIZE;
979 r = S_OK;
980 err:
981 HeapFree(GetProcessHeap(),0,data);
982 if(r != S_OK)
983 return r;
986 This->stde.pps_size = newsize;
989 if (newsize > oldsize) {
990 if (oldsize >= 0x1000) {
991 /* should return the block right before the 'endofchain' */
992 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
993 assert(blocknr>=0);
994 lastblocknr = blocknr;
995 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
996 blocknr = STORAGE_get_free_big_blocknr(hf);
997 if (blocknr<0)
998 return E_FAIL;
999 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1000 return E_FAIL;
1001 lastblocknr = blocknr;
1003 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1004 return E_FAIL;
1005 } else {
1006 if (newsize < 0x1000) {
1007 /* find startblock */
1008 if (!oldsize)
1009 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
1010 else
1011 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
1012 if (blocknr<0)
1013 return E_FAIL;
1015 /* allocate required new small blocks */
1016 lastblocknr = blocknr;
1017 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1018 blocknr = STORAGE_get_free_small_blocknr(hf);
1019 if (blocknr<0)
1020 return E_FAIL;
1021 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
1022 return E_FAIL;
1023 lastblocknr = blocknr;
1025 /* and terminate the chain */
1026 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1027 return E_FAIL;
1028 } else {
1029 if (!oldsize) {
1030 /* no single block allocated yet */
1031 blocknr=STORAGE_get_free_big_blocknr(hf);
1032 if (blocknr<0)
1033 return E_FAIL;
1034 This->stde.pps_sb = blocknr;
1035 } else {
1036 /* Migrate small blocks to big blocks */
1037 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1038 HRESULT r = E_FAIL;
1040 cc = oldsize;
1041 blocknr = This->stde.pps_sb;
1042 curdata = data;
1043 /* slurp in */
1044 while (cc>0) {
1045 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1046 goto err2;
1047 curdata += SMALLSIZE;
1048 cc -= SMALLSIZE;
1049 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1051 /* free small block chain */
1052 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1053 goto err2;
1054 curdata = data;
1055 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1056 if (blocknr<0)
1057 goto err2;
1058 /* put the data into the big blocks */
1059 cc = This->stde.pps_size;
1060 while (cc>0) {
1061 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1062 goto err2;
1063 cc -= BIGSIZE;
1064 if (cc<=0) {
1065 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1066 goto err2;
1067 break;
1068 } else {
1069 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1070 if (newblocknr<0)
1071 goto err2;
1072 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1073 goto err2;
1074 blocknr = newblocknr;
1076 curdata += BIGSIZE;
1078 r = S_OK;
1079 err2:
1080 HeapFree(GetProcessHeap(),0,data);
1081 if(r != S_OK)
1082 return r;
1084 /* generate big blocks to fit the new data */
1085 lastblocknr = blocknr;
1086 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1087 blocknr = STORAGE_get_free_big_blocknr(hf);
1088 if (blocknr<0)
1089 return E_FAIL;
1090 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1091 return E_FAIL;
1092 lastblocknr = blocknr;
1094 /* terminate chain */
1095 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1096 return E_FAIL;
1099 This->stde.pps_size = newsize;
1102 /* There are just some cases where we didn't modify it, we write it out
1103 * everytime
1105 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1106 return E_FAIL;
1108 /* finally the write pass */
1109 if (This->stde.pps_size < 0x1000) {
1110 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1111 assert(blocknr>=0);
1112 while (cb>0) {
1113 /* we ensured that it is allocated above */
1114 assert(blocknr>=0);
1115 /* Read old block everytime, since we can have
1116 * overlapping data at START and END of the write
1118 if (!STORAGE_get_small_block(hf,blocknr,block))
1119 return E_FAIL;
1121 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1122 if (cc>cb)
1123 cc=cb;
1124 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1125 (LPBYTE)((char *) pv+curoffset),
1128 if (!STORAGE_put_small_block(hf,blocknr,block))
1129 return E_FAIL;
1130 cb -= cc;
1131 curoffset += cc;
1132 (LPBYTE)pv += cc;
1133 This->offset.s.LowPart += cc;
1134 *byteswritten += cc;
1135 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1137 } else {
1138 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1139 assert(blocknr>=0);
1140 while (cb>0) {
1141 /* we ensured that it is allocated above, so it better is */
1142 assert(blocknr>=0);
1143 /* read old block everytime, since we can have
1144 * overlapping data at START and END of the write
1146 if (!STORAGE_get_big_block(hf,blocknr,block))
1147 return E_FAIL;
1149 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1150 if (cc>cb)
1151 cc=cb;
1152 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1153 (LPBYTE)((char *) pv+curoffset),
1156 if (!STORAGE_put_big_block(hf,blocknr,block))
1157 return E_FAIL;
1158 cb -= cc;
1159 curoffset += cc;
1160 (LPBYTE)pv += cc;
1161 This->offset.s.LowPart += cc;
1162 *byteswritten += cc;
1163 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1166 return S_OK;
1169 /******************************************************************************
1170 * _create_istream16 [Internal]
1172 static void _create_istream16(LPSTREAM16 *str) {
1173 IStream16Impl* lpst;
1175 if (!strvt16.QueryInterface) {
1176 HMODULE16 wp = GetModuleHandle16("STORAGE");
1177 if (wp>=32) {
1178 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1179 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1180 VTENT(QueryInterface);
1181 VTENT(AddRef);
1182 VTENT(Release);
1183 VTENT(Read);
1184 VTENT(Write);
1185 VTENT(Seek);
1186 VTENT(SetSize);
1187 VTENT(CopyTo);
1188 VTENT(Commit);
1189 VTENT(Revert);
1190 VTENT(LockRegion);
1191 VTENT(UnlockRegion);
1192 VTENT(Stat);
1193 VTENT(Clone);
1194 #undef VTENT
1195 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1196 } else {
1197 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1198 VTENT(QueryInterface);
1199 VTENT(AddRef);
1200 VTENT(Release);
1201 VTENT(Read);
1202 VTENT(Write);
1203 VTENT(Seek);
1205 VTENT(CopyTo);
1206 VTENT(Commit);
1207 VTENT(SetSize);
1208 VTENT(Revert);
1209 VTENT(LockRegion);
1210 VTENT(UnlockRegion);
1211 VTENT(Stat);
1212 VTENT(Clone);
1214 #undef VTENT
1215 segstrvt16 = &strvt16;
1218 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1219 lpst->lpVtbl = segstrvt16;
1220 lpst->ref = 1;
1221 lpst->thisptr = MapLS( lpst );
1222 *str = (void*)lpst->thisptr;
1226 /* --- IStream32 implementation */
1228 typedef struct
1230 /* IUnknown fields */
1231 ICOM_VFIELD(IStream);
1232 DWORD ref;
1233 /* IStream32 fields */
1234 struct storage_pps_entry stde;
1235 int ppsent;
1236 HANDLE hf;
1237 ULARGE_INTEGER offset;
1238 } IStream32Impl;
1240 /*****************************************************************************
1241 * IStream32_QueryInterface [VTABLE]
1243 HRESULT WINAPI IStream_fnQueryInterface(
1244 IStream* iface,REFIID refiid,LPVOID *obj
1246 ICOM_THIS(IStream32Impl,iface);
1248 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1249 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1250 *obj = This;
1251 return 0;
1253 return OLE_E_ENUM_NOMORE;
1257 /******************************************************************************
1258 * IStream32_AddRef [VTABLE]
1260 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1261 ICOM_THIS(IStream32Impl,iface);
1262 return ++(This->ref);
1265 /******************************************************************************
1266 * IStream32_Release [VTABLE]
1268 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1269 ICOM_THIS(IStream32Impl,iface);
1270 FlushFileBuffers(This->hf);
1271 This->ref--;
1272 if (!This->ref) {
1273 CloseHandle(This->hf);
1274 HeapFree( GetProcessHeap(), 0, This );
1275 return 0;
1277 return This->ref;
1280 /* --- IStorage16 implementation */
1282 typedef struct
1284 /* IUnknown fields */
1285 ICOM_VFIELD(IStorage16);
1286 DWORD ref;
1287 /* IStorage16 fields */
1288 SEGPTR thisptr; /* pointer to this struct as segmented */
1289 struct storage_pps_entry stde;
1290 int ppsent;
1291 HANDLE hf;
1292 } IStorage16Impl;
1294 /******************************************************************************
1295 * IStorage16_QueryInterface [STORAGE.500]
1297 HRESULT WINAPI IStorage16_fnQueryInterface(
1298 IStorage16* iface,REFIID refiid,LPVOID *obj
1300 ICOM_THIS(IStorage16Impl,iface);
1302 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1304 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1305 *obj = This;
1306 return 0;
1308 return OLE_E_ENUM_NOMORE;
1311 /******************************************************************************
1312 * IStorage16_AddRef [STORAGE.501]
1314 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1315 ICOM_THIS(IStorage16Impl,iface);
1316 return ++(This->ref);
1319 /******************************************************************************
1320 * IStorage16_Release [STORAGE.502]
1322 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1323 ICOM_THIS(IStorage16Impl,iface);
1324 This->ref--;
1325 if (This->ref)
1326 return This->ref;
1327 UnMapLS( This->thisptr );
1328 HeapFree( GetProcessHeap(), 0, This );
1329 return 0;
1332 /******************************************************************************
1333 * IStorage16_Stat [STORAGE.517]
1335 HRESULT WINAPI IStorage16_fnStat(
1336 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1338 ICOM_THIS(IStorage16Impl,iface);
1339 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1340 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1342 TRACE("(%p)->(%p,0x%08lx)\n",
1343 This,pstatstg,grfStatFlag
1345 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1346 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1347 pstatstg->type = This->stde.pps_type;
1348 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1349 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1350 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1351 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1352 pstatstg->grfMode = 0; /* FIXME */
1353 pstatstg->grfLocksSupported = 0; /* FIXME */
1354 pstatstg->clsid = This->stde.pps_guid;
1355 pstatstg->grfStateBits = 0; /* FIXME */
1356 pstatstg->reserved = 0;
1357 return S_OK;
1360 /******************************************************************************
1361 * IStorage16_Commit [STORAGE.509]
1363 HRESULT WINAPI IStorage16_fnCommit(
1364 LPSTORAGE16 iface,DWORD commitflags
1366 ICOM_THIS(IStorage16Impl,iface);
1367 FIXME("(%p)->(0x%08lx),STUB!\n",
1368 This,commitflags
1370 return S_OK;
1373 /******************************************************************************
1374 * IStorage16_CopyTo [STORAGE.507]
1376 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1377 ICOM_THIS(IStorage16Impl,iface);
1378 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1379 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1381 return S_OK;
1385 /******************************************************************************
1386 * IStorage16_CreateStorage [STORAGE.505]
1388 HRESULT WINAPI IStorage16_fnCreateStorage(
1389 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1391 ICOM_THIS(IStorage16Impl,iface);
1392 IStorage16Impl* lpstg;
1393 int ppsent,x;
1394 struct storage_pps_entry stde;
1395 struct storage_header sth;
1396 HANDLE hf=This->hf;
1397 BOOL ret;
1398 int nPPSEntries;
1400 READ_HEADER;
1402 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1403 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1405 if (grfMode & STGM_TRANSACTED)
1406 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1407 _create_istorage16(ppstg);
1408 lpstg = MapSL((SEGPTR)*ppstg);
1409 lpstg->hf = This->hf;
1411 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1412 if (ppsent<0)
1413 return E_FAIL;
1414 stde=This->stde;
1415 if (stde.pps_dir==-1) {
1416 stde.pps_dir = ppsent;
1417 x = This->ppsent;
1418 } else {
1419 FIXME(" use prev chain too ?\n");
1420 x=stde.pps_dir;
1421 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1422 return E_FAIL;
1423 while (stde.pps_next!=-1) {
1424 x=stde.pps_next;
1425 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1426 return E_FAIL;
1428 stde.pps_next = ppsent;
1430 ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde);
1431 assert(ret);
1432 nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde));
1433 assert(nPPSEntries == 1);
1434 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1435 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1436 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1437 lpstg->stde.pps_next = -1;
1438 lpstg->stde.pps_prev = -1;
1439 lpstg->stde.pps_dir = -1;
1440 lpstg->stde.pps_sb = -1;
1441 lpstg->stde.pps_size = 0;
1442 lpstg->stde.pps_type = 1;
1443 lpstg->ppsent = ppsent;
1444 /* FIXME: timestamps? */
1445 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1446 return E_FAIL;
1447 return S_OK;
1450 /******************************************************************************
1451 * IStorage16_CreateStream [STORAGE.503]
1453 HRESULT WINAPI IStorage16_fnCreateStream(
1454 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1456 ICOM_THIS(IStorage16Impl,iface);
1457 IStream16Impl* lpstr;
1458 int ppsent,x;
1459 struct storage_pps_entry stde;
1460 BOOL ret;
1461 int nPPSEntries;
1463 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1464 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1466 if (grfMode & STGM_TRANSACTED)
1467 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1468 _create_istream16(ppstm);
1469 lpstr = MapSL((SEGPTR)*ppstm);
1470 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1471 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1472 lpstr->offset.s.LowPart = 0;
1473 lpstr->offset.s.HighPart = 0;
1475 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1476 if (ppsent<0)
1477 return E_FAIL;
1478 stde=This->stde;
1479 if (stde.pps_next==-1)
1480 x=This->ppsent;
1481 else
1482 while (stde.pps_next!=-1) {
1483 x=stde.pps_next;
1484 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1485 return E_FAIL;
1487 stde.pps_next = ppsent;
1488 ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde);
1489 assert(ret);
1490 nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde));
1491 assert(nPPSEntries == 1);
1492 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1493 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1494 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1495 lpstr->stde.pps_next = -1;
1496 lpstr->stde.pps_prev = -1;
1497 lpstr->stde.pps_dir = -1;
1498 lpstr->stde.pps_sb = -1;
1499 lpstr->stde.pps_size = 0;
1500 lpstr->stde.pps_type = 2;
1501 lpstr->ppsent = ppsent;
1502 /* FIXME: timestamps? */
1503 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1504 return E_FAIL;
1505 return S_OK;
1508 /******************************************************************************
1509 * IStorage16_OpenStorage [STORAGE.506]
1511 HRESULT WINAPI IStorage16_fnOpenStorage(
1512 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1514 ICOM_THIS(IStorage16Impl,iface);
1515 IStream16Impl* lpstg;
1516 WCHAR name[33];
1517 int newpps;
1519 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1520 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1522 if (grfMode & STGM_TRANSACTED)
1523 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1524 _create_istorage16(ppstg);
1525 lpstg = MapSL((SEGPTR)*ppstg);
1526 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1527 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1528 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1529 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1530 if (newpps==-1) {
1531 IStream16_fnRelease((IStream16*)lpstg);
1532 return E_FAIL;
1535 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1536 IStream16_fnRelease((IStream16*)lpstg);
1537 return E_FAIL;
1539 lpstg->ppsent = newpps;
1540 return S_OK;
1543 /******************************************************************************
1544 * IStorage16_OpenStream [STORAGE.504]
1546 HRESULT WINAPI IStorage16_fnOpenStream(
1547 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1549 ICOM_THIS(IStorage16Impl,iface);
1550 IStream16Impl* lpstr;
1551 WCHAR name[33];
1552 int newpps;
1554 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1555 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1557 if (grfMode & STGM_TRANSACTED)
1558 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1559 _create_istream16(ppstm);
1560 lpstr = MapSL((SEGPTR)*ppstm);
1561 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1562 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1563 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1564 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1565 if (newpps==-1) {
1566 IStream16_fnRelease((IStream16*)lpstr);
1567 return E_FAIL;
1570 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1571 IStream16_fnRelease((IStream16*)lpstr);
1572 return E_FAIL;
1574 lpstr->offset.s.LowPart = 0;
1575 lpstr->offset.s.HighPart = 0;
1576 lpstr->ppsent = newpps;
1577 return S_OK;
1580 /******************************************************************************
1581 * _create_istorage16 [INTERNAL]
1583 static void _create_istorage16(LPSTORAGE16 *stg) {
1584 IStorage16Impl* lpst;
1586 if (!stvt16.QueryInterface) {
1587 HMODULE16 wp = GetModuleHandle16("STORAGE");
1588 if (wp>=32) {
1589 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1590 VTENT(QueryInterface)
1591 VTENT(AddRef)
1592 VTENT(Release)
1593 VTENT(CreateStream)
1594 VTENT(OpenStream)
1595 VTENT(CreateStorage)
1596 VTENT(OpenStorage)
1597 VTENT(CopyTo)
1598 VTENT(MoveElementTo)
1599 VTENT(Commit)
1600 VTENT(Revert)
1601 VTENT(EnumElements)
1602 VTENT(DestroyElement)
1603 VTENT(RenameElement)
1604 VTENT(SetElementTimes)
1605 VTENT(SetClass)
1606 VTENT(SetStateBits)
1607 VTENT(Stat)
1608 #undef VTENT
1609 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1610 } else {
1611 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1612 VTENT(QueryInterface)
1613 VTENT(AddRef)
1614 VTENT(Release)
1615 VTENT(CreateStream)
1616 VTENT(OpenStream)
1617 VTENT(CreateStorage)
1618 VTENT(OpenStorage)
1619 VTENT(CopyTo)
1620 VTENT(Commit)
1621 /* not (yet) implemented ...
1622 VTENT(MoveElementTo)
1623 VTENT(Revert)
1624 VTENT(EnumElements)
1625 VTENT(DestroyElement)
1626 VTENT(RenameElement)
1627 VTENT(SetElementTimes)
1628 VTENT(SetClass)
1629 VTENT(SetStateBits)
1630 VTENT(Stat)
1632 #undef VTENT
1633 segstvt16 = &stvt16;
1636 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1637 lpst->lpVtbl = segstvt16;
1638 lpst->ref = 1;
1639 lpst->thisptr = MapLS(lpst);
1640 *stg = (void*)lpst->thisptr;
1643 /******************************************************************************
1644 * Storage API functions
1647 /******************************************************************************
1648 * StgCreateDocFileA [STORAGE.1]
1650 HRESULT WINAPI StgCreateDocFile16(
1651 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1653 HANDLE hf;
1654 int i,ret;
1655 IStorage16Impl* lpstg;
1656 struct storage_pps_entry stde;
1658 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1659 pwcsName,grfMode,reserved,ppstgOpen
1661 _create_istorage16(ppstgOpen);
1662 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1663 if (hf==INVALID_HANDLE_VALUE) {
1664 WARN("couldn't open file for storage:%ld\n",GetLastError());
1665 return E_FAIL;
1667 lpstg = MapSL((SEGPTR)*ppstgOpen);
1668 lpstg->hf = hf;
1669 /* FIXME: check for existence before overwriting? */
1670 if (!STORAGE_init_storage(hf)) {
1671 CloseHandle(hf);
1672 return E_FAIL;
1674 i=0;ret=0;
1675 while (!ret) { /* neither 1 nor <0 */
1676 ret=STORAGE_get_pps_entry(hf,i,&stde);
1677 if ((ret==1) && (stde.pps_type==5)) {
1678 lpstg->stde = stde;
1679 lpstg->ppsent = i;
1680 break;
1682 i++;
1684 if (ret!=1) {
1685 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1686 return E_FAIL;
1689 return S_OK;
1692 /******************************************************************************
1693 * StgIsStorageFile [STORAGE.5]
1695 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1696 UNICODE_STRING strW;
1697 HRESULT ret;
1699 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1700 ret = StgIsStorageFile( strW.Buffer );
1701 RtlFreeUnicodeString( &strW );
1703 return ret;
1706 /******************************************************************************
1707 * StgOpenStorage [STORAGE.3]
1709 HRESULT WINAPI StgOpenStorage16(
1710 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1711 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1713 HANDLE hf;
1714 int ret,i;
1715 IStorage16Impl* lpstg;
1716 struct storage_pps_entry stde;
1718 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1719 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1721 _create_istorage16(ppstgOpen);
1722 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1723 if (hf==INVALID_HANDLE_VALUE) {
1724 WARN("Couldn't open file for storage\n");
1725 return E_FAIL;
1727 lpstg = MapSL((SEGPTR)*ppstgOpen);
1728 lpstg->hf = hf;
1730 i=0;ret=0;
1731 while (!ret) { /* neither 1 nor <0 */
1732 ret=STORAGE_get_pps_entry(hf,i,&stde);
1733 if ((ret==1) && (stde.pps_type==5)) {
1734 lpstg->stde=stde;
1735 break;
1737 i++;
1739 if (ret!=1) {
1740 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1741 return E_FAIL;
1743 return S_OK;
1747 /******************************************************************************
1748 * StgIsStorageILockBytes [STORAGE.6]
1750 * Determines if the ILockBytes contains a storage object.
1752 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1754 DWORD args[6];
1755 HRESULT hres;
1756 HANDLE16 hsig;
1758 args[0] = (DWORD)plkbyt; /* iface */
1759 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1760 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1761 args[4] = 8;
1762 args[5] = 0;
1764 if (!K32WOWCallback16Ex(
1765 (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1766 (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1767 )->ReadAt,
1768 WCB16_PASCAL,
1769 6*sizeof(DWORD),
1770 (LPVOID)args,
1771 (LPDWORD)&hres
1772 )) {
1773 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1774 return hres;
1776 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1777 K32WOWGlobalUnlockFree16(args[3]);
1778 return S_OK;
1780 K32WOWGlobalUnlockFree16(args[3]);
1781 return S_FALSE;
1784 /******************************************************************************
1785 * StgOpenStorageOnILockBytes [STORAGE.4]
1787 HRESULT WINAPI StgOpenStorageOnILockBytes16(
1788 ILockBytes16 *plkbyt,
1789 IStorage16 *pstgPriority,
1790 DWORD grfMode,
1791 SNB16 snbExclude,
1792 DWORD reserved,
1793 IStorage16 **ppstgOpen)
1795 IStorage16Impl* lpstg;
1797 if ((plkbyt == 0) || (ppstgOpen == 0))
1798 return STG_E_INVALIDPOINTER;
1800 *ppstgOpen = 0;
1802 _create_istorage16(ppstgOpen);
1803 lpstg = MapSL((SEGPTR)*ppstgOpen);
1805 /* just teach it to use HANDLE instead of ilockbytes :/ */
1807 return S_OK;