Removed extra output.
[wine/multimedia.git] / ole / storage.c
blobfac935053283d4a8d358fae22c2d8e2fb107915b
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 IStorage16_VTable stvt16;
37 static IStorage16_VTable *segstvt16 = NULL;
38 static IStorage32_VTable stvt32;
39 static IStream16_VTable strvt16;
40 static IStream16_VTable *segstrvt16 = NULL;
41 static IStream32_VTable 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
49 /******************************************************************************
50 * STORAGE_get_big_block [Internal]
52 * Reading OLE compound storage
54 static BOOL32
55 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
56 assert(n>=-1);
57 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
58 WARN(ole," seek failed (%ld)\n",GetLastError());
59 return FALSE;
61 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
62 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
63 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
64 assert(0);
65 return FALSE;
67 return TRUE;
70 /******************************************************************************
71 * STORAGE_put_big_block [INTERNAL]
73 static BOOL32
74 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
75 assert(n>=-1);
76 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
77 WARN(ole," seek failed (%ld)\n",GetLastError());
78 return FALSE;
80 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
81 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
82 WARN(ole," write failed (%ld)\n",GetLastError());
83 return FALSE;
85 return TRUE;
88 /******************************************************************************
89 * STORAGE_get_next_big_blocknr [INTERNAL]
91 static int
92 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
93 INT32 bbs[BIGSIZE/sizeof(INT32)];
94 struct storage_header sth;
96 READ_HEADER;
98 assert(blocknr>>7<sth.num_of_bbd_blocks);
99 if (sth.bbd_list[blocknr>>7]==0xffffffff)
100 return -5;
101 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
102 return -5;
103 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
104 return bbs[blocknr&0x7f];
107 /******************************************************************************
108 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
110 static int
111 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
112 INT32 bbs[BIGSIZE/sizeof(INT32)];
113 int lastblock = -1;
114 struct storage_header sth;
116 READ_HEADER;
118 assert(blocknr>=0);
119 while (nr--) {
120 assert((blocknr>>7)<sth.num_of_bbd_blocks);
121 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
123 /* simple caching... */
124 if (lastblock!=sth.bbd_list[blocknr>>7]) {
125 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
126 lastblock = sth.bbd_list[blocknr>>7];
128 blocknr = bbs[blocknr&0x7f];
130 return blocknr;
133 /******************************************************************************
134 * STORAGE_get_root_pps_entry [Internal]
136 static BOOL32
137 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
138 int blocknr,i;
139 BYTE block[BIGSIZE];
140 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
141 struct storage_header sth;
143 READ_HEADER;
144 blocknr = sth.root_startblock;
145 while (blocknr>=0) {
146 assert(STORAGE_get_big_block(hf,blocknr,block));
147 for (i=0;i<4;i++) {
148 if (!stde[i].pps_sizeofname)
149 continue;
150 if (stde[i].pps_type==5) {
151 *pstde=stde[i];
152 return TRUE;
155 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
157 return FALSE;
160 /******************************************************************************
161 * STORAGE_get_small_block [INTERNAL]
163 static BOOL32
164 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
165 BYTE block[BIGSIZE];
166 int bigblocknr;
167 struct storage_pps_entry root;
169 assert(blocknr>=0);
170 assert(STORAGE_get_root_pps_entry(hf,&root));
171 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
172 assert(bigblocknr>=0);
173 assert(STORAGE_get_big_block(hf,bigblocknr,block));
175 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
176 return TRUE;
179 /******************************************************************************
180 * STORAGE_put_small_block [INTERNAL]
182 static BOOL32
183 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
184 BYTE block[BIGSIZE];
185 int bigblocknr;
186 struct storage_pps_entry root;
188 assert(blocknr>=0);
190 assert(STORAGE_get_root_pps_entry(hf,&root));
191 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
192 assert(bigblocknr>=0);
193 assert(STORAGE_get_big_block(hf,bigblocknr,block));
195 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
196 assert(STORAGE_put_big_block(hf,bigblocknr,block));
197 return TRUE;
200 /******************************************************************************
201 * STORAGE_get_next_small_blocknr [INTERNAL]
203 static int
204 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
205 BYTE block[BIGSIZE];
206 LPINT32 sbd = (LPINT32)block;
207 int bigblocknr;
208 struct storage_header sth;
210 READ_HEADER;
211 assert(blocknr>=0);
212 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
213 assert(bigblocknr>=0);
214 assert(STORAGE_get_big_block(hf,bigblocknr,block));
215 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
216 return sbd[blocknr & (128-1)];
219 /******************************************************************************
220 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
222 static int
223 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
224 int lastblocknr;
225 BYTE block[BIGSIZE];
226 LPINT32 sbd = (LPINT32)block;
227 struct storage_header sth;
229 READ_HEADER;
230 lastblocknr=-1;
231 assert(blocknr>=0);
232 while ((nr--) && (blocknr>=0)) {
233 if (lastblocknr/128!=blocknr/128) {
234 int bigblocknr;
235 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
236 assert(bigblocknr>=0);
237 assert(STORAGE_get_big_block(hf,bigblocknr,block));
238 lastblocknr = blocknr;
240 assert(lastblocknr>=0);
241 lastblocknr=blocknr;
242 blocknr=sbd[blocknr & (128-1)];
243 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
245 return blocknr;
248 /******************************************************************************
249 * STORAGE_get_pps_entry [INTERNAL]
251 static int
252 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
253 int blocknr;
254 BYTE block[BIGSIZE];
255 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
256 struct storage_header sth;
258 READ_HEADER;
259 /* we have 4 pps entries per big block */
260 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
261 assert(blocknr>=0);
262 assert(STORAGE_get_big_block(hf,blocknr,block));
264 *pstde=*stde;
265 return 1;
268 /******************************************************************************
269 * STORAGE_put_pps_entry [Internal]
271 static int
272 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
273 int blocknr;
274 BYTE block[BIGSIZE];
275 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
276 struct storage_header sth;
278 READ_HEADER;
280 /* we have 4 pps entries per big block */
281 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
282 assert(blocknr>=0);
283 assert(STORAGE_get_big_block(hf,blocknr,block));
284 *stde=*pstde;
285 assert(STORAGE_put_big_block(hf,blocknr,block));
286 return 1;
289 /******************************************************************************
290 * STORAGE_look_for_named_pps [Internal]
292 static int
293 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
294 struct storage_pps_entry stde;
295 int ret;
297 if (n==-1)
298 return -1;
299 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
300 return -1;
302 if (!lstrcmp32W(name,stde.pps_rawname))
303 return n;
304 if (stde.pps_prev != -1) {
305 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
306 if (ret!=-1)
307 return ret;
309 if (stde.pps_next != -1) {
310 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
311 if (ret!=-1)
312 return ret;
314 return -1;
317 /******************************************************************************
318 * STORAGE_dump_pps_entry [Internal]
320 * FIXME
321 * Function is unused
323 void
324 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
325 char name[33],xguid[50];
327 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
329 lstrcpyWtoA(name,stde->pps_rawname);
330 if (!stde->pps_sizeofname)
331 return;
332 DUMP("name: %s\n",name);
333 DUMP("type: %d\n",stde->pps_type);
334 DUMP("prev pps: %ld\n",stde->pps_prev);
335 DUMP("next pps: %ld\n",stde->pps_next);
336 DUMP("dir pps: %ld\n",stde->pps_dir);
337 DUMP("guid: %s\n",xguid);
338 if (stde->pps_type !=2) {
339 time_t t;
341 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
342 DUMP("ts1: %s\n",ctime(&t));
343 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
344 DUMP("ts2: %s\n",ctime(&t));
346 DUMP("startblock: %ld\n",stde->pps_sb);
347 DUMP("size: %ld\n",stde->pps_size);
350 /******************************************************************************
351 * STORAGE_init_storage [INTERNAL]
353 static BOOL32
354 STORAGE_init_storage(HFILE32 hf) {
355 BYTE block[BIGSIZE];
356 LPDWORD bbs;
357 struct storage_header *sth;
358 struct storage_pps_entry *stde;
360 assert(-1!=_llseek32(hf,0,SEEK_SET));
361 /* block -1 is the storage header */
362 sth = (struct storage_header*)block;
363 memcpy(sth->magic,STORAGE_magic,8);
364 memset(sth->unknown1,0,sizeof(sth->unknown1));
365 memset(sth->unknown2,0,sizeof(sth->unknown2));
366 memset(sth->unknown3,0,sizeof(sth->unknown3));
367 sth->num_of_bbd_blocks = 1;
368 sth->root_startblock = 1;
369 sth->sbd_startblock = 0xffffffff;
370 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
371 sth->bbd_list[0] = 0;
372 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
373 /* block 0 is the big block directory */
374 bbs=(LPDWORD)block;
375 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
376 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
377 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
378 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
379 /* block 1 is the root directory entry */
380 memset(block,0x00,sizeof(block));
381 stde = (struct storage_pps_entry*)block;
382 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
383 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
384 stde->pps_type = 5;
385 stde->pps_dir = -1;
386 stde->pps_next = -1;
387 stde->pps_prev = -1;
388 stde->pps_sb = 0xffffffff;
389 stde->pps_size = 0;
390 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
391 return TRUE;
394 /******************************************************************************
395 * STORAGE_set_big_chain [Internal]
397 static BOOL32
398 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
399 BYTE block[BIGSIZE];
400 LPINT32 bbd = (LPINT32)block;
401 int nextblocknr,bigblocknr;
402 struct storage_header sth;
404 READ_HEADER;
405 assert(blocknr!=type);
406 while (blocknr>=0) {
407 bigblocknr = sth.bbd_list[blocknr/128];
408 assert(bigblocknr>=0);
409 assert(STORAGE_get_big_block(hf,bigblocknr,block));
411 nextblocknr = bbd[blocknr&(128-1)];
412 bbd[blocknr&(128-1)] = type;
413 if (type>=0)
414 return TRUE;
415 assert(STORAGE_put_big_block(hf,bigblocknr,block));
416 type = STORAGE_CHAINENTRY_FREE;
417 blocknr = nextblocknr;
419 return TRUE;
422 /******************************************************************************
423 * STORAGE_set_small_chain [INTERNAL]
425 static BOOL32
426 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
427 BYTE block[BIGSIZE];
428 LPINT32 sbd = (LPINT32)block;
429 int lastblocknr,nextsmallblocknr,bigblocknr;
430 struct storage_header sth;
432 READ_HEADER;
434 assert(blocknr!=type);
435 lastblocknr=-129;bigblocknr=-2;
436 while (blocknr>=0) {
437 /* cache block ... */
438 if (lastblocknr/128!=blocknr/128) {
439 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
440 assert(bigblocknr>=0);
441 assert(STORAGE_get_big_block(hf,bigblocknr,block));
443 lastblocknr = blocknr;
444 nextsmallblocknr = sbd[blocknr&(128-1)];
445 sbd[blocknr&(128-1)] = type;
446 assert(STORAGE_put_big_block(hf,bigblocknr,block));
447 if (type>=0)
448 return TRUE;
449 type = STORAGE_CHAINENTRY_FREE;
450 blocknr = nextsmallblocknr;
452 return TRUE;
455 /******************************************************************************
456 * STORAGE_get_free_big_blocknr [Internal]
458 static int
459 STORAGE_get_free_big_blocknr(HFILE32 hf) {
460 BYTE block[BIGSIZE];
461 LPINT32 sbd = (LPINT32)block;
462 int lastbigblocknr,i,curblock,bigblocknr;
463 struct storage_header sth;
465 READ_HEADER;
466 curblock = 0;
467 lastbigblocknr = -1;
468 bigblocknr = sth.bbd_list[curblock];
469 while (curblock<sth.num_of_bbd_blocks) {
470 assert(bigblocknr>=0);
471 assert(STORAGE_get_big_block(hf,bigblocknr,block));
472 for (i=0;i<128;i++)
473 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
474 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
475 assert(STORAGE_put_big_block(hf,bigblocknr,block));
476 memset(block,0x42,sizeof(block));
477 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
478 return i+curblock*128;
480 lastbigblocknr = bigblocknr;
481 bigblocknr = sth.bbd_list[++curblock];
483 bigblocknr = curblock*128;
484 /* since we have marked all blocks from 0 up to curblock*128-1
485 * the next free one is curblock*128, where we happily put our
486 * next large block depot.
488 memset(block,0xff,sizeof(block));
489 /* mark the block allocated and returned by this function */
490 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
491 assert(STORAGE_put_big_block(hf,bigblocknr,block));
493 /* if we had a bbd block already (mostlikely) we need
494 * to link the new one into the chain
496 if (lastbigblocknr!=-1)
497 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
498 sth.bbd_list[curblock]=bigblocknr;
499 sth.num_of_bbd_blocks++;
500 assert(sth.num_of_bbd_blocks==curblock+1);
501 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
503 /* Set the end of the chain for the bigblockdepots */
504 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
505 /* add 1, for the first entry is used for the additional big block
506 * depot. (means we already used bigblocknr) */
507 memset(block,0x42,sizeof(block));
508 /* allocate this block (filled with 0x42) */
509 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
510 return bigblocknr+1;
514 /******************************************************************************
515 * STORAGE_get_free_small_blocknr [Internal]
517 static int
518 STORAGE_get_free_small_blocknr(HFILE32 hf) {
519 BYTE block[BIGSIZE];
520 LPINT32 sbd = (LPINT32)block;
521 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
522 struct storage_pps_entry root;
523 struct storage_header sth;
525 READ_HEADER;
526 bigblocknr = sth.sbd_startblock;
527 curblock = 0;
528 lastbigblocknr = -1;
529 newblocknr = -1;
530 while (bigblocknr>=0) {
531 if (!STORAGE_get_big_block(hf,bigblocknr,block))
532 return -1;
533 for (i=0;i<128;i++)
534 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
535 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
536 newblocknr = i+curblock*128;
537 break;
539 if (i!=128)
540 break;
541 lastbigblocknr = bigblocknr;
542 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
543 curblock++;
545 if (newblocknr==-1) {
546 bigblocknr = STORAGE_get_free_big_blocknr(hf);
547 if (bigblocknr<0)
548 return -1;
549 READ_HEADER;
550 memset(block,0xff,sizeof(block));
551 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
552 if (!STORAGE_put_big_block(hf,bigblocknr,block))
553 return -1;
554 if (lastbigblocknr==-1) {
555 sth.sbd_startblock = bigblocknr;
556 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
557 return -1;
558 } else {
559 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
560 return -1;
562 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
563 return -1;
564 newblocknr = curblock*128;
566 /* allocate enough big blocks for storing the allocated small block */
567 if (!STORAGE_get_root_pps_entry(hf,&root))
568 return -1;
569 if (root.pps_sb==-1)
570 lastbigblocknr = -1;
571 else
572 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
573 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
574 /* we need to allocate more stuff */
575 bigblocknr = STORAGE_get_free_big_blocknr(hf);
576 if (bigblocknr<0)
577 return -1;
578 READ_HEADER;
579 if (root.pps_sb==-1) {
580 root.pps_sb = bigblocknr;
581 root.pps_size += BIGSIZE;
582 } else {
583 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
584 return -1;
585 root.pps_size += BIGSIZE;
587 lastbigblocknr = bigblocknr;
589 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
590 return -1;
591 if (!STORAGE_put_pps_entry(hf,0,&root))
592 return -1;
593 return newblocknr;
596 /******************************************************************************
597 * STORAGE_get_free_pps_entry [Internal]
599 static int
600 STORAGE_get_free_pps_entry(HFILE32 hf) {
601 int blocknr,i,curblock,lastblocknr;
602 BYTE block[BIGSIZE];
603 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
604 struct storage_header sth;
606 READ_HEADER;
607 blocknr = sth.root_startblock;
608 assert(blocknr>=0);
609 curblock=0;
610 while (blocknr>=0) {
611 if (!STORAGE_get_big_block(hf,blocknr,block))
612 return -1;
613 for (i=0;i<4;i++)
614 if (stde[i].pps_sizeofname==0) /* free */
615 return curblock*4+i;
616 lastblocknr = blocknr;
617 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
618 curblock++;
620 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
621 blocknr = STORAGE_get_free_big_blocknr(hf);
622 /* sth invalidated */
623 if (blocknr<0)
624 return -1;
626 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
627 return -1;
628 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
629 return -1;
630 memset(block,0,sizeof(block));
631 STORAGE_put_big_block(hf,blocknr,block);
632 return curblock*4;
635 /******************************************************************************
636 * IStream16_QueryInterface [STORAGE.518]
638 HRESULT WINAPI IStream16_QueryInterface(
639 LPSTREAM16 this,REFIID refiid,LPVOID *obj
641 char xrefiid[50];
643 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
644 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
645 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
646 *obj = this;
647 return 0;
649 return OLE_E_ENUM_NOMORE;
653 /******************************************************************************
654 * IStream16_AddRef [STORAGE.519]
656 ULONG WINAPI IStream16_AddRef(LPSTREAM16 this) {
657 return ++(this->ref);
660 /******************************************************************************
661 * IStream16_Release [STORAGE.520]
663 ULONG WINAPI IStream16_Release(LPSTREAM16 this) {
664 FlushFileBuffers(this->hf);
665 this->ref--;
666 if (!this->ref) {
667 CloseHandle(this->hf);
668 SEGPTR_FREE(this);
669 return 0;
671 return this->ref;
674 /******************************************************************************
675 * IStream16_Seek [STORAGE.523]
677 * FIXME
678 * Does not handle 64 bits
680 HRESULT WINAPI IStream16_Seek(
681 LPSTREAM16 this,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
683 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
685 switch (whence) {
686 /* unix SEEK_xx should be the same as win95 ones */
687 case SEEK_SET:
688 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
689 * right now.
691 assert(offset.HighPart==0);
692 this->offset.HighPart = offset.HighPart;
693 this->offset.LowPart = offset.LowPart;
694 break;
695 case SEEK_CUR:
696 if (offset.HighPart < 0) {
697 /* FIXME: is this negation correct ? */
698 offset.HighPart = -offset.HighPart;
699 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
701 assert(offset.HighPart==0);
702 assert(this->offset.LowPart >= offset.LowPart);
703 this->offset.LowPart -= offset.LowPart;
704 } else {
705 assert(offset.HighPart==0);
706 this->offset.LowPart+= offset.LowPart;
708 break;
709 case SEEK_END:
710 assert(offset.HighPart==0);
711 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
712 break;
714 if (this->offset.LowPart>this->stde.pps_size)
715 this->offset.LowPart=this->stde.pps_size;
716 if (newpos) *newpos = this->offset;
717 return OLE_OK;
720 /******************************************************************************
721 * IStream16_Read [STORAGE.521]
723 HRESULT WINAPI IStream16_Read(
724 LPSTREAM16 this,void *pv,ULONG cb,ULONG *pcbRead
726 BYTE block[BIGSIZE];
727 ULONG *bytesread=pcbRead,xxread;
728 int blocknr;
730 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
731 if (!pcbRead) bytesread=&xxread;
732 *bytesread = 0;
734 if (cb>this->stde.pps_size-this->offset.LowPart)
735 cb=this->stde.pps_size-this->offset.LowPart;
736 if (this->stde.pps_size < 0x1000) {
737 /* use small block reader */
738 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
739 while (cb) {
740 int cc;
742 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
743 WARN(ole,"small block read failed!!!\n");
744 return E_FAIL;
746 cc = cb;
747 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
748 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
749 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
750 this->offset.LowPart+=cc;
751 (LPBYTE)pv+=cc;
752 *bytesread+=cc;
753 cb-=cc;
754 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
756 } else {
757 /* use big block reader */
758 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
759 while (cb) {
760 int cc;
762 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
763 WARN(ole,"big block read failed!!!\n");
764 return E_FAIL;
766 cc = cb;
767 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
768 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
769 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
770 this->offset.LowPart+=cc;
771 (LPBYTE)pv+=cc;
772 *bytesread+=cc;
773 cb-=cc;
774 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
777 return OLE_OK;
780 /******************************************************************************
781 * IStream16_Write [STORAGE.522]
783 HRESULT WINAPI IStream16_Write(
784 LPSTREAM16 this,const void *pv,ULONG cb,ULONG *pcbWrite
786 BYTE block[BIGSIZE];
787 ULONG *byteswritten=pcbWrite,xxwritten;
788 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
789 HFILE32 hf = this->hf;
791 if (!pcbWrite) byteswritten=&xxwritten;
792 *byteswritten = 0;
794 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
795 /* do we need to junk some blocks? */
796 newsize = this->offset.LowPart+cb;
797 oldsize = this->stde.pps_size;
798 if (newsize < oldsize) {
799 if (oldsize < 0x1000) {
800 /* only small blocks */
801 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
803 assert(blocknr>=0);
805 /* will set the rest of the chain to 'free' */
806 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
807 return E_FAIL;
808 } else {
809 if (newsize >= 0x1000) {
810 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
811 assert(blocknr>=0);
813 /* will set the rest of the chain to 'free' */
814 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
815 return E_FAIL;
816 } else {
817 /* Migrate large blocks to small blocks
818 * (we just migrate newsize bytes)
820 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
821 cc = newsize;
822 blocknr = this->stde.pps_sb;
823 curdata = data;
824 while (cc>0) {
825 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
826 HeapFree(GetProcessHeap(),0,data);
827 return E_FAIL;
829 curdata += BIGSIZE;
830 cc -= BIGSIZE;
831 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
833 /* frees complete chain for this stream */
834 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
835 return E_FAIL;
836 curdata = data;
837 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
838 if (blocknr<0)
839 return E_FAIL;
840 cc = newsize;
841 while (cc>0) {
842 if (!STORAGE_put_small_block(hf,blocknr,curdata))
843 return E_FAIL;
844 cc -= SMALLSIZE;
845 if (cc<=0) {
846 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
847 return E_FAIL;
848 break;
849 } else {
850 int newblocknr = STORAGE_get_free_small_blocknr(hf);
851 if (newblocknr<0)
852 return E_FAIL;
853 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
854 return E_FAIL;
855 blocknr = newblocknr;
857 curdata += SMALLSIZE;
859 HeapFree(GetProcessHeap(),0,data);
862 this->stde.pps_size = newsize;
865 if (newsize > oldsize) {
866 if (oldsize >= 0x1000) {
867 /* should return the block right before the 'endofchain' */
868 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
869 assert(blocknr>=0);
870 lastblocknr = blocknr;
871 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
872 blocknr = STORAGE_get_free_big_blocknr(hf);
873 if (blocknr<0)
874 return E_FAIL;
875 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
876 return E_FAIL;
877 lastblocknr = blocknr;
879 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
880 return E_FAIL;
881 } else {
882 if (newsize < 0x1000) {
883 /* find startblock */
884 if (!oldsize)
885 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
886 else
887 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
888 if (blocknr<0)
889 return E_FAIL;
891 /* allocate required new small blocks */
892 lastblocknr = blocknr;
893 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
894 blocknr = STORAGE_get_free_small_blocknr(hf);
895 if (blocknr<0)
896 return E_FAIL;
897 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
898 return E_FAIL;
899 lastblocknr = blocknr;
901 /* and terminate the chain */
902 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
903 return E_FAIL;
904 } else {
905 if (!oldsize) {
906 /* no single block allocated yet */
907 blocknr=STORAGE_get_free_big_blocknr(hf);
908 if (blocknr<0)
909 return E_FAIL;
910 this->stde.pps_sb = blocknr;
911 } else {
912 /* Migrate small blocks to big blocks */
913 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
914 cc = oldsize;
915 blocknr = this->stde.pps_sb;
916 curdata = data;
917 /* slurp in */
918 while (cc>0) {
919 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
920 HeapFree(GetProcessHeap(),0,data);
921 return E_FAIL;
923 curdata += SMALLSIZE;
924 cc -= SMALLSIZE;
925 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
927 /* free small block chain */
928 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
929 return E_FAIL;
930 curdata = data;
931 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
932 if (blocknr<0)
933 return E_FAIL;
934 /* put the data into the big blocks */
935 cc = this->stde.pps_size;
936 while (cc>0) {
937 if (!STORAGE_put_big_block(hf,blocknr,curdata))
938 return E_FAIL;
939 cc -= BIGSIZE;
940 if (cc<=0) {
941 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
942 return E_FAIL;
943 break;
944 } else {
945 int newblocknr = STORAGE_get_free_big_blocknr(hf);
946 if (newblocknr<0)
947 return E_FAIL;
948 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
949 return E_FAIL;
950 blocknr = newblocknr;
952 curdata += BIGSIZE;
954 HeapFree(GetProcessHeap(),0,data);
956 /* generate big blocks to fit the new data */
957 lastblocknr = blocknr;
958 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
959 blocknr = STORAGE_get_free_big_blocknr(hf);
960 if (blocknr<0)
961 return E_FAIL;
962 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
963 return E_FAIL;
964 lastblocknr = blocknr;
966 /* terminate chain */
967 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
968 return E_FAIL;
971 this->stde.pps_size = newsize;
974 /* There are just some cases where we didn't modify it, we write it out
975 * everytime
977 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
978 return E_FAIL;
980 /* finally the write pass */
981 if (this->stde.pps_size < 0x1000) {
982 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
983 assert(blocknr>=0);
984 while (cb>0) {
985 /* we ensured that it is allocated above */
986 assert(blocknr>=0);
987 /* Read old block everytime, since we can have
988 * overlapping data at START and END of the write
990 if (!STORAGE_get_small_block(hf,blocknr,block))
991 return E_FAIL;
993 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
994 if (cc>cb)
995 cc=cb;
996 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
997 (LPBYTE)(pv+curoffset),
1000 if (!STORAGE_put_small_block(hf,blocknr,block))
1001 return E_FAIL;
1002 cb -= cc;
1003 curoffset += cc;
1004 (LPBYTE)pv += cc;
1005 this->offset.LowPart += cc;
1006 *byteswritten += cc;
1007 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1009 } else {
1010 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
1011 assert(blocknr>=0);
1012 while (cb>0) {
1013 /* we ensured that it is allocated above, so it better is */
1014 assert(blocknr>=0);
1015 /* read old block everytime, since we can have
1016 * overlapping data at START and END of the write
1018 if (!STORAGE_get_big_block(hf,blocknr,block))
1019 return E_FAIL;
1021 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
1022 if (cc>cb)
1023 cc=cb;
1024 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
1025 (LPBYTE)(pv+curoffset),
1028 if (!STORAGE_put_big_block(hf,blocknr,block))
1029 return E_FAIL;
1030 cb -= cc;
1031 curoffset += cc;
1032 (LPBYTE)pv += cc;
1033 this->offset.LowPart += cc;
1034 *byteswritten += cc;
1035 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1038 return OLE_OK;
1041 /******************************************************************************
1042 * _create_istream16 [Internal]
1044 static void _create_istream16(LPSTREAM16 *str) {
1045 LPSTREAM16 lpst;
1047 if (!strvt16.fnQueryInterface) {
1048 HMODULE16 wp = GetModuleHandle16("STORAGE");
1049 if (wp>=32) {
1050 #define VTENT(x) strvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#x);
1051 VTENT(QueryInterface)
1052 VTENT(AddRef)
1053 VTENT(Release)
1054 VTENT(Read)
1055 VTENT(Write)
1056 VTENT(Seek)
1057 VTENT(SetSize)
1058 VTENT(CopyTo)
1059 VTENT(Commit)
1060 VTENT(Revert)
1061 VTENT(LockRegion)
1062 VTENT(UnlockRegion)
1063 VTENT(Stat)
1064 VTENT(Clone)
1065 #undef VTENT
1066 segstrvt16 = SEGPTR_NEW(IStream16_VTable);
1067 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1068 segstrvt16 = (LPSTREAM16_VTABLE)SEGPTR_GET(segstrvt16);
1069 } else {
1070 #define VTENT(x) strvt16.fn##x = IStream16_##x;
1071 VTENT(QueryInterface)
1072 VTENT(AddRef)
1073 VTENT(Release)
1074 VTENT(Read)
1075 VTENT(Write)
1076 VTENT(Seek)
1078 VTENT(CopyTo)
1079 VTENT(Commit)
1080 VTENT(SetSize)
1081 VTENT(Revert)
1082 VTENT(LockRegion)
1083 VTENT(UnlockRegion)
1084 VTENT(Stat)
1085 VTENT(Clone)
1087 #undef VTENT
1088 segstrvt16 = &strvt16;
1091 lpst = SEGPTR_NEW(IStream16);
1092 lpst->lpvtbl = segstrvt16;
1093 lpst->ref = 1;
1094 lpst->thisptr = SEGPTR_GET(lpst);
1095 *str = (void*)lpst->thisptr;
1098 /*****************************************************************************
1099 * IStream32_QueryInterface [VTABLE]
1101 HRESULT WINAPI IStream32_QueryInterface(
1102 LPSTREAM32 this,REFIID refiid,LPVOID *obj
1104 char xrefiid[50];
1106 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1107 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1108 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1109 *obj = this;
1110 return 0;
1112 return OLE_E_ENUM_NOMORE;
1116 /******************************************************************************
1117 * IStream32_AddRef [VTABLE]
1119 ULONG WINAPI IStream32_AddRef(LPSTREAM32 this) {
1120 return ++(this->ref);
1123 /******************************************************************************
1124 * IStream32_Release [VTABLE]
1126 ULONG WINAPI IStream32_Release(LPSTREAM32 this) {
1127 FlushFileBuffers(this->hf);
1128 this->ref--;
1129 if (!this->ref) {
1130 CloseHandle(this->hf);
1131 SEGPTR_FREE(this);
1132 return 0;
1134 return this->ref;
1137 static IStream32_VTable strvt32 = {
1138 IStream32_QueryInterface,
1139 IStream32_AddRef,
1140 IStream32_Release,
1141 (void*)4,
1142 (void*)5,
1143 (void*)6,
1144 (void*)7,
1145 (void*)8,
1146 (void*)9,
1147 (void*)10,
1148 (void*)11,
1152 /******************************************************************************
1153 * IStorage16_QueryInterface [STORAGE.500]
1155 HRESULT WINAPI IStorage16_QueryInterface(
1156 LPSTORAGE16 this,REFIID refiid,LPVOID *obj
1158 char xrefiid[50];
1160 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1161 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1163 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1164 *obj = this;
1165 return 0;
1167 return OLE_E_ENUM_NOMORE;
1170 /******************************************************************************
1171 * IStorage16_AddRef [STORAGE.501]
1173 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this) {
1174 return ++(this->ref);
1177 /******************************************************************************
1178 * IStorage16_Release [STORAGE.502]
1180 ULONG WINAPI IStorage16_Release(LPSTORAGE16 this) {
1181 this->ref--;
1182 if (this->ref)
1183 return this->ref;
1184 SEGPTR_FREE(this);
1185 return 0;
1188 /******************************************************************************
1189 * IStorage16_Stat [STORAGE.517]
1191 HRESULT WINAPI IStorage16_Stat(
1192 LPSTORAGE16 this,STATSTG *pstatstg, DWORD grfStatFlag
1194 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1195 this,pstatstg,grfStatFlag
1197 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1198 pstatstg->type = this->stde.pps_type;
1199 pstatstg->cbSize.LowPart = this->stde.pps_size;
1200 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1201 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1202 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1203 pstatstg->grfMode = 0; /* FIXME */
1204 pstatstg->grfLocksSupported = 0; /* FIXME */
1205 pstatstg->clsid = this->stde.pps_guid;
1206 pstatstg->grfStateBits = 0; /* FIXME */
1207 pstatstg->reserved = 0;
1208 return OLE_OK;
1211 /******************************************************************************
1212 * IStorage16_Commit [STORAGE.509]
1214 HRESULT WINAPI IStorage16_Commit(
1215 LPSTORAGE16 this,DWORD commitflags
1217 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1218 this,commitflags
1220 return OLE_OK;
1223 /******************************************************************************
1224 * IStorage16_CopyTo [STORAGE.507]
1226 HRESULT WINAPI IStorage16_CopyTo(LPSTORAGE16 this,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1227 char xguid[50];
1229 if (rgiidExclude)
1230 WINE_StringFromCLSID(rgiidExclude,xguid);
1231 else
1232 strcpy(xguid,"<no guid>");
1233 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1234 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1236 return OLE_OK;
1240 /******************************************************************************
1241 * IStorage16_CreateStorage [STORAGE.505]
1243 HRESULT WINAPI IStorage16_CreateStorage(
1244 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1246 LPSTORAGE16 lpstg;
1247 int ppsent,x;
1248 struct storage_pps_entry stde;
1249 struct storage_header sth;
1250 HFILE32 hf=this->hf;
1252 READ_HEADER;
1254 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1255 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1257 if (grfMode & STGM_TRANSACTED)
1258 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1259 _create_istorage16(ppstg);
1260 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstg);
1261 lpstg->hf = this->hf;
1263 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1264 if (ppsent<0)
1265 return E_FAIL;
1266 stde=this->stde;
1267 if (stde.pps_dir==-1) {
1268 stde.pps_dir = ppsent;
1269 x = this->ppsent;
1270 } else {
1271 FIXME(ole," use prev chain too ?\n");
1272 x=stde.pps_dir;
1273 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1274 return E_FAIL;
1275 while (stde.pps_next!=-1) {
1276 x=stde.pps_next;
1277 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1278 return E_FAIL;
1280 stde.pps_next = ppsent;
1282 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1283 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1284 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1285 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1286 lpstg->stde.pps_next = -1;
1287 lpstg->stde.pps_prev = -1;
1288 lpstg->stde.pps_dir = -1;
1289 lpstg->stde.pps_sb = -1;
1290 lpstg->stde.pps_size = 0;
1291 lpstg->stde.pps_type = 1;
1292 lpstg->ppsent = ppsent;
1293 /* FIXME: timestamps? */
1294 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1295 return E_FAIL;
1296 return OLE_OK;
1299 /******************************************************************************
1300 * IStorage16_CreateStream [STORAGE.503]
1302 HRESULT WINAPI IStorage16_CreateStream(
1303 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1305 LPSTREAM16 lpstr;
1306 int ppsent,x;
1307 struct storage_pps_entry stde;
1309 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1310 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1312 if (grfMode & STGM_TRANSACTED)
1313 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1314 _create_istream16(ppstm);
1315 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1316 lpstr->hf = FILE_Dup(this->hf);
1317 lpstr->offset.LowPart = 0;
1318 lpstr->offset.HighPart = 0;
1320 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1321 if (ppsent<0)
1322 return E_FAIL;
1323 stde=this->stde;
1324 if (stde.pps_next==-1)
1325 x=this->ppsent;
1326 else
1327 while (stde.pps_next!=-1) {
1328 x=stde.pps_next;
1329 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1330 return E_FAIL;
1332 stde.pps_next = ppsent;
1333 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1334 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1335 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1336 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1337 lpstr->stde.pps_next = -1;
1338 lpstr->stde.pps_prev = -1;
1339 lpstr->stde.pps_dir = -1;
1340 lpstr->stde.pps_sb = -1;
1341 lpstr->stde.pps_size = 0;
1342 lpstr->stde.pps_type = 2;
1343 lpstr->ppsent = ppsent;
1344 /* FIXME: timestamps? */
1345 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1346 return E_FAIL;
1347 return OLE_OK;
1350 /******************************************************************************
1351 * IStorage16_OpenStorage [STORAGE.506]
1353 HRESULT WINAPI IStorage16_OpenStorage(
1354 LPSTORAGE16 this,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1356 LPSTREAM16 lpstg;
1357 WCHAR name[33];
1358 int newpps;
1360 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1361 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1363 if (grfMode & STGM_TRANSACTED)
1364 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1365 _create_istorage16(ppstg);
1366 lpstg = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstg);
1367 lpstg->hf = FILE_Dup(this->hf);
1368 lstrcpyAtoW(name,pwcsName);
1369 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1370 if (newpps==-1) {
1371 IStream16_Release(lpstg);
1372 return E_FAIL;
1375 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1376 IStream16_Release(lpstg);
1377 return E_FAIL;
1379 lpstg->ppsent = newpps;
1380 return OLE_OK;
1383 /******************************************************************************
1384 * IStorage16_OpenStream [STORAGE.504]
1386 HRESULT WINAPI IStorage16_OpenStream(
1387 LPSTORAGE16 this,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1389 LPSTREAM16 lpstr;
1390 WCHAR name[33];
1391 int newpps;
1393 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1394 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1396 if (grfMode & STGM_TRANSACTED)
1397 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1398 _create_istream16(ppstm);
1399 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1400 lpstr->hf = FILE_Dup(this->hf);
1401 lstrcpyAtoW(name,pwcsName);
1402 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1403 if (newpps==-1) {
1404 IStream16_Release(lpstr);
1405 return E_FAIL;
1408 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1409 IStream16_Release(lpstr);
1410 return E_FAIL;
1412 lpstr->offset.LowPart = 0;
1413 lpstr->offset.HighPart = 0;
1414 lpstr->ppsent = newpps;
1415 return OLE_OK;
1418 /******************************************************************************
1419 * _create_istorage16 [INTERNAL]
1421 static void _create_istorage16(LPSTORAGE16 *stg) {
1422 LPSTORAGE16 lpst;
1424 if (!stvt16.fnQueryInterface) {
1425 HMODULE16 wp = GetModuleHandle16("STORAGE");
1426 if (wp>=32) {
1427 #define VTENT(x) stvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#x);
1428 VTENT(QueryInterface)
1429 VTENT(AddRef)
1430 VTENT(Release)
1431 VTENT(CreateStream)
1432 VTENT(OpenStream)
1433 VTENT(CreateStorage)
1434 VTENT(OpenStorage)
1435 VTENT(CopyTo)
1436 VTENT(MoveElementTo)
1437 VTENT(Commit)
1438 VTENT(Revert)
1439 VTENT(EnumElements)
1440 VTENT(DestroyElement)
1441 VTENT(RenameElement)
1442 VTENT(SetElementTimes)
1443 VTENT(SetClass)
1444 VTENT(SetStateBits)
1445 VTENT(Stat)
1446 #undef VTENT
1447 segstvt16 = SEGPTR_NEW(IStorage16_VTable);
1448 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1449 segstvt16 = (LPSTORAGE16_VTABLE)SEGPTR_GET(segstvt16);
1450 } else {
1451 #define VTENT(x) stvt16.fn##x = IStorage16_##x;
1452 VTENT(QueryInterface)
1453 VTENT(AddRef)
1454 VTENT(Release)
1455 VTENT(CreateStream)
1456 VTENT(OpenStream)
1457 VTENT(CreateStorage)
1458 VTENT(OpenStorage)
1459 VTENT(CopyTo)
1460 VTENT(Commit)
1461 /* not (yet) implemented ...
1462 VTENT(MoveElementTo)
1463 VTENT(Revert)
1464 VTENT(EnumElements)
1465 VTENT(DestroyElement)
1466 VTENT(RenameElement)
1467 VTENT(SetElementTimes)
1468 VTENT(SetClass)
1469 VTENT(SetStateBits)
1470 VTENT(Stat)
1472 #undef VTENT
1473 segstvt16 = &stvt16;
1476 lpst = SEGPTR_NEW(IStorage16);
1477 lpst->lpvtbl = segstvt16;
1478 lpst->ref = 1;
1479 lpst->thisptr = SEGPTR_GET(lpst);
1480 *stg = (void*)lpst->thisptr;
1483 /******************************************************************************
1484 * IStorage32_QueryInterface [VTABLE]
1486 HRESULT WINAPI IStorage32_QueryInterface(
1487 LPSTORAGE32 this,REFIID refiid,LPVOID *obj
1489 char xrefiid[50];
1491 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1492 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1494 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1495 *obj = this;
1496 return 0;
1498 return OLE_E_ENUM_NOMORE;
1501 /******************************************************************************
1502 * IStorage32_AddRef [VTABLE]
1504 ULONG WINAPI IStorage32_AddRef(LPSTORAGE32 this) {
1505 return ++(this->ref);
1508 /******************************************************************************
1509 * IStorage32_Release [VTABLE]
1511 ULONG WINAPI IStorage32_Release(LPSTORAGE32 this) {
1512 this->ref--;
1513 if (this->ref)
1514 return this->ref;
1515 HeapFree(GetProcessHeap(),0,this);
1516 return 0;
1519 /******************************************************************************
1520 * IStorage32_CreateStream [VTABLE]
1522 HRESULT WINAPI IStorage32_CreateStream(
1523 LPSTORAGE32 this,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1525 TRACE(ole,"(%p)->(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1526 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1528 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1529 (*ppstm)->lpvtbl= &strvt32;
1530 (*ppstm)->ref = 1;
1532 return OLE_OK;
1535 /******************************************************************************
1536 * IStorage32_OpenStream [VTABLE]
1538 HRESULT WINAPI IStorage32_OpenStream(
1539 LPSTORAGE32 this,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1541 TRACE(ole,"(%p)->(%p,%p,0x%08lx,0x%08lx,%p)\n",
1542 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1544 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1545 (*ppstm)->lpvtbl= &strvt32;
1546 (*ppstm)->ref = 1;
1547 return OLE_OK;
1550 static IStorage32_VTable stvt32 = {
1551 IStorage32_QueryInterface,
1552 IStorage32_AddRef,
1553 IStorage32_Release,
1554 IStorage32_CreateStream,
1555 IStorage32_OpenStream,
1556 (void*)6,
1557 (void*)7,
1558 (void*)8,
1559 (void*)9,
1560 (void*)10,
1561 (void*)11,
1562 (void*)12,
1563 (void*)13,
1564 (void*)14,
1565 (void*)15,
1568 /******************************************************************************
1569 * Storage API functions
1572 /******************************************************************************
1573 * StgCreateDocFile16 [STORAGE.1]
1575 OLESTATUS WINAPI StgCreateDocFile16(
1576 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1578 HFILE32 hf;
1579 int i,ret;
1580 LPSTORAGE16 lpstg;
1581 struct storage_pps_entry stde;
1583 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1584 pwcsName,grfMode,reserved,ppstgOpen
1586 _create_istorage16(ppstgOpen);
1587 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1588 if (hf==INVALID_HANDLE_VALUE32) {
1589 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1590 return E_FAIL;
1592 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1593 lpstg->hf = hf;
1594 /* FIXME: check for existance before overwriting? */
1595 if (!STORAGE_init_storage(hf)) {
1596 CloseHandle(hf);
1597 return E_FAIL;
1599 i=0;ret=0;
1600 while (!ret) { /* neither 1 nor <0 */
1601 ret=STORAGE_get_pps_entry(hf,i,&stde);
1602 if ((ret==1) && (stde.pps_type==5)) {
1603 lpstg->stde = stde;
1604 lpstg->ppsent = i;
1605 break;
1607 i++;
1609 if (ret!=1) {
1610 IStorage16_Release(lpstg); /* will remove it */
1611 return E_FAIL;
1613 return OLE_OK;
1616 /******************************************************************************
1617 * StgCreateDocFile32 [OLE32.144]
1619 OLESTATUS WINAPI StgCreateDocFile32(
1620 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1622 TRACE(ole,"(%p,0x%08lx,0x%08lx,%p)\n",
1623 pwcsName,grfMode,reserved,ppstgOpen
1625 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1626 (*ppstgOpen)->ref = 1;
1627 (*ppstgOpen)->lpvtbl = &stvt32;
1628 return OLE_OK;
1631 /******************************************************************************
1632 * StgIsStorageFile16 [STORAGE.5]
1634 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1635 HFILE32 hf;
1636 OFSTRUCT ofs;
1637 BYTE magic[24];
1639 TRACE(ole,"(\'%s\')\n",fn);
1640 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1641 if (hf==HFILE_ERROR32)
1642 return STG_E_FILENOTFOUND;
1643 if (24!=_lread32(hf,magic,24)) {
1644 WARN(ole," too short\n");
1645 _lclose32(hf);
1646 return S_FALSE;
1648 if (!memcmp(magic,STORAGE_magic,8)) {
1649 WARN(ole," -> YES\n");
1650 _lclose32(hf);
1651 return S_OK;
1653 if (!memcmp(magic,STORAGE_notmagic,8)) {
1654 WARN(ole," -> NO\n");
1655 _lclose32(hf);
1656 return S_FALSE;
1658 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1659 WARN(ole," -> old format\n");
1660 _lclose32(hf);
1661 return STG_E_OLDFORMAT;
1663 WARN(ole," -> Invalid header.\n");
1664 _lclose32(hf);
1665 return STG_E_INVALIDHEADER;
1668 /******************************************************************************
1669 * StgIsStorageFile32 [OLE32.146]
1671 OLESTATUS WINAPI
1672 StgIsStorageFile32(LPCOLESTR32 fn)
1674 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1675 OLESTATUS ret = StgIsStorageFile16(xfn);
1677 HeapFree(GetProcessHeap(),0,xfn);
1678 return ret;
1682 /******************************************************************************
1683 * StgOpenStorage16 [STORAGE.3]
1685 OLESTATUS WINAPI StgOpenStorage16(
1686 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1687 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1689 HFILE32 hf;
1690 int ret,i;
1691 LPSTORAGE16 lpstg;
1692 struct storage_pps_entry stde;
1694 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1695 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1697 _create_istorage16(ppstgOpen);
1698 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1699 if (hf==INVALID_HANDLE_VALUE32) {
1700 WARN(ole,"Couldn't open file for storage\n");
1701 return E_FAIL;
1703 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1704 lpstg->hf = hf;
1706 i=0;ret=0;
1707 while (!ret) { /* neither 1 nor <0 */
1708 ret=STORAGE_get_pps_entry(hf,i,&stde);
1709 if ((ret==1) && (stde.pps_type==5)) {
1710 lpstg->stde=stde;
1711 break;
1713 i++;
1715 if (ret!=1) {
1716 IStorage16_Release(lpstg); /* will remove it */
1717 return E_FAIL;
1719 return OLE_OK;
1723 /******************************************************************************
1724 * StgOpenStorage32 [OLE32.148]
1726 OLESTATUS WINAPI StgOpenStorage32(
1727 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1728 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1730 FIXME(ole,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1731 pwcsName,pstgPriority,grfMode,snbExclude,reserved,
1732 ppstgOpen);
1733 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1734 (*ppstgOpen)->ref = 1;
1735 (*ppstgOpen)->lpvtbl = &stvt32;
1736 return OLE_OK;