Removed some unnecessary #includes and dll dependencies.
[wine/multimedia.git] / dlls / ole32 / storage.c
blob0c706114c47b42cb3d2e28a3b205ae210250b58b
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 "wine/obj_base.h"
23 #include "wine/obj_storage.h"
24 #include "heap.h"
25 #include "module.h"
26 #include "ldt.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(ole);
30 DECLARE_DEBUG_CHANNEL(relay);
32 struct storage_header {
33 BYTE magic[8]; /* 00: magic */
34 BYTE unknown1[36]; /* 08: unknown */
35 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
36 DWORD root_startblock;/* 30: root storage first big block */
37 DWORD unknown2[2]; /* 34: unknown */
38 DWORD sbd_startblock; /* 3C: small block depot first big block */
39 DWORD unknown3[3]; /* 40: unknown */
40 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
42 struct storage_pps_entry {
43 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
44 WORD pps_sizeofname; /* 40: namelength in bytes */
45 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
46 BYTE pps_unknown0; /* 43: unknown */
47 DWORD pps_prev; /* 44: previous pps */
48 DWORD pps_next; /* 48: next pps */
49 DWORD pps_dir; /* 4C: directory pps */
50 GUID pps_guid; /* 50: class ID */
51 DWORD pps_unknown1; /* 60: unknown */
52 FILETIME pps_ft1; /* 64: filetime1 */
53 FILETIME pps_ft2; /* 70: filetime2 */
54 DWORD pps_sb; /* 74: data startblock */
55 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
56 DWORD pps_unknown2; /* 7C: unknown */
59 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
60 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
61 #define STORAGE_CHAINENTRY_FREE 0xffffffff
64 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
65 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
66 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
68 #define BIGSIZE 512
69 #define SMALLSIZE 64
71 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
73 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
74 static ICOM_VTABLE(IStorage16) stvt16;
75 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
76 static ICOM_VTABLE(IStream16) strvt16;
77 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
79 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
80 static void _create_istorage16(LPSTORAGE16 *stg);
81 static void _create_istream16(LPSTREAM16 *str);
83 #define IMPLEMENTED 1
86 /******************************************************************************
87 * STORAGE_get_big_block [Internal]
89 * Reading OLE compound storage
91 static BOOL
92 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
93 assert(n>=-1);
94 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
95 WARN(" seek failed (%ld)\n",GetLastError());
96 return FALSE;
98 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
99 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
100 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
101 assert(0);
102 return FALSE;
104 return TRUE;
107 /******************************************************************************
108 * STORAGE_put_big_block [INTERNAL]
110 static BOOL
111 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
112 assert(n>=-1);
113 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
114 WARN(" seek failed (%ld)\n",GetLastError());
115 return FALSE;
117 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
118 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
119 WARN(" write failed (%ld)\n",GetLastError());
120 return FALSE;
122 return TRUE;
125 /******************************************************************************
126 * STORAGE_get_next_big_blocknr [INTERNAL]
128 static int
129 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
130 INT bbs[BIGSIZE/sizeof(INT)];
131 struct storage_header sth;
133 READ_HEADER;
135 assert(blocknr>>7<sth.num_of_bbd_blocks);
136 if (sth.bbd_list[blocknr>>7]==0xffffffff)
137 return -5;
138 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
139 return -5;
140 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
141 return bbs[blocknr&0x7f];
144 /******************************************************************************
145 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
147 static int
148 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
149 INT bbs[BIGSIZE/sizeof(INT)];
150 int lastblock = -1;
151 struct storage_header sth;
153 READ_HEADER;
155 assert(blocknr>=0);
156 while (nr--) {
157 assert((blocknr>>7)<sth.num_of_bbd_blocks);
158 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
160 /* simple caching... */
161 if (lastblock!=sth.bbd_list[blocknr>>7]) {
162 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
163 lastblock = sth.bbd_list[blocknr>>7];
165 blocknr = bbs[blocknr&0x7f];
167 return blocknr;
170 /******************************************************************************
171 * STORAGE_get_root_pps_entry [Internal]
173 static BOOL
174 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
175 int blocknr,i;
176 BYTE block[BIGSIZE];
177 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
178 struct storage_header sth;
180 READ_HEADER;
181 blocknr = sth.root_startblock;
182 while (blocknr>=0) {
183 assert(STORAGE_get_big_block(hf,blocknr,block));
184 for (i=0;i<4;i++) {
185 if (!stde[i].pps_sizeofname)
186 continue;
187 if (stde[i].pps_type==5) {
188 *pstde=stde[i];
189 return TRUE;
192 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
194 return FALSE;
197 /******************************************************************************
198 * STORAGE_get_small_block [INTERNAL]
200 static BOOL
201 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
202 BYTE block[BIGSIZE];
203 int bigblocknr;
204 struct storage_pps_entry root;
206 assert(blocknr>=0);
207 assert(STORAGE_get_root_pps_entry(hf,&root));
208 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
209 assert(bigblocknr>=0);
210 assert(STORAGE_get_big_block(hf,bigblocknr,block));
212 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
213 return TRUE;
216 /******************************************************************************
217 * STORAGE_put_small_block [INTERNAL]
219 static BOOL
220 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
221 BYTE block[BIGSIZE];
222 int bigblocknr;
223 struct storage_pps_entry root;
225 assert(blocknr>=0);
227 assert(STORAGE_get_root_pps_entry(hf,&root));
228 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
229 assert(bigblocknr>=0);
230 assert(STORAGE_get_big_block(hf,bigblocknr,block));
232 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
233 assert(STORAGE_put_big_block(hf,bigblocknr,block));
234 return TRUE;
237 /******************************************************************************
238 * STORAGE_get_next_small_blocknr [INTERNAL]
240 static int
241 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
242 BYTE block[BIGSIZE];
243 LPINT sbd = (LPINT)block;
244 int bigblocknr;
245 struct storage_header sth;
247 READ_HEADER;
248 assert(blocknr>=0);
249 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
250 assert(bigblocknr>=0);
251 assert(STORAGE_get_big_block(hf,bigblocknr,block));
252 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
253 return sbd[blocknr & (128-1)];
256 /******************************************************************************
257 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
259 static int
260 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
261 int lastblocknr;
262 BYTE block[BIGSIZE];
263 LPINT sbd = (LPINT)block;
264 struct storage_header sth;
266 READ_HEADER;
267 lastblocknr=-1;
268 assert(blocknr>=0);
269 while ((nr--) && (blocknr>=0)) {
270 if (lastblocknr/128!=blocknr/128) {
271 int bigblocknr;
272 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
273 assert(bigblocknr>=0);
274 assert(STORAGE_get_big_block(hf,bigblocknr,block));
275 lastblocknr = blocknr;
277 assert(lastblocknr>=0);
278 lastblocknr=blocknr;
279 blocknr=sbd[blocknr & (128-1)];
280 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
282 return blocknr;
285 /******************************************************************************
286 * STORAGE_get_pps_entry [INTERNAL]
288 static int
289 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
290 int blocknr;
291 BYTE block[BIGSIZE];
292 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
293 struct storage_header sth;
295 READ_HEADER;
296 /* we have 4 pps entries per big block */
297 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
298 assert(blocknr>=0);
299 assert(STORAGE_get_big_block(hf,blocknr,block));
301 *pstde=*stde;
302 return 1;
305 /******************************************************************************
306 * STORAGE_put_pps_entry [Internal]
308 static int
309 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
310 int blocknr;
311 BYTE block[BIGSIZE];
312 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
313 struct storage_header sth;
315 READ_HEADER;
317 /* we have 4 pps entries per big block */
318 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
319 assert(blocknr>=0);
320 assert(STORAGE_get_big_block(hf,blocknr,block));
321 *stde=*pstde;
322 assert(STORAGE_put_big_block(hf,blocknr,block));
323 return 1;
326 /******************************************************************************
327 * STORAGE_look_for_named_pps [Internal]
329 static int
330 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
331 struct storage_pps_entry stde;
332 int ret;
334 if (n==-1)
335 return -1;
336 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
337 return -1;
339 if (!lstrcmpW(name,stde.pps_rawname))
340 return n;
341 if (stde.pps_prev != -1) {
342 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
343 if (ret!=-1)
344 return ret;
346 if (stde.pps_next != -1) {
347 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
348 if (ret!=-1)
349 return ret;
351 return -1;
354 /******************************************************************************
355 * STORAGE_dump_pps_entry [Internal]
357 * FIXME
358 * Function is unused
360 void
361 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
362 char name[33];
364 lstrcpyWtoA(name,stde->pps_rawname);
365 if (!stde->pps_sizeofname)
366 return;
367 DPRINTF("name: %s\n",name);
368 DPRINTF("type: %d\n",stde->pps_type);
369 DPRINTF("prev pps: %ld\n",stde->pps_prev);
370 DPRINTF("next pps: %ld\n",stde->pps_next);
371 DPRINTF("dir pps: %ld\n",stde->pps_dir);
372 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
373 if (stde->pps_type !=2) {
374 time_t t;
376 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
377 DPRINTF("ts1: %s\n",ctime(&t));
378 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
379 DPRINTF("ts2: %s\n",ctime(&t));
381 DPRINTF("startblock: %ld\n",stde->pps_sb);
382 DPRINTF("size: %ld\n",stde->pps_size);
385 /******************************************************************************
386 * STORAGE_init_storage [INTERNAL]
388 static BOOL
389 STORAGE_init_storage(HFILE hf) {
390 BYTE block[BIGSIZE];
391 LPDWORD bbs;
392 struct storage_header *sth;
393 struct storage_pps_entry *stde;
395 assert(-1!=_llseek(hf,0,SEEK_SET));
396 /* block -1 is the storage header */
397 sth = (struct storage_header*)block;
398 memcpy(sth->magic,STORAGE_magic,8);
399 memset(sth->unknown1,0,sizeof(sth->unknown1));
400 memset(sth->unknown2,0,sizeof(sth->unknown2));
401 memset(sth->unknown3,0,sizeof(sth->unknown3));
402 sth->num_of_bbd_blocks = 1;
403 sth->root_startblock = 1;
404 sth->sbd_startblock = 0xffffffff;
405 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
406 sth->bbd_list[0] = 0;
407 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
408 /* block 0 is the big block directory */
409 bbs=(LPDWORD)block;
410 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
411 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
412 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
413 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
414 /* block 1 is the root directory entry */
415 memset(block,0x00,sizeof(block));
416 stde = (struct storage_pps_entry*)block;
417 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
418 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
419 stde->pps_type = 5;
420 stde->pps_dir = -1;
421 stde->pps_next = -1;
422 stde->pps_prev = -1;
423 stde->pps_sb = 0xffffffff;
424 stde->pps_size = 0;
425 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
426 return TRUE;
429 /******************************************************************************
430 * STORAGE_set_big_chain [Internal]
432 static BOOL
433 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
434 BYTE block[BIGSIZE];
435 LPINT bbd = (LPINT)block;
436 int nextblocknr,bigblocknr;
437 struct storage_header sth;
439 READ_HEADER;
440 assert(blocknr!=type);
441 while (blocknr>=0) {
442 bigblocknr = sth.bbd_list[blocknr/128];
443 assert(bigblocknr>=0);
444 assert(STORAGE_get_big_block(hf,bigblocknr,block));
446 nextblocknr = bbd[blocknr&(128-1)];
447 bbd[blocknr&(128-1)] = type;
448 if (type>=0)
449 return TRUE;
450 assert(STORAGE_put_big_block(hf,bigblocknr,block));
451 type = STORAGE_CHAINENTRY_FREE;
452 blocknr = nextblocknr;
454 return TRUE;
457 /******************************************************************************
458 * STORAGE_set_small_chain [Internal]
460 static BOOL
461 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
462 BYTE block[BIGSIZE];
463 LPINT sbd = (LPINT)block;
464 int lastblocknr,nextsmallblocknr,bigblocknr;
465 struct storage_header sth;
467 READ_HEADER;
469 assert(blocknr!=type);
470 lastblocknr=-129;bigblocknr=-2;
471 while (blocknr>=0) {
472 /* cache block ... */
473 if (lastblocknr/128!=blocknr/128) {
474 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
475 assert(bigblocknr>=0);
476 assert(STORAGE_get_big_block(hf,bigblocknr,block));
478 lastblocknr = blocknr;
479 nextsmallblocknr = sbd[blocknr&(128-1)];
480 sbd[blocknr&(128-1)] = type;
481 assert(STORAGE_put_big_block(hf,bigblocknr,block));
482 if (type>=0)
483 return TRUE;
484 type = STORAGE_CHAINENTRY_FREE;
485 blocknr = nextsmallblocknr;
487 return TRUE;
490 /******************************************************************************
491 * STORAGE_get_free_big_blocknr [Internal]
493 static int
494 STORAGE_get_free_big_blocknr(HFILE hf) {
495 BYTE block[BIGSIZE];
496 LPINT sbd = (LPINT)block;
497 int lastbigblocknr,i,curblock,bigblocknr;
498 struct storage_header sth;
500 READ_HEADER;
501 curblock = 0;
502 lastbigblocknr = -1;
503 bigblocknr = sth.bbd_list[curblock];
504 while (curblock<sth.num_of_bbd_blocks) {
505 assert(bigblocknr>=0);
506 assert(STORAGE_get_big_block(hf,bigblocknr,block));
507 for (i=0;i<128;i++)
508 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
509 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
510 assert(STORAGE_put_big_block(hf,bigblocknr,block));
511 memset(block,0x42,sizeof(block));
512 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
513 return i+curblock*128;
515 lastbigblocknr = bigblocknr;
516 bigblocknr = sth.bbd_list[++curblock];
518 bigblocknr = curblock*128;
519 /* since we have marked all blocks from 0 up to curblock*128-1
520 * the next free one is curblock*128, where we happily put our
521 * next large block depot.
523 memset(block,0xff,sizeof(block));
524 /* mark the block allocated and returned by this function */
525 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
526 assert(STORAGE_put_big_block(hf,bigblocknr,block));
528 /* if we had a bbd block already (mostlikely) we need
529 * to link the new one into the chain
531 if (lastbigblocknr!=-1)
532 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
533 sth.bbd_list[curblock]=bigblocknr;
534 sth.num_of_bbd_blocks++;
535 assert(sth.num_of_bbd_blocks==curblock+1);
536 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
538 /* Set the end of the chain for the bigblockdepots */
539 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
540 /* add 1, for the first entry is used for the additional big block
541 * depot. (means we already used bigblocknr) */
542 memset(block,0x42,sizeof(block));
543 /* allocate this block (filled with 0x42) */
544 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
545 return bigblocknr+1;
549 /******************************************************************************
550 * STORAGE_get_free_small_blocknr [Internal]
552 static int
553 STORAGE_get_free_small_blocknr(HFILE hf) {
554 BYTE block[BIGSIZE];
555 LPINT sbd = (LPINT)block;
556 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
557 struct storage_pps_entry root;
558 struct storage_header sth;
560 READ_HEADER;
561 bigblocknr = sth.sbd_startblock;
562 curblock = 0;
563 lastbigblocknr = -1;
564 newblocknr = -1;
565 while (bigblocknr>=0) {
566 if (!STORAGE_get_big_block(hf,bigblocknr,block))
567 return -1;
568 for (i=0;i<128;i++)
569 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
570 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
571 newblocknr = i+curblock*128;
572 break;
574 if (i!=128)
575 break;
576 lastbigblocknr = bigblocknr;
577 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
578 curblock++;
580 if (newblocknr==-1) {
581 bigblocknr = STORAGE_get_free_big_blocknr(hf);
582 if (bigblocknr<0)
583 return -1;
584 READ_HEADER;
585 memset(block,0xff,sizeof(block));
586 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
587 if (!STORAGE_put_big_block(hf,bigblocknr,block))
588 return -1;
589 if (lastbigblocknr==-1) {
590 sth.sbd_startblock = bigblocknr;
591 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
592 return -1;
593 } else {
594 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
595 return -1;
597 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
598 return -1;
599 newblocknr = curblock*128;
601 /* allocate enough big blocks for storing the allocated small block */
602 if (!STORAGE_get_root_pps_entry(hf,&root))
603 return -1;
604 if (root.pps_sb==-1)
605 lastbigblocknr = -1;
606 else
607 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
608 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
609 /* we need to allocate more stuff */
610 bigblocknr = STORAGE_get_free_big_blocknr(hf);
611 if (bigblocknr<0)
612 return -1;
613 READ_HEADER;
614 if (root.pps_sb==-1) {
615 root.pps_sb = bigblocknr;
616 root.pps_size += BIGSIZE;
617 } else {
618 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
619 return -1;
620 root.pps_size += BIGSIZE;
622 lastbigblocknr = bigblocknr;
624 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
625 return -1;
626 if (!STORAGE_put_pps_entry(hf,0,&root))
627 return -1;
628 return newblocknr;
631 /******************************************************************************
632 * STORAGE_get_free_pps_entry [Internal]
634 static int
635 STORAGE_get_free_pps_entry(HFILE hf) {
636 int blocknr,i,curblock,lastblocknr;
637 BYTE block[BIGSIZE];
638 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
639 struct storage_header sth;
641 READ_HEADER;
642 blocknr = sth.root_startblock;
643 assert(blocknr>=0);
644 curblock=0;
645 while (blocknr>=0) {
646 if (!STORAGE_get_big_block(hf,blocknr,block))
647 return -1;
648 for (i=0;i<4;i++)
649 if (stde[i].pps_sizeofname==0) /* free */
650 return curblock*4+i;
651 lastblocknr = blocknr;
652 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
653 curblock++;
655 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
656 blocknr = STORAGE_get_free_big_blocknr(hf);
657 /* sth invalidated */
658 if (blocknr<0)
659 return -1;
661 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
662 return -1;
663 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
664 return -1;
665 memset(block,0,sizeof(block));
666 STORAGE_put_big_block(hf,blocknr,block);
667 return curblock*4;
670 /* --- IStream16 implementation */
672 typedef struct
674 /* IUnknown fields */
675 ICOM_VFIELD(IStream16);
676 DWORD ref;
677 /* IStream16 fields */
678 SEGPTR thisptr; /* pointer to this struct as segmented */
679 struct storage_pps_entry stde;
680 int ppsent;
681 HFILE hf;
682 ULARGE_INTEGER offset;
683 } IStream16Impl;
685 /******************************************************************************
686 * IStream16_QueryInterface [STORAGE.518]
688 HRESULT WINAPI IStream16_fnQueryInterface(
689 IStream16* iface,REFIID refiid,LPVOID *obj
691 ICOM_THIS(IStream16Impl,iface);
692 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
693 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
694 *obj = This;
695 return 0;
697 return OLE_E_ENUM_NOMORE;
701 /******************************************************************************
702 * IStream16_AddRef [STORAGE.519]
704 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
705 ICOM_THIS(IStream16Impl,iface);
706 return ++(This->ref);
709 /******************************************************************************
710 * IStream16_Release [STORAGE.520]
712 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
713 ICOM_THIS(IStream16Impl,iface);
714 FlushFileBuffers(This->hf);
715 This->ref--;
716 if (!This->ref) {
717 CloseHandle(This->hf);
718 SEGPTR_FREE(This);
719 return 0;
721 return This->ref;
724 /******************************************************************************
725 * IStream16_Seek [STORAGE.523]
727 * FIXME
728 * Does not handle 64 bits
730 HRESULT WINAPI IStream16_fnSeek(
731 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
733 ICOM_THIS(IStream16Impl,iface);
734 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
736 switch (whence) {
737 /* unix SEEK_xx should be the same as win95 ones */
738 case SEEK_SET:
739 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
740 * right now.
742 assert(offset.s.HighPart==0);
743 This->offset.s.HighPart = offset.s.HighPart;
744 This->offset.s.LowPart = offset.s.LowPart;
745 break;
746 case SEEK_CUR:
747 if (offset.s.HighPart < 0) {
748 /* FIXME: is this negation correct ? */
749 offset.s.HighPart = -offset.s.HighPart;
750 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
752 assert(offset.s.HighPart==0);
753 assert(This->offset.s.LowPart >= offset.s.LowPart);
754 This->offset.s.LowPart -= offset.s.LowPart;
755 } else {
756 assert(offset.s.HighPart==0);
757 This->offset.s.LowPart+= offset.s.LowPart;
759 break;
760 case SEEK_END:
761 assert(offset.s.HighPart==0);
762 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
763 break;
765 if (This->offset.s.LowPart>This->stde.pps_size)
766 This->offset.s.LowPart=This->stde.pps_size;
767 if (newpos) *newpos = This->offset;
768 return S_OK;
771 /******************************************************************************
772 * IStream16_Read [STORAGE.521]
774 HRESULT WINAPI IStream16_fnRead(
775 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
777 ICOM_THIS(IStream16Impl,iface);
778 BYTE block[BIGSIZE];
779 ULONG *bytesread=pcbRead,xxread;
780 int blocknr;
782 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
783 if (!pcbRead) bytesread=&xxread;
784 *bytesread = 0;
786 if (cb>This->stde.pps_size-This->offset.s.LowPart)
787 cb=This->stde.pps_size-This->offset.s.LowPart;
788 if (This->stde.pps_size < 0x1000) {
789 /* use small block reader */
790 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
791 while (cb) {
792 int cc;
794 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
795 WARN("small block read failed!!!\n");
796 return E_FAIL;
798 cc = cb;
799 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
800 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
801 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
802 This->offset.s.LowPart+=cc;
803 (LPBYTE)pv+=cc;
804 *bytesread+=cc;
805 cb-=cc;
806 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
808 } else {
809 /* use big block reader */
810 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
811 while (cb) {
812 int cc;
814 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
815 WARN("big block read failed!!!\n");
816 return E_FAIL;
818 cc = cb;
819 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
820 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
821 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
822 This->offset.s.LowPart+=cc;
823 (LPBYTE)pv+=cc;
824 *bytesread+=cc;
825 cb-=cc;
826 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
829 return S_OK;
832 /******************************************************************************
833 * IStream16_Write [STORAGE.522]
835 HRESULT WINAPI IStream16_fnWrite(
836 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
838 ICOM_THIS(IStream16Impl,iface);
839 BYTE block[BIGSIZE];
840 ULONG *byteswritten=pcbWrite,xxwritten;
841 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
842 HFILE hf = This->hf;
844 if (!pcbWrite) byteswritten=&xxwritten;
845 *byteswritten = 0;
847 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
848 /* do we need to junk some blocks? */
849 newsize = This->offset.s.LowPart+cb;
850 oldsize = This->stde.pps_size;
851 if (newsize < oldsize) {
852 if (oldsize < 0x1000) {
853 /* only small blocks */
854 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
856 assert(blocknr>=0);
858 /* will set the rest of the chain to 'free' */
859 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
860 return E_FAIL;
861 } else {
862 if (newsize >= 0x1000) {
863 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
864 assert(blocknr>=0);
866 /* will set the rest of the chain to 'free' */
867 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
868 return E_FAIL;
869 } else {
870 /* Migrate large blocks to small blocks
871 * (we just migrate newsize bytes)
873 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
874 cc = newsize;
875 blocknr = This->stde.pps_sb;
876 curdata = data;
877 while (cc>0) {
878 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
879 HeapFree(GetProcessHeap(),0,data);
880 return E_FAIL;
882 curdata += BIGSIZE;
883 cc -= BIGSIZE;
884 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
886 /* frees complete chain for this stream */
887 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
888 return E_FAIL;
889 curdata = data;
890 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
891 if (blocknr<0)
892 return E_FAIL;
893 cc = newsize;
894 while (cc>0) {
895 if (!STORAGE_put_small_block(hf,blocknr,curdata))
896 return E_FAIL;
897 cc -= SMALLSIZE;
898 if (cc<=0) {
899 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
900 return E_FAIL;
901 break;
902 } else {
903 int newblocknr = STORAGE_get_free_small_blocknr(hf);
904 if (newblocknr<0)
905 return E_FAIL;
906 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
907 return E_FAIL;
908 blocknr = newblocknr;
910 curdata += SMALLSIZE;
912 HeapFree(GetProcessHeap(),0,data);
915 This->stde.pps_size = newsize;
918 if (newsize > oldsize) {
919 if (oldsize >= 0x1000) {
920 /* should return the block right before the 'endofchain' */
921 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
922 assert(blocknr>=0);
923 lastblocknr = blocknr;
924 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
925 blocknr = STORAGE_get_free_big_blocknr(hf);
926 if (blocknr<0)
927 return E_FAIL;
928 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
929 return E_FAIL;
930 lastblocknr = blocknr;
932 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933 return E_FAIL;
934 } else {
935 if (newsize < 0x1000) {
936 /* find startblock */
937 if (!oldsize)
938 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
939 else
940 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
941 if (blocknr<0)
942 return E_FAIL;
944 /* allocate required new small blocks */
945 lastblocknr = blocknr;
946 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
947 blocknr = STORAGE_get_free_small_blocknr(hf);
948 if (blocknr<0)
949 return E_FAIL;
950 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
951 return E_FAIL;
952 lastblocknr = blocknr;
954 /* and terminate the chain */
955 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
956 return E_FAIL;
957 } else {
958 if (!oldsize) {
959 /* no single block allocated yet */
960 blocknr=STORAGE_get_free_big_blocknr(hf);
961 if (blocknr<0)
962 return E_FAIL;
963 This->stde.pps_sb = blocknr;
964 } else {
965 /* Migrate small blocks to big blocks */
966 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
967 cc = oldsize;
968 blocknr = This->stde.pps_sb;
969 curdata = data;
970 /* slurp in */
971 while (cc>0) {
972 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
973 HeapFree(GetProcessHeap(),0,data);
974 return E_FAIL;
976 curdata += SMALLSIZE;
977 cc -= SMALLSIZE;
978 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
980 /* free small block chain */
981 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
982 return E_FAIL;
983 curdata = data;
984 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
985 if (blocknr<0)
986 return E_FAIL;
987 /* put the data into the big blocks */
988 cc = This->stde.pps_size;
989 while (cc>0) {
990 if (!STORAGE_put_big_block(hf,blocknr,curdata))
991 return E_FAIL;
992 cc -= BIGSIZE;
993 if (cc<=0) {
994 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
995 return E_FAIL;
996 break;
997 } else {
998 int newblocknr = STORAGE_get_free_big_blocknr(hf);
999 if (newblocknr<0)
1000 return E_FAIL;
1001 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1002 return E_FAIL;
1003 blocknr = newblocknr;
1005 curdata += BIGSIZE;
1007 HeapFree(GetProcessHeap(),0,data);
1009 /* generate big blocks to fit the new data */
1010 lastblocknr = blocknr;
1011 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1012 blocknr = STORAGE_get_free_big_blocknr(hf);
1013 if (blocknr<0)
1014 return E_FAIL;
1015 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1016 return E_FAIL;
1017 lastblocknr = blocknr;
1019 /* terminate chain */
1020 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1021 return E_FAIL;
1024 This->stde.pps_size = newsize;
1027 /* There are just some cases where we didn't modify it, we write it out
1028 * everytime
1030 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1031 return E_FAIL;
1033 /* finally the write pass */
1034 if (This->stde.pps_size < 0x1000) {
1035 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1036 assert(blocknr>=0);
1037 while (cb>0) {
1038 /* we ensured that it is allocated above */
1039 assert(blocknr>=0);
1040 /* Read old block everytime, since we can have
1041 * overlapping data at START and END of the write
1043 if (!STORAGE_get_small_block(hf,blocknr,block))
1044 return E_FAIL;
1046 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1047 if (cc>cb)
1048 cc=cb;
1049 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1050 (LPBYTE)((char *) pv+curoffset),
1053 if (!STORAGE_put_small_block(hf,blocknr,block))
1054 return E_FAIL;
1055 cb -= cc;
1056 curoffset += cc;
1057 (LPBYTE)pv += cc;
1058 This->offset.s.LowPart += cc;
1059 *byteswritten += cc;
1060 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1062 } else {
1063 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1064 assert(blocknr>=0);
1065 while (cb>0) {
1066 /* we ensured that it is allocated above, so it better is */
1067 assert(blocknr>=0);
1068 /* read old block everytime, since we can have
1069 * overlapping data at START and END of the write
1071 if (!STORAGE_get_big_block(hf,blocknr,block))
1072 return E_FAIL;
1074 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1075 if (cc>cb)
1076 cc=cb;
1077 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1078 (LPBYTE)((char *) pv+curoffset),
1081 if (!STORAGE_put_big_block(hf,blocknr,block))
1082 return E_FAIL;
1083 cb -= cc;
1084 curoffset += cc;
1085 (LPBYTE)pv += cc;
1086 This->offset.s.LowPart += cc;
1087 *byteswritten += cc;
1088 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1091 return S_OK;
1094 /******************************************************************************
1095 * _create_istream16 [Internal]
1097 static void _create_istream16(LPSTREAM16 *str) {
1098 IStream16Impl* lpst;
1100 if (!strvt16.fnQueryInterface) {
1101 HMODULE16 wp = GetModuleHandle16("STORAGE");
1102 if (wp>=32) {
1103 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1104 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1105 VTENT(QueryInterface);
1106 VTENT(AddRef);
1107 VTENT(Release);
1108 VTENT(Read);
1109 VTENT(Write);
1110 VTENT(Seek);
1111 VTENT(SetSize);
1112 VTENT(CopyTo);
1113 VTENT(Commit);
1114 VTENT(Revert);
1115 VTENT(LockRegion);
1116 VTENT(UnlockRegion);
1117 VTENT(Stat);
1118 VTENT(Clone);
1119 #undef VTENT
1120 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1121 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1122 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1123 } else {
1124 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1125 VTENT(QueryInterface);
1126 VTENT(AddRef);
1127 VTENT(Release);
1128 VTENT(Read);
1129 VTENT(Write);
1130 VTENT(Seek);
1132 VTENT(CopyTo);
1133 VTENT(Commit);
1134 VTENT(SetSize);
1135 VTENT(Revert);
1136 VTENT(LockRegion);
1137 VTENT(UnlockRegion);
1138 VTENT(Stat);
1139 VTENT(Clone);
1141 #undef VTENT
1142 segstrvt16 = &strvt16;
1145 lpst = SEGPTR_NEW(IStream16Impl);
1146 ICOM_VTBL(lpst) = segstrvt16;
1147 lpst->ref = 1;
1148 lpst->thisptr = SEGPTR_GET(lpst);
1149 *str = (void*)lpst->thisptr;
1153 /* --- IStream32 implementation */
1155 typedef struct
1157 /* IUnknown fields */
1158 ICOM_VFIELD(IStream);
1159 DWORD ref;
1160 /* IStream32 fields */
1161 struct storage_pps_entry stde;
1162 int ppsent;
1163 HFILE hf;
1164 ULARGE_INTEGER offset;
1165 } IStream32Impl;
1167 /*****************************************************************************
1168 * IStream32_QueryInterface [VTABLE]
1170 HRESULT WINAPI IStream_fnQueryInterface(
1171 IStream* iface,REFIID refiid,LPVOID *obj
1173 ICOM_THIS(IStream32Impl,iface);
1175 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1176 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1177 *obj = This;
1178 return 0;
1180 return OLE_E_ENUM_NOMORE;
1184 /******************************************************************************
1185 * IStream32_AddRef [VTABLE]
1187 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1188 ICOM_THIS(IStream32Impl,iface);
1189 return ++(This->ref);
1192 /******************************************************************************
1193 * IStream32_Release [VTABLE]
1195 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1196 ICOM_THIS(IStream32Impl,iface);
1197 FlushFileBuffers(This->hf);
1198 This->ref--;
1199 if (!This->ref) {
1200 CloseHandle(This->hf);
1201 SEGPTR_FREE(This);
1202 return 0;
1204 return This->ref;
1207 /* --- IStorage16 implementation */
1209 typedef struct
1211 /* IUnknown fields */
1212 ICOM_VFIELD(IStorage16);
1213 DWORD ref;
1214 /* IStorage16 fields */
1215 SEGPTR thisptr; /* pointer to this struct as segmented */
1216 struct storage_pps_entry stde;
1217 int ppsent;
1218 HFILE hf;
1219 } IStorage16Impl;
1221 /******************************************************************************
1222 * IStorage16_QueryInterface [STORAGE.500]
1224 HRESULT WINAPI IStorage16_fnQueryInterface(
1225 IStorage16* iface,REFIID refiid,LPVOID *obj
1227 ICOM_THIS(IStorage16Impl,iface);
1229 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1231 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1232 *obj = This;
1233 return 0;
1235 return OLE_E_ENUM_NOMORE;
1238 /******************************************************************************
1239 * IStorage16_AddRef [STORAGE.501]
1241 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1242 ICOM_THIS(IStorage16Impl,iface);
1243 return ++(This->ref);
1246 /******************************************************************************
1247 * IStorage16_Release [STORAGE.502]
1249 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1250 ICOM_THIS(IStorage16Impl,iface);
1251 This->ref--;
1252 if (This->ref)
1253 return This->ref;
1254 SEGPTR_FREE(This);
1255 return 0;
1258 /******************************************************************************
1259 * IStorage16_Stat [STORAGE.517]
1261 HRESULT WINAPI IStorage16_fnStat(
1262 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1264 ICOM_THIS(IStorage16Impl,iface);
1265 TRACE("(%p)->(%p,0x%08lx)\n",
1266 This,pstatstg,grfStatFlag
1268 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1269 pstatstg->type = This->stde.pps_type;
1270 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1271 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1272 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1273 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1274 pstatstg->grfMode = 0; /* FIXME */
1275 pstatstg->grfLocksSupported = 0; /* FIXME */
1276 pstatstg->clsid = This->stde.pps_guid;
1277 pstatstg->grfStateBits = 0; /* FIXME */
1278 pstatstg->reserved = 0;
1279 return S_OK;
1282 /******************************************************************************
1283 * IStorage16_Commit [STORAGE.509]
1285 HRESULT WINAPI IStorage16_fnCommit(
1286 LPSTORAGE16 iface,DWORD commitflags
1288 ICOM_THIS(IStorage16Impl,iface);
1289 FIXME("(%p)->(0x%08lx),STUB!\n",
1290 This,commitflags
1292 return S_OK;
1295 /******************************************************************************
1296 * IStorage16_CopyTo [STORAGE.507]
1298 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1299 ICOM_THIS(IStorage16Impl,iface);
1300 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1301 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1303 return S_OK;
1307 /******************************************************************************
1308 * IStorage16_CreateStorage [STORAGE.505]
1310 HRESULT WINAPI IStorage16_fnCreateStorage(
1311 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1313 ICOM_THIS(IStorage16Impl,iface);
1314 IStorage16Impl* lpstg;
1315 int ppsent,x;
1316 struct storage_pps_entry stde;
1317 struct storage_header sth;
1318 HFILE hf=This->hf;
1320 READ_HEADER;
1322 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1323 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1325 if (grfMode & STGM_TRANSACTED)
1326 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1327 _create_istorage16(ppstg);
1328 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1329 lpstg->hf = This->hf;
1331 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1332 if (ppsent<0)
1333 return E_FAIL;
1334 stde=This->stde;
1335 if (stde.pps_dir==-1) {
1336 stde.pps_dir = ppsent;
1337 x = This->ppsent;
1338 } else {
1339 FIXME(" use prev chain too ?\n");
1340 x=stde.pps_dir;
1341 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1342 return E_FAIL;
1343 while (stde.pps_next!=-1) {
1344 x=stde.pps_next;
1345 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1346 return E_FAIL;
1348 stde.pps_next = ppsent;
1350 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1351 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1352 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1353 lpstg->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1354 lpstg->stde.pps_next = -1;
1355 lpstg->stde.pps_prev = -1;
1356 lpstg->stde.pps_dir = -1;
1357 lpstg->stde.pps_sb = -1;
1358 lpstg->stde.pps_size = 0;
1359 lpstg->stde.pps_type = 1;
1360 lpstg->ppsent = ppsent;
1361 /* FIXME: timestamps? */
1362 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1363 return E_FAIL;
1364 return S_OK;
1367 /******************************************************************************
1368 * IStorage16_CreateStream [STORAGE.503]
1370 HRESULT WINAPI IStorage16_fnCreateStream(
1371 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1373 ICOM_THIS(IStorage16Impl,iface);
1374 IStream16Impl* lpstr;
1375 int ppsent,x;
1376 struct storage_pps_entry stde;
1378 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1379 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1381 if (grfMode & STGM_TRANSACTED)
1382 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1383 _create_istream16(ppstm);
1384 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1385 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1386 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1387 lpstr->offset.s.LowPart = 0;
1388 lpstr->offset.s.HighPart = 0;
1390 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1391 if (ppsent<0)
1392 return E_FAIL;
1393 stde=This->stde;
1394 if (stde.pps_next==-1)
1395 x=This->ppsent;
1396 else
1397 while (stde.pps_next!=-1) {
1398 x=stde.pps_next;
1399 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1400 return E_FAIL;
1402 stde.pps_next = ppsent;
1403 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1404 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1405 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1406 lpstr->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1407 lpstr->stde.pps_next = -1;
1408 lpstr->stde.pps_prev = -1;
1409 lpstr->stde.pps_dir = -1;
1410 lpstr->stde.pps_sb = -1;
1411 lpstr->stde.pps_size = 0;
1412 lpstr->stde.pps_type = 2;
1413 lpstr->ppsent = ppsent;
1414 /* FIXME: timestamps? */
1415 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1416 return E_FAIL;
1417 return S_OK;
1420 /******************************************************************************
1421 * IStorage16_OpenStorage [STORAGE.506]
1423 HRESULT WINAPI IStorage16_fnOpenStorage(
1424 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1426 ICOM_THIS(IStorage16Impl,iface);
1427 IStream16Impl* lpstg;
1428 WCHAR name[33];
1429 int newpps;
1431 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1432 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1434 if (grfMode & STGM_TRANSACTED)
1435 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1436 _create_istorage16(ppstg);
1437 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1438 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1439 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1440 lstrcpyAtoW(name,pwcsName);
1441 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1442 if (newpps==-1) {
1443 IStream16_fnRelease((IStream16*)lpstg);
1444 return E_FAIL;
1447 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1448 IStream16_fnRelease((IStream16*)lpstg);
1449 return E_FAIL;
1451 lpstg->ppsent = newpps;
1452 return S_OK;
1455 /******************************************************************************
1456 * IStorage16_OpenStream [STORAGE.504]
1458 HRESULT WINAPI IStorage16_fnOpenStream(
1459 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1461 ICOM_THIS(IStorage16Impl,iface);
1462 IStream16Impl* lpstr;
1463 WCHAR name[33];
1464 int newpps;
1466 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1467 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1469 if (grfMode & STGM_TRANSACTED)
1470 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1471 _create_istream16(ppstm);
1472 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1473 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1474 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1475 lstrcpyAtoW(name,pwcsName);
1476 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1477 if (newpps==-1) {
1478 IStream16_fnRelease((IStream16*)lpstr);
1479 return E_FAIL;
1482 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1483 IStream16_fnRelease((IStream16*)lpstr);
1484 return E_FAIL;
1486 lpstr->offset.s.LowPart = 0;
1487 lpstr->offset.s.HighPart = 0;
1488 lpstr->ppsent = newpps;
1489 return S_OK;
1492 /******************************************************************************
1493 * _create_istorage16 [INTERNAL]
1495 static void _create_istorage16(LPSTORAGE16 *stg) {
1496 IStorage16Impl* lpst;
1498 if (!stvt16.fnQueryInterface) {
1499 HMODULE16 wp = GetModuleHandle16("STORAGE");
1500 if (wp>=32) {
1501 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1502 VTENT(QueryInterface)
1503 VTENT(AddRef)
1504 VTENT(Release)
1505 VTENT(CreateStream)
1506 VTENT(OpenStream)
1507 VTENT(CreateStorage)
1508 VTENT(OpenStorage)
1509 VTENT(CopyTo)
1510 VTENT(MoveElementTo)
1511 VTENT(Commit)
1512 VTENT(Revert)
1513 VTENT(EnumElements)
1514 VTENT(DestroyElement)
1515 VTENT(RenameElement)
1516 VTENT(SetElementTimes)
1517 VTENT(SetClass)
1518 VTENT(SetStateBits)
1519 VTENT(Stat)
1520 #undef VTENT
1521 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1522 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1523 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1524 } else {
1525 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1526 VTENT(QueryInterface)
1527 VTENT(AddRef)
1528 VTENT(Release)
1529 VTENT(CreateStream)
1530 VTENT(OpenStream)
1531 VTENT(CreateStorage)
1532 VTENT(OpenStorage)
1533 VTENT(CopyTo)
1534 VTENT(Commit)
1535 /* not (yet) implemented ...
1536 VTENT(MoveElementTo)
1537 VTENT(Revert)
1538 VTENT(EnumElements)
1539 VTENT(DestroyElement)
1540 VTENT(RenameElement)
1541 VTENT(SetElementTimes)
1542 VTENT(SetClass)
1543 VTENT(SetStateBits)
1544 VTENT(Stat)
1546 #undef VTENT
1547 segstvt16 = &stvt16;
1550 lpst = SEGPTR_NEW(IStorage16Impl);
1551 ICOM_VTBL(lpst) = segstvt16;
1552 lpst->ref = 1;
1553 lpst->thisptr = SEGPTR_GET(lpst);
1554 *stg = (void*)lpst->thisptr;
1557 /******************************************************************************
1558 * Storage API functions
1561 /******************************************************************************
1562 * StgCreateDocFile16 [STORAGE.1]
1564 HRESULT WINAPI StgCreateDocFile16(
1565 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1567 HFILE hf;
1568 int i,ret;
1569 IStorage16Impl* lpstg;
1570 struct storage_pps_entry stde;
1572 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1573 pwcsName,grfMode,reserved,ppstgOpen
1575 _create_istorage16(ppstgOpen);
1576 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1577 if (hf==INVALID_HANDLE_VALUE) {
1578 WARN("couldn't open file for storage:%ld\n",GetLastError());
1579 return E_FAIL;
1581 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1582 lpstg->hf = hf;
1583 /* FIXME: check for existance before overwriting? */
1584 if (!STORAGE_init_storage(hf)) {
1585 CloseHandle(hf);
1586 return E_FAIL;
1588 i=0;ret=0;
1589 while (!ret) { /* neither 1 nor <0 */
1590 ret=STORAGE_get_pps_entry(hf,i,&stde);
1591 if ((ret==1) && (stde.pps_type==5)) {
1592 lpstg->stde = stde;
1593 lpstg->ppsent = i;
1594 break;
1596 i++;
1598 if (ret!=1) {
1599 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1600 return E_FAIL;
1603 return S_OK;
1606 /******************************************************************************
1607 * StgIsStorageFile16 [STORAGE.5]
1609 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1610 HFILE hf;
1611 OFSTRUCT ofs;
1612 BYTE magic[24];
1614 TRACE("(\'%s\')\n",fn);
1615 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1616 if (hf==HFILE_ERROR)
1617 return STG_E_FILENOTFOUND;
1618 if (24!=_lread(hf,magic,24)) {
1619 WARN(" too short\n");
1620 _lclose(hf);
1621 return S_FALSE;
1623 if (!memcmp(magic,STORAGE_magic,8)) {
1624 WARN(" -> YES\n");
1625 _lclose(hf);
1626 return S_OK;
1628 if (!memcmp(magic,STORAGE_notmagic,8)) {
1629 WARN(" -> NO\n");
1630 _lclose(hf);
1631 return S_FALSE;
1633 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1634 WARN(" -> old format\n");
1635 _lclose(hf);
1636 return STG_E_OLDFORMAT;
1638 WARN(" -> Invalid header.\n");
1639 _lclose(hf);
1640 return STG_E_INVALIDHEADER;
1643 /******************************************************************************
1644 * StgIsStorageFile [OLE32.146]
1646 HRESULT WINAPI
1647 StgIsStorageFile(LPCOLESTR fn)
1649 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1650 HRESULT ret = StgIsStorageFile16(xfn);
1652 HeapFree(GetProcessHeap(),0,xfn);
1653 return ret;
1657 /******************************************************************************
1658 * StgOpenStorage16 [STORAGE.3]
1660 HRESULT WINAPI StgOpenStorage16(
1661 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1662 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1664 HFILE hf;
1665 int ret,i;
1666 IStorage16Impl* lpstg;
1667 struct storage_pps_entry stde;
1669 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1670 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1672 _create_istorage16(ppstgOpen);
1673 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1674 if (hf==INVALID_HANDLE_VALUE) {
1675 WARN("Couldn't open file for storage\n");
1676 return E_FAIL;
1678 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1679 lpstg->hf = hf;
1681 i=0;ret=0;
1682 while (!ret) { /* neither 1 nor <0 */
1683 ret=STORAGE_get_pps_entry(hf,i,&stde);
1684 if ((ret==1) && (stde.pps_type==5)) {
1685 lpstg->stde=stde;
1686 break;
1688 i++;
1690 if (ret!=1) {
1691 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1692 return E_FAIL;
1694 return S_OK;