Release 980517
[wine/multimedia.git] / ole / storage.c
blob04dfd3fe022b314c3ecffc18836febcbbea80f6e
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 <stdio.h>
11 #include <assert.h>
12 #include <time.h>
13 #include <string.h>
14 #include "windows.h"
15 #include "winerror.h"
16 #include "file.h"
17 #include "ole.h"
18 #include "ole2.h"
19 #include "compobj.h"
20 #include "interfaces.h"
21 #include "storage.h"
22 #include "heap.h"
23 #include "module.h"
24 #include "ldt.h"
25 #include "debug.h"
27 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
28 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
29 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
31 #define BIGSIZE 512
32 #define SMALLSIZE 64
34 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
36 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
37 static IStorage16_VTable stvt16;
38 static IStorage16_VTable *segstvt16 = NULL;
39 static IStorage32_VTable stvt32;
40 static IStream16_VTable strvt16;
41 static IStream16_VTable *segstrvt16 = NULL;
42 static IStream32_VTable strvt32;
44 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);
45 static void _create_istorage16(LPSTORAGE16 *stg);
46 static void _create_istream16(LPSTREAM16 *str);
48 #define IMPLEMENTED 1
50 /******************************************************************************
51 * Reading OLE compound storage
53 static BOOL32
54 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
55 assert(n>=-1);
56 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
57 WARN(ole," seek failed (%ld)\n",GetLastError());
58 return FALSE;
60 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
61 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
62 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
63 assert(0);
64 return FALSE;
66 return TRUE;
69 static BOOL32
70 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
71 assert(n>=-1);
72 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
73 WARN(ole," seek failed (%ld)\n",GetLastError());
74 return FALSE;
76 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
77 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
78 WARN(ole," write failed (%ld)\n",GetLastError());
79 return FALSE;
81 return TRUE;
84 static int
85 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
86 INT32 bbs[BIGSIZE/sizeof(INT32)];
87 struct storage_header sth;
89 READ_HEADER;
91 assert(blocknr>>7<sth.num_of_bbd_blocks);
92 if (sth.bbd_list[blocknr>>7]==0xffffffff)
93 return -5;
94 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
95 return -5;
96 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
97 return bbs[blocknr&0x7f];
100 static int
101 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
102 INT32 bbs[BIGSIZE/sizeof(INT32)];
103 int lastblock = -1;
104 struct storage_header sth;
106 READ_HEADER;
108 assert(blocknr>=0);
109 while (nr--) {
110 assert((blocknr>>7)<sth.num_of_bbd_blocks);
111 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
113 /* simple caching... */
114 if (lastblock!=sth.bbd_list[blocknr>>7]) {
115 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
116 lastblock = sth.bbd_list[blocknr>>7];
118 blocknr = bbs[blocknr&0x7f];
120 return blocknr;
124 static BOOL32
125 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
126 int blocknr,i;
127 BYTE block[BIGSIZE];
128 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
129 struct storage_header sth;
131 READ_HEADER;
132 blocknr = sth.root_startblock;
133 while (blocknr>=0) {
134 assert(STORAGE_get_big_block(hf,blocknr,block));
135 for (i=0;i<4;i++) {
136 if (!stde[i].pps_sizeofname)
137 continue;
138 if (stde[i].pps_type==5) {
139 *pstde=stde[i];
140 return TRUE;
143 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
145 return FALSE;
148 static BOOL32
149 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
150 BYTE block[BIGSIZE];
151 int bigblocknr;
152 struct storage_pps_entry root;
154 assert(blocknr>=0);
155 assert(STORAGE_get_root_pps_entry(hf,&root));
156 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
157 assert(bigblocknr>=0);
158 assert(STORAGE_get_big_block(hf,bigblocknr,block));
160 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
161 return TRUE;
164 static BOOL32
165 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
166 BYTE block[BIGSIZE];
167 int bigblocknr;
168 struct storage_pps_entry root;
170 assert(blocknr>=0);
172 assert(STORAGE_get_root_pps_entry(hf,&root));
173 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
174 assert(bigblocknr>=0);
175 assert(STORAGE_get_big_block(hf,bigblocknr,block));
177 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
178 assert(STORAGE_put_big_block(hf,bigblocknr,block));
179 return TRUE;
183 static int
184 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
185 BYTE block[BIGSIZE];
186 LPINT32 sbd = (LPINT32)block;
187 int bigblocknr;
188 struct storage_header sth;
190 READ_HEADER;
191 assert(blocknr>=0);
192 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
193 assert(bigblocknr>=0);
194 assert(STORAGE_get_big_block(hf,bigblocknr,block));
195 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
196 return sbd[blocknr & (128-1)];
199 static int
200 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
201 int lastblocknr;
202 BYTE block[BIGSIZE];
203 LPINT32 sbd = (LPINT32)block;
204 struct storage_header sth;
206 READ_HEADER;
207 lastblocknr=-1;
208 assert(blocknr>=0);
209 while ((nr--) && (blocknr>=0)) {
210 if (lastblocknr/128!=blocknr/128) {
211 int bigblocknr;
212 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
213 assert(bigblocknr>=0);
214 assert(STORAGE_get_big_block(hf,bigblocknr,block));
215 lastblocknr = blocknr;
217 assert(lastblocknr>=0);
218 lastblocknr=blocknr;
219 blocknr=sbd[blocknr & (128-1)];
220 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
222 return blocknr;
225 static int
226 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
227 int blocknr;
228 BYTE block[BIGSIZE];
229 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
230 struct storage_header sth;
232 READ_HEADER;
233 /* we have 4 pps entries per big block */
234 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
235 assert(blocknr>=0);
236 assert(STORAGE_get_big_block(hf,blocknr,block));
238 *pstde=*stde;
239 return 1;
242 static int
243 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
244 int blocknr;
245 BYTE block[BIGSIZE];
246 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
247 struct storage_header sth;
249 READ_HEADER;
251 /* we have 4 pps entries per big block */
252 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
253 assert(blocknr>=0);
254 assert(STORAGE_get_big_block(hf,blocknr,block));
255 *stde=*pstde;
256 assert(STORAGE_put_big_block(hf,blocknr,block));
257 return 1;
260 static int
261 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
262 struct storage_pps_entry stde;
263 int ret;
265 if (n==-1)
266 return -1;
267 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
268 return -1;
270 if (!lstrcmp32W(name,stde.pps_rawname))
271 return n;
272 if (stde.pps_prev != -1) {
273 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
274 if (ret!=-1)
275 return ret;
277 if (stde.pps_next != -1) {
278 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
279 if (ret!=-1)
280 return ret;
282 return -1;
285 /* FIXME: Function is unused */
286 void
287 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
288 char name[33],xguid[50];
290 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
292 lstrcpyWtoA(name,stde->pps_rawname);
293 if (!stde->pps_sizeofname)
294 return;
295 DUMP("name: %s\n",name);
296 DUMP("type: %d\n",stde->pps_type);
297 DUMP("prev pps: %ld\n",stde->pps_prev);
298 DUMP("next pps: %ld\n",stde->pps_next);
299 DUMP("dir pps: %ld\n",stde->pps_dir);
300 DUMP("guid: %s\n",xguid);
301 if (stde->pps_type !=2) {
302 time_t t;
304 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
305 DUMP("ts1: %s\n",ctime(&t));
306 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
307 DUMP("ts2: %s\n",ctime(&t));
309 DUMP("startblock: %ld\n",stde->pps_sb);
310 DUMP("size: %ld\n",stde->pps_size);
313 static BOOL32
314 STORAGE_init_storage(HFILE32 hf) {
315 BYTE block[BIGSIZE];
316 LPDWORD bbs;
317 struct storage_header *sth;
318 struct storage_pps_entry *stde;
320 assert(-1!=_llseek32(hf,0,SEEK_SET));
321 /* block -1 is the storage header */
322 sth = (struct storage_header*)block;
323 memcpy(sth->magic,STORAGE_magic,8);
324 memset(sth->unknown1,0,sizeof(sth->unknown1));
325 memset(sth->unknown2,0,sizeof(sth->unknown2));
326 memset(sth->unknown3,0,sizeof(sth->unknown3));
327 sth->num_of_bbd_blocks = 1;
328 sth->root_startblock = 1;
329 sth->sbd_startblock = 0xffffffff;
330 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
331 sth->bbd_list[0] = 0;
332 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
333 /* block 0 is the big block directory */
334 bbs=(LPDWORD)block;
335 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
336 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
337 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
338 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
339 /* block 1 is the root directory entry */
340 memset(block,0x00,sizeof(block));
341 stde = (struct storage_pps_entry*)block;
342 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
343 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
344 stde->pps_type = 5;
345 stde->pps_dir = -1;
346 stde->pps_next = -1;
347 stde->pps_prev = -1;
348 stde->pps_sb = 0xffffffff;
349 stde->pps_size = 0;
350 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
351 return TRUE;
354 static BOOL32
355 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
356 BYTE block[BIGSIZE];
357 LPINT32 bbd = (LPINT32)block;
358 int nextblocknr,bigblocknr;
359 struct storage_header sth;
361 READ_HEADER;
362 assert(blocknr!=type);
363 while (blocknr>=0) {
364 bigblocknr = sth.bbd_list[blocknr/128];
365 assert(bigblocknr>=0);
366 assert(STORAGE_get_big_block(hf,bigblocknr,block));
368 nextblocknr = bbd[blocknr&(128-1)];
369 bbd[blocknr&(128-1)] = type;
370 if (type>=0)
371 return TRUE;
372 assert(STORAGE_put_big_block(hf,bigblocknr,block));
373 type = STORAGE_CHAINENTRY_FREE;
374 blocknr = nextblocknr;
376 return TRUE;
379 static BOOL32
380 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
381 BYTE block[BIGSIZE];
382 LPINT32 sbd = (LPINT32)block;
383 int lastblocknr,nextsmallblocknr,bigblocknr;
384 struct storage_header sth;
386 READ_HEADER;
388 assert(blocknr!=type);
389 lastblocknr=-129;bigblocknr=-2;
390 while (blocknr>=0) {
391 /* cache block ... */
392 if (lastblocknr/128!=blocknr/128) {
393 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
394 assert(bigblocknr>=0);
395 assert(STORAGE_get_big_block(hf,bigblocknr,block));
397 lastblocknr = blocknr;
398 nextsmallblocknr = sbd[blocknr&(128-1)];
399 sbd[blocknr&(128-1)] = type;
400 assert(STORAGE_put_big_block(hf,bigblocknr,block));
401 if (type>=0)
402 return TRUE;
403 type = STORAGE_CHAINENTRY_FREE;
404 blocknr = nextsmallblocknr;
406 return TRUE;
409 static int
410 STORAGE_get_free_big_blocknr(HFILE32 hf) {
411 BYTE block[BIGSIZE];
412 LPINT32 sbd = (LPINT32)block;
413 int lastbigblocknr,i,curblock,bigblocknr;
414 struct storage_header sth;
416 READ_HEADER;
417 curblock = 0;
418 lastbigblocknr = -1;
419 bigblocknr = sth.bbd_list[curblock];
420 while (curblock<sth.num_of_bbd_blocks) {
421 assert(bigblocknr>=0);
422 assert(STORAGE_get_big_block(hf,bigblocknr,block));
423 for (i=0;i<128;i++)
424 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
425 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
426 assert(STORAGE_put_big_block(hf,bigblocknr,block));
427 memset(block,0x42,sizeof(block));
428 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
429 return i+curblock*128;
431 lastbigblocknr = bigblocknr;
432 bigblocknr = sth.bbd_list[++curblock];
434 bigblocknr = curblock*128;
435 /* since we have marked all blocks from 0 up to curblock*128-1
436 * the next free one is curblock*128, where we happily put our
437 * next large block depot.
439 memset(block,0xff,sizeof(block));
440 /* mark the block allocated and returned by this function */
441 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
442 assert(STORAGE_put_big_block(hf,bigblocknr,block));
444 /* if we had a bbd block already (mostlikely) we need
445 * to link the new one into the chain
447 if (lastbigblocknr!=-1)
448 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
449 sth.bbd_list[curblock]=bigblocknr;
450 sth.num_of_bbd_blocks++;
451 assert(sth.num_of_bbd_blocks==curblock+1);
452 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
454 /* Set the end of the chain for the bigblockdepots */
455 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
456 /* add 1, for the first entry is used for the additional big block
457 * depot. (means we already used bigblocknr) */
458 memset(block,0x42,sizeof(block));
459 /* allocate this block (filled with 0x42) */
460 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
461 return bigblocknr+1;
465 static int
466 STORAGE_get_free_small_blocknr(HFILE32 hf) {
467 BYTE block[BIGSIZE];
468 LPINT32 sbd = (LPINT32)block;
469 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
470 struct storage_pps_entry root;
471 struct storage_header sth;
473 READ_HEADER;
474 bigblocknr = sth.sbd_startblock;
475 curblock = 0;
476 lastbigblocknr = -1;
477 newblocknr = -1;
478 while (bigblocknr>=0) {
479 if (!STORAGE_get_big_block(hf,bigblocknr,block))
480 return -1;
481 for (i=0;i<128;i++)
482 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
483 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
484 newblocknr = i+curblock*128;
485 break;
487 if (i!=128)
488 break;
489 lastbigblocknr = bigblocknr;
490 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
491 curblock++;
493 if (newblocknr==-1) {
494 bigblocknr = STORAGE_get_free_big_blocknr(hf);
495 if (bigblocknr<0)
496 return -1;
497 READ_HEADER;
498 memset(block,0xff,sizeof(block));
499 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
500 if (!STORAGE_put_big_block(hf,bigblocknr,block))
501 return -1;
502 if (lastbigblocknr==-1) {
503 sth.sbd_startblock = bigblocknr;
504 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
505 return -1;
506 } else {
507 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
508 return -1;
510 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
511 return -1;
512 newblocknr = curblock*128;
514 /* allocate enough big blocks for storing the allocated small block */
515 if (!STORAGE_get_root_pps_entry(hf,&root))
516 return -1;
517 if (root.pps_sb==-1)
518 lastbigblocknr = -1;
519 else
520 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
521 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
522 /* we need to allocate more stuff */
523 bigblocknr = STORAGE_get_free_big_blocknr(hf);
524 if (bigblocknr<0)
525 return -1;
526 READ_HEADER;
527 if (root.pps_sb==-1) {
528 root.pps_sb = bigblocknr;
529 root.pps_size += BIGSIZE;
530 } else {
531 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
532 return -1;
533 root.pps_size += BIGSIZE;
535 lastbigblocknr = bigblocknr;
537 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
538 return -1;
539 if (!STORAGE_put_pps_entry(hf,0,&root))
540 return -1;
541 return newblocknr;
544 static int
545 STORAGE_get_free_pps_entry(HFILE32 hf) {
546 int blocknr,i,curblock,lastblocknr;
547 BYTE block[BIGSIZE];
548 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
549 struct storage_header sth;
551 READ_HEADER;
552 blocknr = sth.root_startblock;
553 assert(blocknr>=0);
554 curblock=0;
555 while (blocknr>=0) {
556 if (!STORAGE_get_big_block(hf,blocknr,block))
557 return -1;
558 for (i=0;i<4;i++)
559 if (stde[i].pps_sizeofname==0) /* free */
560 return curblock*4+i;
561 lastblocknr = blocknr;
562 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
563 curblock++;
565 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
566 blocknr = STORAGE_get_free_big_blocknr(hf);
567 /* sth invalidated */
568 if (blocknr<0)
569 return -1;
571 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
572 return -1;
573 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
574 return -1;
575 memset(block,0,sizeof(block));
576 STORAGE_put_big_block(hf,blocknr,block);
577 return curblock*4;
580 /******************************************************************************
581 * IStream
583 HRESULT WINAPI IStream16_QueryInterface(
584 LPSTREAM16 this,REFIID refiid,LPVOID *obj
586 char xrefiid[50];
588 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
589 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
590 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
591 *obj = this;
592 return 0;
594 return OLE_E_ENUM_NOMORE;
598 ULONG WINAPI IStream16_AddRef(LPSTREAM16 this) {
599 return ++(this->ref);
602 ULONG WINAPI IStream16_Release(LPSTREAM16 this) {
603 FlushFileBuffers(this->hf);
604 this->ref--;
605 if (!this->ref) {
606 CloseHandle(this->hf);
607 SEGPTR_FREE(this);
608 return 0;
610 return this->ref;
613 /* FIXME: not handling 64 bit */
614 HRESULT WINAPI IStream16_Seek(
615 LPSTREAM16 this,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
617 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
619 switch (whence) {
620 /* unix SEEK_xx should be the same as win95 ones */
621 case SEEK_SET:
622 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
623 * right now.
625 assert(offset.HighPart==0);
626 this->offset.HighPart = offset.HighPart;
627 this->offset.LowPart = offset.LowPart;
628 break;
629 case SEEK_CUR:
630 if (offset.HighPart < 0) {
631 /* FIXME: is this negation correct ? */
632 offset.HighPart = -offset.HighPart;
633 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
635 assert(offset.HighPart==0);
636 assert(this->offset.LowPart >= offset.LowPart);
637 this->offset.LowPart -= offset.LowPart;
638 } else {
639 assert(offset.HighPart==0);
640 this->offset.LowPart+= offset.LowPart;
642 break;
643 case SEEK_END:
644 assert(offset.HighPart==0);
645 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
646 break;
648 if (this->offset.LowPart>this->stde.pps_size)
649 this->offset.LowPart=this->stde.pps_size;
650 if (newpos) *newpos = this->offset;
651 return OLE_OK;
654 HRESULT WINAPI IStream16_Read(
655 LPSTREAM16 this,void *pv,ULONG cb,ULONG *pcbRead
657 BYTE block[BIGSIZE];
658 ULONG *bytesread=pcbRead,xxread;
659 int blocknr;
661 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
662 if (!pcbRead) bytesread=&xxread;
663 *bytesread = 0;
665 if (cb>this->stde.pps_size-this->offset.LowPart)
666 cb=this->stde.pps_size-this->offset.LowPart;
667 if (this->stde.pps_size < 0x1000) {
668 /* use small block reader */
669 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
670 while (cb) {
671 int cc;
673 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
674 WARN(ole,"small block read failed!!!\n");
675 return E_FAIL;
677 cc = cb;
678 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
679 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
680 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
681 this->offset.LowPart+=cc;
682 (LPBYTE)pv+=cc;
683 *bytesread+=cc;
684 cb-=cc;
685 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
687 } else {
688 /* use big block reader */
689 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
690 while (cb) {
691 int cc;
693 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
694 WARN(ole,"big block read failed!!!\n");
695 return E_FAIL;
697 cc = cb;
698 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
699 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
700 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
701 this->offset.LowPart+=cc;
702 (LPBYTE)pv+=cc;
703 *bytesread+=cc;
704 cb-=cc;
705 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
708 return OLE_OK;
711 HRESULT WINAPI IStream16_Write(
712 LPSTREAM16 this,const void *pv,ULONG cb,ULONG *pcbWrite
714 BYTE block[BIGSIZE];
715 ULONG *byteswritten=pcbWrite,xxwritten;
716 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
717 HFILE32 hf = this->hf;
719 if (!pcbWrite) byteswritten=&xxwritten;
720 *byteswritten = 0;
722 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
723 /* do we need to junk some blocks? */
724 newsize = this->offset.LowPart+cb;
725 oldsize = this->stde.pps_size;
726 if (newsize < oldsize) {
727 if (oldsize < 0x1000) {
728 /* only small blocks */
729 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
731 assert(blocknr>=0);
733 /* will set the rest of the chain to 'free' */
734 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
735 return E_FAIL;
736 } else {
737 if (newsize >= 0x1000) {
738 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
739 assert(blocknr>=0);
741 /* will set the rest of the chain to 'free' */
742 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
743 return E_FAIL;
744 } else {
745 /* Migrate large blocks to small blocks
746 * (we just migrate newsize bytes)
748 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
749 cc = newsize;
750 blocknr = this->stde.pps_sb;
751 curdata = data;
752 while (cc>0) {
753 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
754 HeapFree(GetProcessHeap(),0,data);
755 return E_FAIL;
757 curdata += BIGSIZE;
758 cc -= BIGSIZE;
759 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
761 /* frees complete chain for this stream */
762 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
763 return E_FAIL;
764 curdata = data;
765 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
766 if (blocknr<0)
767 return E_FAIL;
768 cc = newsize;
769 while (cc>0) {
770 if (!STORAGE_put_small_block(hf,blocknr,curdata))
771 return E_FAIL;
772 cc -= SMALLSIZE;
773 if (cc<=0) {
774 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
775 return E_FAIL;
776 break;
777 } else {
778 int newblocknr = STORAGE_get_free_small_blocknr(hf);
779 if (newblocknr<0)
780 return E_FAIL;
781 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
782 return E_FAIL;
783 blocknr = newblocknr;
785 curdata += SMALLSIZE;
787 HeapFree(GetProcessHeap(),0,data);
790 this->stde.pps_size = newsize;
793 if (newsize > oldsize) {
794 if (oldsize >= 0x1000) {
795 /* should return the block right before the 'endofchain' */
796 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
797 assert(blocknr>=0);
798 lastblocknr = blocknr;
799 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
800 blocknr = STORAGE_get_free_big_blocknr(hf);
801 if (blocknr<0)
802 return E_FAIL;
803 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
804 return E_FAIL;
805 lastblocknr = blocknr;
807 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
808 return E_FAIL;
809 } else {
810 if (newsize < 0x1000) {
811 /* find startblock */
812 if (!oldsize)
813 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
814 else
815 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
816 if (blocknr<0)
817 return E_FAIL;
819 /* allocate required new small blocks */
820 lastblocknr = blocknr;
821 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
822 blocknr = STORAGE_get_free_small_blocknr(hf);
823 if (blocknr<0)
824 return E_FAIL;
825 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
826 return E_FAIL;
827 lastblocknr = blocknr;
829 /* and terminate the chain */
830 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
831 return E_FAIL;
832 } else {
833 if (!oldsize) {
834 /* no single block allocated yet */
835 blocknr=STORAGE_get_free_big_blocknr(hf);
836 if (blocknr<0)
837 return E_FAIL;
838 this->stde.pps_sb = blocknr;
839 } else {
840 /* Migrate small blocks to big blocks */
841 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
842 cc = oldsize;
843 blocknr = this->stde.pps_sb;
844 curdata = data;
845 /* slurp in */
846 while (cc>0) {
847 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
848 HeapFree(GetProcessHeap(),0,data);
849 return E_FAIL;
851 curdata += SMALLSIZE;
852 cc -= SMALLSIZE;
853 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
855 /* free small block chain */
856 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
857 return E_FAIL;
858 curdata = data;
859 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
860 if (blocknr<0)
861 return E_FAIL;
862 /* put the data into the big blocks */
863 cc = this->stde.pps_size;
864 while (cc>0) {
865 if (!STORAGE_put_big_block(hf,blocknr,curdata))
866 return E_FAIL;
867 cc -= BIGSIZE;
868 if (cc<=0) {
869 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
870 return E_FAIL;
871 break;
872 } else {
873 int newblocknr = STORAGE_get_free_big_blocknr(hf);
874 if (newblocknr<0)
875 return E_FAIL;
876 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
877 return E_FAIL;
878 blocknr = newblocknr;
880 curdata += BIGSIZE;
882 HeapFree(GetProcessHeap(),0,data);
884 /* generate big blocks to fit the new data */
885 lastblocknr = blocknr;
886 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
887 blocknr = STORAGE_get_free_big_blocknr(hf);
888 if (blocknr<0)
889 return E_FAIL;
890 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
891 return E_FAIL;
892 lastblocknr = blocknr;
894 /* terminate chain */
895 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
896 return E_FAIL;
899 this->stde.pps_size = newsize;
902 /* There are just some cases where we didn't modify it, we write it out
903 * everytime
905 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
906 return E_FAIL;
908 /* finally the write pass */
909 if (this->stde.pps_size < 0x1000) {
910 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
911 assert(blocknr>=0);
912 while (cb>0) {
913 /* we ensured that it is allocated above */
914 assert(blocknr>=0);
915 /* Read old block everytime, since we can have
916 * overlapping data at START and END of the write
918 if (!STORAGE_get_small_block(hf,blocknr,block))
919 return E_FAIL;
921 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
922 if (cc>cb)
923 cc=cb;
924 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
925 (LPBYTE)(pv+curoffset),
928 if (!STORAGE_put_small_block(hf,blocknr,block))
929 return E_FAIL;
930 cb -= cc;
931 curoffset += cc;
932 (LPBYTE)pv += cc;
933 this->offset.LowPart += cc;
934 *byteswritten += cc;
935 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
937 } else {
938 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
939 assert(blocknr>=0);
940 while (cb>0) {
941 /* we ensured that it is allocated above, so it better is */
942 assert(blocknr>=0);
943 /* read old block everytime, since we can have
944 * overlapping data at START and END of the write
946 if (!STORAGE_get_big_block(hf,blocknr,block))
947 return E_FAIL;
949 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
950 if (cc>cb)
951 cc=cb;
952 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
953 (LPBYTE)(pv+curoffset),
956 if (!STORAGE_put_big_block(hf,blocknr,block))
957 return E_FAIL;
958 cb -= cc;
959 curoffset += cc;
960 (LPBYTE)pv += cc;
961 this->offset.LowPart += cc;
962 *byteswritten += cc;
963 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
966 return OLE_OK;
969 static void _create_istream16(LPSTREAM16 *str) {
970 LPSTREAM16 lpst;
972 if (!strvt16.fnQueryInterface) {
973 HMODULE16 wp = GetModuleHandle16("STORAGE");
974 if (wp>=32) {
975 #define VTENT(x) strvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#x);
976 VTENT(QueryInterface)
977 VTENT(AddRef)
978 VTENT(Release)
979 VTENT(Read)
980 VTENT(Write)
981 VTENT(Seek)
982 VTENT(SetSize)
983 VTENT(CopyTo)
984 VTENT(Commit)
985 VTENT(Revert)
986 VTENT(LockRegion)
987 VTENT(UnlockRegion)
988 VTENT(Stat)
989 VTENT(Clone)
990 #undef VTENT
991 segstrvt16 = SEGPTR_NEW(IStream16_VTable);
992 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
993 segstrvt16 = (LPSTREAM16_VTABLE)SEGPTR_GET(segstrvt16);
994 } else {
995 #define VTENT(x) strvt16.fn##x = IStream16_##x;
996 VTENT(QueryInterface)
997 VTENT(AddRef)
998 VTENT(Release)
999 VTENT(Read)
1000 VTENT(Write)
1001 VTENT(Seek)
1003 VTENT(CopyTo)
1004 VTENT(Commit)
1005 VTENT(SetSize)
1006 VTENT(Revert)
1007 VTENT(LockRegion)
1008 VTENT(UnlockRegion)
1009 VTENT(Stat)
1010 VTENT(Clone)
1012 #undef VTENT
1013 segstrvt16 = &strvt16;
1016 lpst = SEGPTR_NEW(IStream16);
1017 lpst->lpvtbl = segstrvt16;
1018 lpst->ref = 1;
1019 lpst->thisptr = SEGPTR_GET(lpst);
1020 *str = (void*)lpst->thisptr;
1023 /*****************************************************************************
1024 * IStream32
1026 HRESULT WINAPI IStream32_QueryInterface(
1027 LPSTREAM32 this,REFIID refiid,LPVOID *obj
1029 char xrefiid[50];
1031 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1032 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1033 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1034 *obj = this;
1035 return 0;
1037 return OLE_E_ENUM_NOMORE;
1041 ULONG WINAPI IStream32_AddRef(LPSTREAM32 this) {
1042 return ++(this->ref);
1045 ULONG WINAPI IStream32_Release(LPSTREAM32 this) {
1046 FlushFileBuffers(this->hf);
1047 this->ref--;
1048 if (!this->ref) {
1049 CloseHandle(this->hf);
1050 SEGPTR_FREE(this);
1051 return 0;
1053 return this->ref;
1056 static IStream32_VTable strvt32 = {
1057 IStream32_QueryInterface,
1058 IStream32_AddRef,
1059 IStream32_Release,
1060 (void*)4,
1061 (void*)5,
1062 (void*)6,
1063 (void*)7,
1064 (void*)8,
1065 (void*)9,
1066 (void*)10,
1067 (void*)11,
1070 /******************************************************************************
1071 * IStorage
1073 HRESULT WINAPI IStorage16_QueryInterface(
1074 LPSTORAGE16 this,REFIID refiid,LPVOID *obj
1076 char xrefiid[50];
1078 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1079 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1081 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1082 *obj = this;
1083 return 0;
1085 return OLE_E_ENUM_NOMORE;
1088 ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this) {
1089 return ++(this->ref);
1092 ULONG WINAPI IStorage16_Release(LPSTORAGE16 this) {
1093 this->ref--;
1094 if (this->ref)
1095 return this->ref;
1096 SEGPTR_FREE(this);
1097 return 0;
1100 HRESULT WINAPI IStorage16_Stat(
1101 LPSTORAGE16 this,STATSTG *pstatstg, DWORD grfStatFlag
1103 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1104 this,pstatstg,grfStatFlag
1106 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1107 pstatstg->type = this->stde.pps_type;
1108 pstatstg->cbSize.LowPart = this->stde.pps_size;
1109 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1110 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1111 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1112 pstatstg->grfMode = 0; /* FIXME */
1113 pstatstg->grfLocksSupported = 0; /* FIXME */
1114 pstatstg->clsid = this->stde.pps_guid;
1115 pstatstg->grfStateBits = 0; /* FIXME */
1116 pstatstg->reserved = 0;
1117 return OLE_OK;
1120 HRESULT WINAPI IStorage16_Commit(
1121 LPSTORAGE16 this,DWORD commitflags
1123 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1124 this,commitflags
1126 return OLE_OK;
1129 HRESULT WINAPI IStorage16_CopyTo(LPSTORAGE16 this,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1130 char xguid[50];
1132 if (rgiidExclude)
1133 WINE_StringFromCLSID(rgiidExclude,xguid);
1134 else
1135 strcpy(xguid,"<no guid>");
1136 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1137 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1139 return OLE_OK;
1144 HRESULT WINAPI IStorage16_CreateStorage(
1145 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1147 LPSTORAGE16 lpstg;
1148 int ppsent,x;
1149 struct storage_pps_entry stde;
1150 struct storage_header sth;
1151 HFILE32 hf=this->hf;
1153 READ_HEADER;
1155 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1156 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1158 if (grfMode & STGM_TRANSACTED)
1159 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1160 _create_istorage16(ppstg);
1161 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstg);
1162 lpstg->hf = this->hf;
1164 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1165 if (ppsent<0)
1166 return E_FAIL;
1167 stde=this->stde;
1168 if (stde.pps_dir==-1) {
1169 stde.pps_dir = ppsent;
1170 x = this->ppsent;
1171 } else {
1172 FIXME(ole," use prev chain too ?\n");
1173 x=stde.pps_dir;
1174 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1175 return E_FAIL;
1176 while (stde.pps_next!=-1) {
1177 x=stde.pps_next;
1178 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1179 return E_FAIL;
1181 stde.pps_next = ppsent;
1183 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1184 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1185 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1186 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1187 lpstg->stde.pps_next = -1;
1188 lpstg->stde.pps_prev = -1;
1189 lpstg->stde.pps_dir = -1;
1190 lpstg->stde.pps_sb = -1;
1191 lpstg->stde.pps_size = 0;
1192 lpstg->stde.pps_type = 1;
1193 lpstg->ppsent = ppsent;
1194 /* FIXME: timestamps? */
1195 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1196 return E_FAIL;
1197 return OLE_OK;
1200 HRESULT WINAPI IStorage16_CreateStream(
1201 LPSTORAGE16 this,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1203 LPSTREAM16 lpstr;
1204 int ppsent,x;
1205 struct storage_pps_entry stde;
1207 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1208 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1210 if (grfMode & STGM_TRANSACTED)
1211 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1212 _create_istream16(ppstm);
1213 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1214 lpstr->hf = FILE_Dup(this->hf);
1215 lpstr->offset.LowPart = 0;
1216 lpstr->offset.HighPart = 0;
1218 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1219 if (ppsent<0)
1220 return E_FAIL;
1221 stde=this->stde;
1222 if (stde.pps_next==-1)
1223 x=this->ppsent;
1224 else
1225 while (stde.pps_next!=-1) {
1226 x=stde.pps_next;
1227 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1228 return E_FAIL;
1230 stde.pps_next = ppsent;
1231 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1232 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1233 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1234 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1235 lpstr->stde.pps_next = -1;
1236 lpstr->stde.pps_prev = -1;
1237 lpstr->stde.pps_dir = -1;
1238 lpstr->stde.pps_sb = -1;
1239 lpstr->stde.pps_size = 0;
1240 lpstr->stde.pps_type = 2;
1241 lpstr->ppsent = ppsent;
1242 /* FIXME: timestamps? */
1243 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1244 return E_FAIL;
1245 return OLE_OK;
1248 HRESULT WINAPI IStorage16_OpenStorage(
1249 LPSTORAGE16 this,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1251 LPSTREAM16 lpstg;
1252 WCHAR name[33];
1253 int newpps;
1255 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1256 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1258 if (grfMode & STGM_TRANSACTED)
1259 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1260 _create_istorage16(ppstg);
1261 lpstg = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstg);
1262 lpstg->hf = FILE_Dup(this->hf);
1263 lstrcpyAtoW(name,pwcsName);
1264 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1265 if (newpps==-1) {
1266 IStream16_Release(lpstg);
1267 return E_FAIL;
1270 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1271 IStream16_Release(lpstg);
1272 return E_FAIL;
1274 lpstg->ppsent = newpps;
1275 return OLE_OK;
1278 HRESULT WINAPI IStorage16_OpenStream(
1279 LPSTORAGE16 this,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1281 LPSTREAM16 lpstr;
1282 WCHAR name[33];
1283 int newpps;
1285 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1286 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1288 if (grfMode & STGM_TRANSACTED)
1289 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1290 _create_istream16(ppstm);
1291 lpstr = (LPSTREAM16)PTR_SEG_TO_LIN(*ppstm);
1292 lpstr->hf = FILE_Dup(this->hf);
1293 lstrcpyAtoW(name,pwcsName);
1294 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1295 if (newpps==-1) {
1296 IStream16_Release(lpstr);
1297 return E_FAIL;
1300 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1301 IStream16_Release(lpstr);
1302 return E_FAIL;
1304 lpstr->offset.LowPart = 0;
1305 lpstr->offset.HighPart = 0;
1306 lpstr->ppsent = newpps;
1307 return OLE_OK;
1310 static void _create_istorage16(LPSTORAGE16 *stg) {
1311 LPSTORAGE16 lpst;
1313 if (!stvt16.fnQueryInterface) {
1314 HMODULE16 wp = GetModuleHandle16("STORAGE");
1315 if (wp>=32) {
1316 #define VTENT(x) stvt16.fn##x = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#x);
1317 VTENT(QueryInterface)
1318 VTENT(AddRef)
1319 VTENT(Release)
1320 VTENT(CreateStream)
1321 VTENT(OpenStream)
1322 VTENT(CreateStorage)
1323 VTENT(OpenStorage)
1324 VTENT(CopyTo)
1325 VTENT(MoveElementTo)
1326 VTENT(Commit)
1327 VTENT(Revert)
1328 VTENT(EnumElements)
1329 VTENT(DestroyElement)
1330 VTENT(RenameElement)
1331 VTENT(SetElementTimes)
1332 VTENT(SetClass)
1333 VTENT(SetStateBits)
1334 VTENT(Stat)
1335 #undef VTENT
1336 segstvt16 = SEGPTR_NEW(IStorage16_VTable);
1337 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1338 segstvt16 = (LPSTORAGE16_VTABLE)SEGPTR_GET(segstvt16);
1339 } else {
1340 #define VTENT(x) stvt16.fn##x = IStorage16_##x;
1341 VTENT(QueryInterface)
1342 VTENT(AddRef)
1343 VTENT(Release)
1344 VTENT(CreateStream)
1345 VTENT(OpenStream)
1346 VTENT(CreateStorage)
1347 VTENT(OpenStorage)
1348 VTENT(CopyTo)
1349 VTENT(Commit)
1350 /* not (yet) implemented ...
1351 VTENT(MoveElementTo)
1352 VTENT(Revert)
1353 VTENT(EnumElements)
1354 VTENT(DestroyElement)
1355 VTENT(RenameElement)
1356 VTENT(SetElementTimes)
1357 VTENT(SetClass)
1358 VTENT(SetStateBits)
1359 VTENT(Stat)
1361 #undef VTENT
1362 segstvt16 = &stvt16;
1365 lpst = SEGPTR_NEW(IStorage16);
1366 lpst->lpvtbl = segstvt16;
1367 lpst->ref = 1;
1368 lpst->thisptr = SEGPTR_GET(lpst);
1369 *stg = (void*)lpst->thisptr;
1372 /******************************************************************************
1373 * IStorage32
1375 HRESULT WINAPI IStorage32_QueryInterface(
1376 LPSTORAGE32 this,REFIID refiid,LPVOID *obj
1378 char xrefiid[50];
1380 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1381 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1383 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1384 *obj = this;
1385 return 0;
1387 return OLE_E_ENUM_NOMORE;
1390 ULONG WINAPI IStorage32_AddRef(LPSTORAGE32 this) {
1391 return ++(this->ref);
1394 ULONG WINAPI IStorage32_Release(LPSTORAGE32 this) {
1395 this->ref--;
1396 if (this->ref)
1397 return this->ref;
1398 HeapFree(GetProcessHeap(),0,this);
1399 return 0;
1402 HRESULT WINAPI IStorage32_CreateStream(
1403 LPSTORAGE32 this,LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream32 **ppstm
1405 TRACE(ole,"(%p)->(%p,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1406 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1408 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1409 (*ppstm)->lpvtbl= &strvt32;
1410 (*ppstm)->ref = 1;
1412 return OLE_OK;
1415 HRESULT WINAPI IStorage32_OpenStream(
1416 LPSTORAGE32 this,LPCOLESTR32 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream32 **ppstm
1418 TRACE(ole,"(%p)->(%p,%p,0x%08lx,0x%08lx,%p)\n",
1419 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1421 *ppstm = (IStream32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStream32));
1422 (*ppstm)->lpvtbl= &strvt32;
1423 (*ppstm)->ref = 1;
1424 return OLE_OK;
1427 static IStorage32_VTable stvt32 = {
1428 IStorage32_QueryInterface,
1429 IStorage32_AddRef,
1430 IStorage32_Release,
1431 IStorage32_CreateStream,
1432 IStorage32_OpenStream,
1433 (void*)6,
1434 (void*)7,
1435 (void*)8,
1436 (void*)9,
1437 (void*)10,
1438 (void*)11,
1439 (void*)12,
1440 (void*)13,
1441 (void*)14,
1442 (void*)15,
1445 /******************************************************************************
1446 * Storage API functions
1449 OLESTATUS WINAPI StgCreateDocFile16(
1450 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1452 HFILE32 hf;
1453 int i,ret;
1454 LPSTORAGE16 lpstg;
1455 struct storage_pps_entry stde;
1457 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1458 pwcsName,grfMode,reserved,ppstgOpen
1460 _create_istorage16(ppstgOpen);
1461 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1462 if (hf==INVALID_HANDLE_VALUE32) {
1463 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1464 return E_FAIL;
1466 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1467 lpstg->hf = hf;
1468 /* FIXME: check for existance before overwriting? */
1469 if (!STORAGE_init_storage(hf)) {
1470 CloseHandle(hf);
1471 return E_FAIL;
1473 i=0;ret=0;
1474 while (!ret) { /* neither 1 nor <0 */
1475 ret=STORAGE_get_pps_entry(hf,i,&stde);
1476 if ((ret==1) && (stde.pps_type==5)) {
1477 lpstg->stde = stde;
1478 lpstg->ppsent = i;
1479 break;
1481 i++;
1483 if (ret!=1) {
1484 IStorage16_Release(lpstg); /* will remove it */
1485 return E_FAIL;
1487 return OLE_OK;
1490 OLESTATUS WINAPI StgCreateDocFile32(
1491 LPCOLESTR32 pwcsName,DWORD grfMode,DWORD reserved,IStorage32 **ppstgOpen
1493 TRACE(ole,"(%p,0x%08lx,0x%08lx,%p)\n",
1494 pwcsName,grfMode,reserved,ppstgOpen
1496 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1497 (*ppstgOpen)->ref = 1;
1498 (*ppstgOpen)->lpvtbl = &stvt32;
1499 return OLE_OK;
1502 OLESTATUS WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1503 HFILE32 hf;
1504 OFSTRUCT ofs;
1505 BYTE magic[24];
1507 TRACE(ole,"(\'%s\')",fn);
1508 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1509 if (hf==HFILE_ERROR32)
1510 return STG_E_FILENOTFOUND;
1511 if (24!=_lread32(hf,magic,24)) {
1512 fprintf(stderr," too short\n");
1513 _lclose32(hf);
1514 return S_FALSE;
1516 if (!memcmp(magic,STORAGE_magic,8)) {
1517 fprintf(stderr," -> YES\n");
1518 _lclose32(hf);
1519 return S_OK;
1521 if (!memcmp(magic,STORAGE_notmagic,8)) {
1522 fprintf(stderr," -> NO\n");
1523 _lclose32(hf);
1524 return S_FALSE;
1526 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1527 fprintf(stderr," -> old format\n");
1528 _lclose32(hf);
1529 return STG_E_OLDFORMAT;
1531 WARN(ole," -> Invalid header.\n");
1532 _lclose32(hf);
1533 return STG_E_INVALIDHEADER;
1536 OLESTATUS WINAPI
1537 StgIsStorageFile32(LPCOLESTR32 fn)
1539 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1540 OLESTATUS ret = StgIsStorageFile16(xfn);
1542 HeapFree(GetProcessHeap(),0,xfn);
1543 return ret;
1548 OLESTATUS WINAPI StgOpenStorage16(
1549 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1550 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1552 HFILE32 hf;
1553 int ret,i;
1554 LPSTORAGE16 lpstg;
1555 struct storage_pps_entry stde;
1557 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1558 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1560 _create_istorage16(ppstgOpen);
1561 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1562 if (hf==INVALID_HANDLE_VALUE32) {
1563 fprintf(stderr,"couldn't open file for storage\n");
1564 return E_FAIL;
1566 lpstg = (LPSTORAGE16)PTR_SEG_TO_LIN(*ppstgOpen);
1567 lpstg->hf = hf;
1569 i=0;ret=0;
1570 while (!ret) { /* neither 1 nor <0 */
1571 ret=STORAGE_get_pps_entry(hf,i,&stde);
1572 if ((ret==1) && (stde.pps_type==5)) {
1573 lpstg->stde=stde;
1574 break;
1576 i++;
1578 if (ret!=1) {
1579 IStorage16_Release(lpstg); /* will remove it */
1580 return E_FAIL;
1582 return OLE_OK;
1586 OLESTATUS WINAPI StgOpenStorage32(
1587 const OLECHAR32 * pwcsName,IStorage32 *pstgPriority,DWORD grfMode,
1588 SNB32 snbExclude,DWORD reserved, IStorage32 **ppstgOpen
1590 FIXME(ole,"StgOpenStorage32(%p,%p,0x%08lx,%p,%ld,%p),stub!\n",
1591 pwcsName,pstgPriority,grfMode,snbExclude,reserved,
1592 ppstgOpen);
1593 *ppstgOpen = (IStorage32*)HeapAlloc(GetProcessHeap(),0,sizeof(IStorage32));
1594 (*ppstgOpen)->ref = 1;
1595 (*ppstgOpen)->lpvtbl = &stvt32;
1596 return OLE_OK;