Started the implementation of IMAGEHLP.DLL.
[wine/multimedia.git] / ole / storage.c
blob893c7a1d9b53fd1f1e7dbab421ae4b92f1f46dfc
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 static BOOL32
71 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
72 assert(n>=-1);
73 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
74 WARN(ole," seek failed (%ld)\n",GetLastError());
75 return FALSE;
77 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
78 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
79 WARN(ole," write failed (%ld)\n",GetLastError());
80 return FALSE;
82 return TRUE;
85 static int
86 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
87 INT32 bbs[BIGSIZE/sizeof(INT32)];
88 struct storage_header sth;
90 READ_HEADER;
92 assert(blocknr>>7<sth.num_of_bbd_blocks);
93 if (sth.bbd_list[blocknr>>7]==0xffffffff)
94 return -5;
95 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
96 return -5;
97 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
98 return bbs[blocknr&0x7f];
101 static int
102 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
103 INT32 bbs[BIGSIZE/sizeof(INT32)];
104 int lastblock = -1;
105 struct storage_header sth;
107 READ_HEADER;
109 assert(blocknr>=0);
110 while (nr--) {
111 assert((blocknr>>7)<sth.num_of_bbd_blocks);
112 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
114 /* simple caching... */
115 if (lastblock!=sth.bbd_list[blocknr>>7]) {
116 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
117 lastblock = sth.bbd_list[blocknr>>7];
119 blocknr = bbs[blocknr&0x7f];
121 return blocknr;
124 /******************************************************************************
125 * STORAGE_get_root_pps_entry [Internal]
127 static BOOL32
128 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
129 int blocknr,i;
130 BYTE block[BIGSIZE];
131 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
132 struct storage_header sth;
134 READ_HEADER;
135 blocknr = sth.root_startblock;
136 while (blocknr>=0) {
137 assert(STORAGE_get_big_block(hf,blocknr,block));
138 for (i=0;i<4;i++) {
139 if (!stde[i].pps_sizeofname)
140 continue;
141 if (stde[i].pps_type==5) {
142 *pstde=stde[i];
143 return TRUE;
146 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
148 return FALSE;
151 static BOOL32
152 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
153 BYTE block[BIGSIZE];
154 int bigblocknr;
155 struct storage_pps_entry root;
157 assert(blocknr>=0);
158 assert(STORAGE_get_root_pps_entry(hf,&root));
159 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
160 assert(bigblocknr>=0);
161 assert(STORAGE_get_big_block(hf,bigblocknr,block));
163 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
164 return TRUE;
167 static BOOL32
168 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
169 BYTE block[BIGSIZE];
170 int bigblocknr;
171 struct storage_pps_entry root;
173 assert(blocknr>=0);
175 assert(STORAGE_get_root_pps_entry(hf,&root));
176 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
177 assert(bigblocknr>=0);
178 assert(STORAGE_get_big_block(hf,bigblocknr,block));
180 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
181 assert(STORAGE_put_big_block(hf,bigblocknr,block));
182 return TRUE;
186 static int
187 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
188 BYTE block[BIGSIZE];
189 LPINT32 sbd = (LPINT32)block;
190 int bigblocknr;
191 struct storage_header sth;
193 READ_HEADER;
194 assert(blocknr>=0);
195 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
196 assert(bigblocknr>=0);
197 assert(STORAGE_get_big_block(hf,bigblocknr,block));
198 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
199 return sbd[blocknr & (128-1)];
202 static int
203 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
204 int lastblocknr;
205 BYTE block[BIGSIZE];
206 LPINT32 sbd = (LPINT32)block;
207 struct storage_header sth;
209 READ_HEADER;
210 lastblocknr=-1;
211 assert(blocknr>=0);
212 while ((nr--) && (blocknr>=0)) {
213 if (lastblocknr/128!=blocknr/128) {
214 int bigblocknr;
215 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
216 assert(bigblocknr>=0);
217 assert(STORAGE_get_big_block(hf,bigblocknr,block));
218 lastblocknr = blocknr;
220 assert(lastblocknr>=0);
221 lastblocknr=blocknr;
222 blocknr=sbd[blocknr & (128-1)];
223 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
225 return blocknr;
228 static int
229 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
230 int blocknr;
231 BYTE block[BIGSIZE];
232 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
233 struct storage_header sth;
235 READ_HEADER;
236 /* we have 4 pps entries per big block */
237 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
238 assert(blocknr>=0);
239 assert(STORAGE_get_big_block(hf,blocknr,block));
241 *pstde=*stde;
242 return 1;
245 /******************************************************************************
246 * STORAGE_put_pps_entry [Internal]
248 static int
249 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
250 int blocknr;
251 BYTE block[BIGSIZE];
252 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
253 struct storage_header sth;
255 READ_HEADER;
257 /* we have 4 pps entries per big block */
258 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
259 assert(blocknr>=0);
260 assert(STORAGE_get_big_block(hf,blocknr,block));
261 *stde=*pstde;
262 assert(STORAGE_put_big_block(hf,blocknr,block));
263 return 1;
266 /******************************************************************************
267 * STORAGE_look_for_named_pps [Internal]
269 static int
270 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
271 struct storage_pps_entry stde;
272 int ret;
274 if (n==-1)
275 return -1;
276 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
277 return -1;
279 if (!lstrcmp32W(name,stde.pps_rawname))
280 return n;
281 if (stde.pps_prev != -1) {
282 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
283 if (ret!=-1)
284 return ret;
286 if (stde.pps_next != -1) {
287 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
288 if (ret!=-1)
289 return ret;
291 return -1;
294 /******************************************************************************
295 * STORAGE_dump_pps_entry [Internal]
297 * FIXME
298 * Function is unused
300 void
301 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
302 char name[33],xguid[50];
304 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
306 lstrcpyWtoA(name,stde->pps_rawname);
307 if (!stde->pps_sizeofname)
308 return;
309 DUMP("name: %s\n",name);
310 DUMP("type: %d\n",stde->pps_type);
311 DUMP("prev pps: %ld\n",stde->pps_prev);
312 DUMP("next pps: %ld\n",stde->pps_next);
313 DUMP("dir pps: %ld\n",stde->pps_dir);
314 DUMP("guid: %s\n",xguid);
315 if (stde->pps_type !=2) {
316 time_t t;
318 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
319 DUMP("ts1: %s\n",ctime(&t));
320 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
321 DUMP("ts2: %s\n",ctime(&t));
323 DUMP("startblock: %ld\n",stde->pps_sb);
324 DUMP("size: %ld\n",stde->pps_size);
327 static BOOL32
328 STORAGE_init_storage(HFILE32 hf) {
329 BYTE block[BIGSIZE];
330 LPDWORD bbs;
331 struct storage_header *sth;
332 struct storage_pps_entry *stde;
334 assert(-1!=_llseek32(hf,0,SEEK_SET));
335 /* block -1 is the storage header */
336 sth = (struct storage_header*)block;
337 memcpy(sth->magic,STORAGE_magic,8);
338 memset(sth->unknown1,0,sizeof(sth->unknown1));
339 memset(sth->unknown2,0,sizeof(sth->unknown2));
340 memset(sth->unknown3,0,sizeof(sth->unknown3));
341 sth->num_of_bbd_blocks = 1;
342 sth->root_startblock = 1;
343 sth->sbd_startblock = 0xffffffff;
344 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
345 sth->bbd_list[0] = 0;
346 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
347 /* block 0 is the big block directory */
348 bbs=(LPDWORD)block;
349 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
350 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
351 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
352 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
353 /* block 1 is the root directory entry */
354 memset(block,0x00,sizeof(block));
355 stde = (struct storage_pps_entry*)block;
356 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
357 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
358 stde->pps_type = 5;
359 stde->pps_dir = -1;
360 stde->pps_next = -1;
361 stde->pps_prev = -1;
362 stde->pps_sb = 0xffffffff;
363 stde->pps_size = 0;
364 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
365 return TRUE;
368 /******************************************************************************
369 * STORAGE_set_big_chain [Internal]
371 static BOOL32
372 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
373 BYTE block[BIGSIZE];
374 LPINT32 bbd = (LPINT32)block;
375 int nextblocknr,bigblocknr;
376 struct storage_header sth;
378 READ_HEADER;
379 assert(blocknr!=type);
380 while (blocknr>=0) {
381 bigblocknr = sth.bbd_list[blocknr/128];
382 assert(bigblocknr>=0);
383 assert(STORAGE_get_big_block(hf,bigblocknr,block));
385 nextblocknr = bbd[blocknr&(128-1)];
386 bbd[blocknr&(128-1)] = type;
387 if (type>=0)
388 return TRUE;
389 assert(STORAGE_put_big_block(hf,bigblocknr,block));
390 type = STORAGE_CHAINENTRY_FREE;
391 blocknr = nextblocknr;
393 return TRUE;
396 static BOOL32
397 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
398 BYTE block[BIGSIZE];
399 LPINT32 sbd = (LPINT32)block;
400 int lastblocknr,nextsmallblocknr,bigblocknr;
401 struct storage_header sth;
403 READ_HEADER;
405 assert(blocknr!=type);
406 lastblocknr=-129;bigblocknr=-2;
407 while (blocknr>=0) {
408 /* cache block ... */
409 if (lastblocknr/128!=blocknr/128) {
410 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
411 assert(bigblocknr>=0);
412 assert(STORAGE_get_big_block(hf,bigblocknr,block));
414 lastblocknr = blocknr;
415 nextsmallblocknr = sbd[blocknr&(128-1)];
416 sbd[blocknr&(128-1)] = type;
417 assert(STORAGE_put_big_block(hf,bigblocknr,block));
418 if (type>=0)
419 return TRUE;
420 type = STORAGE_CHAINENTRY_FREE;
421 blocknr = nextsmallblocknr;
423 return TRUE;
426 /******************************************************************************
427 * STORAGE_get_free_big_blocknr [Internal]
429 static int
430 STORAGE_get_free_big_blocknr(HFILE32 hf) {
431 BYTE block[BIGSIZE];
432 LPINT32 sbd = (LPINT32)block;
433 int lastbigblocknr,i,curblock,bigblocknr;
434 struct storage_header sth;
436 READ_HEADER;
437 curblock = 0;
438 lastbigblocknr = -1;
439 bigblocknr = sth.bbd_list[curblock];
440 while (curblock<sth.num_of_bbd_blocks) {
441 assert(bigblocknr>=0);
442 assert(STORAGE_get_big_block(hf,bigblocknr,block));
443 for (i=0;i<128;i++)
444 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
445 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
446 assert(STORAGE_put_big_block(hf,bigblocknr,block));
447 memset(block,0x42,sizeof(block));
448 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
449 return i+curblock*128;
451 lastbigblocknr = bigblocknr;
452 bigblocknr = sth.bbd_list[++curblock];
454 bigblocknr = curblock*128;
455 /* since we have marked all blocks from 0 up to curblock*128-1
456 * the next free one is curblock*128, where we happily put our
457 * next large block depot.
459 memset(block,0xff,sizeof(block));
460 /* mark the block allocated and returned by this function */
461 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
462 assert(STORAGE_put_big_block(hf,bigblocknr,block));
464 /* if we had a bbd block already (mostlikely) we need
465 * to link the new one into the chain
467 if (lastbigblocknr!=-1)
468 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
469 sth.bbd_list[curblock]=bigblocknr;
470 sth.num_of_bbd_blocks++;
471 assert(sth.num_of_bbd_blocks==curblock+1);
472 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
474 /* Set the end of the chain for the bigblockdepots */
475 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
476 /* add 1, for the first entry is used for the additional big block
477 * depot. (means we already used bigblocknr) */
478 memset(block,0x42,sizeof(block));
479 /* allocate this block (filled with 0x42) */
480 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
481 return bigblocknr+1;
485 /******************************************************************************
486 * STORAGE_get_free_small_blocknr [Internal]
488 static int
489 STORAGE_get_free_small_blocknr(HFILE32 hf) {
490 BYTE block[BIGSIZE];
491 LPINT32 sbd = (LPINT32)block;
492 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
493 struct storage_pps_entry root;
494 struct storage_header sth;
496 READ_HEADER;
497 bigblocknr = sth.sbd_startblock;
498 curblock = 0;
499 lastbigblocknr = -1;
500 newblocknr = -1;
501 while (bigblocknr>=0) {
502 if (!STORAGE_get_big_block(hf,bigblocknr,block))
503 return -1;
504 for (i=0;i<128;i++)
505 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
506 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
507 newblocknr = i+curblock*128;
508 break;
510 if (i!=128)
511 break;
512 lastbigblocknr = bigblocknr;
513 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
514 curblock++;
516 if (newblocknr==-1) {
517 bigblocknr = STORAGE_get_free_big_blocknr(hf);
518 if (bigblocknr<0)
519 return -1;
520 READ_HEADER;
521 memset(block,0xff,sizeof(block));
522 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
523 if (!STORAGE_put_big_block(hf,bigblocknr,block))
524 return -1;
525 if (lastbigblocknr==-1) {
526 sth.sbd_startblock = bigblocknr;
527 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
528 return -1;
529 } else {
530 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
531 return -1;
533 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
534 return -1;
535 newblocknr = curblock*128;
537 /* allocate enough big blocks for storing the allocated small block */
538 if (!STORAGE_get_root_pps_entry(hf,&root))
539 return -1;
540 if (root.pps_sb==-1)
541 lastbigblocknr = -1;
542 else
543 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
544 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
545 /* we need to allocate more stuff */
546 bigblocknr = STORAGE_get_free_big_blocknr(hf);
547 if (bigblocknr<0)
548 return -1;
549 READ_HEADER;
550 if (root.pps_sb==-1) {
551 root.pps_sb = bigblocknr;
552 root.pps_size += BIGSIZE;
553 } else {
554 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
555 return -1;
556 root.pps_size += BIGSIZE;
558 lastbigblocknr = bigblocknr;
560 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
561 return -1;
562 if (!STORAGE_put_pps_entry(hf,0,&root))
563 return -1;
564 return newblocknr;
567 /******************************************************************************
568 * STORAGE_get_free_pps_entry [Internal]
570 static int
571 STORAGE_get_free_pps_entry(HFILE32 hf) {
572 int blocknr,i,curblock,lastblocknr;
573 BYTE block[BIGSIZE];
574 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
575 struct storage_header sth;
577 READ_HEADER;
578 blocknr = sth.root_startblock;
579 assert(blocknr>=0);
580 curblock=0;
581 while (blocknr>=0) {
582 if (!STORAGE_get_big_block(hf,blocknr,block))
583 return -1;
584 for (i=0;i<4;i++)
585 if (stde[i].pps_sizeofname==0) /* free */
586 return curblock*4+i;
587 lastblocknr = blocknr;
588 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
589 curblock++;
591 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
592 blocknr = STORAGE_get_free_big_blocknr(hf);
593 /* sth invalidated */
594 if (blocknr<0)
595 return -1;
597 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
598 return -1;
599 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
600 return -1;
601 memset(block,0,sizeof(block));
602 STORAGE_put_big_block(hf,blocknr,block);
603 return curblock*4;
606 /******************************************************************************
607 * IStream16_QueryInterface [STORAGE.518]
609 HRESULT WINAPI IStream16_QueryInterface(
610 LPSTREAM16 this,REFIID refiid,LPVOID *obj
612 char xrefiid[50];
614 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
615 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
616 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
617 *obj = this;
618 return 0;
620 return OLE_E_ENUM_NOMORE;
624 ULONG WINAPI IStream16_AddRef(LPSTREAM16 this) {
625 return ++(this->ref);
628 ULONG WINAPI IStream16_Release(LPSTREAM16 this) {
629 FlushFileBuffers(this->hf);
630 this->ref--;
631 if (!this->ref) {
632 CloseHandle(this->hf);
633 SEGPTR_FREE(this);
634 return 0;
636 return this->ref;
639 /******************************************************************************
640 * IStream16_Seek [STORAGE.523]
642 * FIXME
643 * Does not handle 64 bits
645 HRESULT WINAPI IStream16_Seek(
646 LPSTREAM16 this,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
648 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
650 switch (whence) {
651 /* unix SEEK_xx should be the same as win95 ones */
652 case SEEK_SET:
653 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
654 * right now.
656 assert(offset.HighPart==0);
657 this->offset.HighPart = offset.HighPart;
658 this->offset.LowPart = offset.LowPart;
659 break;
660 case SEEK_CUR:
661 if (offset.HighPart < 0) {
662 /* FIXME: is this negation correct ? */
663 offset.HighPart = -offset.HighPart;
664 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
666 assert(offset.HighPart==0);
667 assert(this->offset.LowPart >= offset.LowPart);
668 this->offset.LowPart -= offset.LowPart;
669 } else {
670 assert(offset.HighPart==0);
671 this->offset.LowPart+= offset.LowPart;
673 break;
674 case SEEK_END:
675 assert(offset.HighPart==0);
676 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
677 break;
679 if (this->offset.LowPart>this->stde.pps_size)
680 this->offset.LowPart=this->stde.pps_size;
681 if (newpos) *newpos = this->offset;
682 return OLE_OK;
685 /******************************************************************************
686 * IStream16_Read [STORAGE.521]
688 HRESULT WINAPI IStream16_Read(
689 LPSTREAM16 this,void *pv,ULONG cb,ULONG *pcbRead
691 BYTE block[BIGSIZE];
692 ULONG *bytesread=pcbRead,xxread;
693 int blocknr;
695 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
696 if (!pcbRead) bytesread=&xxread;
697 *bytesread = 0;
699 if (cb>this->stde.pps_size-this->offset.LowPart)
700 cb=this->stde.pps_size-this->offset.LowPart;
701 if (this->stde.pps_size < 0x1000) {
702 /* use small block reader */
703 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
704 while (cb) {
705 int cc;
707 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
708 WARN(ole,"small block read failed!!!\n");
709 return E_FAIL;
711 cc = cb;
712 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
713 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
714 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
715 this->offset.LowPart+=cc;
716 (LPBYTE)pv+=cc;
717 *bytesread+=cc;
718 cb-=cc;
719 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
721 } else {
722 /* use big block reader */
723 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
724 while (cb) {
725 int cc;
727 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
728 WARN(ole,"big block read failed!!!\n");
729 return E_FAIL;
731 cc = cb;
732 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
733 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
734 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
735 this->offset.LowPart+=cc;
736 (LPBYTE)pv+=cc;
737 *bytesread+=cc;
738 cb-=cc;
739 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
742 return OLE_OK;
745 /******************************************************************************
746 * IStream16_Write [STORAGE.522]
748 HRESULT WINAPI IStream16_Write(
749 LPSTREAM16 this,const void *pv,ULONG cb,ULONG *pcbWrite
751 BYTE block[BIGSIZE];
752 ULONG *byteswritten=pcbWrite,xxwritten;
753 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
754 HFILE32 hf = this->hf;
756 if (!pcbWrite) byteswritten=&xxwritten;
757 *byteswritten = 0;
759 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
760 /* do we need to junk some blocks? */
761 newsize = this->offset.LowPart+cb;
762 oldsize = this->stde.pps_size;
763 if (newsize < oldsize) {
764 if (oldsize < 0x1000) {
765 /* only small blocks */
766 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
768 assert(blocknr>=0);
770 /* will set the rest of the chain to 'free' */
771 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
772 return E_FAIL;
773 } else {
774 if (newsize >= 0x1000) {
775 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
776 assert(blocknr>=0);
778 /* will set the rest of the chain to 'free' */
779 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
780 return E_FAIL;
781 } else {
782 /* Migrate large blocks to small blocks
783 * (we just migrate newsize bytes)
785 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
786 cc = newsize;
787 blocknr = this->stde.pps_sb;
788 curdata = data;
789 while (cc>0) {
790 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
791 HeapFree(GetProcessHeap(),0,data);
792 return E_FAIL;
794 curdata += BIGSIZE;
795 cc -= BIGSIZE;
796 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
798 /* frees complete chain for this stream */
799 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
800 return E_FAIL;
801 curdata = data;
802 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
803 if (blocknr<0)
804 return E_FAIL;
805 cc = newsize;
806 while (cc>0) {
807 if (!STORAGE_put_small_block(hf,blocknr,curdata))
808 return E_FAIL;
809 cc -= SMALLSIZE;
810 if (cc<=0) {
811 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
812 return E_FAIL;
813 break;
814 } else {
815 int newblocknr = STORAGE_get_free_small_blocknr(hf);
816 if (newblocknr<0)
817 return E_FAIL;
818 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
819 return E_FAIL;
820 blocknr = newblocknr;
822 curdata += SMALLSIZE;
824 HeapFree(GetProcessHeap(),0,data);
827 this->stde.pps_size = newsize;
830 if (newsize > oldsize) {
831 if (oldsize >= 0x1000) {
832 /* should return the block right before the 'endofchain' */
833 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
834 assert(blocknr>=0);
835 lastblocknr = blocknr;
836 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
837 blocknr = STORAGE_get_free_big_blocknr(hf);
838 if (blocknr<0)
839 return E_FAIL;
840 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
841 return E_FAIL;
842 lastblocknr = blocknr;
844 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
845 return E_FAIL;
846 } else {
847 if (newsize < 0x1000) {
848 /* find startblock */
849 if (!oldsize)
850 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
851 else
852 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
853 if (blocknr<0)
854 return E_FAIL;
856 /* allocate required new small blocks */
857 lastblocknr = blocknr;
858 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
859 blocknr = STORAGE_get_free_small_blocknr(hf);
860 if (blocknr<0)
861 return E_FAIL;
862 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
863 return E_FAIL;
864 lastblocknr = blocknr;
866 /* and terminate the chain */
867 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
868 return E_FAIL;
869 } else {
870 if (!oldsize) {
871 /* no single block allocated yet */
872 blocknr=STORAGE_get_free_big_blocknr(hf);
873 if (blocknr<0)
874 return E_FAIL;
875 this->stde.pps_sb = blocknr;
876 } else {
877 /* Migrate small blocks to big blocks */
878 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
879 cc = oldsize;
880 blocknr = this->stde.pps_sb;
881 curdata = data;
882 /* slurp in */
883 while (cc>0) {
884 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
885 HeapFree(GetProcessHeap(),0,data);
886 return E_FAIL;
888 curdata += SMALLSIZE;
889 cc -= SMALLSIZE;
890 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
892 /* free small block chain */
893 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
894 return E_FAIL;
895 curdata = data;
896 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
897 if (blocknr<0)
898 return E_FAIL;
899 /* put the data into the big blocks */
900 cc = this->stde.pps_size;
901 while (cc>0) {
902 if (!STORAGE_put_big_block(hf,blocknr,curdata))
903 return E_FAIL;
904 cc -= BIGSIZE;
905 if (cc<=0) {
906 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
907 return E_FAIL;
908 break;
909 } else {
910 int newblocknr = STORAGE_get_free_big_blocknr(hf);
911 if (newblocknr<0)
912 return E_FAIL;
913 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
914 return E_FAIL;
915 blocknr = newblocknr;
917 curdata += BIGSIZE;
919 HeapFree(GetProcessHeap(),0,data);
921 /* generate big blocks to fit the new data */
922 lastblocknr = blocknr;
923 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
924 blocknr = STORAGE_get_free_big_blocknr(hf);
925 if (blocknr<0)
926 return E_FAIL;
927 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
928 return E_FAIL;
929 lastblocknr = blocknr;
931 /* terminate chain */
932 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933 return E_FAIL;
936 this->stde.pps_size = newsize;
939 /* There are just some cases where we didn't modify it, we write it out
940 * everytime
942 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
943 return E_FAIL;
945 /* finally the write pass */
946 if (this->stde.pps_size < 0x1000) {
947 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
948 assert(blocknr>=0);
949 while (cb>0) {
950 /* we ensured that it is allocated above */
951 assert(blocknr>=0);
952 /* Read old block everytime, since we can have
953 * overlapping data at START and END of the write
955 if (!STORAGE_get_small_block(hf,blocknr,block))
956 return E_FAIL;
958 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
959 if (cc>cb)
960 cc=cb;
961 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
962 (LPBYTE)(pv+curoffset),
965 if (!STORAGE_put_small_block(hf,blocknr,block))
966 return E_FAIL;
967 cb -= cc;
968 curoffset += cc;
969 (LPBYTE)pv += cc;
970 this->offset.LowPart += cc;
971 *byteswritten += cc;
972 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
974 } else {
975 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
976 assert(blocknr>=0);
977 while (cb>0) {
978 /* we ensured that it is allocated above, so it better is */
979 assert(blocknr>=0);
980 /* read old block everytime, since we can have
981 * overlapping data at START and END of the write
983 if (!STORAGE_get_big_block(hf,blocknr,block))
984 return E_FAIL;
986 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
987 if (cc>cb)
988 cc=cb;
989 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
990 (LPBYTE)(pv+curoffset),
993 if (!STORAGE_put_big_block(hf,blocknr,block))
994 return E_FAIL;
995 cb -= cc;
996 curoffset += cc;
997 (LPBYTE)pv += cc;
998 this->offset.LowPart += cc;
999 *byteswritten += cc;
1000 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1003 return OLE_OK;
1006 /******************************************************************************
1007 * _create_istream16 [Internal]
1009 static void _create_istream16(LPSTREAM16 *str) {
1010 LPSTREAM16 lpst;
1012 if (!strvt16.fnQueryInterface) {
1013 HMODULE16 wp = GetModuleHandle16("STORAGE");
1014 if (wp>=32) {
1015 #define VTENT(x) strvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#x);
1016 VTENT(QueryInterface)
1017 VTENT(AddRef)
1018 VTENT(Release)
1019 VTENT(Read)
1020 VTENT(Write)
1021 VTENT(Seek)
1022 VTENT(SetSize)
1023 VTENT(CopyTo)
1024 VTENT(Commit)
1025 VTENT(Revert)
1026 VTENT(LockRegion)
1027 VTENT(UnlockRegion)
1028 VTENT(Stat)
1029 VTENT(Clone)
1030 #undef VTENT
1031 segstrvt16 = SEGPTR_NEW(IStream16_VTable);
1032 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1033 segstrvt16 = (LPSTREAM16_VTABLE)SEGPTR_GET(segstrvt16);
1034 } else {
1035 #define VTENT(x) strvt16.fn##x = IStream16_##x;
1036 VTENT(QueryInterface)
1037 VTENT(AddRef)
1038 VTENT(Release)
1039 VTENT(Read)
1040 VTENT(Write)
1041 VTENT(Seek)
1043 VTENT(CopyTo)
1044 VTENT(Commit)
1045 VTENT(SetSize)
1046 VTENT(Revert)
1047 VTENT(LockRegion)
1048 VTENT(UnlockRegion)
1049 VTENT(Stat)
1050 VTENT(Clone)
1052 #undef VTENT
1053 segstrvt16 = &strvt16;
1056 lpst = SEGPTR_NEW(IStream16);
1057 lpst->lpvtbl = segstrvt16;
1058 lpst->ref = 1;
1059 lpst->thisptr = SEGPTR_GET(lpst);
1060 *str = (void*)lpst->thisptr;
1063 /*****************************************************************************
1064 * IStream32_QueryInterface [???]
1066 HRESULT WINAPI IStream32_QueryInterface(
1067 LPSTREAM32 this,REFIID refiid,LPVOID *obj
1069 char xrefiid[50];
1071 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1072 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1073 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1074 *obj = this;
1075 return 0;
1077 return OLE_E_ENUM_NOMORE;
1081 ULONG WINAPI IStream32_AddRef(LPSTREAM32 this) {
1082 return ++(this->ref);
1085 ULONG WINAPI IStream32_Release(LPSTREAM32 this) {
1086 FlushFileBuffers(this->hf);
1087 this->ref--;
1088 if (!this->ref) {
1089 CloseHandle(this->hf);
1090 SEGPTR_FREE(this);
1091 return 0;
1093 return this->ref;
1096 static IStream32_VTable strvt32 = {
1097 IStream32_QueryInterface,
1098 IStream32_AddRef,
1099 IStream32_Release,
1100 (void*)4,
1101 (void*)5,
1102 (void*)6,
1103 (void*)7,
1104 (void*)8,
1105 (void*)9,
1106 (void*)10,
1107 (void*)11,
1111 /******************************************************************************
1112 * IStorage16_QueryInterface [STORAGE.500]
1114 HRESULT WINAPI IStorage16_QueryInterface(
1115 LPSTORAGE16 this,REFIID refiid,LPVOID *obj
1117 char xrefiid[50];
1119 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1120 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1122 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1123 *obj = this;
1124 return 0;
1126 return OLE_E_ENUM_NOMORE;
1129 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this) {
1130 return ++(this->ref);
1133 ULONG WINAPI IStorage16_Release(LPSTORAGE16 this) {
1134 this->ref--;
1135 if (this->ref)
1136 return this->ref;
1137 SEGPTR_FREE(this);
1138 return 0;
1141 HRESULT WINAPI IStorage16_Stat(
1142 LPSTORAGE16 this,STATSTG *pstatstg, DWORD grfStatFlag
1144 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1145 this,pstatstg,grfStatFlag
1147 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1148 pstatstg->type = this->stde.pps_type;
1149 pstatstg->cbSize.LowPart = this->stde.pps_size;
1150 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1151 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1152 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1153 pstatstg->grfMode = 0; /* FIXME */
1154 pstatstg->grfLocksSupported = 0; /* FIXME */
1155 pstatstg->clsid = this->stde.pps_guid;
1156 pstatstg->grfStateBits = 0; /* FIXME */
1157 pstatstg->reserved = 0;
1158 return OLE_OK;
1161 /******************************************************************************
1162 * IStorage16_Commit [STORAGE.509]
1164 HRESULT WINAPI IStorage16_Commit(
1165 LPSTORAGE16 this,DWORD commitflags
1167 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1168 this,commitflags
1170 return OLE_OK;
1173 HRESULT WINAPI IStorage16_CopyTo(LPSTORAGE16 this,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1174 char xguid[50];
1176 if (rgiidExclude)
1177 WINE_StringFromCLSID(rgiidExclude,xguid);
1178 else
1179 strcpy(xguid,"<no guid>");
1180 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1181 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1183 return OLE_OK;
1188 HRESULT WINAPI IStorage16_CreateStorage(
1189 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1191 LPSTORAGE16 lpstg;
1192 int ppsent,x;
1193 struct storage_pps_entry stde;
1194 struct storage_header sth;
1195 HFILE32 hf=this->hf;
1197 READ_HEADER;
1199 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1200 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1202 if (grfMode & STGM_TRANSACTED)
1203 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1204 _create_istorage16(ppstg);
1205 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstg);
1206 lpstg->hf = this->hf;
1208 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1209 if (ppsent<0)
1210 return E_FAIL;
1211 stde=this->stde;
1212 if (stde.pps_dir==-1) {
1213 stde.pps_dir = ppsent;
1214 x = this->ppsent;
1215 } else {
1216 FIXME(ole," use prev chain too ?\n");
1217 x=stde.pps_dir;
1218 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1219 return E_FAIL;
1220 while (stde.pps_next!=-1) {
1221 x=stde.pps_next;
1222 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1223 return E_FAIL;
1225 stde.pps_next = ppsent;
1227 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1228 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1229 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1230 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1231 lpstg->stde.pps_next = -1;
1232 lpstg->stde.pps_prev = -1;
1233 lpstg->stde.pps_dir = -1;
1234 lpstg->stde.pps_sb = -1;
1235 lpstg->stde.pps_size = 0;
1236 lpstg->stde.pps_type = 1;
1237 lpstg->ppsent = ppsent;
1238 /* FIXME: timestamps? */
1239 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1240 return E_FAIL;
1241 return OLE_OK;
1244 /******************************************************************************
1245 * IStorage16_CreateStream [STORAGE.503]
1247 HRESULT WINAPI IStorage16_CreateStream(
1248 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1250 LPSTREAM16 lpstr;
1251 int ppsent,x;
1252 struct storage_pps_entry stde;
1254 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1255 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1257 if (grfMode & STGM_TRANSACTED)
1258 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1259 _create_istream16(ppstm);
1260 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1261 lpstr->hf = FILE_Dup(this->hf);
1262 lpstr->offset.LowPart = 0;
1263 lpstr->offset.HighPart = 0;
1265 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1266 if (ppsent<0)
1267 return E_FAIL;
1268 stde=this->stde;
1269 if (stde.pps_next==-1)
1270 x=this->ppsent;
1271 else
1272 while (stde.pps_next!=-1) {
1273 x=stde.pps_next;
1274 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1275 return E_FAIL;
1277 stde.pps_next = ppsent;
1278 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1279 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1280 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1281 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1282 lpstr->stde.pps_next = -1;
1283 lpstr->stde.pps_prev = -1;
1284 lpstr->stde.pps_dir = -1;
1285 lpstr->stde.pps_sb = -1;
1286 lpstr->stde.pps_size = 0;
1287 lpstr->stde.pps_type = 2;
1288 lpstr->ppsent = ppsent;
1289 /* FIXME: timestamps? */
1290 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1291 return E_FAIL;
1292 return OLE_OK;
1295 /******************************************************************************
1296 * IStorage16_OpenStorage [STORAGE.506]
1298 HRESULT WINAPI IStorage16_OpenStorage(
1299 LPSTORAGE16 this,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1301 LPSTREAM16 lpstg;
1302 WCHAR name[33];
1303 int newpps;
1305 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1306 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1308 if (grfMode & STGM_TRANSACTED)
1309 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1310 _create_istorage16(ppstg);
1311 lpstg = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstg);
1312 lpstg->hf = FILE_Dup(this->hf);
1313 lstrcpyAtoW(name,pwcsName);
1314 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1315 if (newpps==-1) {
1316 IStream16_Release(lpstg);
1317 return E_FAIL;
1320 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1321 IStream16_Release(lpstg);
1322 return E_FAIL;
1324 lpstg->ppsent = newpps;
1325 return OLE_OK;
1328 HRESULT WINAPI IStorage16_OpenStream(
1329 LPSTORAGE16 this,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1331 LPSTREAM16 lpstr;
1332 WCHAR name[33];
1333 int newpps;
1335 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1336 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1338 if (grfMode & STGM_TRANSACTED)
1339 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1340 _create_istream16(ppstm);
1341 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1342 lpstr->hf = FILE_Dup(this->hf);
1343 lstrcpyAtoW(name,pwcsName);
1344 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1345 if (newpps==-1) {
1346 IStream16_Release(lpstr);
1347 return E_FAIL;
1350 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1351 IStream16_Release(lpstr);
1352 return E_FAIL;
1354 lpstr->offset.LowPart = 0;
1355 lpstr->offset.HighPart = 0;
1356 lpstr->ppsent = newpps;
1357 return OLE_OK;
1360 static void _create_istorage16(LPSTORAGE16 *stg) {
1361 LPSTORAGE16 lpst;
1363 if (!stvt16.fnQueryInterface) {
1364 HMODULE16 wp = GetModuleHandle16("STORAGE");
1365 if (wp>=32) {
1366 #define VTENT(x) stvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#x);
1367 VTENT(QueryInterface)
1368 VTENT(AddRef)
1369 VTENT(Release)
1370 VTENT(CreateStream)
1371 VTENT(OpenStream)
1372 VTENT(CreateStorage)
1373 VTENT(OpenStorage)
1374 VTENT(CopyTo)
1375 VTENT(MoveElementTo)
1376 VTENT(Commit)
1377 VTENT(Revert)
1378 VTENT(EnumElements)
1379 VTENT(DestroyElement)
1380 VTENT(RenameElement)
1381 VTENT(SetElementTimes)
1382 VTENT(SetClass)
1383 VTENT(SetStateBits)
1384 VTENT(Stat)
1385 #undef VTENT
1386 segstvt16 = SEGPTR_NEW(IStorage16_VTable);
1387 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1388 segstvt16 = (LPSTORAGE16_VTABLE)SEGPTR_GET(segstvt16);
1389 } else {
1390 #define VTENT(x) stvt16.fn##x = IStorage16_##x;
1391 VTENT(QueryInterface)
1392 VTENT(AddRef)
1393 VTENT(Release)
1394 VTENT(CreateStream)
1395 VTENT(OpenStream)
1396 VTENT(CreateStorage)
1397 VTENT(OpenStorage)
1398 VTENT(CopyTo)
1399 VTENT(Commit)
1400 /* not (yet) implemented ...
1401 VTENT(MoveElementTo)
1402 VTENT(Revert)
1403 VTENT(EnumElements)
1404 VTENT(DestroyElement)
1405 VTENT(RenameElement)
1406 VTENT(SetElementTimes)
1407 VTENT(SetClass)
1408 VTENT(SetStateBits)
1409 VTENT(Stat)
1411 #undef VTENT
1412 segstvt16 = &stvt16;
1415 lpst = SEGPTR_NEW(IStorage16);
1416 lpst->lpvtbl = segstvt16;
1417 lpst->ref = 1;
1418 lpst->thisptr = SEGPTR_GET(lpst);
1419 *stg = (void*)lpst->thisptr;
1422 /******************************************************************************
1423 * IStorage32_QueryInterface [???]
1425 HRESULT WINAPI IStorage32_QueryInterface(
1426 LPSTORAGE32 this,REFIID refiid,LPVOID *obj
1428 char xrefiid[50];
1430 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1431 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1433 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1434 *obj = this;
1435 return 0;
1437 return OLE_E_ENUM_NOMORE;
1440 ULONG WINAPI IStorage32_AddRef(LPSTORAGE32 this) {
1441 return ++(this->ref);
1444 ULONG WINAPI IStorage32_Release(LPSTORAGE32 this) {
1445 this->ref--;
1446 if (this->ref)
1447 return this->ref;
1448 HeapFree(GetProcessHeap(),0,this);
1449 return 0;
1452 HRESULT WINAPI IStorage32_CreateStream(
1453 LPSTORAGE32 this,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1455 TRACE(ole,"(%p)->(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1456 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1458 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1459 (*ppstm)->lpvtbl= &strvt32;
1460 (*ppstm)->ref = 1;
1462 return OLE_OK;
1465 HRESULT WINAPI IStorage32_OpenStream(
1466 LPSTORAGE32 this,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1468 TRACE(ole,"(%p)->(%p,%p,0x%08lx,0x%08lx,%p)\n",
1469 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1471 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1472 (*ppstm)->lpvtbl= &strvt32;
1473 (*ppstm)->ref = 1;
1474 return OLE_OK;
1477 static IStorage32_VTable stvt32 = {
1478 IStorage32_QueryInterface,
1479 IStorage32_AddRef,
1480 IStorage32_Release,
1481 IStorage32_CreateStream,
1482 IStorage32_OpenStream,
1483 (void*)6,
1484 (void*)7,
1485 (void*)8,
1486 (void*)9,
1487 (void*)10,
1488 (void*)11,
1489 (void*)12,
1490 (void*)13,
1491 (void*)14,
1492 (void*)15,
1495 /******************************************************************************
1496 * Storage API functions
1499 /******************************************************************************
1500 * StgCreateDocFile16 [STORAGE.1]
1502 OLESTATUS WINAPI StgCreateDocFile16(
1503 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1505 HFILE32 hf;
1506 int i,ret;
1507 LPSTORAGE16 lpstg;
1508 struct storage_pps_entry stde;
1510 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1511 pwcsName,grfMode,reserved,ppstgOpen
1513 _create_istorage16(ppstgOpen);
1514 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1515 if (hf==INVALID_HANDLE_VALUE32) {
1516 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1517 return E_FAIL;
1519 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1520 lpstg->hf = hf;
1521 /* FIXME: check for existance before overwriting? */
1522 if (!STORAGE_init_storage(hf)) {
1523 CloseHandle(hf);
1524 return E_FAIL;
1526 i=0;ret=0;
1527 while (!ret) { /* neither 1 nor <0 */
1528 ret=STORAGE_get_pps_entry(hf,i,&stde);
1529 if ((ret==1) && (stde.pps_type==5)) {
1530 lpstg->stde = stde;
1531 lpstg->ppsent = i;
1532 break;
1534 i++;
1536 if (ret!=1) {
1537 IStorage16_Release(lpstg); /* will remove it */
1538 return E_FAIL;
1540 return OLE_OK;
1543 /******************************************************************************
1544 * StgCreateDocFile32 [OLE32.144]
1546 OLESTATUS WINAPI StgCreateDocFile32(
1547 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1549 TRACE(ole,"(%p,0x%08lx,0x%08lx,%p)\n",
1550 pwcsName,grfMode,reserved,ppstgOpen
1552 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1553 (*ppstgOpen)->ref = 1;
1554 (*ppstgOpen)->lpvtbl = &stvt32;
1555 return OLE_OK;
1558 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1559 HFILE32 hf;
1560 OFSTRUCT ofs;
1561 BYTE magic[24];
1563 TRACE(ole,"(\'%s\')\n",fn);
1564 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1565 if (hf==HFILE_ERROR32)
1566 return STG_E_FILENOTFOUND;
1567 if (24!=_lread32(hf,magic,24)) {
1568 WARN(ole," too short\n");
1569 _lclose32(hf);
1570 return S_FALSE;
1572 if (!memcmp(magic,STORAGE_magic,8)) {
1573 WARN(ole," -> YES\n");
1574 _lclose32(hf);
1575 return S_OK;
1577 if (!memcmp(magic,STORAGE_notmagic,8)) {
1578 WARN(ole," -> NO\n");
1579 _lclose32(hf);
1580 return S_FALSE;
1582 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1583 WARN(ole," -> old format\n");
1584 _lclose32(hf);
1585 return STG_E_OLDFORMAT;
1587 WARN(ole," -> Invalid header.\n");
1588 _lclose32(hf);
1589 return STG_E_INVALIDHEADER;
1592 OLESTATUS WINAPI
1593 StgIsStorageFile32(LPCOLESTR32 fn)
1595 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1596 OLESTATUS ret = StgIsStorageFile16(xfn);
1598 HeapFree(GetProcessHeap(),0,xfn);
1599 return ret;
1604 OLESTATUS WINAPI StgOpenStorage16(
1605 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1606 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1608 HFILE32 hf;
1609 int ret,i;
1610 LPSTORAGE16 lpstg;
1611 struct storage_pps_entry stde;
1613 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1614 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1616 _create_istorage16(ppstgOpen);
1617 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1618 if (hf==INVALID_HANDLE_VALUE32) {
1619 WARN(ole,"Couldn't open file for storage\n");
1620 return E_FAIL;
1622 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1623 lpstg->hf = hf;
1625 i=0;ret=0;
1626 while (!ret) { /* neither 1 nor <0 */
1627 ret=STORAGE_get_pps_entry(hf,i,&stde);
1628 if ((ret==1) && (stde.pps_type==5)) {
1629 lpstg->stde=stde;
1630 break;
1632 i++;
1634 if (ret!=1) {
1635 IStorage16_Release(lpstg); /* will remove it */
1636 return E_FAIL;
1638 return OLE_OK;
1642 /******************************************************************************
1643 * StgOpenStorage32 [OLE32.148]
1645 OLESTATUS WINAPI StgOpenStorage32(
1646 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1647 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1649 FIXME(ole,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1650 pwcsName,pstgPriority,grfMode,snbExclude,reserved,
1651 ppstgOpen);
1652 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1653 (*ppstgOpen)->ref = 1;
1654 (*ppstgOpen)->lpvtbl = &stvt32;
1655 return OLE_OK;