Hacked stdio functions to use Win32 file handles. Still needs a proper
[wine/multimedia.git] / ole / storage.c
blob83ce52ece49d32e8bdbada26b9e498e21797d7ac
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 "windows.h"
14 #include "winerror.h"
15 #include "file.h"
16 #include "ole.h"
17 #include "ole2.h"
18 #include "compobj.h"
19 #include "interfaces.h"
20 #include "storage.h"
21 #include "heap.h"
22 #include "module.h"
23 #include "ldt.h"
24 #include "debug.h"
26 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
27 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
28 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
30 #define BIGSIZE 512
31 #define SMALLSIZE 64
33 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
35 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
36 static ICOM_VTABLE(IStorage16) stvt16;
37 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
38 static ICOM_VTABLE(IStorage32) stvt32;
39 static ICOM_VTABLE(IStream16) strvt16;
40 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
41 static ICOM_VTABLE(IStream32) strvt32;
43 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
44 static void _create_istorage16(LPSTORAGE16 *stg);
45 static void _create_istream16(LPSTREAM16 *str);
47 #define IMPLEMENTED 1
50 /******************************************************************************
51 * STORAGE_get_big_block [Internal]
53 * Reading OLE compound storage
55 static BOOL32
56 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
57 assert(n>=-1);
58 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
59 WARN(ole," seek failed (%ld)\n",GetLastError());
60 return FALSE;
62 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
63 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
64 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
65 assert(0);
66 return FALSE;
68 return TRUE;
71 /******************************************************************************
72 * STORAGE_put_big_block [INTERNAL]
74 static BOOL32
75 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
76 assert(n>=-1);
77 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
78 WARN(ole," seek failed (%ld)\n",GetLastError());
79 return FALSE;
81 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
82 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
83 WARN(ole," write failed (%ld)\n",GetLastError());
84 return FALSE;
86 return TRUE;
89 /******************************************************************************
90 * STORAGE_get_next_big_blocknr [INTERNAL]
92 static int
93 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
94 INT32 bbs[BIGSIZE/sizeof(INT32)];
95 struct storage_header sth;
97 READ_HEADER;
99 assert(blocknr>>7<sth.num_of_bbd_blocks);
100 if (sth.bbd_list[blocknr>>7]==0xffffffff)
101 return -5;
102 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
103 return -5;
104 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
105 return bbs[blocknr&0x7f];
108 /******************************************************************************
109 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
111 static int
112 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
113 INT32 bbs[BIGSIZE/sizeof(INT32)];
114 int lastblock = -1;
115 struct storage_header sth;
117 READ_HEADER;
119 assert(blocknr>=0);
120 while (nr--) {
121 assert((blocknr>>7)<sth.num_of_bbd_blocks);
122 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
124 /* simple caching... */
125 if (lastblock!=sth.bbd_list[blocknr>>7]) {
126 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
127 lastblock = sth.bbd_list[blocknr>>7];
129 blocknr = bbs[blocknr&0x7f];
131 return blocknr;
134 /******************************************************************************
135 * STORAGE_get_root_pps_entry [Internal]
137 static BOOL32
138 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
139 int blocknr,i;
140 BYTE block[BIGSIZE];
141 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
142 struct storage_header sth;
144 READ_HEADER;
145 blocknr = sth.root_startblock;
146 while (blocknr>=0) {
147 assert(STORAGE_get_big_block(hf,blocknr,block));
148 for (i=0;i<4;i++) {
149 if (!stde[i].pps_sizeofname)
150 continue;
151 if (stde[i].pps_type==5) {
152 *pstde=stde[i];
153 return TRUE;
156 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
158 return FALSE;
161 /******************************************************************************
162 * STORAGE_get_small_block [INTERNAL]
164 static BOOL32
165 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
166 BYTE block[BIGSIZE];
167 int bigblocknr;
168 struct storage_pps_entry root;
170 assert(blocknr>=0);
171 assert(STORAGE_get_root_pps_entry(hf,&root));
172 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
173 assert(bigblocknr>=0);
174 assert(STORAGE_get_big_block(hf,bigblocknr,block));
176 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
177 return TRUE;
180 /******************************************************************************
181 * STORAGE_put_small_block [INTERNAL]
183 static BOOL32
184 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
185 BYTE block[BIGSIZE];
186 int bigblocknr;
187 struct storage_pps_entry root;
189 assert(blocknr>=0);
191 assert(STORAGE_get_root_pps_entry(hf,&root));
192 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
193 assert(bigblocknr>=0);
194 assert(STORAGE_get_big_block(hf,bigblocknr,block));
196 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
197 assert(STORAGE_put_big_block(hf,bigblocknr,block));
198 return TRUE;
201 /******************************************************************************
202 * STORAGE_get_next_small_blocknr [INTERNAL]
204 static int
205 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
206 BYTE block[BIGSIZE];
207 LPINT32 sbd = (LPINT32)block;
208 int bigblocknr;
209 struct storage_header sth;
211 READ_HEADER;
212 assert(blocknr>=0);
213 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
214 assert(bigblocknr>=0);
215 assert(STORAGE_get_big_block(hf,bigblocknr,block));
216 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
217 return sbd[blocknr & (128-1)];
220 /******************************************************************************
221 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
223 static int
224 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
225 int lastblocknr;
226 BYTE block[BIGSIZE];
227 LPINT32 sbd = (LPINT32)block;
228 struct storage_header sth;
230 READ_HEADER;
231 lastblocknr=-1;
232 assert(blocknr>=0);
233 while ((nr--) && (blocknr>=0)) {
234 if (lastblocknr/128!=blocknr/128) {
235 int bigblocknr;
236 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
237 assert(bigblocknr>=0);
238 assert(STORAGE_get_big_block(hf,bigblocknr,block));
239 lastblocknr = blocknr;
241 assert(lastblocknr>=0);
242 lastblocknr=blocknr;
243 blocknr=sbd[blocknr & (128-1)];
244 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
246 return blocknr;
249 /******************************************************************************
250 * STORAGE_get_pps_entry [INTERNAL]
252 static int
253 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
254 int blocknr;
255 BYTE block[BIGSIZE];
256 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
257 struct storage_header sth;
259 READ_HEADER;
260 /* we have 4 pps entries per big block */
261 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
262 assert(blocknr>=0);
263 assert(STORAGE_get_big_block(hf,blocknr,block));
265 *pstde=*stde;
266 return 1;
269 /******************************************************************************
270 * STORAGE_put_pps_entry [Internal]
272 static int
273 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
274 int blocknr;
275 BYTE block[BIGSIZE];
276 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
277 struct storage_header sth;
279 READ_HEADER;
281 /* we have 4 pps entries per big block */
282 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
283 assert(blocknr>=0);
284 assert(STORAGE_get_big_block(hf,blocknr,block));
285 *stde=*pstde;
286 assert(STORAGE_put_big_block(hf,blocknr,block));
287 return 1;
290 /******************************************************************************
291 * STORAGE_look_for_named_pps [Internal]
293 static int
294 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
295 struct storage_pps_entry stde;
296 int ret;
298 if (n==-1)
299 return -1;
300 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
301 return -1;
303 if (!lstrcmp32W(name,stde.pps_rawname))
304 return n;
305 if (stde.pps_prev != -1) {
306 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
307 if (ret!=-1)
308 return ret;
310 if (stde.pps_next != -1) {
311 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
312 if (ret!=-1)
313 return ret;
315 return -1;
318 /******************************************************************************
319 * STORAGE_dump_pps_entry [Internal]
321 * FIXME
322 * Function is unused
324 void
325 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
326 char name[33],xguid[50];
328 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
330 lstrcpyWtoA(name,stde->pps_rawname);
331 if (!stde->pps_sizeofname)
332 return;
333 DUMP("name: %s\n",name);
334 DUMP("type: %d\n",stde->pps_type);
335 DUMP("prev pps: %ld\n",stde->pps_prev);
336 DUMP("next pps: %ld\n",stde->pps_next);
337 DUMP("dir pps: %ld\n",stde->pps_dir);
338 DUMP("guid: %s\n",xguid);
339 if (stde->pps_type !=2) {
340 time_t t;
342 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
343 DUMP("ts1: %s\n",ctime(&t));
344 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
345 DUMP("ts2: %s\n",ctime(&t));
347 DUMP("startblock: %ld\n",stde->pps_sb);
348 DUMP("size: %ld\n",stde->pps_size);
351 /******************************************************************************
352 * STORAGE_init_storage [INTERNAL]
354 static BOOL32
355 STORAGE_init_storage(HFILE32 hf) {
356 BYTE block[BIGSIZE];
357 LPDWORD bbs;
358 struct storage_header *sth;
359 struct storage_pps_entry *stde;
361 assert(-1!=_llseek32(hf,0,SEEK_SET));
362 /* block -1 is the storage header */
363 sth = (struct storage_header*)block;
364 memcpy(sth->magic,STORAGE_magic,8);
365 memset(sth->unknown1,0,sizeof(sth->unknown1));
366 memset(sth->unknown2,0,sizeof(sth->unknown2));
367 memset(sth->unknown3,0,sizeof(sth->unknown3));
368 sth->num_of_bbd_blocks = 1;
369 sth->root_startblock = 1;
370 sth->sbd_startblock = 0xffffffff;
371 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
372 sth->bbd_list[0] = 0;
373 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
374 /* block 0 is the big block directory */
375 bbs=(LPDWORD)block;
376 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
377 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
378 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
379 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
380 /* block 1 is the root directory entry */
381 memset(block,0x00,sizeof(block));
382 stde = (struct storage_pps_entry*)block;
383 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
384 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
385 stde->pps_type = 5;
386 stde->pps_dir = -1;
387 stde->pps_next = -1;
388 stde->pps_prev = -1;
389 stde->pps_sb = 0xffffffff;
390 stde->pps_size = 0;
391 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
392 return TRUE;
395 /******************************************************************************
396 * STORAGE_set_big_chain [Internal]
398 static BOOL32
399 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
400 BYTE block[BIGSIZE];
401 LPINT32 bbd = (LPINT32)block;
402 int nextblocknr,bigblocknr;
403 struct storage_header sth;
405 READ_HEADER;
406 assert(blocknr!=type);
407 while (blocknr>=0) {
408 bigblocknr = sth.bbd_list[blocknr/128];
409 assert(bigblocknr>=0);
410 assert(STORAGE_get_big_block(hf,bigblocknr,block));
412 nextblocknr = bbd[blocknr&(128-1)];
413 bbd[blocknr&(128-1)] = type;
414 if (type>=0)
415 return TRUE;
416 assert(STORAGE_put_big_block(hf,bigblocknr,block));
417 type = STORAGE_CHAINENTRY_FREE;
418 blocknr = nextblocknr;
420 return TRUE;
423 /******************************************************************************
424 * STORAGE_set_small_chain [Internal]
426 static BOOL32
427 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
428 BYTE block[BIGSIZE];
429 LPINT32 sbd = (LPINT32)block;
430 int lastblocknr,nextsmallblocknr,bigblocknr;
431 struct storage_header sth;
433 READ_HEADER;
435 assert(blocknr!=type);
436 lastblocknr=-129;bigblocknr=-2;
437 while (blocknr>=0) {
438 /* cache block ... */
439 if (lastblocknr/128!=blocknr/128) {
440 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
441 assert(bigblocknr>=0);
442 assert(STORAGE_get_big_block(hf,bigblocknr,block));
444 lastblocknr = blocknr;
445 nextsmallblocknr = sbd[blocknr&(128-1)];
446 sbd[blocknr&(128-1)] = type;
447 assert(STORAGE_put_big_block(hf,bigblocknr,block));
448 if (type>=0)
449 return TRUE;
450 type = STORAGE_CHAINENTRY_FREE;
451 blocknr = nextsmallblocknr;
453 return TRUE;
456 /******************************************************************************
457 * STORAGE_get_free_big_blocknr [Internal]
459 static int
460 STORAGE_get_free_big_blocknr(HFILE32 hf) {
461 BYTE block[BIGSIZE];
462 LPINT32 sbd = (LPINT32)block;
463 int lastbigblocknr,i,curblock,bigblocknr;
464 struct storage_header sth;
466 READ_HEADER;
467 curblock = 0;
468 lastbigblocknr = -1;
469 bigblocknr = sth.bbd_list[curblock];
470 while (curblock<sth.num_of_bbd_blocks) {
471 assert(bigblocknr>=0);
472 assert(STORAGE_get_big_block(hf,bigblocknr,block));
473 for (i=0;i<128;i++)
474 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
475 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
476 assert(STORAGE_put_big_block(hf,bigblocknr,block));
477 memset(block,0x42,sizeof(block));
478 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
479 return i+curblock*128;
481 lastbigblocknr = bigblocknr;
482 bigblocknr = sth.bbd_list[++curblock];
484 bigblocknr = curblock*128;
485 /* since we have marked all blocks from 0 up to curblock*128-1
486 * the next free one is curblock*128, where we happily put our
487 * next large block depot.
489 memset(block,0xff,sizeof(block));
490 /* mark the block allocated and returned by this function */
491 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
492 assert(STORAGE_put_big_block(hf,bigblocknr,block));
494 /* if we had a bbd block already (mostlikely) we need
495 * to link the new one into the chain
497 if (lastbigblocknr!=-1)
498 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
499 sth.bbd_list[curblock]=bigblocknr;
500 sth.num_of_bbd_blocks++;
501 assert(sth.num_of_bbd_blocks==curblock+1);
502 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
504 /* Set the end of the chain for the bigblockdepots */
505 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
506 /* add 1, for the first entry is used for the additional big block
507 * depot. (means we already used bigblocknr) */
508 memset(block,0x42,sizeof(block));
509 /* allocate this block (filled with 0x42) */
510 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
511 return bigblocknr+1;
515 /******************************************************************************
516 * STORAGE_get_free_small_blocknr [Internal]
518 static int
519 STORAGE_get_free_small_blocknr(HFILE32 hf) {
520 BYTE block[BIGSIZE];
521 LPINT32 sbd = (LPINT32)block;
522 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
523 struct storage_pps_entry root;
524 struct storage_header sth;
526 READ_HEADER;
527 bigblocknr = sth.sbd_startblock;
528 curblock = 0;
529 lastbigblocknr = -1;
530 newblocknr = -1;
531 while (bigblocknr>=0) {
532 if (!STORAGE_get_big_block(hf,bigblocknr,block))
533 return -1;
534 for (i=0;i<128;i++)
535 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
536 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
537 newblocknr = i+curblock*128;
538 break;
540 if (i!=128)
541 break;
542 lastbigblocknr = bigblocknr;
543 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
544 curblock++;
546 if (newblocknr==-1) {
547 bigblocknr = STORAGE_get_free_big_blocknr(hf);
548 if (bigblocknr<0)
549 return -1;
550 READ_HEADER;
551 memset(block,0xff,sizeof(block));
552 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
553 if (!STORAGE_put_big_block(hf,bigblocknr,block))
554 return -1;
555 if (lastbigblocknr==-1) {
556 sth.sbd_startblock = bigblocknr;
557 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
558 return -1;
559 } else {
560 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
561 return -1;
563 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
564 return -1;
565 newblocknr = curblock*128;
567 /* allocate enough big blocks for storing the allocated small block */
568 if (!STORAGE_get_root_pps_entry(hf,&root))
569 return -1;
570 if (root.pps_sb==-1)
571 lastbigblocknr = -1;
572 else
573 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
574 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
575 /* we need to allocate more stuff */
576 bigblocknr = STORAGE_get_free_big_blocknr(hf);
577 if (bigblocknr<0)
578 return -1;
579 READ_HEADER;
580 if (root.pps_sb==-1) {
581 root.pps_sb = bigblocknr;
582 root.pps_size += BIGSIZE;
583 } else {
584 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
585 return -1;
586 root.pps_size += BIGSIZE;
588 lastbigblocknr = bigblocknr;
590 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
591 return -1;
592 if (!STORAGE_put_pps_entry(hf,0,&root))
593 return -1;
594 return newblocknr;
597 /******************************************************************************
598 * STORAGE_get_free_pps_entry [Internal]
600 static int
601 STORAGE_get_free_pps_entry(HFILE32 hf) {
602 int blocknr,i,curblock,lastblocknr;
603 BYTE block[BIGSIZE];
604 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
605 struct storage_header sth;
607 READ_HEADER;
608 blocknr = sth.root_startblock;
609 assert(blocknr>=0);
610 curblock=0;
611 while (blocknr>=0) {
612 if (!STORAGE_get_big_block(hf,blocknr,block))
613 return -1;
614 for (i=0;i<4;i++)
615 if (stde[i].pps_sizeofname==0) /* free */
616 return curblock*4+i;
617 lastblocknr = blocknr;
618 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
619 curblock++;
621 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
622 blocknr = STORAGE_get_free_big_blocknr(hf);
623 /* sth invalidated */
624 if (blocknr<0)
625 return -1;
627 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
628 return -1;
629 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
630 return -1;
631 memset(block,0,sizeof(block));
632 STORAGE_put_big_block(hf,blocknr,block);
633 return curblock*4;
636 /* --- IStream16 implementation */
638 typedef struct _IStream16 {
639 /* IUnknown fields */
640 ICOM_VTABLE(IStream16)* lpvtbl;
641 DWORD ref;
642 /* IStream16 fields */
643 SEGPTR thisptr; /* pointer to this struct as segmented */
644 struct storage_pps_entry stde;
645 int ppsent;
646 HFILE32 hf;
647 ULARGE_INTEGER offset;
648 } _IStream16;
650 /******************************************************************************
651 * IStream16_QueryInterface [STORAGE.518]
653 HRESULT WINAPI IStream16_fnQueryInterface(
654 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
656 ICOM_THIS(IStream16,iface);
657 char xrefiid[50];
658 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
659 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
660 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
661 *obj = this;
662 return 0;
664 return OLE_E_ENUM_NOMORE;
668 /******************************************************************************
669 * IStream16_AddRef [STORAGE.519]
671 ULONG WINAPI IStream16_fnAddRef(LPUNKNOWN iface) {
672 ICOM_THIS(IStream16,iface);
673 return ++(this->ref);
676 /******************************************************************************
677 * IStream16_Release [STORAGE.520]
679 ULONG WINAPI IStream16_fnRelease(LPUNKNOWN iface) {
680 ICOM_THIS(IStream16,iface);
681 FlushFileBuffers(this->hf);
682 this->ref--;
683 if (!this->ref) {
684 CloseHandle(this->hf);
685 SEGPTR_FREE(this);
686 return 0;
688 return this->ref;
691 /******************************************************************************
692 * IStream16_Seek [STORAGE.523]
694 * FIXME
695 * Does not handle 64 bits
697 HRESULT WINAPI IStream16_fnSeek(
698 LPSTREAM16 iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
700 ICOM_THIS(IStream16,iface);
701 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
703 switch (whence) {
704 /* unix SEEK_xx should be the same as win95 ones */
705 case SEEK_SET:
706 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
707 * right now.
709 assert(offset.HighPart==0);
710 this->offset.HighPart = offset.HighPart;
711 this->offset.LowPart = offset.LowPart;
712 break;
713 case SEEK_CUR:
714 if (offset.HighPart < 0) {
715 /* FIXME: is this negation correct ? */
716 offset.HighPart = -offset.HighPart;
717 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
719 assert(offset.HighPart==0);
720 assert(this->offset.LowPart >= offset.LowPart);
721 this->offset.LowPart -= offset.LowPart;
722 } else {
723 assert(offset.HighPart==0);
724 this->offset.LowPart+= offset.LowPart;
726 break;
727 case SEEK_END:
728 assert(offset.HighPart==0);
729 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
730 break;
732 if (this->offset.LowPart>this->stde.pps_size)
733 this->offset.LowPart=this->stde.pps_size;
734 if (newpos) *newpos = this->offset;
735 return OLE_OK;
738 /******************************************************************************
739 * IStream16_Read [STORAGE.521]
741 HRESULT WINAPI IStream16_fnRead(
742 LPSTREAM16 iface,void *pv,ULONG cb,ULONG *pcbRead
744 ICOM_THIS(IStream16,iface);
745 BYTE block[BIGSIZE];
746 ULONG *bytesread=pcbRead,xxread;
747 int blocknr;
749 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
750 if (!pcbRead) bytesread=&xxread;
751 *bytesread = 0;
753 if (cb>this->stde.pps_size-this->offset.LowPart)
754 cb=this->stde.pps_size-this->offset.LowPart;
755 if (this->stde.pps_size < 0x1000) {
756 /* use small block reader */
757 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
758 while (cb) {
759 int cc;
761 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
762 WARN(ole,"small block read failed!!!\n");
763 return E_FAIL;
765 cc = cb;
766 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
767 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
768 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
769 this->offset.LowPart+=cc;
770 (LPBYTE)pv+=cc;
771 *bytesread+=cc;
772 cb-=cc;
773 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
775 } else {
776 /* use big block reader */
777 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
778 while (cb) {
779 int cc;
781 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
782 WARN(ole,"big block read failed!!!\n");
783 return E_FAIL;
785 cc = cb;
786 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
787 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
788 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
789 this->offset.LowPart+=cc;
790 (LPBYTE)pv+=cc;
791 *bytesread+=cc;
792 cb-=cc;
793 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
796 return OLE_OK;
799 /******************************************************************************
800 * IStream16_Write [STORAGE.522]
802 HRESULT WINAPI IStream16_fnWrite(
803 LPSTREAM16 iface,const void *pv,ULONG cb,ULONG *pcbWrite
805 ICOM_THIS(IStream16,iface);
806 BYTE block[BIGSIZE];
807 ULONG *byteswritten=pcbWrite,xxwritten;
808 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
809 HFILE32 hf = this->hf;
811 if (!pcbWrite) byteswritten=&xxwritten;
812 *byteswritten = 0;
814 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
815 /* do we need to junk some blocks? */
816 newsize = this->offset.LowPart+cb;
817 oldsize = this->stde.pps_size;
818 if (newsize < oldsize) {
819 if (oldsize < 0x1000) {
820 /* only small blocks */
821 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
823 assert(blocknr>=0);
825 /* will set the rest of the chain to 'free' */
826 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
827 return E_FAIL;
828 } else {
829 if (newsize >= 0x1000) {
830 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
831 assert(blocknr>=0);
833 /* will set the rest of the chain to 'free' */
834 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
835 return E_FAIL;
836 } else {
837 /* Migrate large blocks to small blocks
838 * (we just migrate newsize bytes)
840 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
841 cc = newsize;
842 blocknr = this->stde.pps_sb;
843 curdata = data;
844 while (cc>0) {
845 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
846 HeapFree(GetProcessHeap(),0,data);
847 return E_FAIL;
849 curdata += BIGSIZE;
850 cc -= BIGSIZE;
851 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
853 /* frees complete chain for this stream */
854 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
855 return E_FAIL;
856 curdata = data;
857 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
858 if (blocknr<0)
859 return E_FAIL;
860 cc = newsize;
861 while (cc>0) {
862 if (!STORAGE_put_small_block(hf,blocknr,curdata))
863 return E_FAIL;
864 cc -= SMALLSIZE;
865 if (cc<=0) {
866 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
867 return E_FAIL;
868 break;
869 } else {
870 int newblocknr = STORAGE_get_free_small_blocknr(hf);
871 if (newblocknr<0)
872 return E_FAIL;
873 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
874 return E_FAIL;
875 blocknr = newblocknr;
877 curdata += SMALLSIZE;
879 HeapFree(GetProcessHeap(),0,data);
882 this->stde.pps_size = newsize;
885 if (newsize > oldsize) {
886 if (oldsize >= 0x1000) {
887 /* should return the block right before the 'endofchain' */
888 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
889 assert(blocknr>=0);
890 lastblocknr = blocknr;
891 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
892 blocknr = STORAGE_get_free_big_blocknr(hf);
893 if (blocknr<0)
894 return E_FAIL;
895 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
896 return E_FAIL;
897 lastblocknr = blocknr;
899 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
900 return E_FAIL;
901 } else {
902 if (newsize < 0x1000) {
903 /* find startblock */
904 if (!oldsize)
905 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
906 else
907 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
908 if (blocknr<0)
909 return E_FAIL;
911 /* allocate required new small blocks */
912 lastblocknr = blocknr;
913 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
914 blocknr = STORAGE_get_free_small_blocknr(hf);
915 if (blocknr<0)
916 return E_FAIL;
917 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
918 return E_FAIL;
919 lastblocknr = blocknr;
921 /* and terminate the chain */
922 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
923 return E_FAIL;
924 } else {
925 if (!oldsize) {
926 /* no single block allocated yet */
927 blocknr=STORAGE_get_free_big_blocknr(hf);
928 if (blocknr<0)
929 return E_FAIL;
930 this->stde.pps_sb = blocknr;
931 } else {
932 /* Migrate small blocks to big blocks */
933 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
934 cc = oldsize;
935 blocknr = this->stde.pps_sb;
936 curdata = data;
937 /* slurp in */
938 while (cc>0) {
939 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
940 HeapFree(GetProcessHeap(),0,data);
941 return E_FAIL;
943 curdata += SMALLSIZE;
944 cc -= SMALLSIZE;
945 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
947 /* free small block chain */
948 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
949 return E_FAIL;
950 curdata = data;
951 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
952 if (blocknr<0)
953 return E_FAIL;
954 /* put the data into the big blocks */
955 cc = this->stde.pps_size;
956 while (cc>0) {
957 if (!STORAGE_put_big_block(hf,blocknr,curdata))
958 return E_FAIL;
959 cc -= BIGSIZE;
960 if (cc<=0) {
961 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
962 return E_FAIL;
963 break;
964 } else {
965 int newblocknr = STORAGE_get_free_big_blocknr(hf);
966 if (newblocknr<0)
967 return E_FAIL;
968 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
969 return E_FAIL;
970 blocknr = newblocknr;
972 curdata += BIGSIZE;
974 HeapFree(GetProcessHeap(),0,data);
976 /* generate big blocks to fit the new data */
977 lastblocknr = blocknr;
978 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
979 blocknr = STORAGE_get_free_big_blocknr(hf);
980 if (blocknr<0)
981 return E_FAIL;
982 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
983 return E_FAIL;
984 lastblocknr = blocknr;
986 /* terminate chain */
987 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
988 return E_FAIL;
991 this->stde.pps_size = newsize;
994 /* There are just some cases where we didn't modify it, we write it out
995 * everytime
997 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
998 return E_FAIL;
1000 /* finally the write pass */
1001 if (this->stde.pps_size < 0x1000) {
1002 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
1003 assert(blocknr>=0);
1004 while (cb>0) {
1005 /* we ensured that it is allocated above */
1006 assert(blocknr>=0);
1007 /* Read old block everytime, since we can have
1008 * overlapping data at START and END of the write
1010 if (!STORAGE_get_small_block(hf,blocknr,block))
1011 return E_FAIL;
1013 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
1014 if (cc>cb)
1015 cc=cb;
1016 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
1017 (LPBYTE)(pv+curoffset),
1020 if (!STORAGE_put_small_block(hf,blocknr,block))
1021 return E_FAIL;
1022 cb -= cc;
1023 curoffset += cc;
1024 (LPBYTE)pv += cc;
1025 this->offset.LowPart += cc;
1026 *byteswritten += cc;
1027 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1029 } else {
1030 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
1031 assert(blocknr>=0);
1032 while (cb>0) {
1033 /* we ensured that it is allocated above, so it better is */
1034 assert(blocknr>=0);
1035 /* read old block everytime, since we can have
1036 * overlapping data at START and END of the write
1038 if (!STORAGE_get_big_block(hf,blocknr,block))
1039 return E_FAIL;
1041 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
1042 if (cc>cb)
1043 cc=cb;
1044 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
1045 (LPBYTE)(pv+curoffset),
1048 if (!STORAGE_put_big_block(hf,blocknr,block))
1049 return E_FAIL;
1050 cb -= cc;
1051 curoffset += cc;
1052 (LPBYTE)pv += cc;
1053 this->offset.LowPart += cc;
1054 *byteswritten += cc;
1055 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1058 return OLE_OK;
1061 /******************************************************************************
1062 * _create_istream16 [Internal]
1064 static void _create_istream16(LPSTREAM16 *str) {
1065 _IStream16* lpst;
1067 if (!strvt16.bvt.fnQueryInterface) {
1068 HMODULE16 wp = GetModuleHandle16("STORAGE");
1069 if (wp>=32) {
1070 /* FIXME: what is this WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1071 #define VTENT(xfn) strvt16.bvt.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);
1072 VTENT(QueryInterface)
1073 VTENT(AddRef)
1074 VTENT(Release)
1075 #undef VTENT
1076 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);
1077 VTENT(Read)
1078 VTENT(Write)
1079 VTENT(Seek)
1080 VTENT(SetSize)
1081 VTENT(CopyTo)
1082 VTENT(Commit)
1083 VTENT(Revert)
1084 VTENT(LockRegion)
1085 VTENT(UnlockRegion)
1086 VTENT(Stat)
1087 VTENT(Clone)
1088 #undef VTENT
1089 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1090 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1091 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1092 } else {
1093 #define VTENT(xfn) strvt16.bvt.fn##xfn = IStream16_fn##xfn;
1094 VTENT(QueryInterface)
1095 VTENT(AddRef)
1096 VTENT(Release)
1097 #undef VTENT
1098 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1099 VTENT(Read)
1100 VTENT(Write)
1101 VTENT(Seek)
1103 VTENT(CopyTo)
1104 VTENT(Commit)
1105 VTENT(SetSize)
1106 VTENT(Revert)
1107 VTENT(LockRegion)
1108 VTENT(UnlockRegion)
1109 VTENT(Stat)
1110 VTENT(Clone)
1112 #undef VTENT
1113 segstrvt16 = &strvt16;
1116 lpst = SEGPTR_NEW(_IStream16);
1117 lpst->lpvtbl = segstrvt16;
1118 lpst->ref = 1;
1119 lpst->thisptr = SEGPTR_GET(lpst);
1120 *str = (void*)lpst->thisptr;
1124 /* --- IStream32 implementation */
1126 typedef struct _IStream32 {
1127 /* IUnknown fields */
1128 ICOM_VTABLE(IStream32)* lpvtbl;
1129 DWORD ref;
1130 /* IStream32 fields */
1131 struct storage_pps_entry stde;
1132 int ppsent;
1133 HFILE32 hf;
1134 ULARGE_INTEGER offset;
1135 } _IStream32;
1137 /*****************************************************************************
1138 * IStream32_QueryInterface [VTABLE]
1140 HRESULT WINAPI IStream32_fnQueryInterface(
1141 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
1143 ICOM_THIS(IStream32,iface);
1144 char xrefiid[50];
1146 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1147 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1148 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1149 *obj = this;
1150 return 0;
1152 return OLE_E_ENUM_NOMORE;
1156 /******************************************************************************
1157 * IStream32_AddRef [VTABLE]
1159 ULONG WINAPI IStream32_fnAddRef(LPUNKNOWN iface) {
1160 ICOM_THIS(IStream32,iface);
1161 return ++(this->ref);
1164 /******************************************************************************
1165 * IStream32_Release [VTABLE]
1167 ULONG WINAPI IStream32_fnRelease(LPUNKNOWN iface) {
1168 ICOM_THIS(IStream32,iface);
1169 FlushFileBuffers(this->hf);
1170 this->ref--;
1171 if (!this->ref) {
1172 CloseHandle(this->hf);
1173 SEGPTR_FREE(this);
1174 return 0;
1176 return this->ref;
1179 static ICOM_VTABLE(IStream32) strvt32 = {
1181 IStream32_fnQueryInterface,
1182 IStream32_fnAddRef,
1183 IStream32_fnRelease
1185 (void*)0xdead0004,
1186 (void*)0xdead0005,
1187 (void*)0xdead0006,
1188 (void*)0xdead0007,
1189 (void*)0xdead0008,
1190 (void*)0xdead0009,
1191 (void*)0xdead0010,
1192 (void*)0xdead0011
1196 /* --- IStorage16 implementation */
1198 typedef struct _IStorage16 {
1199 /* IUnknown fields */
1200 ICOM_VTABLE(IStorage16)* lpvtbl;
1201 DWORD ref;
1202 /* IStorage16 fields */
1203 SEGPTR thisptr; /* pointer to this struct as segmented */
1204 struct storage_pps_entry stde;
1205 int ppsent;
1206 HFILE32 hf;
1207 } _IStorage16;
1209 /******************************************************************************
1210 * IStorage16_QueryInterface [STORAGE.500]
1212 HRESULT WINAPI IStorage16_fnQueryInterface(
1213 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
1215 ICOM_THIS(IStorage16,iface);
1216 char xrefiid[50];
1218 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1219 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1221 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1222 *obj = this;
1223 return 0;
1225 return OLE_E_ENUM_NOMORE;
1228 /******************************************************************************
1229 * IStorage16_AddRef [STORAGE.501]
1231 ULONG WINAPI IStorage16_fnAddRef(LPUNKNOWN iface) {
1232 ICOM_THIS(IStorage16,iface);
1233 return ++(this->ref);
1236 /******************************************************************************
1237 * IStorage16_Release [STORAGE.502]
1239 ULONG WINAPI IStorage16_fnRelease(LPUNKNOWN iface) {
1240 ICOM_THIS(IStorage16,iface);
1241 this->ref--;
1242 if (this->ref)
1243 return this->ref;
1244 SEGPTR_FREE(this);
1245 return 0;
1248 /******************************************************************************
1249 * IStorage16_Stat [STORAGE.517]
1251 HRESULT WINAPI IStorage16_fnStat(
1252 LPSTORAGE16 iface,STATSTG *pstatstg, DWORD grfStatFlag
1254 ICOM_THIS(IStorage16,iface);
1255 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1256 this,pstatstg,grfStatFlag
1258 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1259 pstatstg->type = this->stde.pps_type;
1260 pstatstg->cbSize.LowPart = this->stde.pps_size;
1261 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1262 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1263 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1264 pstatstg->grfMode = 0; /* FIXME */
1265 pstatstg->grfLocksSupported = 0; /* FIXME */
1266 pstatstg->clsid = this->stde.pps_guid;
1267 pstatstg->grfStateBits = 0; /* FIXME */
1268 pstatstg->reserved = 0;
1269 return OLE_OK;
1272 /******************************************************************************
1273 * IStorage16_Commit [STORAGE.509]
1275 HRESULT WINAPI IStorage16_fnCommit(
1276 LPSTORAGE16 iface,DWORD commitflags
1278 ICOM_THIS(IStorage16,iface);
1279 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1280 this,commitflags
1282 return OLE_OK;
1285 /******************************************************************************
1286 * IStorage16_CopyTo [STORAGE.507]
1288 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1289 ICOM_THIS(IStorage16,iface);
1290 char xguid[50];
1292 if (rgiidExclude)
1293 WINE_StringFromCLSID(rgiidExclude,xguid);
1294 else
1295 strcpy(xguid,"<no guid>");
1296 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1297 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1299 return OLE_OK;
1303 /******************************************************************************
1304 * IStorage16_CreateStorage [STORAGE.505]
1306 HRESULT WINAPI IStorage16_fnCreateStorage(
1307 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1309 ICOM_THIS(IStorage16,iface);
1310 _IStorage16* lpstg;
1311 int ppsent,x;
1312 struct storage_pps_entry stde;
1313 struct storage_header sth;
1314 HFILE32 hf=this->hf;
1316 READ_HEADER;
1318 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1319 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1321 if (grfMode & STGM_TRANSACTED)
1322 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1323 _create_istorage16(ppstg);
1324 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstg);
1325 lpstg->hf = this->hf;
1327 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1328 if (ppsent<0)
1329 return E_FAIL;
1330 stde=this->stde;
1331 if (stde.pps_dir==-1) {
1332 stde.pps_dir = ppsent;
1333 x = this->ppsent;
1334 } else {
1335 FIXME(ole," use prev chain too ?\n");
1336 x=stde.pps_dir;
1337 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1338 return E_FAIL;
1339 while (stde.pps_next!=-1) {
1340 x=stde.pps_next;
1341 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1342 return E_FAIL;
1344 stde.pps_next = ppsent;
1346 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1347 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1348 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1349 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1350 lpstg->stde.pps_next = -1;
1351 lpstg->stde.pps_prev = -1;
1352 lpstg->stde.pps_dir = -1;
1353 lpstg->stde.pps_sb = -1;
1354 lpstg->stde.pps_size = 0;
1355 lpstg->stde.pps_type = 1;
1356 lpstg->ppsent = ppsent;
1357 /* FIXME: timestamps? */
1358 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1359 return E_FAIL;
1360 return OLE_OK;
1363 /******************************************************************************
1364 * IStorage16_CreateStream [STORAGE.503]
1366 HRESULT WINAPI IStorage16_fnCreateStream(
1367 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1369 ICOM_THIS(IStorage16,iface);
1370 _IStream16* lpstr;
1371 int ppsent,x;
1372 struct storage_pps_entry stde;
1374 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1375 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1377 if (grfMode & STGM_TRANSACTED)
1378 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1379 _create_istream16(ppstm);
1380 lpstr = (_IStream16*)PTR_SEG_TO_LIN(*ppstm);
1381 lpstr->hf = FILE_Dup(this->hf);
1382 lpstr->offset.LowPart = 0;
1383 lpstr->offset.HighPart = 0;
1385 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1386 if (ppsent<0)
1387 return E_FAIL;
1388 stde=this->stde;
1389 if (stde.pps_next==-1)
1390 x=this->ppsent;
1391 else
1392 while (stde.pps_next!=-1) {
1393 x=stde.pps_next;
1394 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1395 return E_FAIL;
1397 stde.pps_next = ppsent;
1398 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1399 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1400 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1401 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1402 lpstr->stde.pps_next = -1;
1403 lpstr->stde.pps_prev = -1;
1404 lpstr->stde.pps_dir = -1;
1405 lpstr->stde.pps_sb = -1;
1406 lpstr->stde.pps_size = 0;
1407 lpstr->stde.pps_type = 2;
1408 lpstr->ppsent = ppsent;
1409 /* FIXME: timestamps? */
1410 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1411 return E_FAIL;
1412 return OLE_OK;
1415 /******************************************************************************
1416 * IStorage16_OpenStorage [STORAGE.506]
1418 HRESULT WINAPI IStorage16_fnOpenStorage(
1419 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1421 ICOM_THIS(IStorage16,iface);
1422 _IStream16* lpstg;
1423 WCHAR name[33];
1424 int newpps;
1426 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1427 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1429 if (grfMode & STGM_TRANSACTED)
1430 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1431 _create_istorage16(ppstg);
1432 lpstg = (_IStream16*)PTR_SEG_TO_LIN(*ppstg);
1433 lpstg->hf = FILE_Dup(this->hf);
1434 lstrcpyAtoW(name,pwcsName);
1435 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1436 if (newpps==-1) {
1437 IStream16_fnRelease((IUnknown*)lpstg);
1438 return E_FAIL;
1441 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1442 IStream16_fnRelease((IUnknown*)lpstg);
1443 return E_FAIL;
1445 lpstg->ppsent = newpps;
1446 return OLE_OK;
1449 /******************************************************************************
1450 * IStorage16_OpenStream [STORAGE.504]
1452 HRESULT WINAPI IStorage16_fnOpenStream(
1453 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1455 ICOM_THIS(IStorage16,iface);
1456 _IStream16* lpstr;
1457 WCHAR name[33];
1458 int newpps;
1460 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1461 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1463 if (grfMode & STGM_TRANSACTED)
1464 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1465 _create_istream16(ppstm);
1466 lpstr = (_IStream16*)PTR_SEG_TO_LIN(*ppstm);
1467 lpstr->hf = FILE_Dup(this->hf);
1468 lstrcpyAtoW(name,pwcsName);
1469 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1470 if (newpps==-1) {
1471 IStream16_fnRelease((IUnknown*)lpstr);
1472 return E_FAIL;
1475 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1476 IStream16_fnRelease((IUnknown*)lpstr);
1477 return E_FAIL;
1479 lpstr->offset.LowPart = 0;
1480 lpstr->offset.HighPart = 0;
1481 lpstr->ppsent = newpps;
1482 return OLE_OK;
1485 /******************************************************************************
1486 * _create_istorage16 [INTERNAL]
1488 static void _create_istorage16(LPSTORAGE16 *stg) {
1489 _IStorage16* lpst;
1491 if (!stvt16.bvt.fnQueryInterface) {
1492 HMODULE16 wp = GetModuleHandle16("STORAGE");
1493 if (wp>=32) {
1494 #define VTENT(xfn) stvt16.bvt.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1495 VTENT(QueryInterface)
1496 VTENT(AddRef)
1497 VTENT(Release)
1498 #undef VTENT
1499 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1500 VTENT(CreateStream)
1501 VTENT(OpenStream)
1502 VTENT(CreateStorage)
1503 VTENT(OpenStorage)
1504 VTENT(CopyTo)
1505 VTENT(MoveElementTo)
1506 VTENT(Commit)
1507 VTENT(Revert)
1508 VTENT(EnumElements)
1509 VTENT(DestroyElement)
1510 VTENT(RenameElement)
1511 VTENT(SetElementTimes)
1512 VTENT(SetClass)
1513 VTENT(SetStateBits)
1514 VTENT(Stat)
1515 #undef VTENT
1516 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1517 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1518 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1519 } else {
1520 #define VTENT(xfn) stvt16.bvt.fn##xfn = IStorage16_fn##xfn;
1521 VTENT(QueryInterface)
1522 VTENT(AddRef)
1523 VTENT(Release)
1524 #undef VTENT
1525 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1526 VTENT(CreateStream)
1527 VTENT(OpenStream)
1528 VTENT(CreateStorage)
1529 VTENT(OpenStorage)
1530 VTENT(CopyTo)
1531 VTENT(Commit)
1532 /* not (yet) implemented ...
1533 VTENT(MoveElementTo)
1534 VTENT(Revert)
1535 VTENT(EnumElements)
1536 VTENT(DestroyElement)
1537 VTENT(RenameElement)
1538 VTENT(SetElementTimes)
1539 VTENT(SetClass)
1540 VTENT(SetStateBits)
1541 VTENT(Stat)
1543 #undef VTENT
1544 segstvt16 = &stvt16;
1547 lpst = SEGPTR_NEW(_IStorage16);
1548 lpst->lpvtbl = segstvt16;
1549 lpst->ref = 1;
1550 lpst->thisptr = SEGPTR_GET(lpst);
1551 *stg = (void*)lpst->thisptr;
1555 /* --- IStorage32 implementation */
1557 typedef struct _IStorage32 {
1558 /* IUnknown fields */
1559 ICOM_VTABLE(IStorage32)* lpvtbl;
1560 DWORD ref;
1561 /* IStorage32 fields */
1562 struct storage_pps_entry stde;
1563 int ppsent;
1564 HFILE32 hf;
1565 } _IStorage32;
1567 /******************************************************************************
1568 * IStorage32_QueryInterface [VTABLE]
1570 HRESULT WINAPI IStorage32_fnQueryInterface(
1571 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
1573 ICOM_THIS(IStorage32,iface);
1574 char xrefiid[50];
1576 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1577 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1579 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1580 *obj = this;
1581 return 0;
1583 return OLE_E_ENUM_NOMORE;
1586 /******************************************************************************
1587 * IStorage32_AddRef [VTABLE]
1589 ULONG WINAPI IStorage32_fnAddRef(LPUNKNOWN iface) {
1590 ICOM_THIS(IStorage32,iface);
1591 return ++(this->ref);
1594 /******************************************************************************
1595 * IStorage32_Release [VTABLE]
1597 ULONG WINAPI IStorage32_fnRelease(LPUNKNOWN iface) {
1598 ICOM_THIS(IStorage32,iface);
1599 this->ref--;
1600 if (this->ref)
1601 return this->ref;
1602 HeapFree(GetProcessHeap(),0,this);
1603 return 0;
1606 /******************************************************************************
1607 * IStorage32_CreateStream [VTABLE]
1609 HRESULT WINAPI IStorage32_fnCreateStream(
1610 LPSTORAGE32 iface,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1612 ICOM_THIS(IStorage32,iface);
1613 TRACE(ole,"(%p)->(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1614 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1616 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1617 ((_IStream32*)(*ppstm))->lpvtbl= &strvt32;
1618 ((_IStream32*)(*ppstm))->ref = 1;
1620 return OLE_OK;
1623 /******************************************************************************
1624 * IStorage32_OpenStream [VTABLE]
1626 HRESULT WINAPI IStorage32_fnOpenStream(
1627 LPSTORAGE32 iface,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1629 ICOM_THIS(IStorage32,iface);
1630 TRACE(ole,"(%p)->(%p,%p,0x%08lx,0x%08lx,%p)\n",
1631 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1633 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1634 ((_IStream32*)(*ppstm))->lpvtbl= &strvt32;
1635 ((_IStream32*)(*ppstm))->ref = 1;
1636 return OLE_OK;
1639 static ICOM_VTABLE(IStorage32) stvt32 = {
1641 IStorage32_fnQueryInterface,
1642 IStorage32_fnAddRef,
1643 IStorage32_fnRelease
1645 IStorage32_fnCreateStream,
1646 IStorage32_fnOpenStream,
1647 (void*)0xdead0006,
1648 (void*)0xdead0007,
1649 (void*)0xdead0008,
1650 (void*)0xdead0009,
1651 (void*)0xdead0010,
1652 (void*)0xdead0011,
1653 (void*)0xdead0012,
1654 (void*)0xdead0013,
1655 (void*)0xdead0014,
1656 (void*)0xdead0015,
1657 (void*)0xdead0016,
1658 (void*)0xdead0017,
1659 (void*)0xdead0018,
1662 /******************************************************************************
1663 * Storage API functions
1666 /******************************************************************************
1667 * StgCreateDocFile16 [STORAGE.1]
1669 OLESTATUS WINAPI StgCreateDocFile16(
1670 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1672 HFILE32 hf;
1673 int i,ret;
1674 _IStorage16* lpstg;
1675 struct storage_pps_entry stde;
1677 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1678 pwcsName,grfMode,reserved,ppstgOpen
1680 _create_istorage16(ppstgOpen);
1681 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1682 if (hf==INVALID_HANDLE_VALUE32) {
1683 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1684 return E_FAIL;
1686 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstgOpen);
1687 lpstg->hf = hf;
1688 /* FIXME: check for existance before overwriting? */
1689 if (!STORAGE_init_storage(hf)) {
1690 CloseHandle(hf);
1691 return E_FAIL;
1693 i=0;ret=0;
1694 while (!ret) { /* neither 1 nor <0 */
1695 ret=STORAGE_get_pps_entry(hf,i,&stde);
1696 if ((ret==1) && (stde.pps_type==5)) {
1697 lpstg->stde = stde;
1698 lpstg->ppsent = i;
1699 break;
1701 i++;
1703 if (ret!=1) {
1704 IStorage16_fnRelease((IUnknown*)lpstg); /* will remove it */
1705 return E_FAIL;
1707 return OLE_OK;
1710 /******************************************************************************
1711 * StgCreateDocFile32 [OLE32.144]
1713 OLESTATUS WINAPI StgCreateDocFile32(
1714 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1716 TRACE(ole,"(%p,0x%08lx,0x%08lx,%p)\n",
1717 pwcsName,grfMode,reserved,ppstgOpen
1719 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1720 ((_IStorage32*)(*ppstgOpen))->ref = 1;
1721 ((_IStorage32*)(*ppstgOpen))->lpvtbl = &stvt32;
1722 return OLE_OK;
1725 /******************************************************************************
1726 * StgIsStorageFile16 [STORAGE.5]
1728 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1729 HFILE32 hf;
1730 OFSTRUCT ofs;
1731 BYTE magic[24];
1733 TRACE(ole,"(\'%s\')\n",fn);
1734 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1735 if (hf==HFILE_ERROR32)
1736 return STG_E_FILENOTFOUND;
1737 if (24!=_lread32(hf,magic,24)) {
1738 WARN(ole," too short\n");
1739 _lclose32(hf);
1740 return S_FALSE;
1742 if (!memcmp(magic,STORAGE_magic,8)) {
1743 WARN(ole," -> YES\n");
1744 _lclose32(hf);
1745 return S_OK;
1747 if (!memcmp(magic,STORAGE_notmagic,8)) {
1748 WARN(ole," -> NO\n");
1749 _lclose32(hf);
1750 return S_FALSE;
1752 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1753 WARN(ole," -> old format\n");
1754 _lclose32(hf);
1755 return STG_E_OLDFORMAT;
1757 WARN(ole," -> Invalid header.\n");
1758 _lclose32(hf);
1759 return STG_E_INVALIDHEADER;
1762 /******************************************************************************
1763 * StgIsStorageFile32 [OLE32.146]
1765 OLESTATUS WINAPI
1766 StgIsStorageFile32(LPCOLESTR32 fn)
1768 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1769 OLESTATUS ret = StgIsStorageFile16(xfn);
1771 HeapFree(GetProcessHeap(),0,xfn);
1772 return ret;
1776 /******************************************************************************
1777 * StgOpenStorage16 [STORAGE.3]
1779 OLESTATUS WINAPI StgOpenStorage16(
1780 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1781 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1783 HFILE32 hf;
1784 int ret,i;
1785 _IStorage16* lpstg;
1786 struct storage_pps_entry stde;
1788 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1789 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1791 _create_istorage16(ppstgOpen);
1792 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1793 if (hf==INVALID_HANDLE_VALUE32) {
1794 WARN(ole,"Couldn't open file for storage\n");
1795 return E_FAIL;
1797 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstgOpen);
1798 lpstg->hf = hf;
1800 i=0;ret=0;
1801 while (!ret) { /* neither 1 nor <0 */
1802 ret=STORAGE_get_pps_entry(hf,i,&stde);
1803 if ((ret==1) && (stde.pps_type==5)) {
1804 lpstg->stde=stde;
1805 break;
1807 i++;
1809 if (ret!=1) {
1810 IStorage16_fnRelease((IUnknown*)lpstg); /* will remove it */
1811 return E_FAIL;
1813 return OLE_OK;
1817 /******************************************************************************
1818 * StgOpenStorage32 [OLE32.148]
1820 OLESTATUS WINAPI StgOpenStorage32(
1821 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1822 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1824 FIXME(ole,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1825 pwcsName,pstgPriority,grfMode,snbExclude,reserved,
1826 ppstgOpen);
1827 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1828 ((_IStorage32*)(*ppstgOpen))->ref = 1;
1829 ((_IStorage32*)(*ppstgOpen))->lpvtbl = &stvt32;
1830 return OLE_OK;