MCI_OPEN_DRIVER_PARMS - Add win32 version of structure.
[wine.git] / ole / storage.c
blob0e29d7d311304fbfc27f0ca64329868fd0402ef3
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 "heap.h"
22 #include "module.h"
23 #include "ldt.h"
24 #include "debug.h"
26 struct storage_header {
27 BYTE magic[8]; /* 00: magic */
28 BYTE unknown1[36]; /* 08: unknown */
29 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
30 DWORD root_startblock;/* 30: root storage first big block */
31 DWORD unknown2[2]; /* 34: unknown */
32 DWORD sbd_startblock; /* 3C: small block depot first big block */
33 DWORD unknown3[3]; /* 40: unknown */
34 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
36 struct storage_pps_entry {
37 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
38 WORD pps_sizeofname; /* 40: namelength in bytes */
39 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
40 BYTE pps_unknown0; /* 43: unknown */
41 DWORD pps_prev; /* 44: previous pps */
42 DWORD pps_next; /* 48: next pps */
43 DWORD pps_dir; /* 4C: directory pps */
44 GUID pps_guid; /* 50: class ID */
45 DWORD pps_unknown1; /* 60: unknown */
46 FILETIME pps_ft1; /* 64: filetime1 */
47 FILETIME pps_ft2; /* 70: filetime2 */
48 DWORD pps_sb; /* 74: data startblock */
49 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
50 DWORD pps_unknown2; /* 7C: unknown */
53 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
54 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
55 #define STORAGE_CHAINENTRY_FREE 0xffffffff
58 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
59 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
60 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
62 #define BIGSIZE 512
63 #define SMALLSIZE 64
65 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
67 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
68 static ICOM_VTABLE(IStorage16) stvt16;
69 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
70 static ICOM_VTABLE(IStream16) strvt16;
71 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
73 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
74 static void _create_istorage16(LPSTORAGE16 *stg);
75 static void _create_istream16(LPSTREAM16 *str);
77 #define IMPLEMENTED 1
80 /******************************************************************************
81 * STORAGE_get_big_block [Internal]
83 * Reading OLE compound storage
85 static BOOL
86 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
87 assert(n>=-1);
88 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
89 WARN(ole," seek failed (%ld)\n",GetLastError());
90 return FALSE;
92 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
93 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
94 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
95 assert(0);
96 return FALSE;
98 return TRUE;
101 /******************************************************************************
102 * STORAGE_put_big_block [INTERNAL]
104 static BOOL
105 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
106 assert(n>=-1);
107 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
108 WARN(ole," seek failed (%ld)\n",GetLastError());
109 return FALSE;
111 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
112 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
113 WARN(ole," write failed (%ld)\n",GetLastError());
114 return FALSE;
116 return TRUE;
119 /******************************************************************************
120 * STORAGE_get_next_big_blocknr [INTERNAL]
122 static int
123 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
124 INT bbs[BIGSIZE/sizeof(INT)];
125 struct storage_header sth;
127 READ_HEADER;
129 assert(blocknr>>7<sth.num_of_bbd_blocks);
130 if (sth.bbd_list[blocknr>>7]==0xffffffff)
131 return -5;
132 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
133 return -5;
134 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
135 return bbs[blocknr&0x7f];
138 /******************************************************************************
139 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
141 static int
142 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
143 INT bbs[BIGSIZE/sizeof(INT)];
144 int lastblock = -1;
145 struct storage_header sth;
147 READ_HEADER;
149 assert(blocknr>=0);
150 while (nr--) {
151 assert((blocknr>>7)<sth.num_of_bbd_blocks);
152 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
154 /* simple caching... */
155 if (lastblock!=sth.bbd_list[blocknr>>7]) {
156 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
157 lastblock = sth.bbd_list[blocknr>>7];
159 blocknr = bbs[blocknr&0x7f];
161 return blocknr;
164 /******************************************************************************
165 * STORAGE_get_root_pps_entry [Internal]
167 static BOOL
168 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
169 int blocknr,i;
170 BYTE block[BIGSIZE];
171 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
172 struct storage_header sth;
174 READ_HEADER;
175 blocknr = sth.root_startblock;
176 while (blocknr>=0) {
177 assert(STORAGE_get_big_block(hf,blocknr,block));
178 for (i=0;i<4;i++) {
179 if (!stde[i].pps_sizeofname)
180 continue;
181 if (stde[i].pps_type==5) {
182 *pstde=stde[i];
183 return TRUE;
186 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
188 return FALSE;
191 /******************************************************************************
192 * STORAGE_get_small_block [INTERNAL]
194 static BOOL
195 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
196 BYTE block[BIGSIZE];
197 int bigblocknr;
198 struct storage_pps_entry root;
200 assert(blocknr>=0);
201 assert(STORAGE_get_root_pps_entry(hf,&root));
202 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
203 assert(bigblocknr>=0);
204 assert(STORAGE_get_big_block(hf,bigblocknr,block));
206 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
207 return TRUE;
210 /******************************************************************************
211 * STORAGE_put_small_block [INTERNAL]
213 static BOOL
214 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
215 BYTE block[BIGSIZE];
216 int bigblocknr;
217 struct storage_pps_entry root;
219 assert(blocknr>=0);
221 assert(STORAGE_get_root_pps_entry(hf,&root));
222 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
223 assert(bigblocknr>=0);
224 assert(STORAGE_get_big_block(hf,bigblocknr,block));
226 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
227 assert(STORAGE_put_big_block(hf,bigblocknr,block));
228 return TRUE;
231 /******************************************************************************
232 * STORAGE_get_next_small_blocknr [INTERNAL]
234 static int
235 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
236 BYTE block[BIGSIZE];
237 LPINT sbd = (LPINT)block;
238 int bigblocknr;
239 struct storage_header sth;
241 READ_HEADER;
242 assert(blocknr>=0);
243 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
244 assert(bigblocknr>=0);
245 assert(STORAGE_get_big_block(hf,bigblocknr,block));
246 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
247 return sbd[blocknr & (128-1)];
250 /******************************************************************************
251 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
253 static int
254 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
255 int lastblocknr;
256 BYTE block[BIGSIZE];
257 LPINT sbd = (LPINT)block;
258 struct storage_header sth;
260 READ_HEADER;
261 lastblocknr=-1;
262 assert(blocknr>=0);
263 while ((nr--) && (blocknr>=0)) {
264 if (lastblocknr/128!=blocknr/128) {
265 int bigblocknr;
266 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
267 assert(bigblocknr>=0);
268 assert(STORAGE_get_big_block(hf,bigblocknr,block));
269 lastblocknr = blocknr;
271 assert(lastblocknr>=0);
272 lastblocknr=blocknr;
273 blocknr=sbd[blocknr & (128-1)];
274 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
276 return blocknr;
279 /******************************************************************************
280 * STORAGE_get_pps_entry [INTERNAL]
282 static int
283 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
284 int blocknr;
285 BYTE block[BIGSIZE];
286 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
287 struct storage_header sth;
289 READ_HEADER;
290 /* we have 4 pps entries per big block */
291 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
292 assert(blocknr>=0);
293 assert(STORAGE_get_big_block(hf,blocknr,block));
295 *pstde=*stde;
296 return 1;
299 /******************************************************************************
300 * STORAGE_put_pps_entry [Internal]
302 static int
303 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
304 int blocknr;
305 BYTE block[BIGSIZE];
306 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
307 struct storage_header sth;
309 READ_HEADER;
311 /* we have 4 pps entries per big block */
312 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
313 assert(blocknr>=0);
314 assert(STORAGE_get_big_block(hf,blocknr,block));
315 *stde=*pstde;
316 assert(STORAGE_put_big_block(hf,blocknr,block));
317 return 1;
320 /******************************************************************************
321 * STORAGE_look_for_named_pps [Internal]
323 static int
324 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
325 struct storage_pps_entry stde;
326 int ret;
328 if (n==-1)
329 return -1;
330 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
331 return -1;
333 if (!lstrcmpW(name,stde.pps_rawname))
334 return n;
335 if (stde.pps_prev != -1) {
336 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
337 if (ret!=-1)
338 return ret;
340 if (stde.pps_next != -1) {
341 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
342 if (ret!=-1)
343 return ret;
345 return -1;
348 /******************************************************************************
349 * STORAGE_dump_pps_entry [Internal]
351 * FIXME
352 * Function is unused
354 void
355 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
356 char name[33],xguid[50];
358 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
360 lstrcpyWtoA(name,stde->pps_rawname);
361 if (!stde->pps_sizeofname)
362 return;
363 DUMP("name: %s\n",name);
364 DUMP("type: %d\n",stde->pps_type);
365 DUMP("prev pps: %ld\n",stde->pps_prev);
366 DUMP("next pps: %ld\n",stde->pps_next);
367 DUMP("dir pps: %ld\n",stde->pps_dir);
368 DUMP("guid: %s\n",xguid);
369 if (stde->pps_type !=2) {
370 time_t t;
372 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
373 DUMP("ts1: %s\n",ctime(&t));
374 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
375 DUMP("ts2: %s\n",ctime(&t));
377 DUMP("startblock: %ld\n",stde->pps_sb);
378 DUMP("size: %ld\n",stde->pps_size);
381 /******************************************************************************
382 * STORAGE_init_storage [INTERNAL]
384 static BOOL
385 STORAGE_init_storage(HFILE hf) {
386 BYTE block[BIGSIZE];
387 LPDWORD bbs;
388 struct storage_header *sth;
389 struct storage_pps_entry *stde;
391 assert(-1!=_llseek(hf,0,SEEK_SET));
392 /* block -1 is the storage header */
393 sth = (struct storage_header*)block;
394 memcpy(sth->magic,STORAGE_magic,8);
395 memset(sth->unknown1,0,sizeof(sth->unknown1));
396 memset(sth->unknown2,0,sizeof(sth->unknown2));
397 memset(sth->unknown3,0,sizeof(sth->unknown3));
398 sth->num_of_bbd_blocks = 1;
399 sth->root_startblock = 1;
400 sth->sbd_startblock = 0xffffffff;
401 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
402 sth->bbd_list[0] = 0;
403 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
404 /* block 0 is the big block directory */
405 bbs=(LPDWORD)block;
406 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
407 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
408 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
409 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
410 /* block 1 is the root directory entry */
411 memset(block,0x00,sizeof(block));
412 stde = (struct storage_pps_entry*)block;
413 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
414 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
415 stde->pps_type = 5;
416 stde->pps_dir = -1;
417 stde->pps_next = -1;
418 stde->pps_prev = -1;
419 stde->pps_sb = 0xffffffff;
420 stde->pps_size = 0;
421 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
422 return TRUE;
425 /******************************************************************************
426 * STORAGE_set_big_chain [Internal]
428 static BOOL
429 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
430 BYTE block[BIGSIZE];
431 LPINT bbd = (LPINT)block;
432 int nextblocknr,bigblocknr;
433 struct storage_header sth;
435 READ_HEADER;
436 assert(blocknr!=type);
437 while (blocknr>=0) {
438 bigblocknr = sth.bbd_list[blocknr/128];
439 assert(bigblocknr>=0);
440 assert(STORAGE_get_big_block(hf,bigblocknr,block));
442 nextblocknr = bbd[blocknr&(128-1)];
443 bbd[blocknr&(128-1)] = type;
444 if (type>=0)
445 return TRUE;
446 assert(STORAGE_put_big_block(hf,bigblocknr,block));
447 type = STORAGE_CHAINENTRY_FREE;
448 blocknr = nextblocknr;
450 return TRUE;
453 /******************************************************************************
454 * STORAGE_set_small_chain [Internal]
456 static BOOL
457 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
458 BYTE block[BIGSIZE];
459 LPINT sbd = (LPINT)block;
460 int lastblocknr,nextsmallblocknr,bigblocknr;
461 struct storage_header sth;
463 READ_HEADER;
465 assert(blocknr!=type);
466 lastblocknr=-129;bigblocknr=-2;
467 while (blocknr>=0) {
468 /* cache block ... */
469 if (lastblocknr/128!=blocknr/128) {
470 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
471 assert(bigblocknr>=0);
472 assert(STORAGE_get_big_block(hf,bigblocknr,block));
474 lastblocknr = blocknr;
475 nextsmallblocknr = sbd[blocknr&(128-1)];
476 sbd[blocknr&(128-1)] = type;
477 assert(STORAGE_put_big_block(hf,bigblocknr,block));
478 if (type>=0)
479 return TRUE;
480 type = STORAGE_CHAINENTRY_FREE;
481 blocknr = nextsmallblocknr;
483 return TRUE;
486 /******************************************************************************
487 * STORAGE_get_free_big_blocknr [Internal]
489 static int
490 STORAGE_get_free_big_blocknr(HFILE hf) {
491 BYTE block[BIGSIZE];
492 LPINT sbd = (LPINT)block;
493 int lastbigblocknr,i,curblock,bigblocknr;
494 struct storage_header sth;
496 READ_HEADER;
497 curblock = 0;
498 lastbigblocknr = -1;
499 bigblocknr = sth.bbd_list[curblock];
500 while (curblock<sth.num_of_bbd_blocks) {
501 assert(bigblocknr>=0);
502 assert(STORAGE_get_big_block(hf,bigblocknr,block));
503 for (i=0;i<128;i++)
504 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
505 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
506 assert(STORAGE_put_big_block(hf,bigblocknr,block));
507 memset(block,0x42,sizeof(block));
508 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
509 return i+curblock*128;
511 lastbigblocknr = bigblocknr;
512 bigblocknr = sth.bbd_list[++curblock];
514 bigblocknr = curblock*128;
515 /* since we have marked all blocks from 0 up to curblock*128-1
516 * the next free one is curblock*128, where we happily put our
517 * next large block depot.
519 memset(block,0xff,sizeof(block));
520 /* mark the block allocated and returned by this function */
521 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
522 assert(STORAGE_put_big_block(hf,bigblocknr,block));
524 /* if we had a bbd block already (mostlikely) we need
525 * to link the new one into the chain
527 if (lastbigblocknr!=-1)
528 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
529 sth.bbd_list[curblock]=bigblocknr;
530 sth.num_of_bbd_blocks++;
531 assert(sth.num_of_bbd_blocks==curblock+1);
532 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
534 /* Set the end of the chain for the bigblockdepots */
535 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
536 /* add 1, for the first entry is used for the additional big block
537 * depot. (means we already used bigblocknr) */
538 memset(block,0x42,sizeof(block));
539 /* allocate this block (filled with 0x42) */
540 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
541 return bigblocknr+1;
545 /******************************************************************************
546 * STORAGE_get_free_small_blocknr [Internal]
548 static int
549 STORAGE_get_free_small_blocknr(HFILE hf) {
550 BYTE block[BIGSIZE];
551 LPINT sbd = (LPINT)block;
552 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
553 struct storage_pps_entry root;
554 struct storage_header sth;
556 READ_HEADER;
557 bigblocknr = sth.sbd_startblock;
558 curblock = 0;
559 lastbigblocknr = -1;
560 newblocknr = -1;
561 while (bigblocknr>=0) {
562 if (!STORAGE_get_big_block(hf,bigblocknr,block))
563 return -1;
564 for (i=0;i<128;i++)
565 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
566 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
567 newblocknr = i+curblock*128;
568 break;
570 if (i!=128)
571 break;
572 lastbigblocknr = bigblocknr;
573 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
574 curblock++;
576 if (newblocknr==-1) {
577 bigblocknr = STORAGE_get_free_big_blocknr(hf);
578 if (bigblocknr<0)
579 return -1;
580 READ_HEADER;
581 memset(block,0xff,sizeof(block));
582 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
583 if (!STORAGE_put_big_block(hf,bigblocknr,block))
584 return -1;
585 if (lastbigblocknr==-1) {
586 sth.sbd_startblock = bigblocknr;
587 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
588 return -1;
589 } else {
590 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
591 return -1;
593 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
594 return -1;
595 newblocknr = curblock*128;
597 /* allocate enough big blocks for storing the allocated small block */
598 if (!STORAGE_get_root_pps_entry(hf,&root))
599 return -1;
600 if (root.pps_sb==-1)
601 lastbigblocknr = -1;
602 else
603 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
604 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
605 /* we need to allocate more stuff */
606 bigblocknr = STORAGE_get_free_big_blocknr(hf);
607 if (bigblocknr<0)
608 return -1;
609 READ_HEADER;
610 if (root.pps_sb==-1) {
611 root.pps_sb = bigblocknr;
612 root.pps_size += BIGSIZE;
613 } else {
614 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
615 return -1;
616 root.pps_size += BIGSIZE;
618 lastbigblocknr = bigblocknr;
620 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
621 return -1;
622 if (!STORAGE_put_pps_entry(hf,0,&root))
623 return -1;
624 return newblocknr;
627 /******************************************************************************
628 * STORAGE_get_free_pps_entry [Internal]
630 static int
631 STORAGE_get_free_pps_entry(HFILE hf) {
632 int blocknr,i,curblock,lastblocknr;
633 BYTE block[BIGSIZE];
634 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
635 struct storage_header sth;
637 READ_HEADER;
638 blocknr = sth.root_startblock;
639 assert(blocknr>=0);
640 curblock=0;
641 while (blocknr>=0) {
642 if (!STORAGE_get_big_block(hf,blocknr,block))
643 return -1;
644 for (i=0;i<4;i++)
645 if (stde[i].pps_sizeofname==0) /* free */
646 return curblock*4+i;
647 lastblocknr = blocknr;
648 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
649 curblock++;
651 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
652 blocknr = STORAGE_get_free_big_blocknr(hf);
653 /* sth invalidated */
654 if (blocknr<0)
655 return -1;
657 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
658 return -1;
659 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
660 return -1;
661 memset(block,0,sizeof(block));
662 STORAGE_put_big_block(hf,blocknr,block);
663 return curblock*4;
666 /* --- IStream16 implementation */
668 typedef struct
670 /* IUnknown fields */
671 ICOM_VTABLE(IStream16)* lpvtbl;
672 DWORD ref;
673 /* IStream16 fields */
674 SEGPTR thisptr; /* pointer to this struct as segmented */
675 struct storage_pps_entry stde;
676 int ppsent;
677 HFILE hf;
678 ULARGE_INTEGER offset;
679 } IStream16Impl;
681 /******************************************************************************
682 * IStream16_QueryInterface [STORAGE.518]
684 HRESULT WINAPI IStream16_fnQueryInterface(
685 IStream16* iface,REFIID refiid,LPVOID *obj
687 ICOM_THIS(IStream16Impl,iface);
688 char xrefiid[50];
689 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
690 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,obj);
691 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
692 *obj = This;
693 return 0;
695 return OLE_E_ENUM_NOMORE;
699 /******************************************************************************
700 * IStream16_AddRef [STORAGE.519]
702 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
703 ICOM_THIS(IStream16Impl,iface);
704 return ++(This->ref);
707 /******************************************************************************
708 * IStream16_Release [STORAGE.520]
710 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
711 ICOM_THIS(IStream16Impl,iface);
712 FlushFileBuffers(This->hf);
713 This->ref--;
714 if (!This->ref) {
715 CloseHandle(This->hf);
716 SEGPTR_FREE(This);
717 return 0;
719 return This->ref;
722 /******************************************************************************
723 * IStream16_Seek [STORAGE.523]
725 * FIXME
726 * Does not handle 64 bits
728 HRESULT WINAPI IStream16_fnSeek(
729 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
731 ICOM_THIS(IStream16Impl,iface);
732 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",This,offset.HighPart,offset.LowPart,whence,newpos);
734 switch (whence) {
735 /* unix SEEK_xx should be the same as win95 ones */
736 case SEEK_SET:
737 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
738 * right now.
740 assert(offset.HighPart==0);
741 This->offset.HighPart = offset.HighPart;
742 This->offset.LowPart = offset.LowPart;
743 break;
744 case SEEK_CUR:
745 if (offset.HighPart < 0) {
746 /* FIXME: is this negation correct ? */
747 offset.HighPart = -offset.HighPart;
748 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
750 assert(offset.HighPart==0);
751 assert(This->offset.LowPart >= offset.LowPart);
752 This->offset.LowPart -= offset.LowPart;
753 } else {
754 assert(offset.HighPart==0);
755 This->offset.LowPart+= offset.LowPart;
757 break;
758 case SEEK_END:
759 assert(offset.HighPart==0);
760 This->offset.LowPart = This->stde.pps_size-offset.LowPart;
761 break;
763 if (This->offset.LowPart>This->stde.pps_size)
764 This->offset.LowPart=This->stde.pps_size;
765 if (newpos) *newpos = This->offset;
766 return S_OK;
769 /******************************************************************************
770 * IStream16_Read [STORAGE.521]
772 HRESULT WINAPI IStream16_fnRead(
773 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
775 ICOM_THIS(IStream16Impl,iface);
776 BYTE block[BIGSIZE];
777 ULONG *bytesread=pcbRead,xxread;
778 int blocknr;
780 TRACE(relay,"(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
781 if (!pcbRead) bytesread=&xxread;
782 *bytesread = 0;
784 if (cb>This->stde.pps_size-This->offset.LowPart)
785 cb=This->stde.pps_size-This->offset.LowPart;
786 if (This->stde.pps_size < 0x1000) {
787 /* use small block reader */
788 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
789 while (cb) {
790 int cc;
792 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
793 WARN(ole,"small block read failed!!!\n");
794 return E_FAIL;
796 cc = cb;
797 if (cc>SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1)))
798 cc=SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
799 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(SMALLSIZE-1)),cc);
800 This->offset.LowPart+=cc;
801 (LPBYTE)pv+=cc;
802 *bytesread+=cc;
803 cb-=cc;
804 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
806 } else {
807 /* use big block reader */
808 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
809 while (cb) {
810 int cc;
812 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
813 WARN(ole,"big block read failed!!!\n");
814 return E_FAIL;
816 cc = cb;
817 if (cc>BIGSIZE-(This->offset.LowPart&(BIGSIZE-1)))
818 cc=BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
819 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(BIGSIZE-1)),cc);
820 This->offset.LowPart+=cc;
821 (LPBYTE)pv+=cc;
822 *bytesread+=cc;
823 cb-=cc;
824 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
827 return S_OK;
830 /******************************************************************************
831 * IStream16_Write [STORAGE.522]
833 HRESULT WINAPI IStream16_fnWrite(
834 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
836 ICOM_THIS(IStream16Impl,iface);
837 BYTE block[BIGSIZE];
838 ULONG *byteswritten=pcbWrite,xxwritten;
839 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
840 HFILE hf = This->hf;
842 if (!pcbWrite) byteswritten=&xxwritten;
843 *byteswritten = 0;
845 TRACE(relay,"(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
846 /* do we need to junk some blocks? */
847 newsize = This->offset.LowPart+cb;
848 oldsize = This->stde.pps_size;
849 if (newsize < oldsize) {
850 if (oldsize < 0x1000) {
851 /* only small blocks */
852 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
854 assert(blocknr>=0);
856 /* will set the rest of the chain to 'free' */
857 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
858 return E_FAIL;
859 } else {
860 if (newsize >= 0x1000) {
861 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
862 assert(blocknr>=0);
864 /* will set the rest of the chain to 'free' */
865 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
866 return E_FAIL;
867 } else {
868 /* Migrate large blocks to small blocks
869 * (we just migrate newsize bytes)
871 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
872 cc = newsize;
873 blocknr = This->stde.pps_sb;
874 curdata = data;
875 while (cc>0) {
876 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
877 HeapFree(GetProcessHeap(),0,data);
878 return E_FAIL;
880 curdata += BIGSIZE;
881 cc -= BIGSIZE;
882 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
884 /* frees complete chain for this stream */
885 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
886 return E_FAIL;
887 curdata = data;
888 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
889 if (blocknr<0)
890 return E_FAIL;
891 cc = newsize;
892 while (cc>0) {
893 if (!STORAGE_put_small_block(hf,blocknr,curdata))
894 return E_FAIL;
895 cc -= SMALLSIZE;
896 if (cc<=0) {
897 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
898 return E_FAIL;
899 break;
900 } else {
901 int newblocknr = STORAGE_get_free_small_blocknr(hf);
902 if (newblocknr<0)
903 return E_FAIL;
904 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
905 return E_FAIL;
906 blocknr = newblocknr;
908 curdata += SMALLSIZE;
910 HeapFree(GetProcessHeap(),0,data);
913 This->stde.pps_size = newsize;
916 if (newsize > oldsize) {
917 if (oldsize >= 0x1000) {
918 /* should return the block right before the 'endofchain' */
919 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
920 assert(blocknr>=0);
921 lastblocknr = blocknr;
922 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
923 blocknr = STORAGE_get_free_big_blocknr(hf);
924 if (blocknr<0)
925 return E_FAIL;
926 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
927 return E_FAIL;
928 lastblocknr = blocknr;
930 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
931 return E_FAIL;
932 } else {
933 if (newsize < 0x1000) {
934 /* find startblock */
935 if (!oldsize)
936 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
937 else
938 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
939 if (blocknr<0)
940 return E_FAIL;
942 /* allocate required new small blocks */
943 lastblocknr = blocknr;
944 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
945 blocknr = STORAGE_get_free_small_blocknr(hf);
946 if (blocknr<0)
947 return E_FAIL;
948 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
949 return E_FAIL;
950 lastblocknr = blocknr;
952 /* and terminate the chain */
953 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
954 return E_FAIL;
955 } else {
956 if (!oldsize) {
957 /* no single block allocated yet */
958 blocknr=STORAGE_get_free_big_blocknr(hf);
959 if (blocknr<0)
960 return E_FAIL;
961 This->stde.pps_sb = blocknr;
962 } else {
963 /* Migrate small blocks to big blocks */
964 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
965 cc = oldsize;
966 blocknr = This->stde.pps_sb;
967 curdata = data;
968 /* slurp in */
969 while (cc>0) {
970 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
971 HeapFree(GetProcessHeap(),0,data);
972 return E_FAIL;
974 curdata += SMALLSIZE;
975 cc -= SMALLSIZE;
976 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
978 /* free small block chain */
979 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
980 return E_FAIL;
981 curdata = data;
982 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
983 if (blocknr<0)
984 return E_FAIL;
985 /* put the data into the big blocks */
986 cc = This->stde.pps_size;
987 while (cc>0) {
988 if (!STORAGE_put_big_block(hf,blocknr,curdata))
989 return E_FAIL;
990 cc -= BIGSIZE;
991 if (cc<=0) {
992 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
993 return E_FAIL;
994 break;
995 } else {
996 int newblocknr = STORAGE_get_free_big_blocknr(hf);
997 if (newblocknr<0)
998 return E_FAIL;
999 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1000 return E_FAIL;
1001 blocknr = newblocknr;
1003 curdata += BIGSIZE;
1005 HeapFree(GetProcessHeap(),0,data);
1007 /* generate big blocks to fit the new data */
1008 lastblocknr = blocknr;
1009 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1010 blocknr = STORAGE_get_free_big_blocknr(hf);
1011 if (blocknr<0)
1012 return E_FAIL;
1013 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1014 return E_FAIL;
1015 lastblocknr = blocknr;
1017 /* terminate chain */
1018 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1019 return E_FAIL;
1022 This->stde.pps_size = newsize;
1025 /* There are just some cases where we didn't modify it, we write it out
1026 * everytime
1028 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1029 return E_FAIL;
1031 /* finally the write pass */
1032 if (This->stde.pps_size < 0x1000) {
1033 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
1034 assert(blocknr>=0);
1035 while (cb>0) {
1036 /* we ensured that it is allocated above */
1037 assert(blocknr>=0);
1038 /* Read old block everytime, since we can have
1039 * overlapping data at START and END of the write
1041 if (!STORAGE_get_small_block(hf,blocknr,block))
1042 return E_FAIL;
1044 cc = SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
1045 if (cc>cb)
1046 cc=cb;
1047 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(SMALLSIZE-1)),
1048 (LPBYTE)(pv+curoffset),
1051 if (!STORAGE_put_small_block(hf,blocknr,block))
1052 return E_FAIL;
1053 cb -= cc;
1054 curoffset += cc;
1055 (LPBYTE)pv += cc;
1056 This->offset.LowPart += cc;
1057 *byteswritten += cc;
1058 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1060 } else {
1061 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
1062 assert(blocknr>=0);
1063 while (cb>0) {
1064 /* we ensured that it is allocated above, so it better is */
1065 assert(blocknr>=0);
1066 /* read old block everytime, since we can have
1067 * overlapping data at START and END of the write
1069 if (!STORAGE_get_big_block(hf,blocknr,block))
1070 return E_FAIL;
1072 cc = BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
1073 if (cc>cb)
1074 cc=cb;
1075 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(BIGSIZE-1)),
1076 (LPBYTE)(pv+curoffset),
1079 if (!STORAGE_put_big_block(hf,blocknr,block))
1080 return E_FAIL;
1081 cb -= cc;
1082 curoffset += cc;
1083 (LPBYTE)pv += cc;
1084 This->offset.LowPart += cc;
1085 *byteswritten += cc;
1086 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1089 return S_OK;
1092 /******************************************************************************
1093 * _create_istream16 [Internal]
1095 static void _create_istream16(LPSTREAM16 *str) {
1096 IStream16Impl* lpst;
1098 if (!strvt16.fnQueryInterface) {
1099 HMODULE16 wp = GetModuleHandle16("STORAGE");
1100 if (wp>=32) {
1101 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1102 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1103 VTENT(QueryInterface);
1104 VTENT(AddRef);
1105 VTENT(Release);
1106 VTENT(Read);
1107 VTENT(Write);
1108 VTENT(Seek);
1109 VTENT(SetSize);
1110 VTENT(CopyTo);
1111 VTENT(Commit);
1112 VTENT(Revert);
1113 VTENT(LockRegion);
1114 VTENT(UnlockRegion);
1115 VTENT(Stat);
1116 VTENT(Clone);
1117 #undef VTENT
1118 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1119 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1120 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1121 } else {
1122 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1123 VTENT(QueryInterface);
1124 VTENT(AddRef);
1125 VTENT(Release);
1126 VTENT(Read);
1127 VTENT(Write);
1128 VTENT(Seek);
1130 VTENT(CopyTo);
1131 VTENT(Commit);
1132 VTENT(SetSize);
1133 VTENT(Revert);
1134 VTENT(LockRegion);
1135 VTENT(UnlockRegion);
1136 VTENT(Stat);
1137 VTENT(Clone);
1139 #undef VTENT
1140 segstrvt16 = &strvt16;
1143 lpst = SEGPTR_NEW(IStream16Impl);
1144 lpst->lpvtbl = segstrvt16;
1145 lpst->ref = 1;
1146 lpst->thisptr = SEGPTR_GET(lpst);
1147 *str = (void*)lpst->thisptr;
1151 /* --- IStream32 implementation */
1153 typedef struct
1155 /* IUnknown fields */
1156 ICOM_VTABLE(IStream)* lpvtbl;
1157 DWORD ref;
1158 /* IStream32 fields */
1159 struct storage_pps_entry stde;
1160 int ppsent;
1161 HFILE hf;
1162 ULARGE_INTEGER offset;
1163 } IStream32Impl;
1165 /*****************************************************************************
1166 * IStream32_QueryInterface [VTABLE]
1168 HRESULT WINAPI IStream_fnQueryInterface(
1169 IStream* iface,REFIID refiid,LPVOID *obj
1171 ICOM_THIS(IStream32Impl,iface);
1172 char xrefiid[50];
1174 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1175 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,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_VTABLE(IStorage16)* lpvtbl;
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);
1228 char xrefiid[50];
1230 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1231 TRACE(relay,"(%p)->(%s,%p)\n",This,xrefiid,obj);
1233 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1234 *obj = This;
1235 return 0;
1237 return OLE_E_ENUM_NOMORE;
1240 /******************************************************************************
1241 * IStorage16_AddRef [STORAGE.501]
1243 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1244 ICOM_THIS(IStorage16Impl,iface);
1245 return ++(This->ref);
1248 /******************************************************************************
1249 * IStorage16_Release [STORAGE.502]
1251 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1252 ICOM_THIS(IStorage16Impl,iface);
1253 This->ref--;
1254 if (This->ref)
1255 return This->ref;
1256 SEGPTR_FREE(This);
1257 return 0;
1260 /******************************************************************************
1261 * IStorage16_Stat [STORAGE.517]
1263 HRESULT WINAPI IStorage16_fnStat(
1264 LPSTORAGE16 iface,STATSTG *pstatstg, DWORD grfStatFlag
1266 ICOM_THIS(IStorage16Impl,iface);
1267 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1268 This,pstatstg,grfStatFlag
1270 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1271 pstatstg->type = This->stde.pps_type;
1272 pstatstg->cbSize.LowPart = This->stde.pps_size;
1273 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1274 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1275 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1276 pstatstg->grfMode = 0; /* FIXME */
1277 pstatstg->grfLocksSupported = 0; /* FIXME */
1278 pstatstg->clsid = This->stde.pps_guid;
1279 pstatstg->grfStateBits = 0; /* FIXME */
1280 pstatstg->reserved = 0;
1281 return S_OK;
1284 /******************************************************************************
1285 * IStorage16_Commit [STORAGE.509]
1287 HRESULT WINAPI IStorage16_fnCommit(
1288 LPSTORAGE16 iface,DWORD commitflags
1290 ICOM_THIS(IStorage16Impl,iface);
1291 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1292 This,commitflags
1294 return S_OK;
1297 /******************************************************************************
1298 * IStorage16_CopyTo [STORAGE.507]
1300 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1301 ICOM_THIS(IStorage16Impl,iface);
1302 char xguid[50];
1304 if (rgiidExclude)
1305 WINE_StringFromCLSID(rgiidExclude,xguid);
1306 else
1307 strcpy(xguid,"<no guid>");
1308 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1309 This,ciidExclude,xguid,SNB16Exclude,pstgDest
1311 return S_OK;
1315 /******************************************************************************
1316 * IStorage16_CreateStorage [STORAGE.505]
1318 HRESULT WINAPI IStorage16_fnCreateStorage(
1319 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1321 ICOM_THIS(IStorage16Impl,iface);
1322 IStorage16Impl* lpstg;
1323 int ppsent,x;
1324 struct storage_pps_entry stde;
1325 struct storage_header sth;
1326 HFILE hf=This->hf;
1328 READ_HEADER;
1330 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1331 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1333 if (grfMode & STGM_TRANSACTED)
1334 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1335 _create_istorage16(ppstg);
1336 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1337 lpstg->hf = This->hf;
1339 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1340 if (ppsent<0)
1341 return E_FAIL;
1342 stde=This->stde;
1343 if (stde.pps_dir==-1) {
1344 stde.pps_dir = ppsent;
1345 x = This->ppsent;
1346 } else {
1347 FIXME(ole," use prev chain too ?\n");
1348 x=stde.pps_dir;
1349 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1350 return E_FAIL;
1351 while (stde.pps_next!=-1) {
1352 x=stde.pps_next;
1353 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1354 return E_FAIL;
1356 stde.pps_next = ppsent;
1358 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1359 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1360 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1361 lpstg->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1362 lpstg->stde.pps_next = -1;
1363 lpstg->stde.pps_prev = -1;
1364 lpstg->stde.pps_dir = -1;
1365 lpstg->stde.pps_sb = -1;
1366 lpstg->stde.pps_size = 0;
1367 lpstg->stde.pps_type = 1;
1368 lpstg->ppsent = ppsent;
1369 /* FIXME: timestamps? */
1370 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1371 return E_FAIL;
1372 return S_OK;
1375 /******************************************************************************
1376 * IStorage16_CreateStream [STORAGE.503]
1378 HRESULT WINAPI IStorage16_fnCreateStream(
1379 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1381 ICOM_THIS(IStorage16Impl,iface);
1382 IStream16Impl* lpstr;
1383 int ppsent,x;
1384 struct storage_pps_entry stde;
1386 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1387 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1389 if (grfMode & STGM_TRANSACTED)
1390 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1391 _create_istream16(ppstm);
1392 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1393 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1394 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1395 lpstr->offset.LowPart = 0;
1396 lpstr->offset.HighPart = 0;
1398 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1399 if (ppsent<0)
1400 return E_FAIL;
1401 stde=This->stde;
1402 if (stde.pps_next==-1)
1403 x=This->ppsent;
1404 else
1405 while (stde.pps_next!=-1) {
1406 x=stde.pps_next;
1407 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1408 return E_FAIL;
1410 stde.pps_next = ppsent;
1411 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1412 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1413 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1414 lpstr->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1415 lpstr->stde.pps_next = -1;
1416 lpstr->stde.pps_prev = -1;
1417 lpstr->stde.pps_dir = -1;
1418 lpstr->stde.pps_sb = -1;
1419 lpstr->stde.pps_size = 0;
1420 lpstr->stde.pps_type = 2;
1421 lpstr->ppsent = ppsent;
1422 /* FIXME: timestamps? */
1423 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1424 return E_FAIL;
1425 return S_OK;
1428 /******************************************************************************
1429 * IStorage16_OpenStorage [STORAGE.506]
1431 HRESULT WINAPI IStorage16_fnOpenStorage(
1432 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1434 ICOM_THIS(IStorage16Impl,iface);
1435 IStream16Impl* lpstg;
1436 WCHAR name[33];
1437 int newpps;
1439 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1440 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1442 if (grfMode & STGM_TRANSACTED)
1443 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1444 _create_istorage16(ppstg);
1445 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1446 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1447 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1448 lstrcpyAtoW(name,pwcsName);
1449 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1450 if (newpps==-1) {
1451 IStream16_fnRelease((IStream16*)lpstg);
1452 return E_FAIL;
1455 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1456 IStream16_fnRelease((IStream16*)lpstg);
1457 return E_FAIL;
1459 lpstg->ppsent = newpps;
1460 return S_OK;
1463 /******************************************************************************
1464 * IStorage16_OpenStream [STORAGE.504]
1466 HRESULT WINAPI IStorage16_fnOpenStream(
1467 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1469 ICOM_THIS(IStorage16Impl,iface);
1470 IStream16Impl* lpstr;
1471 WCHAR name[33];
1472 int newpps;
1474 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1475 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1477 if (grfMode & STGM_TRANSACTED)
1478 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1479 _create_istream16(ppstm);
1480 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1481 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1482 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1483 lstrcpyAtoW(name,pwcsName);
1484 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1485 if (newpps==-1) {
1486 IStream16_fnRelease((IStream16*)lpstr);
1487 return E_FAIL;
1490 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1491 IStream16_fnRelease((IStream16*)lpstr);
1492 return E_FAIL;
1494 lpstr->offset.LowPart = 0;
1495 lpstr->offset.HighPart = 0;
1496 lpstr->ppsent = newpps;
1497 return S_OK;
1500 /******************************************************************************
1501 * _create_istorage16 [INTERNAL]
1503 static void _create_istorage16(LPSTORAGE16 *stg) {
1504 IStorage16Impl* lpst;
1506 if (!stvt16.fnQueryInterface) {
1507 HMODULE16 wp = GetModuleHandle16("STORAGE");
1508 if (wp>=32) {
1509 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1510 VTENT(QueryInterface)
1511 VTENT(AddRef)
1512 VTENT(Release)
1513 VTENT(CreateStream)
1514 VTENT(OpenStream)
1515 VTENT(CreateStorage)
1516 VTENT(OpenStorage)
1517 VTENT(CopyTo)
1518 VTENT(MoveElementTo)
1519 VTENT(Commit)
1520 VTENT(Revert)
1521 VTENT(EnumElements)
1522 VTENT(DestroyElement)
1523 VTENT(RenameElement)
1524 VTENT(SetElementTimes)
1525 VTENT(SetClass)
1526 VTENT(SetStateBits)
1527 VTENT(Stat)
1528 #undef VTENT
1529 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1530 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1531 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1532 } else {
1533 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1534 VTENT(QueryInterface)
1535 VTENT(AddRef)
1536 VTENT(Release)
1537 VTENT(CreateStream)
1538 VTENT(OpenStream)
1539 VTENT(CreateStorage)
1540 VTENT(OpenStorage)
1541 VTENT(CopyTo)
1542 VTENT(Commit)
1543 /* not (yet) implemented ...
1544 VTENT(MoveElementTo)
1545 VTENT(Revert)
1546 VTENT(EnumElements)
1547 VTENT(DestroyElement)
1548 VTENT(RenameElement)
1549 VTENT(SetElementTimes)
1550 VTENT(SetClass)
1551 VTENT(SetStateBits)
1552 VTENT(Stat)
1554 #undef VTENT
1555 segstvt16 = &stvt16;
1558 lpst = SEGPTR_NEW(IStorage16Impl);
1559 lpst->lpvtbl = segstvt16;
1560 lpst->ref = 1;
1561 lpst->thisptr = SEGPTR_GET(lpst);
1562 *stg = (void*)lpst->thisptr;
1565 /******************************************************************************
1566 * Storage API functions
1569 /******************************************************************************
1570 * StgCreateDocFile16 [STORAGE.1]
1572 HRESULT WINAPI StgCreateDocFile16(
1573 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1575 HFILE hf;
1576 int i,ret;
1577 IStorage16Impl* lpstg;
1578 struct storage_pps_entry stde;
1580 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1581 pwcsName,grfMode,reserved,ppstgOpen
1583 _create_istorage16(ppstgOpen);
1584 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1585 if (hf==INVALID_HANDLE_VALUE) {
1586 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1587 return E_FAIL;
1589 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1590 lpstg->hf = hf;
1591 /* FIXME: check for existance before overwriting? */
1592 if (!STORAGE_init_storage(hf)) {
1593 CloseHandle(hf);
1594 return E_FAIL;
1596 i=0;ret=0;
1597 while (!ret) { /* neither 1 nor <0 */
1598 ret=STORAGE_get_pps_entry(hf,i,&stde);
1599 if ((ret==1) && (stde.pps_type==5)) {
1600 lpstg->stde = stde;
1601 lpstg->ppsent = i;
1602 break;
1604 i++;
1606 if (ret!=1) {
1607 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1608 return E_FAIL;
1611 return S_OK;
1614 /******************************************************************************
1615 * StgIsStorageFile16 [STORAGE.5]
1617 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1618 HFILE hf;
1619 OFSTRUCT ofs;
1620 BYTE magic[24];
1622 TRACE(ole,"(\'%s\')\n",fn);
1623 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1624 if (hf==HFILE_ERROR)
1625 return STG_E_FILENOTFOUND;
1626 if (24!=_lread(hf,magic,24)) {
1627 WARN(ole," too short\n");
1628 _lclose(hf);
1629 return S_FALSE;
1631 if (!memcmp(magic,STORAGE_magic,8)) {
1632 WARN(ole," -> YES\n");
1633 _lclose(hf);
1634 return S_OK;
1636 if (!memcmp(magic,STORAGE_notmagic,8)) {
1637 WARN(ole," -> NO\n");
1638 _lclose(hf);
1639 return S_FALSE;
1641 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1642 WARN(ole," -> old format\n");
1643 _lclose(hf);
1644 return STG_E_OLDFORMAT;
1646 WARN(ole," -> Invalid header.\n");
1647 _lclose(hf);
1648 return STG_E_INVALIDHEADER;
1651 /******************************************************************************
1652 * StgIsStorageFile32 [OLE32.146]
1654 HRESULT WINAPI
1655 StgIsStorageFile(LPCOLESTR fn)
1657 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1658 OLESTATUS ret = StgIsStorageFile16(xfn);
1660 HeapFree(GetProcessHeap(),0,xfn);
1661 return ret;
1665 /******************************************************************************
1666 * StgOpenStorage16 [STORAGE.3]
1668 HRESULT WINAPI StgOpenStorage16(
1669 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1670 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1672 HFILE hf;
1673 int ret,i;
1674 IStorage16Impl* lpstg;
1675 struct storage_pps_entry stde;
1677 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1678 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1680 _create_istorage16(ppstgOpen);
1681 hf = CreateFileA(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1682 if (hf==INVALID_HANDLE_VALUE) {
1683 WARN(ole,"Couldn't open file for storage\n");
1684 return E_FAIL;
1686 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1687 lpstg->hf = hf;
1689 i=0;ret=0;
1690 while (!ret) { /* neither 1 nor <0 */
1691 ret=STORAGE_get_pps_entry(hf,i,&stde);
1692 if ((ret==1) && (stde.pps_type==5)) {
1693 lpstg->stde=stde;
1694 break;
1696 i++;
1698 if (ret!=1) {
1699 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1700 return E_FAIL;
1702 return S_OK;