Temporary hack to share handles between processes sharing the same
[wine/multimedia.git] / dlls / ole32 / storage.c
blobc7c40b36da8cfc1fab1a604f08bdb4618f759dfa
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
8 */
10 #include <assert.h>
11 #include <time.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "winerror.h"
17 #include "wine/winestring.h"
18 #include "wine/winbase16.h"
19 #include "wingdi.h"
20 #include "wtypes.h"
21 #include "file.h"
22 #include "ole.h"
23 #include "wine/obj_base.h"
24 #include "wine/obj_storage.h"
25 #include "heap.h"
26 #include "module.h"
27 #include "ldt.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(ole);
31 DECLARE_DEBUG_CHANNEL(relay);
33 struct storage_header {
34 BYTE magic[8]; /* 00: magic */
35 BYTE unknown1[36]; /* 08: unknown */
36 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
37 DWORD root_startblock;/* 30: root storage first big block */
38 DWORD unknown2[2]; /* 34: unknown */
39 DWORD sbd_startblock; /* 3C: small block depot first big block */
40 DWORD unknown3[3]; /* 40: unknown */
41 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
43 struct storage_pps_entry {
44 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
45 WORD pps_sizeofname; /* 40: namelength in bytes */
46 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
47 BYTE pps_unknown0; /* 43: unknown */
48 DWORD pps_prev; /* 44: previous pps */
49 DWORD pps_next; /* 48: next pps */
50 DWORD pps_dir; /* 4C: directory pps */
51 GUID pps_guid; /* 50: class ID */
52 DWORD pps_unknown1; /* 60: unknown */
53 FILETIME pps_ft1; /* 64: filetime1 */
54 FILETIME pps_ft2; /* 70: filetime2 */
55 DWORD pps_sb; /* 74: data startblock */
56 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
57 DWORD pps_unknown2; /* 7C: unknown */
60 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
61 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
62 #define STORAGE_CHAINENTRY_FREE 0xffffffff
65 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
66 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
67 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
69 #define BIGSIZE 512
70 #define SMALLSIZE 64
72 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
74 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
75 static ICOM_VTABLE(IStorage16) stvt16;
76 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
77 static ICOM_VTABLE(IStream16) strvt16;
78 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
80 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
81 static void _create_istorage16(LPSTORAGE16 *stg);
82 static void _create_istream16(LPSTREAM16 *str);
84 #define IMPLEMENTED 1
87 /******************************************************************************
88 * STORAGE_get_big_block [Internal]
90 * Reading OLE compound storage
92 static BOOL
93 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
94 assert(n>=-1);
95 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
96 WARN(" seek failed (%ld)\n",GetLastError());
97 return FALSE;
99 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
100 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
101 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
102 assert(0);
103 return FALSE;
105 return TRUE;
108 /******************************************************************************
109 * STORAGE_put_big_block [INTERNAL]
111 static BOOL
112 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
113 assert(n>=-1);
114 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
115 WARN(" seek failed (%ld)\n",GetLastError());
116 return FALSE;
118 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
119 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
120 WARN(" write failed (%ld)\n",GetLastError());
121 return FALSE;
123 return TRUE;
126 /******************************************************************************
127 * STORAGE_get_next_big_blocknr [INTERNAL]
129 static int
130 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
131 INT bbs[BIGSIZE/sizeof(INT)];
132 struct storage_header sth;
134 READ_HEADER;
136 assert(blocknr>>7<sth.num_of_bbd_blocks);
137 if (sth.bbd_list[blocknr>>7]==0xffffffff)
138 return -5;
139 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
140 return -5;
141 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
142 return bbs[blocknr&0x7f];
145 /******************************************************************************
146 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
148 static int
149 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
150 INT bbs[BIGSIZE/sizeof(INT)];
151 int lastblock = -1;
152 struct storage_header sth;
154 READ_HEADER;
156 assert(blocknr>=0);
157 while (nr--) {
158 assert((blocknr>>7)<sth.num_of_bbd_blocks);
159 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
161 /* simple caching... */
162 if (lastblock!=sth.bbd_list[blocknr>>7]) {
163 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
164 lastblock = sth.bbd_list[blocknr>>7];
166 blocknr = bbs[blocknr&0x7f];
168 return blocknr;
171 /******************************************************************************
172 * STORAGE_get_root_pps_entry [Internal]
174 static BOOL
175 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
176 int blocknr,i;
177 BYTE block[BIGSIZE];
178 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
179 struct storage_header sth;
181 READ_HEADER;
182 blocknr = sth.root_startblock;
183 while (blocknr>=0) {
184 assert(STORAGE_get_big_block(hf,blocknr,block));
185 for (i=0;i<4;i++) {
186 if (!stde[i].pps_sizeofname)
187 continue;
188 if (stde[i].pps_type==5) {
189 *pstde=stde[i];
190 return TRUE;
193 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
195 return FALSE;
198 /******************************************************************************
199 * STORAGE_get_small_block [INTERNAL]
201 static BOOL
202 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
203 BYTE block[BIGSIZE];
204 int bigblocknr;
205 struct storage_pps_entry root;
207 assert(blocknr>=0);
208 assert(STORAGE_get_root_pps_entry(hf,&root));
209 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
210 assert(bigblocknr>=0);
211 assert(STORAGE_get_big_block(hf,bigblocknr,block));
213 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
214 return TRUE;
217 /******************************************************************************
218 * STORAGE_put_small_block [INTERNAL]
220 static BOOL
221 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
222 BYTE block[BIGSIZE];
223 int bigblocknr;
224 struct storage_pps_entry root;
226 assert(blocknr>=0);
228 assert(STORAGE_get_root_pps_entry(hf,&root));
229 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
230 assert(bigblocknr>=0);
231 assert(STORAGE_get_big_block(hf,bigblocknr,block));
233 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
234 assert(STORAGE_put_big_block(hf,bigblocknr,block));
235 return TRUE;
238 /******************************************************************************
239 * STORAGE_get_next_small_blocknr [INTERNAL]
241 static int
242 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
243 BYTE block[BIGSIZE];
244 LPINT sbd = (LPINT)block;
245 int bigblocknr;
246 struct storage_header sth;
248 READ_HEADER;
249 assert(blocknr>=0);
250 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
251 assert(bigblocknr>=0);
252 assert(STORAGE_get_big_block(hf,bigblocknr,block));
253 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
254 return sbd[blocknr & (128-1)];
257 /******************************************************************************
258 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
260 static int
261 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
262 int lastblocknr;
263 BYTE block[BIGSIZE];
264 LPINT sbd = (LPINT)block;
265 struct storage_header sth;
267 READ_HEADER;
268 lastblocknr=-1;
269 assert(blocknr>=0);
270 while ((nr--) && (blocknr>=0)) {
271 if (lastblocknr/128!=blocknr/128) {
272 int bigblocknr;
273 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
274 assert(bigblocknr>=0);
275 assert(STORAGE_get_big_block(hf,bigblocknr,block));
276 lastblocknr = blocknr;
278 assert(lastblocknr>=0);
279 lastblocknr=blocknr;
280 blocknr=sbd[blocknr & (128-1)];
281 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
283 return blocknr;
286 /******************************************************************************
287 * STORAGE_get_pps_entry [INTERNAL]
289 static int
290 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
291 int blocknr;
292 BYTE block[BIGSIZE];
293 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
294 struct storage_header sth;
296 READ_HEADER;
297 /* we have 4 pps entries per big block */
298 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
299 assert(blocknr>=0);
300 assert(STORAGE_get_big_block(hf,blocknr,block));
302 *pstde=*stde;
303 return 1;
306 /******************************************************************************
307 * STORAGE_put_pps_entry [Internal]
309 static int
310 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
311 int blocknr;
312 BYTE block[BIGSIZE];
313 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
314 struct storage_header sth;
316 READ_HEADER;
318 /* we have 4 pps entries per big block */
319 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
320 assert(blocknr>=0);
321 assert(STORAGE_get_big_block(hf,blocknr,block));
322 *stde=*pstde;
323 assert(STORAGE_put_big_block(hf,blocknr,block));
324 return 1;
327 /******************************************************************************
328 * STORAGE_look_for_named_pps [Internal]
330 static int
331 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
332 struct storage_pps_entry stde;
333 int ret;
335 if (n==-1)
336 return -1;
337 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
338 return -1;
340 if (!lstrcmpW(name,stde.pps_rawname))
341 return n;
342 if (stde.pps_prev != -1) {
343 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
344 if (ret!=-1)
345 return ret;
347 if (stde.pps_next != -1) {
348 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
349 if (ret!=-1)
350 return ret;
352 return -1;
355 /******************************************************************************
356 * STORAGE_dump_pps_entry [Internal]
358 * FIXME
359 * Function is unused
361 void
362 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
363 char name[33];
365 lstrcpyWtoA(name,stde->pps_rawname);
366 if (!stde->pps_sizeofname)
367 return;
368 DPRINTF("name: %s\n",name);
369 DPRINTF("type: %d\n",stde->pps_type);
370 DPRINTF("prev pps: %ld\n",stde->pps_prev);
371 DPRINTF("next pps: %ld\n",stde->pps_next);
372 DPRINTF("dir pps: %ld\n",stde->pps_dir);
373 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
374 if (stde->pps_type !=2) {
375 time_t t;
377 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
378 DPRINTF("ts1: %s\n",ctime(&t));
379 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
380 DPRINTF("ts2: %s\n",ctime(&t));
382 DPRINTF("startblock: %ld\n",stde->pps_sb);
383 DPRINTF("size: %ld\n",stde->pps_size);
386 /******************************************************************************
387 * STORAGE_init_storage [INTERNAL]
389 static BOOL
390 STORAGE_init_storage(HFILE hf) {
391 BYTE block[BIGSIZE];
392 LPDWORD bbs;
393 struct storage_header *sth;
394 struct storage_pps_entry *stde;
396 assert(-1!=_llseek(hf,0,SEEK_SET));
397 /* block -1 is the storage header */
398 sth = (struct storage_header*)block;
399 memcpy(sth->magic,STORAGE_magic,8);
400 memset(sth->unknown1,0,sizeof(sth->unknown1));
401 memset(sth->unknown2,0,sizeof(sth->unknown2));
402 memset(sth->unknown3,0,sizeof(sth->unknown3));
403 sth->num_of_bbd_blocks = 1;
404 sth->root_startblock = 1;
405 sth->sbd_startblock = 0xffffffff;
406 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
407 sth->bbd_list[0] = 0;
408 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
409 /* block 0 is the big block directory */
410 bbs=(LPDWORD)block;
411 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
412 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
413 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
414 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
415 /* block 1 is the root directory entry */
416 memset(block,0x00,sizeof(block));
417 stde = (struct storage_pps_entry*)block;
418 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
419 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
420 stde->pps_type = 5;
421 stde->pps_dir = -1;
422 stde->pps_next = -1;
423 stde->pps_prev = -1;
424 stde->pps_sb = 0xffffffff;
425 stde->pps_size = 0;
426 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
427 return TRUE;
430 /******************************************************************************
431 * STORAGE_set_big_chain [Internal]
433 static BOOL
434 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
435 BYTE block[BIGSIZE];
436 LPINT bbd = (LPINT)block;
437 int nextblocknr,bigblocknr;
438 struct storage_header sth;
440 READ_HEADER;
441 assert(blocknr!=type);
442 while (blocknr>=0) {
443 bigblocknr = sth.bbd_list[blocknr/128];
444 assert(bigblocknr>=0);
445 assert(STORAGE_get_big_block(hf,bigblocknr,block));
447 nextblocknr = bbd[blocknr&(128-1)];
448 bbd[blocknr&(128-1)] = type;
449 if (type>=0)
450 return TRUE;
451 assert(STORAGE_put_big_block(hf,bigblocknr,block));
452 type = STORAGE_CHAINENTRY_FREE;
453 blocknr = nextblocknr;
455 return TRUE;
458 /******************************************************************************
459 * STORAGE_set_small_chain [Internal]
461 static BOOL
462 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
463 BYTE block[BIGSIZE];
464 LPINT sbd = (LPINT)block;
465 int lastblocknr,nextsmallblocknr,bigblocknr;
466 struct storage_header sth;
468 READ_HEADER;
470 assert(blocknr!=type);
471 lastblocknr=-129;bigblocknr=-2;
472 while (blocknr>=0) {
473 /* cache block ... */
474 if (lastblocknr/128!=blocknr/128) {
475 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
476 assert(bigblocknr>=0);
477 assert(STORAGE_get_big_block(hf,bigblocknr,block));
479 lastblocknr = blocknr;
480 nextsmallblocknr = sbd[blocknr&(128-1)];
481 sbd[blocknr&(128-1)] = type;
482 assert(STORAGE_put_big_block(hf,bigblocknr,block));
483 if (type>=0)
484 return TRUE;
485 type = STORAGE_CHAINENTRY_FREE;
486 blocknr = nextsmallblocknr;
488 return TRUE;
491 /******************************************************************************
492 * STORAGE_get_free_big_blocknr [Internal]
494 static int
495 STORAGE_get_free_big_blocknr(HFILE hf) {
496 BYTE block[BIGSIZE];
497 LPINT sbd = (LPINT)block;
498 int lastbigblocknr,i,curblock,bigblocknr;
499 struct storage_header sth;
501 READ_HEADER;
502 curblock = 0;
503 lastbigblocknr = -1;
504 bigblocknr = sth.bbd_list[curblock];
505 while (curblock<sth.num_of_bbd_blocks) {
506 assert(bigblocknr>=0);
507 assert(STORAGE_get_big_block(hf,bigblocknr,block));
508 for (i=0;i<128;i++)
509 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
510 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
511 assert(STORAGE_put_big_block(hf,bigblocknr,block));
512 memset(block,0x42,sizeof(block));
513 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
514 return i+curblock*128;
516 lastbigblocknr = bigblocknr;
517 bigblocknr = sth.bbd_list[++curblock];
519 bigblocknr = curblock*128;
520 /* since we have marked all blocks from 0 up to curblock*128-1
521 * the next free one is curblock*128, where we happily put our
522 * next large block depot.
524 memset(block,0xff,sizeof(block));
525 /* mark the block allocated and returned by this function */
526 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
527 assert(STORAGE_put_big_block(hf,bigblocknr,block));
529 /* if we had a bbd block already (mostlikely) we need
530 * to link the new one into the chain
532 if (lastbigblocknr!=-1)
533 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
534 sth.bbd_list[curblock]=bigblocknr;
535 sth.num_of_bbd_blocks++;
536 assert(sth.num_of_bbd_blocks==curblock+1);
537 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
539 /* Set the end of the chain for the bigblockdepots */
540 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
541 /* add 1, for the first entry is used for the additional big block
542 * depot. (means we already used bigblocknr) */
543 memset(block,0x42,sizeof(block));
544 /* allocate this block (filled with 0x42) */
545 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
546 return bigblocknr+1;
550 /******************************************************************************
551 * STORAGE_get_free_small_blocknr [Internal]
553 static int
554 STORAGE_get_free_small_blocknr(HFILE hf) {
555 BYTE block[BIGSIZE];
556 LPINT sbd = (LPINT)block;
557 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
558 struct storage_pps_entry root;
559 struct storage_header sth;
561 READ_HEADER;
562 bigblocknr = sth.sbd_startblock;
563 curblock = 0;
564 lastbigblocknr = -1;
565 newblocknr = -1;
566 while (bigblocknr>=0) {
567 if (!STORAGE_get_big_block(hf,bigblocknr,block))
568 return -1;
569 for (i=0;i<128;i++)
570 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
571 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
572 newblocknr = i+curblock*128;
573 break;
575 if (i!=128)
576 break;
577 lastbigblocknr = bigblocknr;
578 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
579 curblock++;
581 if (newblocknr==-1) {
582 bigblocknr = STORAGE_get_free_big_blocknr(hf);
583 if (bigblocknr<0)
584 return -1;
585 READ_HEADER;
586 memset(block,0xff,sizeof(block));
587 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
588 if (!STORAGE_put_big_block(hf,bigblocknr,block))
589 return -1;
590 if (lastbigblocknr==-1) {
591 sth.sbd_startblock = bigblocknr;
592 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
593 return -1;
594 } else {
595 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
596 return -1;
598 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
599 return -1;
600 newblocknr = curblock*128;
602 /* allocate enough big blocks for storing the allocated small block */
603 if (!STORAGE_get_root_pps_entry(hf,&root))
604 return -1;
605 if (root.pps_sb==-1)
606 lastbigblocknr = -1;
607 else
608 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
609 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
610 /* we need to allocate more stuff */
611 bigblocknr = STORAGE_get_free_big_blocknr(hf);
612 if (bigblocknr<0)
613 return -1;
614 READ_HEADER;
615 if (root.pps_sb==-1) {
616 root.pps_sb = bigblocknr;
617 root.pps_size += BIGSIZE;
618 } else {
619 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
620 return -1;
621 root.pps_size += BIGSIZE;
623 lastbigblocknr = bigblocknr;
625 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
626 return -1;
627 if (!STORAGE_put_pps_entry(hf,0,&root))
628 return -1;
629 return newblocknr;
632 /******************************************************************************
633 * STORAGE_get_free_pps_entry [Internal]
635 static int
636 STORAGE_get_free_pps_entry(HFILE hf) {
637 int blocknr,i,curblock,lastblocknr;
638 BYTE block[BIGSIZE];
639 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
640 struct storage_header sth;
642 READ_HEADER;
643 blocknr = sth.root_startblock;
644 assert(blocknr>=0);
645 curblock=0;
646 while (blocknr>=0) {
647 if (!STORAGE_get_big_block(hf,blocknr,block))
648 return -1;
649 for (i=0;i<4;i++)
650 if (stde[i].pps_sizeofname==0) /* free */
651 return curblock*4+i;
652 lastblocknr = blocknr;
653 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
654 curblock++;
656 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
657 blocknr = STORAGE_get_free_big_blocknr(hf);
658 /* sth invalidated */
659 if (blocknr<0)
660 return -1;
662 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
663 return -1;
664 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
665 return -1;
666 memset(block,0,sizeof(block));
667 STORAGE_put_big_block(hf,blocknr,block);
668 return curblock*4;
671 /* --- IStream16 implementation */
673 typedef struct
675 /* IUnknown fields */
676 ICOM_VFIELD(IStream16);
677 DWORD ref;
678 /* IStream16 fields */
679 SEGPTR thisptr; /* pointer to this struct as segmented */
680 struct storage_pps_entry stde;
681 int ppsent;
682 HFILE hf;
683 ULARGE_INTEGER offset;
684 } IStream16Impl;
686 /******************************************************************************
687 * IStream16_QueryInterface [STORAGE.518]
689 HRESULT WINAPI IStream16_fnQueryInterface(
690 IStream16* iface,REFIID refiid,LPVOID *obj
692 ICOM_THIS(IStream16Impl,iface);
693 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
694 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
695 *obj = This;
696 return 0;
698 return OLE_E_ENUM_NOMORE;
702 /******************************************************************************
703 * IStream16_AddRef [STORAGE.519]
705 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
706 ICOM_THIS(IStream16Impl,iface);
707 return ++(This->ref);
710 /******************************************************************************
711 * IStream16_Release [STORAGE.520]
713 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
714 ICOM_THIS(IStream16Impl,iface);
715 FlushFileBuffers(This->hf);
716 This->ref--;
717 if (!This->ref) {
718 CloseHandle(This->hf);
719 SEGPTR_FREE(This);
720 return 0;
722 return This->ref;
725 /******************************************************************************
726 * IStream16_Seek [STORAGE.523]
728 * FIXME
729 * Does not handle 64 bits
731 HRESULT WINAPI IStream16_fnSeek(
732 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
734 ICOM_THIS(IStream16Impl,iface);
735 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
737 switch (whence) {
738 /* unix SEEK_xx should be the same as win95 ones */
739 case SEEK_SET:
740 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
741 * right now.
743 assert(offset.s.HighPart==0);
744 This->offset.s.HighPart = offset.s.HighPart;
745 This->offset.s.LowPart = offset.s.LowPart;
746 break;
747 case SEEK_CUR:
748 if (offset.s.HighPart < 0) {
749 /* FIXME: is this negation correct ? */
750 offset.s.HighPart = -offset.s.HighPart;
751 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
753 assert(offset.s.HighPart==0);
754 assert(This->offset.s.LowPart >= offset.s.LowPart);
755 This->offset.s.LowPart -= offset.s.LowPart;
756 } else {
757 assert(offset.s.HighPart==0);
758 This->offset.s.LowPart+= offset.s.LowPart;
760 break;
761 case SEEK_END:
762 assert(offset.s.HighPart==0);
763 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
764 break;
766 if (This->offset.s.LowPart>This->stde.pps_size)
767 This->offset.s.LowPart=This->stde.pps_size;
768 if (newpos) *newpos = This->offset;
769 return S_OK;
772 /******************************************************************************
773 * IStream16_Read [STORAGE.521]
775 HRESULT WINAPI IStream16_fnRead(
776 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
778 ICOM_THIS(IStream16Impl,iface);
779 BYTE block[BIGSIZE];
780 ULONG *bytesread=pcbRead,xxread;
781 int blocknr;
783 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
784 if (!pcbRead) bytesread=&xxread;
785 *bytesread = 0;
787 if (cb>This->stde.pps_size-This->offset.s.LowPart)
788 cb=This->stde.pps_size-This->offset.s.LowPart;
789 if (This->stde.pps_size < 0x1000) {
790 /* use small block reader */
791 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
792 while (cb) {
793 int cc;
795 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
796 WARN("small block read failed!!!\n");
797 return E_FAIL;
799 cc = cb;
800 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
801 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
802 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
803 This->offset.s.LowPart+=cc;
804 (LPBYTE)pv+=cc;
805 *bytesread+=cc;
806 cb-=cc;
807 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
809 } else {
810 /* use big block reader */
811 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
812 while (cb) {
813 int cc;
815 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
816 WARN("big block read failed!!!\n");
817 return E_FAIL;
819 cc = cb;
820 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
821 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
822 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
823 This->offset.s.LowPart+=cc;
824 (LPBYTE)pv+=cc;
825 *bytesread+=cc;
826 cb-=cc;
827 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
830 return S_OK;
833 /******************************************************************************
834 * IStream16_Write [STORAGE.522]
836 HRESULT WINAPI IStream16_fnWrite(
837 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
839 ICOM_THIS(IStream16Impl,iface);
840 BYTE block[BIGSIZE];
841 ULONG *byteswritten=pcbWrite,xxwritten;
842 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
843 HFILE hf = This->hf;
845 if (!pcbWrite) byteswritten=&xxwritten;
846 *byteswritten = 0;
848 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
849 /* do we need to junk some blocks? */
850 newsize = This->offset.s.LowPart+cb;
851 oldsize = This->stde.pps_size;
852 if (newsize < oldsize) {
853 if (oldsize < 0x1000) {
854 /* only small blocks */
855 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
857 assert(blocknr>=0);
859 /* will set the rest of the chain to 'free' */
860 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
861 return E_FAIL;
862 } else {
863 if (newsize >= 0x1000) {
864 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
865 assert(blocknr>=0);
867 /* will set the rest of the chain to 'free' */
868 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
869 return E_FAIL;
870 } else {
871 /* Migrate large blocks to small blocks
872 * (we just migrate newsize bytes)
874 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
875 cc = newsize;
876 blocknr = This->stde.pps_sb;
877 curdata = data;
878 while (cc>0) {
879 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
880 HeapFree(GetProcessHeap(),0,data);
881 return E_FAIL;
883 curdata += BIGSIZE;
884 cc -= BIGSIZE;
885 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
887 /* frees complete chain for this stream */
888 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
889 return E_FAIL;
890 curdata = data;
891 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
892 if (blocknr<0)
893 return E_FAIL;
894 cc = newsize;
895 while (cc>0) {
896 if (!STORAGE_put_small_block(hf,blocknr,curdata))
897 return E_FAIL;
898 cc -= SMALLSIZE;
899 if (cc<=0) {
900 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
901 return E_FAIL;
902 break;
903 } else {
904 int newblocknr = STORAGE_get_free_small_blocknr(hf);
905 if (newblocknr<0)
906 return E_FAIL;
907 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
908 return E_FAIL;
909 blocknr = newblocknr;
911 curdata += SMALLSIZE;
913 HeapFree(GetProcessHeap(),0,data);
916 This->stde.pps_size = newsize;
919 if (newsize > oldsize) {
920 if (oldsize >= 0x1000) {
921 /* should return the block right before the 'endofchain' */
922 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
923 assert(blocknr>=0);
924 lastblocknr = blocknr;
925 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
926 blocknr = STORAGE_get_free_big_blocknr(hf);
927 if (blocknr<0)
928 return E_FAIL;
929 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
930 return E_FAIL;
931 lastblocknr = blocknr;
933 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
934 return E_FAIL;
935 } else {
936 if (newsize < 0x1000) {
937 /* find startblock */
938 if (!oldsize)
939 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
940 else
941 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
942 if (blocknr<0)
943 return E_FAIL;
945 /* allocate required new small blocks */
946 lastblocknr = blocknr;
947 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
948 blocknr = STORAGE_get_free_small_blocknr(hf);
949 if (blocknr<0)
950 return E_FAIL;
951 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
952 return E_FAIL;
953 lastblocknr = blocknr;
955 /* and terminate the chain */
956 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
957 return E_FAIL;
958 } else {
959 if (!oldsize) {
960 /* no single block allocated yet */
961 blocknr=STORAGE_get_free_big_blocknr(hf);
962 if (blocknr<0)
963 return E_FAIL;
964 This->stde.pps_sb = blocknr;
965 } else {
966 /* Migrate small blocks to big blocks */
967 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
968 cc = oldsize;
969 blocknr = This->stde.pps_sb;
970 curdata = data;
971 /* slurp in */
972 while (cc>0) {
973 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
974 HeapFree(GetProcessHeap(),0,data);
975 return E_FAIL;
977 curdata += SMALLSIZE;
978 cc -= SMALLSIZE;
979 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
981 /* free small block chain */
982 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
983 return E_FAIL;
984 curdata = data;
985 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
986 if (blocknr<0)
987 return E_FAIL;
988 /* put the data into the big blocks */
989 cc = This->stde.pps_size;
990 while (cc>0) {
991 if (!STORAGE_put_big_block(hf,blocknr,curdata))
992 return E_FAIL;
993 cc -= BIGSIZE;
994 if (cc<=0) {
995 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
996 return E_FAIL;
997 break;
998 } else {
999 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1000 if (newblocknr<0)
1001 return E_FAIL;
1002 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1003 return E_FAIL;
1004 blocknr = newblocknr;
1006 curdata += BIGSIZE;
1008 HeapFree(GetProcessHeap(),0,data);
1010 /* generate big blocks to fit the new data */
1011 lastblocknr = blocknr;
1012 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1013 blocknr = STORAGE_get_free_big_blocknr(hf);
1014 if (blocknr<0)
1015 return E_FAIL;
1016 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1017 return E_FAIL;
1018 lastblocknr = blocknr;
1020 /* terminate chain */
1021 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1022 return E_FAIL;
1025 This->stde.pps_size = newsize;
1028 /* There are just some cases where we didn't modify it, we write it out
1029 * everytime
1031 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1032 return E_FAIL;
1034 /* finally the write pass */
1035 if (This->stde.pps_size < 0x1000) {
1036 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1037 assert(blocknr>=0);
1038 while (cb>0) {
1039 /* we ensured that it is allocated above */
1040 assert(blocknr>=0);
1041 /* Read old block everytime, since we can have
1042 * overlapping data at START and END of the write
1044 if (!STORAGE_get_small_block(hf,blocknr,block))
1045 return E_FAIL;
1047 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1048 if (cc>cb)
1049 cc=cb;
1050 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1051 (LPBYTE)((char *) pv+curoffset),
1054 if (!STORAGE_put_small_block(hf,blocknr,block))
1055 return E_FAIL;
1056 cb -= cc;
1057 curoffset += cc;
1058 (LPBYTE)pv += cc;
1059 This->offset.s.LowPart += cc;
1060 *byteswritten += cc;
1061 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1063 } else {
1064 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1065 assert(blocknr>=0);
1066 while (cb>0) {
1067 /* we ensured that it is allocated above, so it better is */
1068 assert(blocknr>=0);
1069 /* read old block everytime, since we can have
1070 * overlapping data at START and END of the write
1072 if (!STORAGE_get_big_block(hf,blocknr,block))
1073 return E_FAIL;
1075 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1076 if (cc>cb)
1077 cc=cb;
1078 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1079 (LPBYTE)((char *) pv+curoffset),
1082 if (!STORAGE_put_big_block(hf,blocknr,block))
1083 return E_FAIL;
1084 cb -= cc;
1085 curoffset += cc;
1086 (LPBYTE)pv += cc;
1087 This->offset.s.LowPart += cc;
1088 *byteswritten += cc;
1089 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1092 return S_OK;
1095 /******************************************************************************
1096 * _create_istream16 [Internal]
1098 static void _create_istream16(LPSTREAM16 *str) {
1099 IStream16Impl* lpst;
1101 if (!strvt16.fnQueryInterface) {
1102 HMODULE16 wp = GetModuleHandle16("STORAGE");
1103 if (wp>=32) {
1104 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1105 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1106 VTENT(QueryInterface);
1107 VTENT(AddRef);
1108 VTENT(Release);
1109 VTENT(Read);
1110 VTENT(Write);
1111 VTENT(Seek);
1112 VTENT(SetSize);
1113 VTENT(CopyTo);
1114 VTENT(Commit);
1115 VTENT(Revert);
1116 VTENT(LockRegion);
1117 VTENT(UnlockRegion);
1118 VTENT(Stat);
1119 VTENT(Clone);
1120 #undef VTENT
1121 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1122 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1123 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1124 } else {
1125 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1126 VTENT(QueryInterface);
1127 VTENT(AddRef);
1128 VTENT(Release);
1129 VTENT(Read);
1130 VTENT(Write);
1131 VTENT(Seek);
1133 VTENT(CopyTo);
1134 VTENT(Commit);
1135 VTENT(SetSize);
1136 VTENT(Revert);
1137 VTENT(LockRegion);
1138 VTENT(UnlockRegion);
1139 VTENT(Stat);
1140 VTENT(Clone);
1142 #undef VTENT
1143 segstrvt16 = &strvt16;
1146 lpst = SEGPTR_NEW(IStream16Impl);
1147 ICOM_VTBL(lpst) = segstrvt16;
1148 lpst->ref = 1;
1149 lpst->thisptr = SEGPTR_GET(lpst);
1150 *str = (void*)lpst->thisptr;
1154 /* --- IStream32 implementation */
1156 typedef struct
1158 /* IUnknown fields */
1159 ICOM_VFIELD(IStream);
1160 DWORD ref;
1161 /* IStream32 fields */
1162 struct storage_pps_entry stde;
1163 int ppsent;
1164 HFILE hf;
1165 ULARGE_INTEGER offset;
1166 } IStream32Impl;
1168 /*****************************************************************************
1169 * IStream32_QueryInterface [VTABLE]
1171 HRESULT WINAPI IStream_fnQueryInterface(
1172 IStream* iface,REFIID refiid,LPVOID *obj
1174 ICOM_THIS(IStream32Impl,iface);
1176 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1177 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1178 *obj = This;
1179 return 0;
1181 return OLE_E_ENUM_NOMORE;
1185 /******************************************************************************
1186 * IStream32_AddRef [VTABLE]
1188 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1189 ICOM_THIS(IStream32Impl,iface);
1190 return ++(This->ref);
1193 /******************************************************************************
1194 * IStream32_Release [VTABLE]
1196 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1197 ICOM_THIS(IStream32Impl,iface);
1198 FlushFileBuffers(This->hf);
1199 This->ref--;
1200 if (!This->ref) {
1201 CloseHandle(This->hf);
1202 SEGPTR_FREE(This);
1203 return 0;
1205 return This->ref;
1208 /* --- IStorage16 implementation */
1210 typedef struct
1212 /* IUnknown fields */
1213 ICOM_VFIELD(IStorage16);
1214 DWORD ref;
1215 /* IStorage16 fields */
1216 SEGPTR thisptr; /* pointer to this struct as segmented */
1217 struct storage_pps_entry stde;
1218 int ppsent;
1219 HFILE hf;
1220 } IStorage16Impl;
1222 /******************************************************************************
1223 * IStorage16_QueryInterface [STORAGE.500]
1225 HRESULT WINAPI IStorage16_fnQueryInterface(
1226 IStorage16* iface,REFIID refiid,LPVOID *obj
1228 ICOM_THIS(IStorage16Impl,iface);
1230 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1232 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1233 *obj = This;
1234 return 0;
1236 return OLE_E_ENUM_NOMORE;
1239 /******************************************************************************
1240 * IStorage16_AddRef [STORAGE.501]
1242 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1243 ICOM_THIS(IStorage16Impl,iface);
1244 return ++(This->ref);
1247 /******************************************************************************
1248 * IStorage16_Release [STORAGE.502]
1250 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1251 ICOM_THIS(IStorage16Impl,iface);
1252 This->ref--;
1253 if (This->ref)
1254 return This->ref;
1255 SEGPTR_FREE(This);
1256 return 0;
1259 /******************************************************************************
1260 * IStorage16_Stat [STORAGE.517]
1262 HRESULT WINAPI IStorage16_fnStat(
1263 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1265 ICOM_THIS(IStorage16Impl,iface);
1266 TRACE("(%p)->(%p,0x%08lx)\n",
1267 This,pstatstg,grfStatFlag
1269 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1270 pstatstg->type = This->stde.pps_type;
1271 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1272 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1273 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1274 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1275 pstatstg->grfMode = 0; /* FIXME */
1276 pstatstg->grfLocksSupported = 0; /* FIXME */
1277 pstatstg->clsid = This->stde.pps_guid;
1278 pstatstg->grfStateBits = 0; /* FIXME */
1279 pstatstg->reserved = 0;
1280 return S_OK;
1283 /******************************************************************************
1284 * IStorage16_Commit [STORAGE.509]
1286 HRESULT WINAPI IStorage16_fnCommit(
1287 LPSTORAGE16 iface,DWORD commitflags
1289 ICOM_THIS(IStorage16Impl,iface);
1290 FIXME("(%p)->(0x%08lx),STUB!\n",
1291 This,commitflags
1293 return S_OK;
1296 /******************************************************************************
1297 * IStorage16_CopyTo [STORAGE.507]
1299 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1300 ICOM_THIS(IStorage16Impl,iface);
1301 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1302 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1304 return S_OK;
1308 /******************************************************************************
1309 * IStorage16_CreateStorage [STORAGE.505]
1311 HRESULT WINAPI IStorage16_fnCreateStorage(
1312 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1314 ICOM_THIS(IStorage16Impl,iface);
1315 IStorage16Impl* lpstg;
1316 int ppsent,x;
1317 struct storage_pps_entry stde;
1318 struct storage_header sth;
1319 HFILE hf=This->hf;
1321 READ_HEADER;
1323 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1324 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1326 if (grfMode & STGM_TRANSACTED)
1327 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1328 _create_istorage16(ppstg);
1329 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1330 lpstg->hf = This->hf;
1332 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1333 if (ppsent<0)
1334 return E_FAIL;
1335 stde=This->stde;
1336 if (stde.pps_dir==-1) {
1337 stde.pps_dir = ppsent;
1338 x = This->ppsent;
1339 } else {
1340 FIXME(" use prev chain too ?\n");
1341 x=stde.pps_dir;
1342 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1343 return E_FAIL;
1344 while (stde.pps_next!=-1) {
1345 x=stde.pps_next;
1346 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1347 return E_FAIL;
1349 stde.pps_next = ppsent;
1351 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1352 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1353 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1354 lpstg->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1355 lpstg->stde.pps_next = -1;
1356 lpstg->stde.pps_prev = -1;
1357 lpstg->stde.pps_dir = -1;
1358 lpstg->stde.pps_sb = -1;
1359 lpstg->stde.pps_size = 0;
1360 lpstg->stde.pps_type = 1;
1361 lpstg->ppsent = ppsent;
1362 /* FIXME: timestamps? */
1363 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1364 return E_FAIL;
1365 return S_OK;
1368 /******************************************************************************
1369 * IStorage16_CreateStream [STORAGE.503]
1371 HRESULT WINAPI IStorage16_fnCreateStream(
1372 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1374 ICOM_THIS(IStorage16Impl,iface);
1375 IStream16Impl* lpstr;
1376 int ppsent,x;
1377 struct storage_pps_entry stde;
1379 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1380 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1382 if (grfMode & STGM_TRANSACTED)
1383 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1384 _create_istream16(ppstm);
1385 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1386 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1387 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1388 lpstr->offset.s.LowPart = 0;
1389 lpstr->offset.s.HighPart = 0;
1391 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1392 if (ppsent<0)
1393 return E_FAIL;
1394 stde=This->stde;
1395 if (stde.pps_next==-1)
1396 x=This->ppsent;
1397 else
1398 while (stde.pps_next!=-1) {
1399 x=stde.pps_next;
1400 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1401 return E_FAIL;
1403 stde.pps_next = ppsent;
1404 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1405 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1406 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1407 lpstr->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1408 lpstr->stde.pps_next = -1;
1409 lpstr->stde.pps_prev = -1;
1410 lpstr->stde.pps_dir = -1;
1411 lpstr->stde.pps_sb = -1;
1412 lpstr->stde.pps_size = 0;
1413 lpstr->stde.pps_type = 2;
1414 lpstr->ppsent = ppsent;
1415 /* FIXME: timestamps? */
1416 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1417 return E_FAIL;
1418 return S_OK;
1421 /******************************************************************************
1422 * IStorage16_OpenStorage [STORAGE.506]
1424 HRESULT WINAPI IStorage16_fnOpenStorage(
1425 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1427 ICOM_THIS(IStorage16Impl,iface);
1428 IStream16Impl* lpstg;
1429 WCHAR name[33];
1430 int newpps;
1432 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1433 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1435 if (grfMode & STGM_TRANSACTED)
1436 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1437 _create_istorage16(ppstg);
1438 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1439 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1440 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1441 lstrcpyAtoW(name,pwcsName);
1442 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1443 if (newpps==-1) {
1444 IStream16_fnRelease((IStream16*)lpstg);
1445 return E_FAIL;
1448 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1449 IStream16_fnRelease((IStream16*)lpstg);
1450 return E_FAIL;
1452 lpstg->ppsent = newpps;
1453 return S_OK;
1456 /******************************************************************************
1457 * IStorage16_OpenStream [STORAGE.504]
1459 HRESULT WINAPI IStorage16_fnOpenStream(
1460 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1462 ICOM_THIS(IStorage16Impl,iface);
1463 IStream16Impl* lpstr;
1464 WCHAR name[33];
1465 int newpps;
1467 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1468 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1470 if (grfMode & STGM_TRANSACTED)
1471 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1472 _create_istream16(ppstm);
1473 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1474 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1475 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1476 lstrcpyAtoW(name,pwcsName);
1477 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1478 if (newpps==-1) {
1479 IStream16_fnRelease((IStream16*)lpstr);
1480 return E_FAIL;
1483 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1484 IStream16_fnRelease((IStream16*)lpstr);
1485 return E_FAIL;
1487 lpstr->offset.s.LowPart = 0;
1488 lpstr->offset.s.HighPart = 0;
1489 lpstr->ppsent = newpps;
1490 return S_OK;
1493 /******************************************************************************
1494 * _create_istorage16 [INTERNAL]
1496 static void _create_istorage16(LPSTORAGE16 *stg) {
1497 IStorage16Impl* lpst;
1499 if (!stvt16.fnQueryInterface) {
1500 HMODULE16 wp = GetModuleHandle16("STORAGE");
1501 if (wp>=32) {
1502 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1503 VTENT(QueryInterface)
1504 VTENT(AddRef)
1505 VTENT(Release)
1506 VTENT(CreateStream)
1507 VTENT(OpenStream)
1508 VTENT(CreateStorage)
1509 VTENT(OpenStorage)
1510 VTENT(CopyTo)
1511 VTENT(MoveElementTo)
1512 VTENT(Commit)
1513 VTENT(Revert)
1514 VTENT(EnumElements)
1515 VTENT(DestroyElement)
1516 VTENT(RenameElement)
1517 VTENT(SetElementTimes)
1518 VTENT(SetClass)
1519 VTENT(SetStateBits)
1520 VTENT(Stat)
1521 #undef VTENT
1522 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1523 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1524 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1525 } else {
1526 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1527 VTENT(QueryInterface)
1528 VTENT(AddRef)
1529 VTENT(Release)
1530 VTENT(CreateStream)
1531 VTENT(OpenStream)
1532 VTENT(CreateStorage)
1533 VTENT(OpenStorage)
1534 VTENT(CopyTo)
1535 VTENT(Commit)
1536 /* not (yet) implemented ...
1537 VTENT(MoveElementTo)
1538 VTENT(Revert)
1539 VTENT(EnumElements)
1540 VTENT(DestroyElement)
1541 VTENT(RenameElement)
1542 VTENT(SetElementTimes)
1543 VTENT(SetClass)
1544 VTENT(SetStateBits)
1545 VTENT(Stat)
1547 #undef VTENT
1548 segstvt16 = &stvt16;
1551 lpst = SEGPTR_NEW(IStorage16Impl);
1552 ICOM_VTBL(lpst) = segstvt16;
1553 lpst->ref = 1;
1554 lpst->thisptr = SEGPTR_GET(lpst);
1555 *stg = (void*)lpst->thisptr;
1558 /******************************************************************************
1559 * Storage API functions
1562 /******************************************************************************
1563 * StgCreateDocFile16 [STORAGE.1]
1565 HRESULT WINAPI StgCreateDocFile16(
1566 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1568 HFILE hf;
1569 int i,ret;
1570 IStorage16Impl* lpstg;
1571 struct storage_pps_entry stde;
1573 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1574 pwcsName,grfMode,reserved,ppstgOpen
1576 _create_istorage16(ppstgOpen);
1577 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1578 if (hf==INVALID_HANDLE_VALUE) {
1579 WARN("couldn't open file for storage:%ld\n",GetLastError());
1580 return E_FAIL;
1582 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1583 lpstg->hf = hf;
1584 /* FIXME: check for existance before overwriting? */
1585 if (!STORAGE_init_storage(hf)) {
1586 CloseHandle(hf);
1587 return E_FAIL;
1589 i=0;ret=0;
1590 while (!ret) { /* neither 1 nor <0 */
1591 ret=STORAGE_get_pps_entry(hf,i,&stde);
1592 if ((ret==1) && (stde.pps_type==5)) {
1593 lpstg->stde = stde;
1594 lpstg->ppsent = i;
1595 break;
1597 i++;
1599 if (ret!=1) {
1600 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1601 return E_FAIL;
1604 return S_OK;
1607 /******************************************************************************
1608 * StgIsStorageFile16 [STORAGE.5]
1610 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1611 HFILE hf;
1612 OFSTRUCT ofs;
1613 BYTE magic[24];
1615 TRACE("(\'%s\')\n",fn);
1616 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1617 if (hf==HFILE_ERROR)
1618 return STG_E_FILENOTFOUND;
1619 if (24!=_lread(hf,magic,24)) {
1620 WARN(" too short\n");
1621 _lclose(hf);
1622 return S_FALSE;
1624 if (!memcmp(magic,STORAGE_magic,8)) {
1625 WARN(" -> YES\n");
1626 _lclose(hf);
1627 return S_OK;
1629 if (!memcmp(magic,STORAGE_notmagic,8)) {
1630 WARN(" -> NO\n");
1631 _lclose(hf);
1632 return S_FALSE;
1634 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1635 WARN(" -> old format\n");
1636 _lclose(hf);
1637 return STG_E_OLDFORMAT;
1639 WARN(" -> Invalid header.\n");
1640 _lclose(hf);
1641 return STG_E_INVALIDHEADER;
1644 /******************************************************************************
1645 * StgIsStorageFile [OLE32.146]
1647 HRESULT WINAPI
1648 StgIsStorageFile(LPCOLESTR fn)
1650 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1651 OLESTATUS ret = StgIsStorageFile16(xfn);
1653 HeapFree(GetProcessHeap(),0,xfn);
1654 return ret;
1658 /******************************************************************************
1659 * StgOpenStorage16 [STORAGE.3]
1661 HRESULT WINAPI StgOpenStorage16(
1662 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1663 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1665 HFILE hf;
1666 int ret,i;
1667 IStorage16Impl* lpstg;
1668 struct storage_pps_entry stde;
1670 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1671 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1673 _create_istorage16(ppstgOpen);
1674 hf = CreateFileA(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1675 if (hf==INVALID_HANDLE_VALUE) {
1676 WARN("Couldn't open file for storage\n");
1677 return E_FAIL;
1679 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1680 lpstg->hf = hf;
1682 i=0;ret=0;
1683 while (!ret) { /* neither 1 nor <0 */
1684 ret=STORAGE_get_pps_entry(hf,i,&stde);
1685 if ((ret==1) && (stde.pps_type==5)) {
1686 lpstg->stde=stde;
1687 break;
1689 i++;
1691 if (ret!=1) {
1692 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1693 return E_FAIL;
1695 return S_OK;