Release 990226.
[wine/gsoc-2012-control.git] / ole / storage.c
blobf9b18379b4f12b141c5acd10bc3584662ef245b3
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 "windef.h"
14 #include "winerror.h"
15 #include "wine/winestring.h"
16 #include "wine/winbase16.h"
17 #include "file.h"
18 #include "ole.h"
19 #include "wine/obj_base.h"
20 #include "wine/obj_storage.h"
21 #include "objbase.h"
22 #include "heap.h"
23 #include "module.h"
24 #include "ldt.h"
25 #include "debug.h"
27 struct storage_header {
28 BYTE magic[8]; /* 00: magic */
29 BYTE unknown1[36]; /* 08: unknown */
30 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
31 DWORD root_startblock;/* 30: root storage first big block */
32 DWORD unknown2[2]; /* 34: unknown */
33 DWORD sbd_startblock; /* 3C: small block depot first big block */
34 DWORD unknown3[3]; /* 40: unknown */
35 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
37 struct storage_pps_entry {
38 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
39 WORD pps_sizeofname; /* 40: namelength in bytes */
40 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
41 BYTE pps_unknown0; /* 43: unknown */
42 DWORD pps_prev; /* 44: previous pps */
43 DWORD pps_next; /* 48: next pps */
44 DWORD pps_dir; /* 4C: directory pps */
45 GUID pps_guid; /* 50: class ID */
46 DWORD pps_unknown1; /* 60: unknown */
47 FILETIME pps_ft1; /* 64: filetime1 */
48 FILETIME pps_ft2; /* 70: filetime2 */
49 DWORD pps_sb; /* 74: data startblock */
50 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
51 DWORD pps_unknown2; /* 7C: unknown */
54 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
55 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
56 #define STORAGE_CHAINENTRY_FREE 0xffffffff
59 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
60 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
61 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
63 #define BIGSIZE 512
64 #define SMALLSIZE 64
66 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
68 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
69 static ICOM_VTABLE(IStorage16) stvt16;
70 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
71 static ICOM_VTABLE(IStream16) strvt16;
72 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
74 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
75 static void _create_istorage16(LPSTORAGE16 *stg);
76 static void _create_istream16(LPSTREAM16 *str);
78 #define IMPLEMENTED 1
81 /******************************************************************************
82 * STORAGE_get_big_block [Internal]
84 * Reading OLE compound storage
86 static BOOL
87 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
88 assert(n>=-1);
89 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
90 WARN(ole," seek failed (%ld)\n",GetLastError());
91 return FALSE;
93 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
94 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
95 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
96 assert(0);
97 return FALSE;
99 return TRUE;
102 /******************************************************************************
103 * STORAGE_put_big_block [INTERNAL]
105 static BOOL
106 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
107 assert(n>=-1);
108 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
109 WARN(ole," seek failed (%ld)\n",GetLastError());
110 return FALSE;
112 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
113 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
114 WARN(ole," write failed (%ld)\n",GetLastError());
115 return FALSE;
117 return TRUE;
120 /******************************************************************************
121 * STORAGE_get_next_big_blocknr [INTERNAL]
123 static int
124 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
125 INT bbs[BIGSIZE/sizeof(INT)];
126 struct storage_header sth;
128 READ_HEADER;
130 assert(blocknr>>7<sth.num_of_bbd_blocks);
131 if (sth.bbd_list[blocknr>>7]==0xffffffff)
132 return -5;
133 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
134 return -5;
135 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
136 return bbs[blocknr&0x7f];
139 /******************************************************************************
140 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
142 static int
143 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
144 INT bbs[BIGSIZE/sizeof(INT)];
145 int lastblock = -1;
146 struct storage_header sth;
148 READ_HEADER;
150 assert(blocknr>=0);
151 while (nr--) {
152 assert((blocknr>>7)<sth.num_of_bbd_blocks);
153 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
155 /* simple caching... */
156 if (lastblock!=sth.bbd_list[blocknr>>7]) {
157 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
158 lastblock = sth.bbd_list[blocknr>>7];
160 blocknr = bbs[blocknr&0x7f];
162 return blocknr;
165 /******************************************************************************
166 * STORAGE_get_root_pps_entry [Internal]
168 static BOOL
169 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
170 int blocknr,i;
171 BYTE block[BIGSIZE];
172 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
173 struct storage_header sth;
175 READ_HEADER;
176 blocknr = sth.root_startblock;
177 while (blocknr>=0) {
178 assert(STORAGE_get_big_block(hf,blocknr,block));
179 for (i=0;i<4;i++) {
180 if (!stde[i].pps_sizeofname)
181 continue;
182 if (stde[i].pps_type==5) {
183 *pstde=stde[i];
184 return TRUE;
187 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
189 return FALSE;
192 /******************************************************************************
193 * STORAGE_get_small_block [INTERNAL]
195 static BOOL
196 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
197 BYTE block[BIGSIZE];
198 int bigblocknr;
199 struct storage_pps_entry root;
201 assert(blocknr>=0);
202 assert(STORAGE_get_root_pps_entry(hf,&root));
203 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
204 assert(bigblocknr>=0);
205 assert(STORAGE_get_big_block(hf,bigblocknr,block));
207 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
208 return TRUE;
211 /******************************************************************************
212 * STORAGE_put_small_block [INTERNAL]
214 static BOOL
215 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
216 BYTE block[BIGSIZE];
217 int bigblocknr;
218 struct storage_pps_entry root;
220 assert(blocknr>=0);
222 assert(STORAGE_get_root_pps_entry(hf,&root));
223 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
224 assert(bigblocknr>=0);
225 assert(STORAGE_get_big_block(hf,bigblocknr,block));
227 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
228 assert(STORAGE_put_big_block(hf,bigblocknr,block));
229 return TRUE;
232 /******************************************************************************
233 * STORAGE_get_next_small_blocknr [INTERNAL]
235 static int
236 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
237 BYTE block[BIGSIZE];
238 LPINT sbd = (LPINT)block;
239 int bigblocknr;
240 struct storage_header sth;
242 READ_HEADER;
243 assert(blocknr>=0);
244 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
245 assert(bigblocknr>=0);
246 assert(STORAGE_get_big_block(hf,bigblocknr,block));
247 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
248 return sbd[blocknr & (128-1)];
251 /******************************************************************************
252 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
254 static int
255 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
256 int lastblocknr;
257 BYTE block[BIGSIZE];
258 LPINT sbd = (LPINT)block;
259 struct storage_header sth;
261 READ_HEADER;
262 lastblocknr=-1;
263 assert(blocknr>=0);
264 while ((nr--) && (blocknr>=0)) {
265 if (lastblocknr/128!=blocknr/128) {
266 int bigblocknr;
267 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
268 assert(bigblocknr>=0);
269 assert(STORAGE_get_big_block(hf,bigblocknr,block));
270 lastblocknr = blocknr;
272 assert(lastblocknr>=0);
273 lastblocknr=blocknr;
274 blocknr=sbd[blocknr & (128-1)];
275 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
277 return blocknr;
280 /******************************************************************************
281 * STORAGE_get_pps_entry [INTERNAL]
283 static int
284 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
285 int blocknr;
286 BYTE block[BIGSIZE];
287 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
288 struct storage_header sth;
290 READ_HEADER;
291 /* we have 4 pps entries per big block */
292 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
293 assert(blocknr>=0);
294 assert(STORAGE_get_big_block(hf,blocknr,block));
296 *pstde=*stde;
297 return 1;
300 /******************************************************************************
301 * STORAGE_put_pps_entry [Internal]
303 static int
304 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
305 int blocknr;
306 BYTE block[BIGSIZE];
307 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
308 struct storage_header sth;
310 READ_HEADER;
312 /* we have 4 pps entries per big block */
313 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
314 assert(blocknr>=0);
315 assert(STORAGE_get_big_block(hf,blocknr,block));
316 *stde=*pstde;
317 assert(STORAGE_put_big_block(hf,blocknr,block));
318 return 1;
321 /******************************************************************************
322 * STORAGE_look_for_named_pps [Internal]
324 static int
325 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
326 struct storage_pps_entry stde;
327 int ret;
329 if (n==-1)
330 return -1;
331 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
332 return -1;
334 if (!lstrcmpW(name,stde.pps_rawname))
335 return n;
336 if (stde.pps_prev != -1) {
337 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
338 if (ret!=-1)
339 return ret;
341 if (stde.pps_next != -1) {
342 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
343 if (ret!=-1)
344 return ret;
346 return -1;
349 /******************************************************************************
350 * STORAGE_dump_pps_entry [Internal]
352 * FIXME
353 * Function is unused
355 void
356 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
357 char name[33],xguid[50];
359 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
361 lstrcpyWtoA(name,stde->pps_rawname);
362 if (!stde->pps_sizeofname)
363 return;
364 DUMP("name: %s\n",name);
365 DUMP("type: %d\n",stde->pps_type);
366 DUMP("prev pps: %ld\n",stde->pps_prev);
367 DUMP("next pps: %ld\n",stde->pps_next);
368 DUMP("dir pps: %ld\n",stde->pps_dir);
369 DUMP("guid: %s\n",xguid);
370 if (stde->pps_type !=2) {
371 time_t t;
373 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
374 DUMP("ts1: %s\n",ctime(&t));
375 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
376 DUMP("ts2: %s\n",ctime(&t));
378 DUMP("startblock: %ld\n",stde->pps_sb);
379 DUMP("size: %ld\n",stde->pps_size);
382 /******************************************************************************
383 * STORAGE_init_storage [INTERNAL]
385 static BOOL
386 STORAGE_init_storage(HFILE hf) {
387 BYTE block[BIGSIZE];
388 LPDWORD bbs;
389 struct storage_header *sth;
390 struct storage_pps_entry *stde;
392 assert(-1!=_llseek(hf,0,SEEK_SET));
393 /* block -1 is the storage header */
394 sth = (struct storage_header*)block;
395 memcpy(sth->magic,STORAGE_magic,8);
396 memset(sth->unknown1,0,sizeof(sth->unknown1));
397 memset(sth->unknown2,0,sizeof(sth->unknown2));
398 memset(sth->unknown3,0,sizeof(sth->unknown3));
399 sth->num_of_bbd_blocks = 1;
400 sth->root_startblock = 1;
401 sth->sbd_startblock = 0xffffffff;
402 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
403 sth->bbd_list[0] = 0;
404 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
405 /* block 0 is the big block directory */
406 bbs=(LPDWORD)block;
407 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
408 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
409 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
410 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
411 /* block 1 is the root directory entry */
412 memset(block,0x00,sizeof(block));
413 stde = (struct storage_pps_entry*)block;
414 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
415 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
416 stde->pps_type = 5;
417 stde->pps_dir = -1;
418 stde->pps_next = -1;
419 stde->pps_prev = -1;
420 stde->pps_sb = 0xffffffff;
421 stde->pps_size = 0;
422 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
423 return TRUE;
426 /******************************************************************************
427 * STORAGE_set_big_chain [Internal]
429 static BOOL
430 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
431 BYTE block[BIGSIZE];
432 LPINT bbd = (LPINT)block;
433 int nextblocknr,bigblocknr;
434 struct storage_header sth;
436 READ_HEADER;
437 assert(blocknr!=type);
438 while (blocknr>=0) {
439 bigblocknr = sth.bbd_list[blocknr/128];
440 assert(bigblocknr>=0);
441 assert(STORAGE_get_big_block(hf,bigblocknr,block));
443 nextblocknr = bbd[blocknr&(128-1)];
444 bbd[blocknr&(128-1)] = type;
445 if (type>=0)
446 return TRUE;
447 assert(STORAGE_put_big_block(hf,bigblocknr,block));
448 type = STORAGE_CHAINENTRY_FREE;
449 blocknr = nextblocknr;
451 return TRUE;
454 /******************************************************************************
455 * STORAGE_set_small_chain [Internal]
457 static BOOL
458 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
459 BYTE block[BIGSIZE];
460 LPINT sbd = (LPINT)block;
461 int lastblocknr,nextsmallblocknr,bigblocknr;
462 struct storage_header sth;
464 READ_HEADER;
466 assert(blocknr!=type);
467 lastblocknr=-129;bigblocknr=-2;
468 while (blocknr>=0) {
469 /* cache block ... */
470 if (lastblocknr/128!=blocknr/128) {
471 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
472 assert(bigblocknr>=0);
473 assert(STORAGE_get_big_block(hf,bigblocknr,block));
475 lastblocknr = blocknr;
476 nextsmallblocknr = sbd[blocknr&(128-1)];
477 sbd[blocknr&(128-1)] = type;
478 assert(STORAGE_put_big_block(hf,bigblocknr,block));
479 if (type>=0)
480 return TRUE;
481 type = STORAGE_CHAINENTRY_FREE;
482 blocknr = nextsmallblocknr;
484 return TRUE;
487 /******************************************************************************
488 * STORAGE_get_free_big_blocknr [Internal]
490 static int
491 STORAGE_get_free_big_blocknr(HFILE hf) {
492 BYTE block[BIGSIZE];
493 LPINT sbd = (LPINT)block;
494 int lastbigblocknr,i,curblock,bigblocknr;
495 struct storage_header sth;
497 READ_HEADER;
498 curblock = 0;
499 lastbigblocknr = -1;
500 bigblocknr = sth.bbd_list[curblock];
501 while (curblock<sth.num_of_bbd_blocks) {
502 assert(bigblocknr>=0);
503 assert(STORAGE_get_big_block(hf,bigblocknr,block));
504 for (i=0;i<128;i++)
505 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
506 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
507 assert(STORAGE_put_big_block(hf,bigblocknr,block));
508 memset(block,0x42,sizeof(block));
509 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
510 return i+curblock*128;
512 lastbigblocknr = bigblocknr;
513 bigblocknr = sth.bbd_list[++curblock];
515 bigblocknr = curblock*128;
516 /* since we have marked all blocks from 0 up to curblock*128-1
517 * the next free one is curblock*128, where we happily put our
518 * next large block depot.
520 memset(block,0xff,sizeof(block));
521 /* mark the block allocated and returned by this function */
522 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
523 assert(STORAGE_put_big_block(hf,bigblocknr,block));
525 /* if we had a bbd block already (mostlikely) we need
526 * to link the new one into the chain
528 if (lastbigblocknr!=-1)
529 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
530 sth.bbd_list[curblock]=bigblocknr;
531 sth.num_of_bbd_blocks++;
532 assert(sth.num_of_bbd_blocks==curblock+1);
533 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
535 /* Set the end of the chain for the bigblockdepots */
536 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
537 /* add 1, for the first entry is used for the additional big block
538 * depot. (means we already used bigblocknr) */
539 memset(block,0x42,sizeof(block));
540 /* allocate this block (filled with 0x42) */
541 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
542 return bigblocknr+1;
546 /******************************************************************************
547 * STORAGE_get_free_small_blocknr [Internal]
549 static int
550 STORAGE_get_free_small_blocknr(HFILE hf) {
551 BYTE block[BIGSIZE];
552 LPINT sbd = (LPINT)block;
553 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
554 struct storage_pps_entry root;
555 struct storage_header sth;
557 READ_HEADER;
558 bigblocknr = sth.sbd_startblock;
559 curblock = 0;
560 lastbigblocknr = -1;
561 newblocknr = -1;
562 while (bigblocknr>=0) {
563 if (!STORAGE_get_big_block(hf,bigblocknr,block))
564 return -1;
565 for (i=0;i<128;i++)
566 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
567 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
568 newblocknr = i+curblock*128;
569 break;
571 if (i!=128)
572 break;
573 lastbigblocknr = bigblocknr;
574 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
575 curblock++;
577 if (newblocknr==-1) {
578 bigblocknr = STORAGE_get_free_big_blocknr(hf);
579 if (bigblocknr<0)
580 return -1;
581 READ_HEADER;
582 memset(block,0xff,sizeof(block));
583 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
584 if (!STORAGE_put_big_block(hf,bigblocknr,block))
585 return -1;
586 if (lastbigblocknr==-1) {
587 sth.sbd_startblock = bigblocknr;
588 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
589 return -1;
590 } else {
591 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
592 return -1;
594 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
595 return -1;
596 newblocknr = curblock*128;
598 /* allocate enough big blocks for storing the allocated small block */
599 if (!STORAGE_get_root_pps_entry(hf,&root))
600 return -1;
601 if (root.pps_sb==-1)
602 lastbigblocknr = -1;
603 else
604 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
605 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
606 /* we need to allocate more stuff */
607 bigblocknr = STORAGE_get_free_big_blocknr(hf);
608 if (bigblocknr<0)
609 return -1;
610 READ_HEADER;
611 if (root.pps_sb==-1) {
612 root.pps_sb = bigblocknr;
613 root.pps_size += BIGSIZE;
614 } else {
615 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
616 return -1;
617 root.pps_size += BIGSIZE;
619 lastbigblocknr = bigblocknr;
621 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
622 return -1;
623 if (!STORAGE_put_pps_entry(hf,0,&root))
624 return -1;
625 return newblocknr;
628 /******************************************************************************
629 * STORAGE_get_free_pps_entry [Internal]
631 static int
632 STORAGE_get_free_pps_entry(HFILE hf) {
633 int blocknr,i,curblock,lastblocknr;
634 BYTE block[BIGSIZE];
635 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
636 struct storage_header sth;
638 READ_HEADER;
639 blocknr = sth.root_startblock;
640 assert(blocknr>=0);
641 curblock=0;
642 while (blocknr>=0) {
643 if (!STORAGE_get_big_block(hf,blocknr,block))
644 return -1;
645 for (i=0;i<4;i++)
646 if (stde[i].pps_sizeofname==0) /* free */
647 return curblock*4+i;
648 lastblocknr = blocknr;
649 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
650 curblock++;
652 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
653 blocknr = STORAGE_get_free_big_blocknr(hf);
654 /* sth invalidated */
655 if (blocknr<0)
656 return -1;
658 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
659 return -1;
660 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
661 return -1;
662 memset(block,0,sizeof(block));
663 STORAGE_put_big_block(hf,blocknr,block);
664 return curblock*4;
667 /* --- IStream16 implementation */
669 typedef struct
671 /* IUnknown fields */
672 ICOM_VTABLE(IStream16)* lpvtbl;
673 DWORD ref;
674 /* IStream16 fields */
675 SEGPTR thisptr; /* pointer to this struct as segmented */
676 struct storage_pps_entry stde;
677 int ppsent;
678 HFILE hf;
679 ULARGE_INTEGER offset;
680 } IStream16Impl;
682 /******************************************************************************
683 * IStream16_QueryInterface [STORAGE.518]
685 HRESULT WINAPI IStream16_fnQueryInterface(
686 IStream16* iface,REFIID refiid,LPVOID *obj
688 ICOM_THIS(IStream16Impl,iface);
689 char xrefiid[50];
690 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
691 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,obj);
692 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
693 *obj = This;
694 return 0;
696 return OLE_E_ENUM_NOMORE;
700 /******************************************************************************
701 * IStream16_AddRef [STORAGE.519]
703 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
704 ICOM_THIS(IStream16Impl,iface);
705 return ++(This->ref);
708 /******************************************************************************
709 * IStream16_Release [STORAGE.520]
711 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
712 ICOM_THIS(IStream16Impl,iface);
713 FlushFileBuffers(This->hf);
714 This->ref--;
715 if (!This->ref) {
716 CloseHandle(This->hf);
717 SEGPTR_FREE(This);
718 return 0;
720 return This->ref;
723 /******************************************************************************
724 * IStream16_Seek [STORAGE.523]
726 * FIXME
727 * Does not handle 64 bits
729 HRESULT WINAPI IStream16_fnSeek(
730 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
732 ICOM_THIS(IStream16Impl,iface);
733 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",This,offset.HighPart,offset.LowPart,whence,newpos);
735 switch (whence) {
736 /* unix SEEK_xx should be the same as win95 ones */
737 case SEEK_SET:
738 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
739 * right now.
741 assert(offset.HighPart==0);
742 This->offset.HighPart = offset.HighPart;
743 This->offset.LowPart = offset.LowPart;
744 break;
745 case SEEK_CUR:
746 if (offset.HighPart < 0) {
747 /* FIXME: is this negation correct ? */
748 offset.HighPart = -offset.HighPart;
749 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
751 assert(offset.HighPart==0);
752 assert(This->offset.LowPart >= offset.LowPart);
753 This->offset.LowPart -= offset.LowPart;
754 } else {
755 assert(offset.HighPart==0);
756 This->offset.LowPart+= offset.LowPart;
758 break;
759 case SEEK_END:
760 assert(offset.HighPart==0);
761 This->offset.LowPart = This->stde.pps_size-offset.LowPart;
762 break;
764 if (This->offset.LowPart>This->stde.pps_size)
765 This->offset.LowPart=This->stde.pps_size;
766 if (newpos) *newpos = This->offset;
767 return S_OK;
770 /******************************************************************************
771 * IStream16_Read [STORAGE.521]
773 HRESULT WINAPI IStream16_fnRead(
774 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
776 ICOM_THIS(IStream16Impl,iface);
777 BYTE block[BIGSIZE];
778 ULONG *bytesread=pcbRead,xxread;
779 int blocknr;
781 TRACE(relay,"(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
782 if (!pcbRead) bytesread=&xxread;
783 *bytesread = 0;
785 if (cb>This->stde.pps_size-This->offset.LowPart)
786 cb=This->stde.pps_size-This->offset.LowPart;
787 if (This->stde.pps_size < 0x1000) {
788 /* use small block reader */
789 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
790 while (cb) {
791 int cc;
793 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
794 WARN(ole,"small block read failed!!!\n");
795 return E_FAIL;
797 cc = cb;
798 if (cc>SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1)))
799 cc=SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
800 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(SMALLSIZE-1)),cc);
801 This->offset.LowPart+=cc;
802 (LPBYTE)pv+=cc;
803 *bytesread+=cc;
804 cb-=cc;
805 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
807 } else {
808 /* use big block reader */
809 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
810 while (cb) {
811 int cc;
813 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
814 WARN(ole,"big block read failed!!!\n");
815 return E_FAIL;
817 cc = cb;
818 if (cc>BIGSIZE-(This->offset.LowPart&(BIGSIZE-1)))
819 cc=BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
820 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(BIGSIZE-1)),cc);
821 This->offset.LowPart+=cc;
822 (LPBYTE)pv+=cc;
823 *bytesread+=cc;
824 cb-=cc;
825 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
828 return S_OK;
831 /******************************************************************************
832 * IStream16_Write [STORAGE.522]
834 HRESULT WINAPI IStream16_fnWrite(
835 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
837 ICOM_THIS(IStream16Impl,iface);
838 BYTE block[BIGSIZE];
839 ULONG *byteswritten=pcbWrite,xxwritten;
840 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
841 HFILE hf = This->hf;
843 if (!pcbWrite) byteswritten=&xxwritten;
844 *byteswritten = 0;
846 TRACE(relay,"(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
847 /* do we need to junk some blocks? */
848 newsize = This->offset.LowPart+cb;
849 oldsize = This->stde.pps_size;
850 if (newsize < oldsize) {
851 if (oldsize < 0x1000) {
852 /* only small blocks */
853 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
855 assert(blocknr>=0);
857 /* will set the rest of the chain to 'free' */
858 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
859 return E_FAIL;
860 } else {
861 if (newsize >= 0x1000) {
862 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
863 assert(blocknr>=0);
865 /* will set the rest of the chain to 'free' */
866 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
867 return E_FAIL;
868 } else {
869 /* Migrate large blocks to small blocks
870 * (we just migrate newsize bytes)
872 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
873 cc = newsize;
874 blocknr = This->stde.pps_sb;
875 curdata = data;
876 while (cc>0) {
877 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
878 HeapFree(GetProcessHeap(),0,data);
879 return E_FAIL;
881 curdata += BIGSIZE;
882 cc -= BIGSIZE;
883 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
885 /* frees complete chain for this stream */
886 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
887 return E_FAIL;
888 curdata = data;
889 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
890 if (blocknr<0)
891 return E_FAIL;
892 cc = newsize;
893 while (cc>0) {
894 if (!STORAGE_put_small_block(hf,blocknr,curdata))
895 return E_FAIL;
896 cc -= SMALLSIZE;
897 if (cc<=0) {
898 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
899 return E_FAIL;
900 break;
901 } else {
902 int newblocknr = STORAGE_get_free_small_blocknr(hf);
903 if (newblocknr<0)
904 return E_FAIL;
905 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
906 return E_FAIL;
907 blocknr = newblocknr;
909 curdata += SMALLSIZE;
911 HeapFree(GetProcessHeap(),0,data);
914 This->stde.pps_size = newsize;
917 if (newsize > oldsize) {
918 if (oldsize >= 0x1000) {
919 /* should return the block right before the 'endofchain' */
920 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
921 assert(blocknr>=0);
922 lastblocknr = blocknr;
923 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
924 blocknr = STORAGE_get_free_big_blocknr(hf);
925 if (blocknr<0)
926 return E_FAIL;
927 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
928 return E_FAIL;
929 lastblocknr = blocknr;
931 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
932 return E_FAIL;
933 } else {
934 if (newsize < 0x1000) {
935 /* find startblock */
936 if (!oldsize)
937 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
938 else
939 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
940 if (blocknr<0)
941 return E_FAIL;
943 /* allocate required new small blocks */
944 lastblocknr = blocknr;
945 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
946 blocknr = STORAGE_get_free_small_blocknr(hf);
947 if (blocknr<0)
948 return E_FAIL;
949 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
950 return E_FAIL;
951 lastblocknr = blocknr;
953 /* and terminate the chain */
954 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
955 return E_FAIL;
956 } else {
957 if (!oldsize) {
958 /* no single block allocated yet */
959 blocknr=STORAGE_get_free_big_blocknr(hf);
960 if (blocknr<0)
961 return E_FAIL;
962 This->stde.pps_sb = blocknr;
963 } else {
964 /* Migrate small blocks to big blocks */
965 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
966 cc = oldsize;
967 blocknr = This->stde.pps_sb;
968 curdata = data;
969 /* slurp in */
970 while (cc>0) {
971 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
972 HeapFree(GetProcessHeap(),0,data);
973 return E_FAIL;
975 curdata += SMALLSIZE;
976 cc -= SMALLSIZE;
977 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
979 /* free small block chain */
980 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
981 return E_FAIL;
982 curdata = data;
983 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
984 if (blocknr<0)
985 return E_FAIL;
986 /* put the data into the big blocks */
987 cc = This->stde.pps_size;
988 while (cc>0) {
989 if (!STORAGE_put_big_block(hf,blocknr,curdata))
990 return E_FAIL;
991 cc -= BIGSIZE;
992 if (cc<=0) {
993 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
994 return E_FAIL;
995 break;
996 } else {
997 int newblocknr = STORAGE_get_free_big_blocknr(hf);
998 if (newblocknr<0)
999 return E_FAIL;
1000 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1001 return E_FAIL;
1002 blocknr = newblocknr;
1004 curdata += BIGSIZE;
1006 HeapFree(GetProcessHeap(),0,data);
1008 /* generate big blocks to fit the new data */
1009 lastblocknr = blocknr;
1010 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1011 blocknr = STORAGE_get_free_big_blocknr(hf);
1012 if (blocknr<0)
1013 return E_FAIL;
1014 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1015 return E_FAIL;
1016 lastblocknr = blocknr;
1018 /* terminate chain */
1019 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1020 return E_FAIL;
1023 This->stde.pps_size = newsize;
1026 /* There are just some cases where we didn't modify it, we write it out
1027 * everytime
1029 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1030 return E_FAIL;
1032 /* finally the write pass */
1033 if (This->stde.pps_size < 0x1000) {
1034 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
1035 assert(blocknr>=0);
1036 while (cb>0) {
1037 /* we ensured that it is allocated above */
1038 assert(blocknr>=0);
1039 /* Read old block everytime, since we can have
1040 * overlapping data at START and END of the write
1042 if (!STORAGE_get_small_block(hf,blocknr,block))
1043 return E_FAIL;
1045 cc = SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
1046 if (cc>cb)
1047 cc=cb;
1048 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(SMALLSIZE-1)),
1049 (LPBYTE)(pv+curoffset),
1052 if (!STORAGE_put_small_block(hf,blocknr,block))
1053 return E_FAIL;
1054 cb -= cc;
1055 curoffset += cc;
1056 (LPBYTE)pv += cc;
1057 This->offset.LowPart += cc;
1058 *byteswritten += cc;
1059 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1061 } else {
1062 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
1063 assert(blocknr>=0);
1064 while (cb>0) {
1065 /* we ensured that it is allocated above, so it better is */
1066 assert(blocknr>=0);
1067 /* read old block everytime, since we can have
1068 * overlapping data at START and END of the write
1070 if (!STORAGE_get_big_block(hf,blocknr,block))
1071 return E_FAIL;
1073 cc = BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
1074 if (cc>cb)
1075 cc=cb;
1076 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(BIGSIZE-1)),
1077 (LPBYTE)(pv+curoffset),
1080 if (!STORAGE_put_big_block(hf,blocknr,block))
1081 return E_FAIL;
1082 cb -= cc;
1083 curoffset += cc;
1084 (LPBYTE)pv += cc;
1085 This->offset.LowPart += cc;
1086 *byteswritten += cc;
1087 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1090 return S_OK;
1093 /******************************************************************************
1094 * _create_istream16 [Internal]
1096 static void _create_istream16(LPSTREAM16 *str) {
1097 IStream16Impl* lpst;
1099 if (!strvt16.fnQueryInterface) {
1100 HMODULE16 wp = GetModuleHandle16("STORAGE");
1101 if (wp>=32) {
1102 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1103 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1104 VTENT(QueryInterface);
1105 VTENT(AddRef);
1106 VTENT(Release);
1107 VTENT(Read);
1108 VTENT(Write);
1109 VTENT(Seek);
1110 VTENT(SetSize);
1111 VTENT(CopyTo);
1112 VTENT(Commit);
1113 VTENT(Revert);
1114 VTENT(LockRegion);
1115 VTENT(UnlockRegion);
1116 VTENT(Stat);
1117 VTENT(Clone);
1118 #undef VTENT
1119 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1120 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1121 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1122 } else {
1123 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1124 VTENT(QueryInterface);
1125 VTENT(AddRef);
1126 VTENT(Release);
1127 VTENT(Read);
1128 VTENT(Write);
1129 VTENT(Seek);
1131 VTENT(CopyTo);
1132 VTENT(Commit);
1133 VTENT(SetSize);
1134 VTENT(Revert);
1135 VTENT(LockRegion);
1136 VTENT(UnlockRegion);
1137 VTENT(Stat);
1138 VTENT(Clone);
1140 #undef VTENT
1141 segstrvt16 = &strvt16;
1144 lpst = SEGPTR_NEW(IStream16Impl);
1145 lpst->lpvtbl = segstrvt16;
1146 lpst->ref = 1;
1147 lpst->thisptr = SEGPTR_GET(lpst);
1148 *str = (void*)lpst->thisptr;
1152 /* --- IStream32 implementation */
1154 typedef struct
1156 /* IUnknown fields */
1157 ICOM_VTABLE(IStream)* lpvtbl;
1158 DWORD ref;
1159 /* IStream32 fields */
1160 struct storage_pps_entry stde;
1161 int ppsent;
1162 HFILE hf;
1163 ULARGE_INTEGER offset;
1164 } IStream32Impl;
1166 /*****************************************************************************
1167 * IStream32_QueryInterface [VTABLE]
1169 HRESULT WINAPI IStream_fnQueryInterface(
1170 IStream* iface,REFIID refiid,LPVOID *obj
1172 ICOM_THIS(IStream32Impl,iface);
1173 char xrefiid[50];
1175 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1176 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,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_VTABLE(IStorage16)* lpvtbl;
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);
1229 char xrefiid[50];
1231 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1232 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,obj);
1234 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1235 *obj = This;
1236 return 0;
1238 return OLE_E_ENUM_NOMORE;
1241 /******************************************************************************
1242 * IStorage16_AddRef [STORAGE.501]
1244 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1245 ICOM_THIS(IStorage16Impl,iface);
1246 return ++(This->ref);
1249 /******************************************************************************
1250 * IStorage16_Release [STORAGE.502]
1252 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1253 ICOM_THIS(IStorage16Impl,iface);
1254 This->ref--;
1255 if (This->ref)
1256 return This->ref;
1257 SEGPTR_FREE(This);
1258 return 0;
1261 /******************************************************************************
1262 * IStorage16_Stat [STORAGE.517]
1264 HRESULT WINAPI IStorage16_fnStat(
1265 LPSTORAGE16 iface,STATSTG *pstatstg, DWORD grfStatFlag
1267 ICOM_THIS(IStorage16Impl,iface);
1268 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1269 This,pstatstg,grfStatFlag
1271 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1272 pstatstg->type = This->stde.pps_type;
1273 pstatstg->cbSize.LowPart = This->stde.pps_size;
1274 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1275 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1276 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1277 pstatstg->grfMode = 0; /* FIXME */
1278 pstatstg->grfLocksSupported = 0; /* FIXME */
1279 pstatstg->clsid = This->stde.pps_guid;
1280 pstatstg->grfStateBits = 0; /* FIXME */
1281 pstatstg->reserved = 0;
1282 return S_OK;
1285 /******************************************************************************
1286 * IStorage16_Commit [STORAGE.509]
1288 HRESULT WINAPI IStorage16_fnCommit(
1289 LPSTORAGE16 iface,DWORD commitflags
1291 ICOM_THIS(IStorage16Impl,iface);
1292 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1293 This,commitflags
1295 return S_OK;
1298 /******************************************************************************
1299 * IStorage16_CopyTo [STORAGE.507]
1301 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1302 ICOM_THIS(IStorage16Impl,iface);
1303 char xguid[50];
1305 if (rgiidExclude)
1306 WINE_StringFromCLSID(rgiidExclude,xguid);
1307 else
1308 strcpy(xguid,"<no guid>");
1309 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1310 This,ciidExclude,xguid,SNB16Exclude,pstgDest
1312 return S_OK;
1316 /******************************************************************************
1317 * IStorage16_CreateStorage [STORAGE.505]
1319 HRESULT WINAPI IStorage16_fnCreateStorage(
1320 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1322 ICOM_THIS(IStorage16Impl,iface);
1323 IStorage16Impl* lpstg;
1324 int ppsent,x;
1325 struct storage_pps_entry stde;
1326 struct storage_header sth;
1327 HFILE hf=This->hf;
1329 READ_HEADER;
1331 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1332 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1334 if (grfMode & STGM_TRANSACTED)
1335 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1336 _create_istorage16(ppstg);
1337 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1338 lpstg->hf = This->hf;
1340 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1341 if (ppsent<0)
1342 return E_FAIL;
1343 stde=This->stde;
1344 if (stde.pps_dir==-1) {
1345 stde.pps_dir = ppsent;
1346 x = This->ppsent;
1347 } else {
1348 FIXME(ole," use prev chain too ?\n");
1349 x=stde.pps_dir;
1350 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1351 return E_FAIL;
1352 while (stde.pps_next!=-1) {
1353 x=stde.pps_next;
1354 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1355 return E_FAIL;
1357 stde.pps_next = ppsent;
1359 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1360 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1361 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1362 lpstg->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1363 lpstg->stde.pps_next = -1;
1364 lpstg->stde.pps_prev = -1;
1365 lpstg->stde.pps_dir = -1;
1366 lpstg->stde.pps_sb = -1;
1367 lpstg->stde.pps_size = 0;
1368 lpstg->stde.pps_type = 1;
1369 lpstg->ppsent = ppsent;
1370 /* FIXME: timestamps? */
1371 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1372 return E_FAIL;
1373 return S_OK;
1376 /******************************************************************************
1377 * IStorage16_CreateStream [STORAGE.503]
1379 HRESULT WINAPI IStorage16_fnCreateStream(
1380 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1382 ICOM_THIS(IStorage16Impl,iface);
1383 IStream16Impl* lpstr;
1384 int ppsent,x;
1385 struct storage_pps_entry stde;
1387 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1388 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1390 if (grfMode & STGM_TRANSACTED)
1391 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1392 _create_istream16(ppstm);
1393 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1394 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1395 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1396 lpstr->offset.LowPart = 0;
1397 lpstr->offset.HighPart = 0;
1399 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1400 if (ppsent<0)
1401 return E_FAIL;
1402 stde=This->stde;
1403 if (stde.pps_next==-1)
1404 x=This->ppsent;
1405 else
1406 while (stde.pps_next!=-1) {
1407 x=stde.pps_next;
1408 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1409 return E_FAIL;
1411 stde.pps_next = ppsent;
1412 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1413 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1414 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1415 lpstr->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1416 lpstr->stde.pps_next = -1;
1417 lpstr->stde.pps_prev = -1;
1418 lpstr->stde.pps_dir = -1;
1419 lpstr->stde.pps_sb = -1;
1420 lpstr->stde.pps_size = 0;
1421 lpstr->stde.pps_type = 2;
1422 lpstr->ppsent = ppsent;
1423 /* FIXME: timestamps? */
1424 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1425 return E_FAIL;
1426 return S_OK;
1429 /******************************************************************************
1430 * IStorage16_OpenStorage [STORAGE.506]
1432 HRESULT WINAPI IStorage16_fnOpenStorage(
1433 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1435 ICOM_THIS(IStorage16Impl,iface);
1436 IStream16Impl* lpstg;
1437 WCHAR name[33];
1438 int newpps;
1440 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1441 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1443 if (grfMode & STGM_TRANSACTED)
1444 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1445 _create_istorage16(ppstg);
1446 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1447 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1448 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1449 lstrcpyAtoW(name,pwcsName);
1450 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1451 if (newpps==-1) {
1452 IStream16_fnRelease((IStream16*)lpstg);
1453 return E_FAIL;
1456 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1457 IStream16_fnRelease((IStream16*)lpstg);
1458 return E_FAIL;
1460 lpstg->ppsent = newpps;
1461 return S_OK;
1464 /******************************************************************************
1465 * IStorage16_OpenStream [STORAGE.504]
1467 HRESULT WINAPI IStorage16_fnOpenStream(
1468 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1470 ICOM_THIS(IStorage16Impl,iface);
1471 IStream16Impl* lpstr;
1472 WCHAR name[33];
1473 int newpps;
1475 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1476 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1478 if (grfMode & STGM_TRANSACTED)
1479 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1480 _create_istream16(ppstm);
1481 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1482 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1483 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1484 lstrcpyAtoW(name,pwcsName);
1485 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1486 if (newpps==-1) {
1487 IStream16_fnRelease((IStream16*)lpstr);
1488 return E_FAIL;
1491 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1492 IStream16_fnRelease((IStream16*)lpstr);
1493 return E_FAIL;
1495 lpstr->offset.LowPart = 0;
1496 lpstr->offset.HighPart = 0;
1497 lpstr->ppsent = newpps;
1498 return S_OK;
1501 /******************************************************************************
1502 * _create_istorage16 [INTERNAL]
1504 static void _create_istorage16(LPSTORAGE16 *stg) {
1505 IStorage16Impl* lpst;
1507 if (!stvt16.fnQueryInterface) {
1508 HMODULE16 wp = GetModuleHandle16("STORAGE");
1509 if (wp>=32) {
1510 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1511 VTENT(QueryInterface)
1512 VTENT(AddRef)
1513 VTENT(Release)
1514 VTENT(CreateStream)
1515 VTENT(OpenStream)
1516 VTENT(CreateStorage)
1517 VTENT(OpenStorage)
1518 VTENT(CopyTo)
1519 VTENT(MoveElementTo)
1520 VTENT(Commit)
1521 VTENT(Revert)
1522 VTENT(EnumElements)
1523 VTENT(DestroyElement)
1524 VTENT(RenameElement)
1525 VTENT(SetElementTimes)
1526 VTENT(SetClass)
1527 VTENT(SetStateBits)
1528 VTENT(Stat)
1529 #undef VTENT
1530 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1531 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1532 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1533 } else {
1534 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1535 VTENT(QueryInterface)
1536 VTENT(AddRef)
1537 VTENT(Release)
1538 VTENT(CreateStream)
1539 VTENT(OpenStream)
1540 VTENT(CreateStorage)
1541 VTENT(OpenStorage)
1542 VTENT(CopyTo)
1543 VTENT(Commit)
1544 /* not (yet) implemented ...
1545 VTENT(MoveElementTo)
1546 VTENT(Revert)
1547 VTENT(EnumElements)
1548 VTENT(DestroyElement)
1549 VTENT(RenameElement)
1550 VTENT(SetElementTimes)
1551 VTENT(SetClass)
1552 VTENT(SetStateBits)
1553 VTENT(Stat)
1555 #undef VTENT
1556 segstvt16 = &stvt16;
1559 lpst = SEGPTR_NEW(IStorage16Impl);
1560 lpst->lpvtbl = segstvt16;
1561 lpst->ref = 1;
1562 lpst->thisptr = SEGPTR_GET(lpst);
1563 *stg = (void*)lpst->thisptr;
1566 /******************************************************************************
1567 * Storage API functions
1570 /******************************************************************************
1571 * StgCreateDocFile16 [STORAGE.1]
1573 HRESULT WINAPI StgCreateDocFile16(
1574 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1576 HFILE hf;
1577 int i,ret;
1578 IStorage16Impl* lpstg;
1579 struct storage_pps_entry stde;
1581 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1582 pwcsName,grfMode,reserved,ppstgOpen
1584 _create_istorage16(ppstgOpen);
1585 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1586 if (hf==INVALID_HANDLE_VALUE) {
1587 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1588 return E_FAIL;
1590 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1591 lpstg->hf = hf;
1592 /* FIXME: check for existance before overwriting? */
1593 if (!STORAGE_init_storage(hf)) {
1594 CloseHandle(hf);
1595 return E_FAIL;
1597 i=0;ret=0;
1598 while (!ret) { /* neither 1 nor <0 */
1599 ret=STORAGE_get_pps_entry(hf,i,&stde);
1600 if ((ret==1) && (stde.pps_type==5)) {
1601 lpstg->stde = stde;
1602 lpstg->ppsent = i;
1603 break;
1605 i++;
1607 if (ret!=1) {
1608 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1609 return E_FAIL;
1612 return S_OK;
1615 /******************************************************************************
1616 * StgIsStorageFile16 [STORAGE.5]
1618 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1619 HFILE hf;
1620 OFSTRUCT ofs;
1621 BYTE magic[24];
1623 TRACE(ole,"(\'%s\')\n",fn);
1624 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1625 if (hf==HFILE_ERROR)
1626 return STG_E_FILENOTFOUND;
1627 if (24!=_lread(hf,magic,24)) {
1628 WARN(ole," too short\n");
1629 _lclose(hf);
1630 return S_FALSE;
1632 if (!memcmp(magic,STORAGE_magic,8)) {
1633 WARN(ole," -> YES\n");
1634 _lclose(hf);
1635 return S_OK;
1637 if (!memcmp(magic,STORAGE_notmagic,8)) {
1638 WARN(ole," -> NO\n");
1639 _lclose(hf);
1640 return S_FALSE;
1642 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1643 WARN(ole," -> old format\n");
1644 _lclose(hf);
1645 return STG_E_OLDFORMAT;
1647 WARN(ole," -> Invalid header.\n");
1648 _lclose(hf);
1649 return STG_E_INVALIDHEADER;
1652 /******************************************************************************
1653 * StgIsStorageFile32 [OLE32.146]
1655 HRESULT WINAPI
1656 StgIsStorageFile(LPCOLESTR fn)
1658 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1659 OLESTATUS ret = StgIsStorageFile16(xfn);
1661 HeapFree(GetProcessHeap(),0,xfn);
1662 return ret;
1666 /******************************************************************************
1667 * StgOpenStorage16 [STORAGE.3]
1669 HRESULT WINAPI StgOpenStorage16(
1670 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1671 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1673 HFILE hf;
1674 int ret,i;
1675 IStorage16Impl* lpstg;
1676 struct storage_pps_entry stde;
1678 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1679 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1681 _create_istorage16(ppstgOpen);
1682 hf = CreateFileA(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1683 if (hf==INVALID_HANDLE_VALUE) {
1684 WARN(ole,"Couldn't open file for storage\n");
1685 return E_FAIL;
1687 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1688 lpstg->hf = hf;
1690 i=0;ret=0;
1691 while (!ret) { /* neither 1 nor <0 */
1692 ret=STORAGE_get_pps_entry(hf,i,&stde);
1693 if ((ret==1) && (stde.pps_type==5)) {
1694 lpstg->stde=stde;
1695 break;
1697 i++;
1699 if (ret!=1) {
1700 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1701 return E_FAIL;
1703 return S_OK;