Added hack to call CreateFileW through a pointer so that we don't need
[wine/multimedia.git] / dlls / ole32 / storage.c
blob3edad0e98c52340a4da68bc5a259fa649a866d85
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 assert(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 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
191 lastblock = sth.bbd_list[blocknr>>7];
193 blocknr = bbs[blocknr&0x7f];
195 return blocknr;
198 /******************************************************************************
199 * STORAGE_get_root_pps_entry [Internal]
201 static BOOL
202 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
203 int blocknr,i;
204 BYTE block[BIGSIZE];
205 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
206 struct storage_header sth;
208 READ_HEADER;
209 blocknr = sth.root_startblock;
210 while (blocknr>=0) {
211 assert(STORAGE_get_big_block(hf,blocknr,block));
212 for (i=0;i<4;i++) {
213 if (!stde[i].pps_sizeofname)
214 continue;
215 if (stde[i].pps_type==5) {
216 *pstde=stde[i];
217 return TRUE;
220 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
222 return FALSE;
225 /******************************************************************************
226 * STORAGE_get_small_block [INTERNAL]
228 static BOOL
229 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
230 BYTE block[BIGSIZE];
231 int bigblocknr;
232 struct storage_pps_entry root;
234 assert(blocknr>=0);
235 assert(STORAGE_get_root_pps_entry(hf,&root));
236 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
237 assert(bigblocknr>=0);
238 assert(STORAGE_get_big_block(hf,bigblocknr,block));
240 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
241 return TRUE;
244 /******************************************************************************
245 * STORAGE_put_small_block [INTERNAL]
247 static BOOL
248 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
249 BYTE block[BIGSIZE];
250 int bigblocknr;
251 struct storage_pps_entry root;
253 assert(blocknr>=0);
255 assert(STORAGE_get_root_pps_entry(hf,&root));
256 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
257 assert(bigblocknr>=0);
258 assert(STORAGE_get_big_block(hf,bigblocknr,block));
260 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
261 assert(STORAGE_put_big_block(hf,bigblocknr,block));
262 return TRUE;
265 /******************************************************************************
266 * STORAGE_get_next_small_blocknr [INTERNAL]
268 static int
269 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
270 BYTE block[BIGSIZE];
271 LPINT sbd = (LPINT)block;
272 int bigblocknr;
273 struct storage_header sth;
275 READ_HEADER;
276 assert(blocknr>=0);
277 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
278 assert(bigblocknr>=0);
279 assert(STORAGE_get_big_block(hf,bigblocknr,block));
280 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
281 return sbd[blocknr & (128-1)];
284 /******************************************************************************
285 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
287 static int
288 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
289 int lastblocknr=-1;
290 BYTE block[BIGSIZE];
291 LPINT sbd = (LPINT)block;
292 struct storage_header sth;
294 READ_HEADER;
295 assert(blocknr>=0);
296 while ((nr--) && (blocknr>=0)) {
297 if (lastblocknr/128!=blocknr/128) {
298 int bigblocknr;
299 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
300 assert(bigblocknr>=0);
301 assert(STORAGE_get_big_block(hf,bigblocknr,block));
302 lastblocknr = blocknr;
304 assert(lastblocknr>=0);
305 lastblocknr=blocknr;
306 blocknr=sbd[blocknr & (128-1)];
307 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
309 return blocknr;
312 /******************************************************************************
313 * STORAGE_get_pps_entry [INTERNAL]
315 static int
316 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
317 int blocknr;
318 BYTE block[BIGSIZE];
319 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
320 struct storage_header sth;
322 READ_HEADER;
323 /* we have 4 pps entries per big block */
324 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
325 assert(blocknr>=0);
326 assert(STORAGE_get_big_block(hf,blocknr,block));
328 *pstde=*stde;
329 return 1;
332 /******************************************************************************
333 * STORAGE_put_pps_entry [Internal]
335 static int
336 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
337 int blocknr;
338 BYTE block[BIGSIZE];
339 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
340 struct storage_header sth;
342 READ_HEADER;
344 /* we have 4 pps entries per big block */
345 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
346 assert(blocknr>=0);
347 assert(STORAGE_get_big_block(hf,blocknr,block));
348 *stde=*pstde;
349 assert(STORAGE_put_big_block(hf,blocknr,block));
350 return 1;
353 /******************************************************************************
354 * STORAGE_look_for_named_pps [Internal]
356 static int
357 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
358 struct storage_pps_entry stde;
359 int ret;
361 if (n==-1)
362 return -1;
363 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
364 return -1;
366 if (!lstrcmpW(name,stde.pps_rawname))
367 return n;
368 if (stde.pps_prev != -1) {
369 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
370 if (ret!=-1)
371 return ret;
373 if (stde.pps_next != -1) {
374 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
375 if (ret!=-1)
376 return ret;
378 return -1;
381 /******************************************************************************
382 * STORAGE_dump_pps_entry [Internal]
384 * FIXME
385 * Function is unused
387 void
388 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
389 char name[33];
391 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
392 if (!stde->pps_sizeofname)
393 return;
394 DPRINTF("name: %s\n",name);
395 DPRINTF("type: %d\n",stde->pps_type);
396 DPRINTF("prev pps: %ld\n",stde->pps_prev);
397 DPRINTF("next pps: %ld\n",stde->pps_next);
398 DPRINTF("dir pps: %ld\n",stde->pps_dir);
399 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
400 if (stde->pps_type !=2) {
401 time_t t;
402 DWORD dw;
403 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
404 t = dw;
405 DPRINTF("ts1: %s\n",ctime(&t));
406 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
407 t = dw;
408 DPRINTF("ts2: %s\n",ctime(&t));
410 DPRINTF("startblock: %ld\n",stde->pps_sb);
411 DPRINTF("size: %ld\n",stde->pps_size);
414 /******************************************************************************
415 * STORAGE_init_storage [INTERNAL]
417 static BOOL
418 STORAGE_init_storage(HANDLE hf) {
419 BYTE block[BIGSIZE];
420 LPDWORD bbs;
421 struct storage_header *sth;
422 struct storage_pps_entry *stde;
423 DWORD result;
425 SetFilePointer( hf, 0, NULL, SEEK_SET );
426 /* block -1 is the storage header */
427 sth = (struct storage_header*)block;
428 memcpy(sth->magic,STORAGE_magic,8);
429 memset(sth->unknown1,0,sizeof(sth->unknown1));
430 memset(sth->unknown2,0,sizeof(sth->unknown2));
431 memset(sth->unknown3,0,sizeof(sth->unknown3));
432 sth->num_of_bbd_blocks = 1;
433 sth->root_startblock = 1;
434 sth->sbd_startblock = 0xffffffff;
435 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
436 sth->bbd_list[0] = 0;
437 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
438 /* block 0 is the big block directory */
439 bbs=(LPDWORD)block;
440 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
441 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
442 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
443 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
444 /* block 1 is the root directory entry */
445 memset(block,0x00,sizeof(block));
446 stde = (struct storage_pps_entry*)block;
447 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
448 sizeof(stde->pps_rawname)/sizeof(WCHAR));
449 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
450 stde->pps_type = 5;
451 stde->pps_dir = -1;
452 stde->pps_next = -1;
453 stde->pps_prev = -1;
454 stde->pps_sb = 0xffffffff;
455 stde->pps_size = 0;
456 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
459 /******************************************************************************
460 * STORAGE_set_big_chain [Internal]
462 static BOOL
463 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
464 BYTE block[BIGSIZE];
465 LPINT bbd = (LPINT)block;
466 int nextblocknr,bigblocknr;
467 struct storage_header sth;
469 READ_HEADER;
470 assert(blocknr!=type);
471 while (blocknr>=0) {
472 bigblocknr = sth.bbd_list[blocknr/128];
473 assert(bigblocknr>=0);
474 assert(STORAGE_get_big_block(hf,bigblocknr,block));
476 nextblocknr = bbd[blocknr&(128-1)];
477 bbd[blocknr&(128-1)] = type;
478 if (type>=0)
479 return TRUE;
480 assert(STORAGE_put_big_block(hf,bigblocknr,block));
481 type = STORAGE_CHAINENTRY_FREE;
482 blocknr = nextblocknr;
484 return TRUE;
487 /******************************************************************************
488 * STORAGE_set_small_chain [Internal]
490 static BOOL
491 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
492 BYTE block[BIGSIZE];
493 LPINT sbd = (LPINT)block;
494 int lastblocknr,nextsmallblocknr,bigblocknr;
495 struct storage_header sth;
497 READ_HEADER;
499 assert(blocknr!=type);
500 lastblocknr=-129;bigblocknr=-2;
501 while (blocknr>=0) {
502 /* cache block ... */
503 if (lastblocknr/128!=blocknr/128) {
504 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
505 assert(bigblocknr>=0);
506 assert(STORAGE_get_big_block(hf,bigblocknr,block));
508 lastblocknr = blocknr;
509 nextsmallblocknr = sbd[blocknr&(128-1)];
510 sbd[blocknr&(128-1)] = type;
511 assert(STORAGE_put_big_block(hf,bigblocknr,block));
512 if (type>=0)
513 return TRUE;
514 type = STORAGE_CHAINENTRY_FREE;
515 blocknr = nextsmallblocknr;
517 return TRUE;
520 /******************************************************************************
521 * STORAGE_get_free_big_blocknr [Internal]
523 static int
524 STORAGE_get_free_big_blocknr(HANDLE hf) {
525 BYTE block[BIGSIZE];
526 LPINT sbd = (LPINT)block;
527 int lastbigblocknr,i,curblock,bigblocknr;
528 struct storage_header sth;
530 READ_HEADER;
531 curblock = 0;
532 lastbigblocknr = -1;
533 bigblocknr = sth.bbd_list[curblock];
534 while (curblock<sth.num_of_bbd_blocks) {
535 assert(bigblocknr>=0);
536 assert(STORAGE_get_big_block(hf,bigblocknr,block));
537 for (i=0;i<128;i++)
538 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
539 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
540 assert(STORAGE_put_big_block(hf,bigblocknr,block));
541 memset(block,0x42,sizeof(block));
542 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
543 return i+curblock*128;
545 lastbigblocknr = bigblocknr;
546 bigblocknr = sth.bbd_list[++curblock];
548 bigblocknr = curblock*128;
549 /* since we have marked all blocks from 0 up to curblock*128-1
550 * the next free one is curblock*128, where we happily put our
551 * next large block depot.
553 memset(block,0xff,sizeof(block));
554 /* mark the block allocated and returned by this function */
555 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
556 assert(STORAGE_put_big_block(hf,bigblocknr,block));
558 /* if we had a bbd block already (mostlikely) we need
559 * to link the new one into the chain
561 if (lastbigblocknr!=-1)
562 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
563 sth.bbd_list[curblock]=bigblocknr;
564 sth.num_of_bbd_blocks++;
565 assert(sth.num_of_bbd_blocks==curblock+1);
566 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
568 /* Set the end of the chain for the bigblockdepots */
569 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
570 /* add 1, for the first entry is used for the additional big block
571 * depot. (means we already used bigblocknr) */
572 memset(block,0x42,sizeof(block));
573 /* allocate this block (filled with 0x42) */
574 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
575 return bigblocknr+1;
579 /******************************************************************************
580 * STORAGE_get_free_small_blocknr [Internal]
582 static int
583 STORAGE_get_free_small_blocknr(HANDLE hf) {
584 BYTE block[BIGSIZE];
585 LPINT sbd = (LPINT)block;
586 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
587 struct storage_pps_entry root;
588 struct storage_header sth;
590 READ_HEADER;
591 bigblocknr = sth.sbd_startblock;
592 curblock = 0;
593 lastbigblocknr = -1;
594 newblocknr = -1;
595 while (bigblocknr>=0) {
596 if (!STORAGE_get_big_block(hf,bigblocknr,block))
597 return -1;
598 for (i=0;i<128;i++)
599 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
600 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
601 newblocknr = i+curblock*128;
602 break;
604 if (i!=128)
605 break;
606 lastbigblocknr = bigblocknr;
607 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
608 curblock++;
610 if (newblocknr==-1) {
611 bigblocknr = STORAGE_get_free_big_blocknr(hf);
612 if (bigblocknr<0)
613 return -1;
614 READ_HEADER;
615 memset(block,0xff,sizeof(block));
616 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
617 if (!STORAGE_put_big_block(hf,bigblocknr,block))
618 return -1;
619 if (lastbigblocknr==-1) {
620 sth.sbd_startblock = bigblocknr;
621 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
622 return -1;
623 } else {
624 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
625 return -1;
627 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
628 return -1;
629 newblocknr = curblock*128;
631 /* allocate enough big blocks for storing the allocated small block */
632 if (!STORAGE_get_root_pps_entry(hf,&root))
633 return -1;
634 if (root.pps_sb==-1)
635 lastbigblocknr = -1;
636 else
637 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
638 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
639 /* we need to allocate more stuff */
640 bigblocknr = STORAGE_get_free_big_blocknr(hf);
641 if (bigblocknr<0)
642 return -1;
643 READ_HEADER;
644 if (root.pps_sb==-1) {
645 root.pps_sb = bigblocknr;
646 root.pps_size += BIGSIZE;
647 } else {
648 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
649 return -1;
650 root.pps_size += BIGSIZE;
652 lastbigblocknr = bigblocknr;
654 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
655 return -1;
656 if (!STORAGE_put_pps_entry(hf,0,&root))
657 return -1;
658 return newblocknr;
661 /******************************************************************************
662 * STORAGE_get_free_pps_entry [Internal]
664 static int
665 STORAGE_get_free_pps_entry(HANDLE hf) {
666 int blocknr, i, curblock, lastblocknr=-1;
667 BYTE block[BIGSIZE];
668 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
669 struct storage_header sth;
671 READ_HEADER;
672 blocknr = sth.root_startblock;
673 assert(blocknr>=0);
674 curblock=0;
675 while (blocknr>=0) {
676 if (!STORAGE_get_big_block(hf,blocknr,block))
677 return -1;
678 for (i=0;i<4;i++)
679 if (stde[i].pps_sizeofname==0) /* free */
680 return curblock*4+i;
681 lastblocknr = blocknr;
682 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
683 curblock++;
685 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
686 blocknr = STORAGE_get_free_big_blocknr(hf);
687 /* sth invalidated */
688 if (blocknr<0)
689 return -1;
691 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
692 return -1;
693 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
694 return -1;
695 memset(block,0,sizeof(block));
696 STORAGE_put_big_block(hf,blocknr,block);
697 return curblock*4;
700 /* --- IStream16 implementation */
702 typedef struct
704 /* IUnknown fields */
705 ICOM_VFIELD(IStream16);
706 DWORD ref;
707 /* IStream16 fields */
708 SEGPTR thisptr; /* pointer to this struct as segmented */
709 struct storage_pps_entry stde;
710 int ppsent;
711 HANDLE hf;
712 ULARGE_INTEGER offset;
713 } IStream16Impl;
715 /******************************************************************************
716 * IStream16_QueryInterface [STORAGE.518]
718 HRESULT WINAPI IStream16_fnQueryInterface(
719 IStream16* iface,REFIID refiid,LPVOID *obj
721 ICOM_THIS(IStream16Impl,iface);
722 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
723 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
724 *obj = This;
725 return 0;
727 return OLE_E_ENUM_NOMORE;
731 /******************************************************************************
732 * IStream16_AddRef [STORAGE.519]
734 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
735 ICOM_THIS(IStream16Impl,iface);
736 return ++(This->ref);
739 /******************************************************************************
740 * IStream16_Release [STORAGE.520]
742 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
743 ICOM_THIS(IStream16Impl,iface);
744 FlushFileBuffers(This->hf);
745 This->ref--;
746 if (!This->ref) {
747 CloseHandle(This->hf);
748 UnMapLS( This->thisptr );
749 HeapFree( GetProcessHeap(), 0, This );
750 return 0;
752 return This->ref;
755 /******************************************************************************
756 * IStream16_Seek [STORAGE.523]
758 * FIXME
759 * Does not handle 64 bits
761 HRESULT WINAPI IStream16_fnSeek(
762 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
764 ICOM_THIS(IStream16Impl,iface);
765 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
767 switch (whence) {
768 /* unix SEEK_xx should be the same as win95 ones */
769 case SEEK_SET:
770 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
771 * right now.
773 assert(offset.s.HighPart==0);
774 This->offset.s.HighPart = offset.s.HighPart;
775 This->offset.s.LowPart = offset.s.LowPart;
776 break;
777 case SEEK_CUR:
778 if (offset.s.HighPart < 0) {
779 /* FIXME: is this negation correct ? */
780 offset.s.HighPart = -offset.s.HighPart;
781 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
783 assert(offset.s.HighPart==0);
784 assert(This->offset.s.LowPart >= offset.s.LowPart);
785 This->offset.s.LowPart -= offset.s.LowPart;
786 } else {
787 assert(offset.s.HighPart==0);
788 This->offset.s.LowPart+= offset.s.LowPart;
790 break;
791 case SEEK_END:
792 assert(offset.s.HighPart==0);
793 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
794 break;
796 if (This->offset.s.LowPart>This->stde.pps_size)
797 This->offset.s.LowPart=This->stde.pps_size;
798 if (newpos) *newpos = This->offset;
799 return S_OK;
802 /******************************************************************************
803 * IStream16_Read [STORAGE.521]
805 HRESULT WINAPI IStream16_fnRead(
806 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
808 ICOM_THIS(IStream16Impl,iface);
809 BYTE block[BIGSIZE];
810 ULONG *bytesread=pcbRead,xxread;
811 int blocknr;
813 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
814 if (!pcbRead) bytesread=&xxread;
815 *bytesread = 0;
817 if (cb>This->stde.pps_size-This->offset.s.LowPart)
818 cb=This->stde.pps_size-This->offset.s.LowPart;
819 if (This->stde.pps_size < 0x1000) {
820 /* use small block reader */
821 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
822 while (cb) {
823 int cc;
825 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
826 WARN("small block read failed!!!\n");
827 return E_FAIL;
829 cc = cb;
830 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
831 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
832 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
833 This->offset.s.LowPart+=cc;
834 (LPBYTE)pv+=cc;
835 *bytesread+=cc;
836 cb-=cc;
837 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
839 } else {
840 /* use big block reader */
841 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
842 while (cb) {
843 int cc;
845 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
846 WARN("big block read failed!!!\n");
847 return E_FAIL;
849 cc = cb;
850 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
851 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
852 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
853 This->offset.s.LowPart+=cc;
854 (LPBYTE)pv+=cc;
855 *bytesread+=cc;
856 cb-=cc;
857 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
860 return S_OK;
863 /******************************************************************************
864 * IStream16_Write [STORAGE.522]
866 HRESULT WINAPI IStream16_fnWrite(
867 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
869 ICOM_THIS(IStream16Impl,iface);
870 BYTE block[BIGSIZE];
871 ULONG *byteswritten=pcbWrite,xxwritten;
872 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
873 HANDLE hf = This->hf;
875 if (!pcbWrite) byteswritten=&xxwritten;
876 *byteswritten = 0;
878 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
879 /* do we need to junk some blocks? */
880 newsize = This->offset.s.LowPart+cb;
881 oldsize = This->stde.pps_size;
882 if (newsize < oldsize) {
883 if (oldsize < 0x1000) {
884 /* only small blocks */
885 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
887 assert(blocknr>=0);
889 /* will set the rest of the chain to 'free' */
890 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
891 return E_FAIL;
892 } else {
893 if (newsize >= 0x1000) {
894 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
895 assert(blocknr>=0);
897 /* will set the rest of the chain to 'free' */
898 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
899 return E_FAIL;
900 } else {
901 /* Migrate large blocks to small blocks
902 * (we just migrate newsize bytes)
904 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
905 HRESULT r = E_FAIL;
907 cc = newsize;
908 blocknr = This->stde.pps_sb;
909 curdata = data;
910 while (cc>0) {
911 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
912 HeapFree(GetProcessHeap(),0,data);
913 return E_FAIL;
915 curdata += BIGSIZE;
916 cc -= BIGSIZE;
917 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
919 /* frees complete chain for this stream */
920 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
921 goto err;
922 curdata = data;
923 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
924 if (blocknr<0)
925 goto err;
926 cc = newsize;
927 while (cc>0) {
928 if (!STORAGE_put_small_block(hf,blocknr,curdata))
929 goto err;
930 cc -= SMALLSIZE;
931 if (cc<=0) {
932 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933 goto err;
934 break;
935 } else {
936 int newblocknr = STORAGE_get_free_small_blocknr(hf);
937 if (newblocknr<0)
938 goto err;
939 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
940 goto err;
941 blocknr = newblocknr;
943 curdata += SMALLSIZE;
945 r = S_OK;
946 err:
947 HeapFree(GetProcessHeap(),0,data);
948 if(r != S_OK)
949 return r;
952 This->stde.pps_size = newsize;
955 if (newsize > oldsize) {
956 if (oldsize >= 0x1000) {
957 /* should return the block right before the 'endofchain' */
958 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
959 assert(blocknr>=0);
960 lastblocknr = blocknr;
961 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
962 blocknr = STORAGE_get_free_big_blocknr(hf);
963 if (blocknr<0)
964 return E_FAIL;
965 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
966 return E_FAIL;
967 lastblocknr = blocknr;
969 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
970 return E_FAIL;
971 } else {
972 if (newsize < 0x1000) {
973 /* find startblock */
974 if (!oldsize)
975 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
976 else
977 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
978 if (blocknr<0)
979 return E_FAIL;
981 /* allocate required new small blocks */
982 lastblocknr = blocknr;
983 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
984 blocknr = STORAGE_get_free_small_blocknr(hf);
985 if (blocknr<0)
986 return E_FAIL;
987 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
988 return E_FAIL;
989 lastblocknr = blocknr;
991 /* and terminate the chain */
992 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
993 return E_FAIL;
994 } else {
995 if (!oldsize) {
996 /* no single block allocated yet */
997 blocknr=STORAGE_get_free_big_blocknr(hf);
998 if (blocknr<0)
999 return E_FAIL;
1000 This->stde.pps_sb = blocknr;
1001 } else {
1002 /* Migrate small blocks to big blocks */
1003 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1004 HRESULT r = E_FAIL;
1006 cc = oldsize;
1007 blocknr = This->stde.pps_sb;
1008 curdata = data;
1009 /* slurp in */
1010 while (cc>0) {
1011 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1012 goto err2;
1013 curdata += SMALLSIZE;
1014 cc -= SMALLSIZE;
1015 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1017 /* free small block chain */
1018 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1019 goto err2;
1020 curdata = data;
1021 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1022 if (blocknr<0)
1023 goto err2;
1024 /* put the data into the big blocks */
1025 cc = This->stde.pps_size;
1026 while (cc>0) {
1027 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1028 goto err2;
1029 cc -= BIGSIZE;
1030 if (cc<=0) {
1031 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1032 goto err2;
1033 break;
1034 } else {
1035 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1036 if (newblocknr<0)
1037 goto err2;
1038 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1039 goto err2;
1040 blocknr = newblocknr;
1042 curdata += BIGSIZE;
1044 r = S_OK;
1045 err2:
1046 HeapFree(GetProcessHeap(),0,data);
1047 if(r != S_OK)
1048 return r;
1050 /* generate big blocks to fit the new data */
1051 lastblocknr = blocknr;
1052 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1053 blocknr = STORAGE_get_free_big_blocknr(hf);
1054 if (blocknr<0)
1055 return E_FAIL;
1056 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1057 return E_FAIL;
1058 lastblocknr = blocknr;
1060 /* terminate chain */
1061 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1062 return E_FAIL;
1065 This->stde.pps_size = newsize;
1068 /* There are just some cases where we didn't modify it, we write it out
1069 * everytime
1071 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1072 return E_FAIL;
1074 /* finally the write pass */
1075 if (This->stde.pps_size < 0x1000) {
1076 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1077 assert(blocknr>=0);
1078 while (cb>0) {
1079 /* we ensured that it is allocated above */
1080 assert(blocknr>=0);
1081 /* Read old block everytime, since we can have
1082 * overlapping data at START and END of the write
1084 if (!STORAGE_get_small_block(hf,blocknr,block))
1085 return E_FAIL;
1087 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1088 if (cc>cb)
1089 cc=cb;
1090 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1091 (LPBYTE)((char *) pv+curoffset),
1094 if (!STORAGE_put_small_block(hf,blocknr,block))
1095 return E_FAIL;
1096 cb -= cc;
1097 curoffset += cc;
1098 (LPBYTE)pv += cc;
1099 This->offset.s.LowPart += cc;
1100 *byteswritten += cc;
1101 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1103 } else {
1104 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1105 assert(blocknr>=0);
1106 while (cb>0) {
1107 /* we ensured that it is allocated above, so it better is */
1108 assert(blocknr>=0);
1109 /* read old block everytime, since we can have
1110 * overlapping data at START and END of the write
1112 if (!STORAGE_get_big_block(hf,blocknr,block))
1113 return E_FAIL;
1115 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1116 if (cc>cb)
1117 cc=cb;
1118 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1119 (LPBYTE)((char *) pv+curoffset),
1122 if (!STORAGE_put_big_block(hf,blocknr,block))
1123 return E_FAIL;
1124 cb -= cc;
1125 curoffset += cc;
1126 (LPBYTE)pv += cc;
1127 This->offset.s.LowPart += cc;
1128 *byteswritten += cc;
1129 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1132 return S_OK;
1135 /******************************************************************************
1136 * _create_istream16 [Internal]
1138 static void _create_istream16(LPSTREAM16 *str) {
1139 IStream16Impl* lpst;
1141 if (!strvt16.QueryInterface) {
1142 HMODULE16 wp = GetModuleHandle16("STORAGE");
1143 if (wp>=32) {
1144 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1145 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1146 VTENT(QueryInterface);
1147 VTENT(AddRef);
1148 VTENT(Release);
1149 VTENT(Read);
1150 VTENT(Write);
1151 VTENT(Seek);
1152 VTENT(SetSize);
1153 VTENT(CopyTo);
1154 VTENT(Commit);
1155 VTENT(Revert);
1156 VTENT(LockRegion);
1157 VTENT(UnlockRegion);
1158 VTENT(Stat);
1159 VTENT(Clone);
1160 #undef VTENT
1161 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1162 } else {
1163 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1164 VTENT(QueryInterface);
1165 VTENT(AddRef);
1166 VTENT(Release);
1167 VTENT(Read);
1168 VTENT(Write);
1169 VTENT(Seek);
1171 VTENT(CopyTo);
1172 VTENT(Commit);
1173 VTENT(SetSize);
1174 VTENT(Revert);
1175 VTENT(LockRegion);
1176 VTENT(UnlockRegion);
1177 VTENT(Stat);
1178 VTENT(Clone);
1180 #undef VTENT
1181 segstrvt16 = &strvt16;
1184 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1185 lpst->lpVtbl = segstrvt16;
1186 lpst->ref = 1;
1187 lpst->thisptr = MapLS( lpst );
1188 *str = (void*)lpst->thisptr;
1192 /* --- IStream32 implementation */
1194 typedef struct
1196 /* IUnknown fields */
1197 ICOM_VFIELD(IStream);
1198 DWORD ref;
1199 /* IStream32 fields */
1200 struct storage_pps_entry stde;
1201 int ppsent;
1202 HANDLE hf;
1203 ULARGE_INTEGER offset;
1204 } IStream32Impl;
1206 /*****************************************************************************
1207 * IStream32_QueryInterface [VTABLE]
1209 HRESULT WINAPI IStream_fnQueryInterface(
1210 IStream* iface,REFIID refiid,LPVOID *obj
1212 ICOM_THIS(IStream32Impl,iface);
1214 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1215 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1216 *obj = This;
1217 return 0;
1219 return OLE_E_ENUM_NOMORE;
1223 /******************************************************************************
1224 * IStream32_AddRef [VTABLE]
1226 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1227 ICOM_THIS(IStream32Impl,iface);
1228 return ++(This->ref);
1231 /******************************************************************************
1232 * IStream32_Release [VTABLE]
1234 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1235 ICOM_THIS(IStream32Impl,iface);
1236 FlushFileBuffers(This->hf);
1237 This->ref--;
1238 if (!This->ref) {
1239 CloseHandle(This->hf);
1240 HeapFree( GetProcessHeap(), 0, This );
1241 return 0;
1243 return This->ref;
1246 /* --- IStorage16 implementation */
1248 typedef struct
1250 /* IUnknown fields */
1251 ICOM_VFIELD(IStorage16);
1252 DWORD ref;
1253 /* IStorage16 fields */
1254 SEGPTR thisptr; /* pointer to this struct as segmented */
1255 struct storage_pps_entry stde;
1256 int ppsent;
1257 HANDLE hf;
1258 } IStorage16Impl;
1260 /******************************************************************************
1261 * IStorage16_QueryInterface [STORAGE.500]
1263 HRESULT WINAPI IStorage16_fnQueryInterface(
1264 IStorage16* iface,REFIID refiid,LPVOID *obj
1266 ICOM_THIS(IStorage16Impl,iface);
1268 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1270 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1271 *obj = This;
1272 return 0;
1274 return OLE_E_ENUM_NOMORE;
1277 /******************************************************************************
1278 * IStorage16_AddRef [STORAGE.501]
1280 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1281 ICOM_THIS(IStorage16Impl,iface);
1282 return ++(This->ref);
1285 /******************************************************************************
1286 * IStorage16_Release [STORAGE.502]
1288 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1289 ICOM_THIS(IStorage16Impl,iface);
1290 This->ref--;
1291 if (This->ref)
1292 return This->ref;
1293 UnMapLS( This->thisptr );
1294 HeapFree( GetProcessHeap(), 0, This );
1295 return 0;
1298 /******************************************************************************
1299 * IStorage16_Stat [STORAGE.517]
1301 HRESULT WINAPI IStorage16_fnStat(
1302 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1304 ICOM_THIS(IStorage16Impl,iface);
1305 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1306 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1308 TRACE("(%p)->(%p,0x%08lx)\n",
1309 This,pstatstg,grfStatFlag
1311 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1312 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1313 pstatstg->type = This->stde.pps_type;
1314 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1315 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1316 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1317 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1318 pstatstg->grfMode = 0; /* FIXME */
1319 pstatstg->grfLocksSupported = 0; /* FIXME */
1320 pstatstg->clsid = This->stde.pps_guid;
1321 pstatstg->grfStateBits = 0; /* FIXME */
1322 pstatstg->reserved = 0;
1323 return S_OK;
1326 /******************************************************************************
1327 * IStorage16_Commit [STORAGE.509]
1329 HRESULT WINAPI IStorage16_fnCommit(
1330 LPSTORAGE16 iface,DWORD commitflags
1332 ICOM_THIS(IStorage16Impl,iface);
1333 FIXME("(%p)->(0x%08lx),STUB!\n",
1334 This,commitflags
1336 return S_OK;
1339 /******************************************************************************
1340 * IStorage16_CopyTo [STORAGE.507]
1342 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1343 ICOM_THIS(IStorage16Impl,iface);
1344 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1345 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1347 return S_OK;
1351 /******************************************************************************
1352 * IStorage16_CreateStorage [STORAGE.505]
1354 HRESULT WINAPI IStorage16_fnCreateStorage(
1355 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1357 ICOM_THIS(IStorage16Impl,iface);
1358 IStorage16Impl* lpstg;
1359 int ppsent,x;
1360 struct storage_pps_entry stde;
1361 struct storage_header sth;
1362 HANDLE hf=This->hf;
1364 READ_HEADER;
1366 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1367 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1369 if (grfMode & STGM_TRANSACTED)
1370 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1371 _create_istorage16(ppstg);
1372 lpstg = MapSL((SEGPTR)*ppstg);
1373 lpstg->hf = This->hf;
1375 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1376 if (ppsent<0)
1377 return E_FAIL;
1378 stde=This->stde;
1379 if (stde.pps_dir==-1) {
1380 stde.pps_dir = ppsent;
1381 x = This->ppsent;
1382 } else {
1383 FIXME(" use prev chain too ?\n");
1384 x=stde.pps_dir;
1385 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1386 return E_FAIL;
1387 while (stde.pps_next!=-1) {
1388 x=stde.pps_next;
1389 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1390 return E_FAIL;
1392 stde.pps_next = ppsent;
1394 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1395 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1396 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1397 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1398 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1399 lpstg->stde.pps_next = -1;
1400 lpstg->stde.pps_prev = -1;
1401 lpstg->stde.pps_dir = -1;
1402 lpstg->stde.pps_sb = -1;
1403 lpstg->stde.pps_size = 0;
1404 lpstg->stde.pps_type = 1;
1405 lpstg->ppsent = ppsent;
1406 /* FIXME: timestamps? */
1407 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1408 return E_FAIL;
1409 return S_OK;
1412 /******************************************************************************
1413 * IStorage16_CreateStream [STORAGE.503]
1415 HRESULT WINAPI IStorage16_fnCreateStream(
1416 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1418 ICOM_THIS(IStorage16Impl,iface);
1419 IStream16Impl* lpstr;
1420 int ppsent,x;
1421 struct storage_pps_entry stde;
1423 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1424 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1426 if (grfMode & STGM_TRANSACTED)
1427 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1428 _create_istream16(ppstm);
1429 lpstr = MapSL((SEGPTR)*ppstm);
1430 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1431 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1432 lpstr->offset.s.LowPart = 0;
1433 lpstr->offset.s.HighPart = 0;
1435 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1436 if (ppsent<0)
1437 return E_FAIL;
1438 stde=This->stde;
1439 if (stde.pps_next==-1)
1440 x=This->ppsent;
1441 else
1442 while (stde.pps_next!=-1) {
1443 x=stde.pps_next;
1444 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1445 return E_FAIL;
1447 stde.pps_next = ppsent;
1448 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1449 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1450 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1451 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1452 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1453 lpstr->stde.pps_next = -1;
1454 lpstr->stde.pps_prev = -1;
1455 lpstr->stde.pps_dir = -1;
1456 lpstr->stde.pps_sb = -1;
1457 lpstr->stde.pps_size = 0;
1458 lpstr->stde.pps_type = 2;
1459 lpstr->ppsent = ppsent;
1460 /* FIXME: timestamps? */
1461 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1462 return E_FAIL;
1463 return S_OK;
1466 /******************************************************************************
1467 * IStorage16_OpenStorage [STORAGE.506]
1469 HRESULT WINAPI IStorage16_fnOpenStorage(
1470 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1472 ICOM_THIS(IStorage16Impl,iface);
1473 IStream16Impl* lpstg;
1474 WCHAR name[33];
1475 int newpps;
1477 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1478 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1480 if (grfMode & STGM_TRANSACTED)
1481 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1482 _create_istorage16(ppstg);
1483 lpstg = MapSL((SEGPTR)*ppstg);
1484 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1485 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1486 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1487 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1488 if (newpps==-1) {
1489 IStream16_fnRelease((IStream16*)lpstg);
1490 return E_FAIL;
1493 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1494 IStream16_fnRelease((IStream16*)lpstg);
1495 return E_FAIL;
1497 lpstg->ppsent = newpps;
1498 return S_OK;
1501 /******************************************************************************
1502 * IStorage16_OpenStream [STORAGE.504]
1504 HRESULT WINAPI IStorage16_fnOpenStream(
1505 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1507 ICOM_THIS(IStorage16Impl,iface);
1508 IStream16Impl* lpstr;
1509 WCHAR name[33];
1510 int newpps;
1512 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1513 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1515 if (grfMode & STGM_TRANSACTED)
1516 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1517 _create_istream16(ppstm);
1518 lpstr = MapSL((SEGPTR)*ppstm);
1519 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1520 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1521 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1522 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1523 if (newpps==-1) {
1524 IStream16_fnRelease((IStream16*)lpstr);
1525 return E_FAIL;
1528 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1529 IStream16_fnRelease((IStream16*)lpstr);
1530 return E_FAIL;
1532 lpstr->offset.s.LowPart = 0;
1533 lpstr->offset.s.HighPart = 0;
1534 lpstr->ppsent = newpps;
1535 return S_OK;
1538 /******************************************************************************
1539 * _create_istorage16 [INTERNAL]
1541 static void _create_istorage16(LPSTORAGE16 *stg) {
1542 IStorage16Impl* lpst;
1544 if (!stvt16.QueryInterface) {
1545 HMODULE16 wp = GetModuleHandle16("STORAGE");
1546 if (wp>=32) {
1547 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1548 VTENT(QueryInterface)
1549 VTENT(AddRef)
1550 VTENT(Release)
1551 VTENT(CreateStream)
1552 VTENT(OpenStream)
1553 VTENT(CreateStorage)
1554 VTENT(OpenStorage)
1555 VTENT(CopyTo)
1556 VTENT(MoveElementTo)
1557 VTENT(Commit)
1558 VTENT(Revert)
1559 VTENT(EnumElements)
1560 VTENT(DestroyElement)
1561 VTENT(RenameElement)
1562 VTENT(SetElementTimes)
1563 VTENT(SetClass)
1564 VTENT(SetStateBits)
1565 VTENT(Stat)
1566 #undef VTENT
1567 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1568 } else {
1569 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1570 VTENT(QueryInterface)
1571 VTENT(AddRef)
1572 VTENT(Release)
1573 VTENT(CreateStream)
1574 VTENT(OpenStream)
1575 VTENT(CreateStorage)
1576 VTENT(OpenStorage)
1577 VTENT(CopyTo)
1578 VTENT(Commit)
1579 /* not (yet) implemented ...
1580 VTENT(MoveElementTo)
1581 VTENT(Revert)
1582 VTENT(EnumElements)
1583 VTENT(DestroyElement)
1584 VTENT(RenameElement)
1585 VTENT(SetElementTimes)
1586 VTENT(SetClass)
1587 VTENT(SetStateBits)
1588 VTENT(Stat)
1590 #undef VTENT
1591 segstvt16 = &stvt16;
1594 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1595 lpst->lpVtbl = segstvt16;
1596 lpst->ref = 1;
1597 lpst->thisptr = MapLS(lpst);
1598 *stg = (void*)lpst->thisptr;
1601 /******************************************************************************
1602 * Storage API functions
1605 /******************************************************************************
1606 * StgCreateDocFileA [STORAGE.1]
1608 HRESULT WINAPI StgCreateDocFile16(
1609 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1611 HANDLE hf;
1612 int i,ret;
1613 IStorage16Impl* lpstg;
1614 struct storage_pps_entry stde;
1616 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1617 pwcsName,grfMode,reserved,ppstgOpen
1619 _create_istorage16(ppstgOpen);
1620 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1621 if (hf==INVALID_HANDLE_VALUE) {
1622 WARN("couldn't open file for storage:%ld\n",GetLastError());
1623 return E_FAIL;
1625 lpstg = MapSL((SEGPTR)*ppstgOpen);
1626 lpstg->hf = hf;
1627 /* FIXME: check for existence before overwriting? */
1628 if (!STORAGE_init_storage(hf)) {
1629 CloseHandle(hf);
1630 return E_FAIL;
1632 i=0;ret=0;
1633 while (!ret) { /* neither 1 nor <0 */
1634 ret=STORAGE_get_pps_entry(hf,i,&stde);
1635 if ((ret==1) && (stde.pps_type==5)) {
1636 lpstg->stde = stde;
1637 lpstg->ppsent = i;
1638 break;
1640 i++;
1642 if (ret!=1) {
1643 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1644 return E_FAIL;
1647 return S_OK;
1650 /******************************************************************************
1651 * StgIsStorageFile [STORAGE.5]
1653 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1654 UNICODE_STRING strW;
1655 HRESULT ret;
1657 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1658 ret = StgIsStorageFile( strW.Buffer );
1659 RtlFreeUnicodeString( &strW );
1661 return ret;
1664 /******************************************************************************
1665 * StgOpenStorage [STORAGE.3]
1667 HRESULT WINAPI StgOpenStorage16(
1668 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1669 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1671 HANDLE hf;
1672 int ret,i;
1673 IStorage16Impl* lpstg;
1674 struct storage_pps_entry stde;
1676 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1677 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1679 _create_istorage16(ppstgOpen);
1680 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1681 if (hf==INVALID_HANDLE_VALUE) {
1682 WARN("Couldn't open file for storage\n");
1683 return E_FAIL;
1685 lpstg = MapSL((SEGPTR)*ppstgOpen);
1686 lpstg->hf = hf;
1688 i=0;ret=0;
1689 while (!ret) { /* neither 1 nor <0 */
1690 ret=STORAGE_get_pps_entry(hf,i,&stde);
1691 if ((ret==1) && (stde.pps_type==5)) {
1692 lpstg->stde=stde;
1693 break;
1695 i++;
1697 if (ret!=1) {
1698 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1699 return E_FAIL;
1701 return S_OK;
1705 /******************************************************************************
1706 * StgIsStorageILockBytes [STORAGE.6]
1708 * Determines if the ILockBytes contains a storage object.
1710 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1712 DWORD args[6];
1713 HRESULT hres;
1714 HANDLE16 hsig;
1716 args[0] = (DWORD)plkbyt; /* iface */
1717 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1718 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1719 args[4] = 8;
1720 args[5] = 0;
1722 if (!K32WOWCallback16Ex(
1723 (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1724 (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1725 )->ReadAt,
1726 WCB16_PASCAL,
1727 6*sizeof(DWORD),
1728 (LPVOID)args,
1729 (LPDWORD)&hres
1730 )) {
1731 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1732 return hres;
1734 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1735 K32WOWGlobalUnlockFree16(args[3]);
1736 return S_OK;
1738 K32WOWGlobalUnlockFree16(args[3]);
1739 return S_FALSE;
1742 /******************************************************************************
1743 * StgOpenStorageOnILockBytes [STORAGE.4]
1745 HRESULT WINAPI StgOpenStorageOnILockBytes16(
1746 ILockBytes16 *plkbyt,
1747 IStorage16 *pstgPriority,
1748 DWORD grfMode,
1749 SNB16 snbExclude,
1750 DWORD reserved,
1751 IStorage16 **ppstgOpen)
1753 IStorage16Impl* lpstg;
1755 if ((plkbyt == 0) || (ppstgOpen == 0))
1756 return STG_E_INVALIDPOINTER;
1758 *ppstgOpen = 0;
1760 _create_istorage16(ppstgOpen);
1761 lpstg = MapSL((SEGPTR)*ppstgOpen);
1763 /* just teach it to use HANDLE instead of ilockbytes :/ */
1765 return S_OK;