Release 980601
[wine/multimedia.git] / ole / storage.c
blob768549baacf77e9992376c26bf691e5287acb5a8
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 * Reading OLE compound storage
52 static BOOL32
53 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
54 assert(n>=-1);
55 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
56 WARN(ole," seek failed (%ld)\n",GetLastError());
57 return FALSE;
59 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
60 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
61 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
62 assert(0);
63 return FALSE;
65 return TRUE;
68 static BOOL32
69 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
70 assert(n>=-1);
71 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
72 WARN(ole," seek failed (%ld)\n",GetLastError());
73 return FALSE;
75 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
76 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
77 WARN(ole," write failed (%ld)\n",GetLastError());
78 return FALSE;
80 return TRUE;
83 static int
84 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
85 INT32 bbs[BIGSIZE/sizeof(INT32)];
86 struct storage_header sth;
88 READ_HEADER;
90 assert(blocknr>>7<sth.num_of_bbd_blocks);
91 if (sth.bbd_list[blocknr>>7]==0xffffffff)
92 return -5;
93 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
94 return -5;
95 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
96 return bbs[blocknr&0x7f];
99 static int
100 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
101 INT32 bbs[BIGSIZE/sizeof(INT32)];
102 int lastblock = -1;
103 struct storage_header sth;
105 READ_HEADER;
107 assert(blocknr>=0);
108 while (nr--) {
109 assert((blocknr>>7)<sth.num_of_bbd_blocks);
110 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
112 /* simple caching... */
113 if (lastblock!=sth.bbd_list[blocknr>>7]) {
114 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
115 lastblock = sth.bbd_list[blocknr>>7];
117 blocknr = bbs[blocknr&0x7f];
119 return blocknr;
123 static BOOL32
124 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
125 int blocknr,i;
126 BYTE block[BIGSIZE];
127 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
128 struct storage_header sth;
130 READ_HEADER;
131 blocknr = sth.root_startblock;
132 while (blocknr>=0) {
133 assert(STORAGE_get_big_block(hf,blocknr,block));
134 for (i=0;i<4;i++) {
135 if (!stde[i].pps_sizeofname)
136 continue;
137 if (stde[i].pps_type==5) {
138 *pstde=stde[i];
139 return TRUE;
142 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
144 return FALSE;
147 static BOOL32
148 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
149 BYTE block[BIGSIZE];
150 int bigblocknr;
151 struct storage_pps_entry root;
153 assert(blocknr>=0);
154 assert(STORAGE_get_root_pps_entry(hf,&root));
155 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
156 assert(bigblocknr>=0);
157 assert(STORAGE_get_big_block(hf,bigblocknr,block));
159 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
160 return TRUE;
163 static BOOL32
164 STORAGE_put_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);
171 assert(STORAGE_get_root_pps_entry(hf,&root));
172 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
173 assert(bigblocknr>=0);
174 assert(STORAGE_get_big_block(hf,bigblocknr,block));
176 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
177 assert(STORAGE_put_big_block(hf,bigblocknr,block));
178 return TRUE;
182 static int
183 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
184 BYTE block[BIGSIZE];
185 LPINT32 sbd = (LPINT32)block;
186 int bigblocknr;
187 struct storage_header sth;
189 READ_HEADER;
190 assert(blocknr>=0);
191 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
192 assert(bigblocknr>=0);
193 assert(STORAGE_get_big_block(hf,bigblocknr,block));
194 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
195 return sbd[blocknr & (128-1)];
198 static int
199 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
200 int lastblocknr;
201 BYTE block[BIGSIZE];
202 LPINT32 sbd = (LPINT32)block;
203 struct storage_header sth;
205 READ_HEADER;
206 lastblocknr=-1;
207 assert(blocknr>=0);
208 while ((nr--) && (blocknr>=0)) {
209 if (lastblocknr/128!=blocknr/128) {
210 int bigblocknr;
211 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
212 assert(bigblocknr>=0);
213 assert(STORAGE_get_big_block(hf,bigblocknr,block));
214 lastblocknr = blocknr;
216 assert(lastblocknr>=0);
217 lastblocknr=blocknr;
218 blocknr=sbd[blocknr & (128-1)];
219 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
221 return blocknr;
224 static int
225 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
226 int blocknr;
227 BYTE block[BIGSIZE];
228 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
229 struct storage_header sth;
231 READ_HEADER;
232 /* we have 4 pps entries per big block */
233 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
234 assert(blocknr>=0);
235 assert(STORAGE_get_big_block(hf,blocknr,block));
237 *pstde=*stde;
238 return 1;
241 static int
242 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
243 int blocknr;
244 BYTE block[BIGSIZE];
245 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
246 struct storage_header sth;
248 READ_HEADER;
250 /* we have 4 pps entries per big block */
251 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
252 assert(blocknr>=0);
253 assert(STORAGE_get_big_block(hf,blocknr,block));
254 *stde=*pstde;
255 assert(STORAGE_put_big_block(hf,blocknr,block));
256 return 1;
259 static int
260 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
261 struct storage_pps_entry stde;
262 int ret;
264 if (n==-1)
265 return -1;
266 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
267 return -1;
269 if (!lstrcmp32W(name,stde.pps_rawname))
270 return n;
271 if (stde.pps_prev != -1) {
272 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
273 if (ret!=-1)
274 return ret;
276 if (stde.pps_next != -1) {
277 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
278 if (ret!=-1)
279 return ret;
281 return -1;
284 /* FIXME: Function is unused */
285 void
286 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
287 char name[33],xguid[50];
289 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
291 lstrcpyWtoA(name,stde->pps_rawname);
292 if (!stde->pps_sizeofname)
293 return;
294 DUMP("name: %s\n",name);
295 DUMP("type: %d\n",stde->pps_type);
296 DUMP("prev pps: %ld\n",stde->pps_prev);
297 DUMP("next pps: %ld\n",stde->pps_next);
298 DUMP("dir pps: %ld\n",stde->pps_dir);
299 DUMP("guid: %s\n",xguid);
300 if (stde->pps_type !=2) {
301 time_t t;
303 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
304 DUMP("ts1: %s\n",ctime(&t));
305 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
306 DUMP("ts2: %s\n",ctime(&t));
308 DUMP("startblock: %ld\n",stde->pps_sb);
309 DUMP("size: %ld\n",stde->pps_size);
312 static BOOL32
313 STORAGE_init_storage(HFILE32 hf) {
314 BYTE block[BIGSIZE];
315 LPDWORD bbs;
316 struct storage_header *sth;
317 struct storage_pps_entry *stde;
319 assert(-1!=_llseek32(hf,0,SEEK_SET));
320 /* block -1 is the storage header */
321 sth = (struct storage_header*)block;
322 memcpy(sth->magic,STORAGE_magic,8);
323 memset(sth->unknown1,0,sizeof(sth->unknown1));
324 memset(sth->unknown2,0,sizeof(sth->unknown2));
325 memset(sth->unknown3,0,sizeof(sth->unknown3));
326 sth->num_of_bbd_blocks = 1;
327 sth->root_startblock = 1;
328 sth->sbd_startblock = 0xffffffff;
329 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
330 sth->bbd_list[0] = 0;
331 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
332 /* block 0 is the big block directory */
333 bbs=(LPDWORD)block;
334 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
335 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
336 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
337 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
338 /* block 1 is the root directory entry */
339 memset(block,0x00,sizeof(block));
340 stde = (struct storage_pps_entry*)block;
341 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
342 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
343 stde->pps_type = 5;
344 stde->pps_dir = -1;
345 stde->pps_next = -1;
346 stde->pps_prev = -1;
347 stde->pps_sb = 0xffffffff;
348 stde->pps_size = 0;
349 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
350 return TRUE;
353 static BOOL32
354 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
355 BYTE block[BIGSIZE];
356 LPINT32 bbd = (LPINT32)block;
357 int nextblocknr,bigblocknr;
358 struct storage_header sth;
360 READ_HEADER;
361 assert(blocknr!=type);
362 while (blocknr>=0) {
363 bigblocknr = sth.bbd_list[blocknr/128];
364 assert(bigblocknr>=0);
365 assert(STORAGE_get_big_block(hf,bigblocknr,block));
367 nextblocknr = bbd[blocknr&(128-1)];
368 bbd[blocknr&(128-1)] = type;
369 if (type>=0)
370 return TRUE;
371 assert(STORAGE_put_big_block(hf,bigblocknr,block));
372 type = STORAGE_CHAINENTRY_FREE;
373 blocknr = nextblocknr;
375 return TRUE;
378 static BOOL32
379 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
380 BYTE block[BIGSIZE];
381 LPINT32 sbd = (LPINT32)block;
382 int lastblocknr,nextsmallblocknr,bigblocknr;
383 struct storage_header sth;
385 READ_HEADER;
387 assert(blocknr!=type);
388 lastblocknr=-129;bigblocknr=-2;
389 while (blocknr>=0) {
390 /* cache block ... */
391 if (lastblocknr/128!=blocknr/128) {
392 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
393 assert(bigblocknr>=0);
394 assert(STORAGE_get_big_block(hf,bigblocknr,block));
396 lastblocknr = blocknr;
397 nextsmallblocknr = sbd[blocknr&(128-1)];
398 sbd[blocknr&(128-1)] = type;
399 assert(STORAGE_put_big_block(hf,bigblocknr,block));
400 if (type>=0)
401 return TRUE;
402 type = STORAGE_CHAINENTRY_FREE;
403 blocknr = nextsmallblocknr;
405 return TRUE;
408 static int
409 STORAGE_get_free_big_blocknr(HFILE32 hf) {
410 BYTE block[BIGSIZE];
411 LPINT32 sbd = (LPINT32)block;
412 int lastbigblocknr,i,curblock,bigblocknr;
413 struct storage_header sth;
415 READ_HEADER;
416 curblock = 0;
417 lastbigblocknr = -1;
418 bigblocknr = sth.bbd_list[curblock];
419 while (curblock<sth.num_of_bbd_blocks) {
420 assert(bigblocknr>=0);
421 assert(STORAGE_get_big_block(hf,bigblocknr,block));
422 for (i=0;i<128;i++)
423 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
424 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
425 assert(STORAGE_put_big_block(hf,bigblocknr,block));
426 memset(block,0x42,sizeof(block));
427 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
428 return i+curblock*128;
430 lastbigblocknr = bigblocknr;
431 bigblocknr = sth.bbd_list[++curblock];
433 bigblocknr = curblock*128;
434 /* since we have marked all blocks from 0 up to curblock*128-1
435 * the next free one is curblock*128, where we happily put our
436 * next large block depot.
438 memset(block,0xff,sizeof(block));
439 /* mark the block allocated and returned by this function */
440 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
441 assert(STORAGE_put_big_block(hf,bigblocknr,block));
443 /* if we had a bbd block already (mostlikely) we need
444 * to link the new one into the chain
446 if (lastbigblocknr!=-1)
447 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
448 sth.bbd_list[curblock]=bigblocknr;
449 sth.num_of_bbd_blocks++;
450 assert(sth.num_of_bbd_blocks==curblock+1);
451 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
453 /* Set the end of the chain for the bigblockdepots */
454 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
455 /* add 1, for the first entry is used for the additional big block
456 * depot. (means we already used bigblocknr) */
457 memset(block,0x42,sizeof(block));
458 /* allocate this block (filled with 0x42) */
459 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
460 return bigblocknr+1;
464 static int
465 STORAGE_get_free_small_blocknr(HFILE32 hf) {
466 BYTE block[BIGSIZE];
467 LPINT32 sbd = (LPINT32)block;
468 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
469 struct storage_pps_entry root;
470 struct storage_header sth;
472 READ_HEADER;
473 bigblocknr = sth.sbd_startblock;
474 curblock = 0;
475 lastbigblocknr = -1;
476 newblocknr = -1;
477 while (bigblocknr>=0) {
478 if (!STORAGE_get_big_block(hf,bigblocknr,block))
479 return -1;
480 for (i=0;i<128;i++)
481 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
482 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
483 newblocknr = i+curblock*128;
484 break;
486 if (i!=128)
487 break;
488 lastbigblocknr = bigblocknr;
489 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
490 curblock++;
492 if (newblocknr==-1) {
493 bigblocknr = STORAGE_get_free_big_blocknr(hf);
494 if (bigblocknr<0)
495 return -1;
496 READ_HEADER;
497 memset(block,0xff,sizeof(block));
498 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
499 if (!STORAGE_put_big_block(hf,bigblocknr,block))
500 return -1;
501 if (lastbigblocknr==-1) {
502 sth.sbd_startblock = bigblocknr;
503 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
504 return -1;
505 } else {
506 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
507 return -1;
509 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
510 return -1;
511 newblocknr = curblock*128;
513 /* allocate enough big blocks for storing the allocated small block */
514 if (!STORAGE_get_root_pps_entry(hf,&root))
515 return -1;
516 if (root.pps_sb==-1)
517 lastbigblocknr = -1;
518 else
519 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
520 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
521 /* we need to allocate more stuff */
522 bigblocknr = STORAGE_get_free_big_blocknr(hf);
523 if (bigblocknr<0)
524 return -1;
525 READ_HEADER;
526 if (root.pps_sb==-1) {
527 root.pps_sb = bigblocknr;
528 root.pps_size += BIGSIZE;
529 } else {
530 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
531 return -1;
532 root.pps_size += BIGSIZE;
534 lastbigblocknr = bigblocknr;
536 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
537 return -1;
538 if (!STORAGE_put_pps_entry(hf,0,&root))
539 return -1;
540 return newblocknr;
543 static int
544 STORAGE_get_free_pps_entry(HFILE32 hf) {
545 int blocknr,i,curblock,lastblocknr;
546 BYTE block[BIGSIZE];
547 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
548 struct storage_header sth;
550 READ_HEADER;
551 blocknr = sth.root_startblock;
552 assert(blocknr>=0);
553 curblock=0;
554 while (blocknr>=0) {
555 if (!STORAGE_get_big_block(hf,blocknr,block))
556 return -1;
557 for (i=0;i<4;i++)
558 if (stde[i].pps_sizeofname==0) /* free */
559 return curblock*4+i;
560 lastblocknr = blocknr;
561 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
562 curblock++;
564 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
565 blocknr = STORAGE_get_free_big_blocknr(hf);
566 /* sth invalidated */
567 if (blocknr<0)
568 return -1;
570 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
571 return -1;
572 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
573 return -1;
574 memset(block,0,sizeof(block));
575 STORAGE_put_big_block(hf,blocknr,block);
576 return curblock*4;
579 /******************************************************************************
580 * IStream
582 HRESULT WINAPI IStream16_QueryInterface(
583 LPSTREAM16 this,REFIID refiid,LPVOID *obj
585 char xrefiid[50];
587 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
588 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
589 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
590 *obj = this;
591 return 0;
593 return OLE_E_ENUM_NOMORE;
597 ULONG WINAPI IStream16_AddRef(LPSTREAM16 this) {
598 return ++(this->ref);
601 ULONG WINAPI IStream16_Release(LPSTREAM16 this) {
602 FlushFileBuffers(this->hf);
603 this->ref--;
604 if (!this->ref) {
605 CloseHandle(this->hf);
606 SEGPTR_FREE(this);
607 return 0;
609 return this->ref;
612 /* FIXME: not handling 64 bit */
613 HRESULT WINAPI IStream16_Seek(
614 LPSTREAM16 this,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
616 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
618 switch (whence) {
619 /* unix SEEK_xx should be the same as win95 ones */
620 case SEEK_SET:
621 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
622 * right now.
624 assert(offset.HighPart==0);
625 this->offset.HighPart = offset.HighPart;
626 this->offset.LowPart = offset.LowPart;
627 break;
628 case SEEK_CUR:
629 if (offset.HighPart < 0) {
630 /* FIXME: is this negation correct ? */
631 offset.HighPart = -offset.HighPart;
632 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
634 assert(offset.HighPart==0);
635 assert(this->offset.LowPart >= offset.LowPart);
636 this->offset.LowPart -= offset.LowPart;
637 } else {
638 assert(offset.HighPart==0);
639 this->offset.LowPart+= offset.LowPart;
641 break;
642 case SEEK_END:
643 assert(offset.HighPart==0);
644 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
645 break;
647 if (this->offset.LowPart>this->stde.pps_size)
648 this->offset.LowPart=this->stde.pps_size;
649 if (newpos) *newpos = this->offset;
650 return OLE_OK;
653 HRESULT WINAPI IStream16_Read(
654 LPSTREAM16 this,void *pv,ULONG cb,ULONG *pcbRead
656 BYTE block[BIGSIZE];
657 ULONG *bytesread=pcbRead,xxread;
658 int blocknr;
660 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
661 if (!pcbRead) bytesread=&xxread;
662 *bytesread = 0;
664 if (cb>this->stde.pps_size-this->offset.LowPart)
665 cb=this->stde.pps_size-this->offset.LowPart;
666 if (this->stde.pps_size < 0x1000) {
667 /* use small block reader */
668 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
669 while (cb) {
670 int cc;
672 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
673 WARN(ole,"small block read failed!!!\n");
674 return E_FAIL;
676 cc = cb;
677 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
678 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
679 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
680 this->offset.LowPart+=cc;
681 (LPBYTE)pv+=cc;
682 *bytesread+=cc;
683 cb-=cc;
684 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
686 } else {
687 /* use big block reader */
688 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
689 while (cb) {
690 int cc;
692 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
693 WARN(ole,"big block read failed!!!\n");
694 return E_FAIL;
696 cc = cb;
697 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
698 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
699 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
700 this->offset.LowPart+=cc;
701 (LPBYTE)pv+=cc;
702 *bytesread+=cc;
703 cb-=cc;
704 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
707 return OLE_OK;
710 HRESULT WINAPI IStream16_Write(
711 LPSTREAM16 this,const void *pv,ULONG cb,ULONG *pcbWrite
713 BYTE block[BIGSIZE];
714 ULONG *byteswritten=pcbWrite,xxwritten;
715 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
716 HFILE32 hf = this->hf;
718 if (!pcbWrite) byteswritten=&xxwritten;
719 *byteswritten = 0;
721 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
722 /* do we need to junk some blocks? */
723 newsize = this->offset.LowPart+cb;
724 oldsize = this->stde.pps_size;
725 if (newsize < oldsize) {
726 if (oldsize < 0x1000) {
727 /* only small blocks */
728 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
730 assert(blocknr>=0);
732 /* will set the rest of the chain to 'free' */
733 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
734 return E_FAIL;
735 } else {
736 if (newsize >= 0x1000) {
737 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
738 assert(blocknr>=0);
740 /* will set the rest of the chain to 'free' */
741 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
742 return E_FAIL;
743 } else {
744 /* Migrate large blocks to small blocks
745 * (we just migrate newsize bytes)
747 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
748 cc = newsize;
749 blocknr = this->stde.pps_sb;
750 curdata = data;
751 while (cc>0) {
752 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
753 HeapFree(GetProcessHeap(),0,data);
754 return E_FAIL;
756 curdata += BIGSIZE;
757 cc -= BIGSIZE;
758 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
760 /* frees complete chain for this stream */
761 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
762 return E_FAIL;
763 curdata = data;
764 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
765 if (blocknr<0)
766 return E_FAIL;
767 cc = newsize;
768 while (cc>0) {
769 if (!STORAGE_put_small_block(hf,blocknr,curdata))
770 return E_FAIL;
771 cc -= SMALLSIZE;
772 if (cc<=0) {
773 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
774 return E_FAIL;
775 break;
776 } else {
777 int newblocknr = STORAGE_get_free_small_blocknr(hf);
778 if (newblocknr<0)
779 return E_FAIL;
780 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
781 return E_FAIL;
782 blocknr = newblocknr;
784 curdata += SMALLSIZE;
786 HeapFree(GetProcessHeap(),0,data);
789 this->stde.pps_size = newsize;
792 if (newsize > oldsize) {
793 if (oldsize >= 0x1000) {
794 /* should return the block right before the 'endofchain' */
795 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
796 assert(blocknr>=0);
797 lastblocknr = blocknr;
798 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
799 blocknr = STORAGE_get_free_big_blocknr(hf);
800 if (blocknr<0)
801 return E_FAIL;
802 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
803 return E_FAIL;
804 lastblocknr = blocknr;
806 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
807 return E_FAIL;
808 } else {
809 if (newsize < 0x1000) {
810 /* find startblock */
811 if (!oldsize)
812 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
813 else
814 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
815 if (blocknr<0)
816 return E_FAIL;
818 /* allocate required new small blocks */
819 lastblocknr = blocknr;
820 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
821 blocknr = STORAGE_get_free_small_blocknr(hf);
822 if (blocknr<0)
823 return E_FAIL;
824 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
825 return E_FAIL;
826 lastblocknr = blocknr;
828 /* and terminate the chain */
829 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
830 return E_FAIL;
831 } else {
832 if (!oldsize) {
833 /* no single block allocated yet */
834 blocknr=STORAGE_get_free_big_blocknr(hf);
835 if (blocknr<0)
836 return E_FAIL;
837 this->stde.pps_sb = blocknr;
838 } else {
839 /* Migrate small blocks to big blocks */
840 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
841 cc = oldsize;
842 blocknr = this->stde.pps_sb;
843 curdata = data;
844 /* slurp in */
845 while (cc>0) {
846 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
847 HeapFree(GetProcessHeap(),0,data);
848 return E_FAIL;
850 curdata += SMALLSIZE;
851 cc -= SMALLSIZE;
852 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
854 /* free small block chain */
855 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
856 return E_FAIL;
857 curdata = data;
858 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
859 if (blocknr<0)
860 return E_FAIL;
861 /* put the data into the big blocks */
862 cc = this->stde.pps_size;
863 while (cc>0) {
864 if (!STORAGE_put_big_block(hf,blocknr,curdata))
865 return E_FAIL;
866 cc -= BIGSIZE;
867 if (cc<=0) {
868 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
869 return E_FAIL;
870 break;
871 } else {
872 int newblocknr = STORAGE_get_free_big_blocknr(hf);
873 if (newblocknr<0)
874 return E_FAIL;
875 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
876 return E_FAIL;
877 blocknr = newblocknr;
879 curdata += BIGSIZE;
881 HeapFree(GetProcessHeap(),0,data);
883 /* generate big blocks to fit the new data */
884 lastblocknr = blocknr;
885 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
886 blocknr = STORAGE_get_free_big_blocknr(hf);
887 if (blocknr<0)
888 return E_FAIL;
889 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
890 return E_FAIL;
891 lastblocknr = blocknr;
893 /* terminate chain */
894 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
895 return E_FAIL;
898 this->stde.pps_size = newsize;
901 /* There are just some cases where we didn't modify it, we write it out
902 * everytime
904 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
905 return E_FAIL;
907 /* finally the write pass */
908 if (this->stde.pps_size < 0x1000) {
909 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
910 assert(blocknr>=0);
911 while (cb>0) {
912 /* we ensured that it is allocated above */
913 assert(blocknr>=0);
914 /* Read old block everytime, since we can have
915 * overlapping data at START and END of the write
917 if (!STORAGE_get_small_block(hf,blocknr,block))
918 return E_FAIL;
920 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
921 if (cc>cb)
922 cc=cb;
923 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
924 (LPBYTE)(pv+curoffset),
927 if (!STORAGE_put_small_block(hf,blocknr,block))
928 return E_FAIL;
929 cb -= cc;
930 curoffset += cc;
931 (LPBYTE)pv += cc;
932 this->offset.LowPart += cc;
933 *byteswritten += cc;
934 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
936 } else {
937 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
938 assert(blocknr>=0);
939 while (cb>0) {
940 /* we ensured that it is allocated above, so it better is */
941 assert(blocknr>=0);
942 /* read old block everytime, since we can have
943 * overlapping data at START and END of the write
945 if (!STORAGE_get_big_block(hf,blocknr,block))
946 return E_FAIL;
948 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
949 if (cc>cb)
950 cc=cb;
951 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
952 (LPBYTE)(pv+curoffset),
955 if (!STORAGE_put_big_block(hf,blocknr,block))
956 return E_FAIL;
957 cb -= cc;
958 curoffset += cc;
959 (LPBYTE)pv += cc;
960 this->offset.LowPart += cc;
961 *byteswritten += cc;
962 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
965 return OLE_OK;
968 static void _create_istream16(LPSTREAM16 *str) {
969 LPSTREAM16 lpst;
971 if (!strvt16.fnQueryInterface) {
972 HMODULE16 wp = GetModuleHandle16("STORAGE");
973 if (wp>=32) {
974 #define VTENT(x) strvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#x);
975 VTENT(QueryInterface)
976 VTENT(AddRef)
977 VTENT(Release)
978 VTENT(Read)
979 VTENT(Write)
980 VTENT(Seek)
981 VTENT(SetSize)
982 VTENT(CopyTo)
983 VTENT(Commit)
984 VTENT(Revert)
985 VTENT(LockRegion)
986 VTENT(UnlockRegion)
987 VTENT(Stat)
988 VTENT(Clone)
989 #undef VTENT
990 segstrvt16 = SEGPTR_NEW(IStream16_VTable);
991 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
992 segstrvt16 = (LPSTREAM16_VTABLE)SEGPTR_GET(segstrvt16);
993 } else {
994 #define VTENT(x) strvt16.fn##x = IStream16_##x;
995 VTENT(QueryInterface)
996 VTENT(AddRef)
997 VTENT(Release)
998 VTENT(Read)
999 VTENT(Write)
1000 VTENT(Seek)
1002 VTENT(CopyTo)
1003 VTENT(Commit)
1004 VTENT(SetSize)
1005 VTENT(Revert)
1006 VTENT(LockRegion)
1007 VTENT(UnlockRegion)
1008 VTENT(Stat)
1009 VTENT(Clone)
1011 #undef VTENT
1012 segstrvt16 = &strvt16;
1015 lpst = SEGPTR_NEW(IStream16);
1016 lpst->lpvtbl = segstrvt16;
1017 lpst->ref = 1;
1018 lpst->thisptr = SEGPTR_GET(lpst);
1019 *str = (void*)lpst->thisptr;
1022 /*****************************************************************************
1023 * IStream32
1025 HRESULT WINAPI IStream32_QueryInterface(
1026 LPSTREAM32 this,REFIID refiid,LPVOID *obj
1028 char xrefiid[50];
1030 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1031 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1032 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1033 *obj = this;
1034 return 0;
1036 return OLE_E_ENUM_NOMORE;
1040 ULONG WINAPI IStream32_AddRef(LPSTREAM32 this) {
1041 return ++(this->ref);
1044 ULONG WINAPI IStream32_Release(LPSTREAM32 this) {
1045 FlushFileBuffers(this->hf);
1046 this->ref--;
1047 if (!this->ref) {
1048 CloseHandle(this->hf);
1049 SEGPTR_FREE(this);
1050 return 0;
1052 return this->ref;
1055 static IStream32_VTable strvt32 = {
1056 IStream32_QueryInterface,
1057 IStream32_AddRef,
1058 IStream32_Release,
1059 (void*)4,
1060 (void*)5,
1061 (void*)6,
1062 (void*)7,
1063 (void*)8,
1064 (void*)9,
1065 (void*)10,
1066 (void*)11,
1069 /******************************************************************************
1070 * IStorage
1072 HRESULT WINAPI IStorage16_QueryInterface(
1073 LPSTORAGE16 this,REFIID refiid,LPVOID *obj
1075 char xrefiid[50];
1077 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1078 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1080 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1081 *obj = this;
1082 return 0;
1084 return OLE_E_ENUM_NOMORE;
1087 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this) {
1088 return ++(this->ref);
1091 ULONG WINAPI IStorage16_Release(LPSTORAGE16 this) {
1092 this->ref--;
1093 if (this->ref)
1094 return this->ref;
1095 SEGPTR_FREE(this);
1096 return 0;
1099 HRESULT WINAPI IStorage16_Stat(
1100 LPSTORAGE16 this,STATSTG *pstatstg, DWORD grfStatFlag
1102 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1103 this,pstatstg,grfStatFlag
1105 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1106 pstatstg->type = this->stde.pps_type;
1107 pstatstg->cbSize.LowPart = this->stde.pps_size;
1108 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1109 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1110 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1111 pstatstg->grfMode = 0; /* FIXME */
1112 pstatstg->grfLocksSupported = 0; /* FIXME */
1113 pstatstg->clsid = this->stde.pps_guid;
1114 pstatstg->grfStateBits = 0; /* FIXME */
1115 pstatstg->reserved = 0;
1116 return OLE_OK;
1119 HRESULT WINAPI IStorage16_Commit(
1120 LPSTORAGE16 this,DWORD commitflags
1122 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1123 this,commitflags
1125 return OLE_OK;
1128 HRESULT WINAPI IStorage16_CopyTo(LPSTORAGE16 this,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1129 char xguid[50];
1131 if (rgiidExclude)
1132 WINE_StringFromCLSID(rgiidExclude,xguid);
1133 else
1134 strcpy(xguid,"<no guid>");
1135 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1136 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1138 return OLE_OK;
1143 HRESULT WINAPI IStorage16_CreateStorage(
1144 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1146 LPSTORAGE16 lpstg;
1147 int ppsent,x;
1148 struct storage_pps_entry stde;
1149 struct storage_header sth;
1150 HFILE32 hf=this->hf;
1152 READ_HEADER;
1154 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1155 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1157 if (grfMode & STGM_TRANSACTED)
1158 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1159 _create_istorage16(ppstg);
1160 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstg);
1161 lpstg->hf = this->hf;
1163 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1164 if (ppsent<0)
1165 return E_FAIL;
1166 stde=this->stde;
1167 if (stde.pps_dir==-1) {
1168 stde.pps_dir = ppsent;
1169 x = this->ppsent;
1170 } else {
1171 FIXME(ole," use prev chain too ?\n");
1172 x=stde.pps_dir;
1173 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1174 return E_FAIL;
1175 while (stde.pps_next!=-1) {
1176 x=stde.pps_next;
1177 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1178 return E_FAIL;
1180 stde.pps_next = ppsent;
1182 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1183 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1184 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1185 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1186 lpstg->stde.pps_next = -1;
1187 lpstg->stde.pps_prev = -1;
1188 lpstg->stde.pps_dir = -1;
1189 lpstg->stde.pps_sb = -1;
1190 lpstg->stde.pps_size = 0;
1191 lpstg->stde.pps_type = 1;
1192 lpstg->ppsent = ppsent;
1193 /* FIXME: timestamps? */
1194 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1195 return E_FAIL;
1196 return OLE_OK;
1199 HRESULT WINAPI IStorage16_CreateStream(
1200 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1202 LPSTREAM16 lpstr;
1203 int ppsent,x;
1204 struct storage_pps_entry stde;
1206 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1207 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1209 if (grfMode & STGM_TRANSACTED)
1210 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1211 _create_istream16(ppstm);
1212 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1213 lpstr->hf = FILE_Dup(this->hf);
1214 lpstr->offset.LowPart = 0;
1215 lpstr->offset.HighPart = 0;
1217 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1218 if (ppsent<0)
1219 return E_FAIL;
1220 stde=this->stde;
1221 if (stde.pps_next==-1)
1222 x=this->ppsent;
1223 else
1224 while (stde.pps_next!=-1) {
1225 x=stde.pps_next;
1226 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1227 return E_FAIL;
1229 stde.pps_next = ppsent;
1230 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1231 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1232 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1233 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1234 lpstr->stde.pps_next = -1;
1235 lpstr->stde.pps_prev = -1;
1236 lpstr->stde.pps_dir = -1;
1237 lpstr->stde.pps_sb = -1;
1238 lpstr->stde.pps_size = 0;
1239 lpstr->stde.pps_type = 2;
1240 lpstr->ppsent = ppsent;
1241 /* FIXME: timestamps? */
1242 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1243 return E_FAIL;
1244 return OLE_OK;
1247 HRESULT WINAPI IStorage16_OpenStorage(
1248 LPSTORAGE16 this,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1250 LPSTREAM16 lpstg;
1251 WCHAR name[33];
1252 int newpps;
1254 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1255 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,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 = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstg);
1261 lpstg->hf = FILE_Dup(this->hf);
1262 lstrcpyAtoW(name,pwcsName);
1263 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1264 if (newpps==-1) {
1265 IStream16_Release(lpstg);
1266 return E_FAIL;
1269 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1270 IStream16_Release(lpstg);
1271 return E_FAIL;
1273 lpstg->ppsent = newpps;
1274 return OLE_OK;
1277 HRESULT WINAPI IStorage16_OpenStream(
1278 LPSTORAGE16 this,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1280 LPSTREAM16 lpstr;
1281 WCHAR name[33];
1282 int newpps;
1284 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1285 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1287 if (grfMode & STGM_TRANSACTED)
1288 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1289 _create_istream16(ppstm);
1290 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1291 lpstr->hf = FILE_Dup(this->hf);
1292 lstrcpyAtoW(name,pwcsName);
1293 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1294 if (newpps==-1) {
1295 IStream16_Release(lpstr);
1296 return E_FAIL;
1299 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1300 IStream16_Release(lpstr);
1301 return E_FAIL;
1303 lpstr->offset.LowPart = 0;
1304 lpstr->offset.HighPart = 0;
1305 lpstr->ppsent = newpps;
1306 return OLE_OK;
1309 static void _create_istorage16(LPSTORAGE16 *stg) {
1310 LPSTORAGE16 lpst;
1312 if (!stvt16.fnQueryInterface) {
1313 HMODULE16 wp = GetModuleHandle16("STORAGE");
1314 if (wp>=32) {
1315 #define VTENT(x) stvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#x);
1316 VTENT(QueryInterface)
1317 VTENT(AddRef)
1318 VTENT(Release)
1319 VTENT(CreateStream)
1320 VTENT(OpenStream)
1321 VTENT(CreateStorage)
1322 VTENT(OpenStorage)
1323 VTENT(CopyTo)
1324 VTENT(MoveElementTo)
1325 VTENT(Commit)
1326 VTENT(Revert)
1327 VTENT(EnumElements)
1328 VTENT(DestroyElement)
1329 VTENT(RenameElement)
1330 VTENT(SetElementTimes)
1331 VTENT(SetClass)
1332 VTENT(SetStateBits)
1333 VTENT(Stat)
1334 #undef VTENT
1335 segstvt16 = SEGPTR_NEW(IStorage16_VTable);
1336 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1337 segstvt16 = (LPSTORAGE16_VTABLE)SEGPTR_GET(segstvt16);
1338 } else {
1339 #define VTENT(x) stvt16.fn##x = IStorage16_##x;
1340 VTENT(QueryInterface)
1341 VTENT(AddRef)
1342 VTENT(Release)
1343 VTENT(CreateStream)
1344 VTENT(OpenStream)
1345 VTENT(CreateStorage)
1346 VTENT(OpenStorage)
1347 VTENT(CopyTo)
1348 VTENT(Commit)
1349 /* not (yet) implemented ...
1350 VTENT(MoveElementTo)
1351 VTENT(Revert)
1352 VTENT(EnumElements)
1353 VTENT(DestroyElement)
1354 VTENT(RenameElement)
1355 VTENT(SetElementTimes)
1356 VTENT(SetClass)
1357 VTENT(SetStateBits)
1358 VTENT(Stat)
1360 #undef VTENT
1361 segstvt16 = &stvt16;
1364 lpst = SEGPTR_NEW(IStorage16);
1365 lpst->lpvtbl = segstvt16;
1366 lpst->ref = 1;
1367 lpst->thisptr = SEGPTR_GET(lpst);
1368 *stg = (void*)lpst->thisptr;
1371 /******************************************************************************
1372 * IStorage32
1374 HRESULT WINAPI IStorage32_QueryInterface(
1375 LPSTORAGE32 this,REFIID refiid,LPVOID *obj
1377 char xrefiid[50];
1379 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1380 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1382 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1383 *obj = this;
1384 return 0;
1386 return OLE_E_ENUM_NOMORE;
1389 ULONG WINAPI IStorage32_AddRef(LPSTORAGE32 this) {
1390 return ++(this->ref);
1393 ULONG WINAPI IStorage32_Release(LPSTORAGE32 this) {
1394 this->ref--;
1395 if (this->ref)
1396 return this->ref;
1397 HeapFree(GetProcessHeap(),0,this);
1398 return 0;
1401 HRESULT WINAPI IStorage32_CreateStream(
1402 LPSTORAGE32 this,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1404 TRACE(ole,"(%p)->(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1405 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1407 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1408 (*ppstm)->lpvtbl= &strvt32;
1409 (*ppstm)->ref = 1;
1411 return OLE_OK;
1414 HRESULT WINAPI IStorage32_OpenStream(
1415 LPSTORAGE32 this,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1417 TRACE(ole,"(%p)->(%p,%p,0x%08lx,0x%08lx,%p)\n",
1418 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1420 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1421 (*ppstm)->lpvtbl= &strvt32;
1422 (*ppstm)->ref = 1;
1423 return OLE_OK;
1426 static IStorage32_VTable stvt32 = {
1427 IStorage32_QueryInterface,
1428 IStorage32_AddRef,
1429 IStorage32_Release,
1430 IStorage32_CreateStream,
1431 IStorage32_OpenStream,
1432 (void*)6,
1433 (void*)7,
1434 (void*)8,
1435 (void*)9,
1436 (void*)10,
1437 (void*)11,
1438 (void*)12,
1439 (void*)13,
1440 (void*)14,
1441 (void*)15,
1444 /******************************************************************************
1445 * Storage API functions
1448 OLESTATUS WINAPI StgCreateDocFile16(
1449 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1451 HFILE32 hf;
1452 int i,ret;
1453 LPSTORAGE16 lpstg;
1454 struct storage_pps_entry stde;
1456 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1457 pwcsName,grfMode,reserved,ppstgOpen
1459 _create_istorage16(ppstgOpen);
1460 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1461 if (hf==INVALID_HANDLE_VALUE32) {
1462 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1463 return E_FAIL;
1465 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1466 lpstg->hf = hf;
1467 /* FIXME: check for existance before overwriting? */
1468 if (!STORAGE_init_storage(hf)) {
1469 CloseHandle(hf);
1470 return E_FAIL;
1472 i=0;ret=0;
1473 while (!ret) { /* neither 1 nor <0 */
1474 ret=STORAGE_get_pps_entry(hf,i,&stde);
1475 if ((ret==1) && (stde.pps_type==5)) {
1476 lpstg->stde = stde;
1477 lpstg->ppsent = i;
1478 break;
1480 i++;
1482 if (ret!=1) {
1483 IStorage16_Release(lpstg); /* will remove it */
1484 return E_FAIL;
1486 return OLE_OK;
1489 OLESTATUS WINAPI StgCreateDocFile32(
1490 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1492 TRACE(ole,"(%p,0x%08lx,0x%08lx,%p)\n",
1493 pwcsName,grfMode,reserved,ppstgOpen
1495 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1496 (*ppstgOpen)->ref = 1;
1497 (*ppstgOpen)->lpvtbl = &stvt32;
1498 return OLE_OK;
1501 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1502 HFILE32 hf;
1503 OFSTRUCT ofs;
1504 BYTE magic[24];
1506 TRACE(ole,"(\'%s\')\n",fn);
1507 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1508 if (hf==HFILE_ERROR32)
1509 return STG_E_FILENOTFOUND;
1510 if (24!=_lread32(hf,magic,24)) {
1511 WARN(ole," too short\n");
1512 _lclose32(hf);
1513 return S_FALSE;
1515 if (!memcmp(magic,STORAGE_magic,8)) {
1516 WARN(ole," -> YES\n");
1517 _lclose32(hf);
1518 return S_OK;
1520 if (!memcmp(magic,STORAGE_notmagic,8)) {
1521 WARN(ole," -> NO\n");
1522 _lclose32(hf);
1523 return S_FALSE;
1525 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1526 WARN(ole," -> old format\n");
1527 _lclose32(hf);
1528 return STG_E_OLDFORMAT;
1530 WARN(ole," -> Invalid header.\n");
1531 _lclose32(hf);
1532 return STG_E_INVALIDHEADER;
1535 OLESTATUS WINAPI
1536 StgIsStorageFile32(LPCOLESTR32 fn)
1538 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1539 OLESTATUS ret = StgIsStorageFile16(xfn);
1541 HeapFree(GetProcessHeap(),0,xfn);
1542 return ret;
1547 OLESTATUS WINAPI StgOpenStorage16(
1548 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1549 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1551 HFILE32 hf;
1552 int ret,i;
1553 LPSTORAGE16 lpstg;
1554 struct storage_pps_entry stde;
1556 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1557 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1559 _create_istorage16(ppstgOpen);
1560 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1561 if (hf==INVALID_HANDLE_VALUE32) {
1562 WARN(ole,"Couldn't open file for storage\n");
1563 return E_FAIL;
1565 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1566 lpstg->hf = hf;
1568 i=0;ret=0;
1569 while (!ret) { /* neither 1 nor <0 */
1570 ret=STORAGE_get_pps_entry(hf,i,&stde);
1571 if ((ret==1) && (stde.pps_type==5)) {
1572 lpstg->stde=stde;
1573 break;
1575 i++;
1577 if (ret!=1) {
1578 IStorage16_Release(lpstg); /* will remove it */
1579 return E_FAIL;
1581 return OLE_OK;
1585 OLESTATUS WINAPI StgOpenStorage32(
1586 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1587 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1589 FIXME(ole,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1590 pwcsName,pstgPriority,grfMode,snbExclude,reserved,
1591 ppstgOpen);
1592 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1593 (*ppstgOpen)->ref = 1;
1594 (*ppstgOpen)->lpvtbl = &stvt32;
1595 return OLE_OK;