Release 990214.
[wine/multimedia.git] / ole / storage.c
blobcca1f27f949fece375f26f2f3072badf4022f622
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 "wine/obj_base.h"
18 #include "wine/obj_storage.h"
19 #include "objbase.h"
20 #include "heap.h"
21 #include "module.h"
22 #include "ldt.h"
23 #include "debug.h"
25 struct storage_header {
26 BYTE magic[8]; /* 00: magic */
27 BYTE unknown1[36]; /* 08: unknown */
28 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
29 DWORD root_startblock;/* 30: root storage first big block */
30 DWORD unknown2[2]; /* 34: unknown */
31 DWORD sbd_startblock; /* 3C: small block depot first big block */
32 DWORD unknown3[3]; /* 40: unknown */
33 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
35 struct storage_pps_entry {
36 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
37 WORD pps_sizeofname; /* 40: namelength in bytes */
38 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
39 BYTE pps_unknown0; /* 43: unknown */
40 DWORD pps_prev; /* 44: previous pps */
41 DWORD pps_next; /* 48: next pps */
42 DWORD pps_dir; /* 4C: directory pps */
43 GUID pps_guid; /* 50: class ID */
44 DWORD pps_unknown1; /* 60: unknown */
45 FILETIME pps_ft1; /* 64: filetime1 */
46 FILETIME pps_ft2; /* 70: filetime2 */
47 DWORD pps_sb; /* 74: data startblock */
48 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
49 DWORD pps_unknown2; /* 7C: unknown */
52 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
53 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
54 #define STORAGE_CHAINENTRY_FREE 0xffffffff
57 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
58 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
59 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
61 #define BIGSIZE 512
62 #define SMALLSIZE 64
64 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
66 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
67 static ICOM_VTABLE(IStorage16) stvt16;
68 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
69 static ICOM_VTABLE(IStream16) strvt16;
70 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
72 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
73 static void _create_istorage16(LPSTORAGE16 *stg);
74 static void _create_istream16(LPSTREAM16 *str);
76 #define IMPLEMENTED 1
79 /******************************************************************************
80 * STORAGE_get_big_block [Internal]
82 * Reading OLE compound storage
84 static BOOL32
85 STORAGE_get_big_block(HFILE32 hf,int n,BYTE *block) {
86 assert(n>=-1);
87 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
88 WARN(ole," seek failed (%ld)\n",GetLastError());
89 return FALSE;
91 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
92 if (BIGSIZE!=_lread32(hf,block,BIGSIZE)) {
93 WARN(ole,"(block size %d): read didn't read (%ld)\n",n,GetLastError());
94 assert(0);
95 return FALSE;
97 return TRUE;
100 /******************************************************************************
101 * STORAGE_put_big_block [INTERNAL]
103 static BOOL32
104 STORAGE_put_big_block(HFILE32 hf,int n,BYTE *block) {
105 assert(n>=-1);
106 if (-1==_llseek32(hf,(n+1)*BIGSIZE,SEEK_SET)) {
107 WARN(ole," seek failed (%ld)\n",GetLastError());
108 return FALSE;
110 assert((n+1)*BIGSIZE==_llseek32(hf,0,SEEK_CUR));
111 if (BIGSIZE!=_lwrite32(hf,block,BIGSIZE)) {
112 WARN(ole," write failed (%ld)\n",GetLastError());
113 return FALSE;
115 return TRUE;
118 /******************************************************************************
119 * STORAGE_get_next_big_blocknr [INTERNAL]
121 static int
122 STORAGE_get_next_big_blocknr(HFILE32 hf,int blocknr) {
123 INT32 bbs[BIGSIZE/sizeof(INT32)];
124 struct storage_header sth;
126 READ_HEADER;
128 assert(blocknr>>7<sth.num_of_bbd_blocks);
129 if (sth.bbd_list[blocknr>>7]==0xffffffff)
130 return -5;
131 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
132 return -5;
133 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
134 return bbs[blocknr&0x7f];
137 /******************************************************************************
138 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
140 static int
141 STORAGE_get_nth_next_big_blocknr(HFILE32 hf,int blocknr,int nr) {
142 INT32 bbs[BIGSIZE/sizeof(INT32)];
143 int lastblock = -1;
144 struct storage_header sth;
146 READ_HEADER;
148 assert(blocknr>=0);
149 while (nr--) {
150 assert((blocknr>>7)<sth.num_of_bbd_blocks);
151 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
153 /* simple caching... */
154 if (lastblock!=sth.bbd_list[blocknr>>7]) {
155 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
156 lastblock = sth.bbd_list[blocknr>>7];
158 blocknr = bbs[blocknr&0x7f];
160 return blocknr;
163 /******************************************************************************
164 * STORAGE_get_root_pps_entry [Internal]
166 static BOOL32
167 STORAGE_get_root_pps_entry(HFILE32 hf,struct storage_pps_entry *pstde) {
168 int blocknr,i;
169 BYTE block[BIGSIZE];
170 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
171 struct storage_header sth;
173 READ_HEADER;
174 blocknr = sth.root_startblock;
175 while (blocknr>=0) {
176 assert(STORAGE_get_big_block(hf,blocknr,block));
177 for (i=0;i<4;i++) {
178 if (!stde[i].pps_sizeofname)
179 continue;
180 if (stde[i].pps_type==5) {
181 *pstde=stde[i];
182 return TRUE;
185 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
187 return FALSE;
190 /******************************************************************************
191 * STORAGE_get_small_block [INTERNAL]
193 static BOOL32
194 STORAGE_get_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
195 BYTE block[BIGSIZE];
196 int bigblocknr;
197 struct storage_pps_entry root;
199 assert(blocknr>=0);
200 assert(STORAGE_get_root_pps_entry(hf,&root));
201 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
202 assert(bigblocknr>=0);
203 assert(STORAGE_get_big_block(hf,bigblocknr,block));
205 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
206 return TRUE;
209 /******************************************************************************
210 * STORAGE_put_small_block [INTERNAL]
212 static BOOL32
213 STORAGE_put_small_block(HFILE32 hf,int blocknr,BYTE *sblock) {
214 BYTE block[BIGSIZE];
215 int bigblocknr;
216 struct storage_pps_entry root;
218 assert(blocknr>=0);
220 assert(STORAGE_get_root_pps_entry(hf,&root));
221 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
222 assert(bigblocknr>=0);
223 assert(STORAGE_get_big_block(hf,bigblocknr,block));
225 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
226 assert(STORAGE_put_big_block(hf,bigblocknr,block));
227 return TRUE;
230 /******************************************************************************
231 * STORAGE_get_next_small_blocknr [INTERNAL]
233 static int
234 STORAGE_get_next_small_blocknr(HFILE32 hf,int blocknr) {
235 BYTE block[BIGSIZE];
236 LPINT32 sbd = (LPINT32)block;
237 int bigblocknr;
238 struct storage_header sth;
240 READ_HEADER;
241 assert(blocknr>=0);
242 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
243 assert(bigblocknr>=0);
244 assert(STORAGE_get_big_block(hf,bigblocknr,block));
245 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
246 return sbd[blocknr & (128-1)];
249 /******************************************************************************
250 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
252 static int
253 STORAGE_get_nth_next_small_blocknr(HFILE32 hf,int blocknr,int nr) {
254 int lastblocknr;
255 BYTE block[BIGSIZE];
256 LPINT32 sbd = (LPINT32)block;
257 struct storage_header sth;
259 READ_HEADER;
260 lastblocknr=-1;
261 assert(blocknr>=0);
262 while ((nr--) && (blocknr>=0)) {
263 if (lastblocknr/128!=blocknr/128) {
264 int bigblocknr;
265 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
266 assert(bigblocknr>=0);
267 assert(STORAGE_get_big_block(hf,bigblocknr,block));
268 lastblocknr = blocknr;
270 assert(lastblocknr>=0);
271 lastblocknr=blocknr;
272 blocknr=sbd[blocknr & (128-1)];
273 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
275 return blocknr;
278 /******************************************************************************
279 * STORAGE_get_pps_entry [INTERNAL]
281 static int
282 STORAGE_get_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
283 int blocknr;
284 BYTE block[BIGSIZE];
285 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
286 struct storage_header sth;
288 READ_HEADER;
289 /* we have 4 pps entries per big block */
290 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
291 assert(blocknr>=0);
292 assert(STORAGE_get_big_block(hf,blocknr,block));
294 *pstde=*stde;
295 return 1;
298 /******************************************************************************
299 * STORAGE_put_pps_entry [Internal]
301 static int
302 STORAGE_put_pps_entry(HFILE32 hf,int n,struct storage_pps_entry *pstde) {
303 int blocknr;
304 BYTE block[BIGSIZE];
305 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
306 struct storage_header sth;
308 READ_HEADER;
310 /* we have 4 pps entries per big block */
311 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
312 assert(blocknr>=0);
313 assert(STORAGE_get_big_block(hf,blocknr,block));
314 *stde=*pstde;
315 assert(STORAGE_put_big_block(hf,blocknr,block));
316 return 1;
319 /******************************************************************************
320 * STORAGE_look_for_named_pps [Internal]
322 static int
323 STORAGE_look_for_named_pps(HFILE32 hf,int n,LPOLESTR32 name) {
324 struct storage_pps_entry stde;
325 int ret;
327 if (n==-1)
328 return -1;
329 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
330 return -1;
332 if (!lstrcmp32W(name,stde.pps_rawname))
333 return n;
334 if (stde.pps_prev != -1) {
335 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
336 if (ret!=-1)
337 return ret;
339 if (stde.pps_next != -1) {
340 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
341 if (ret!=-1)
342 return ret;
344 return -1;
347 /******************************************************************************
348 * STORAGE_dump_pps_entry [Internal]
350 * FIXME
351 * Function is unused
353 void
354 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
355 char name[33],xguid[50];
357 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
359 lstrcpyWtoA(name,stde->pps_rawname);
360 if (!stde->pps_sizeofname)
361 return;
362 DUMP("name: %s\n",name);
363 DUMP("type: %d\n",stde->pps_type);
364 DUMP("prev pps: %ld\n",stde->pps_prev);
365 DUMP("next pps: %ld\n",stde->pps_next);
366 DUMP("dir pps: %ld\n",stde->pps_dir);
367 DUMP("guid: %s\n",xguid);
368 if (stde->pps_type !=2) {
369 time_t t;
371 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
372 DUMP("ts1: %s\n",ctime(&t));
373 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
374 DUMP("ts2: %s\n",ctime(&t));
376 DUMP("startblock: %ld\n",stde->pps_sb);
377 DUMP("size: %ld\n",stde->pps_size);
380 /******************************************************************************
381 * STORAGE_init_storage [INTERNAL]
383 static BOOL32
384 STORAGE_init_storage(HFILE32 hf) {
385 BYTE block[BIGSIZE];
386 LPDWORD bbs;
387 struct storage_header *sth;
388 struct storage_pps_entry *stde;
390 assert(-1!=_llseek32(hf,0,SEEK_SET));
391 /* block -1 is the storage header */
392 sth = (struct storage_header*)block;
393 memcpy(sth->magic,STORAGE_magic,8);
394 memset(sth->unknown1,0,sizeof(sth->unknown1));
395 memset(sth->unknown2,0,sizeof(sth->unknown2));
396 memset(sth->unknown3,0,sizeof(sth->unknown3));
397 sth->num_of_bbd_blocks = 1;
398 sth->root_startblock = 1;
399 sth->sbd_startblock = 0xffffffff;
400 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
401 sth->bbd_list[0] = 0;
402 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
403 /* block 0 is the big block directory */
404 bbs=(LPDWORD)block;
405 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
406 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
407 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
408 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
409 /* block 1 is the root directory entry */
410 memset(block,0x00,sizeof(block));
411 stde = (struct storage_pps_entry*)block;
412 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
413 stde->pps_sizeofname = lstrlen32W(stde->pps_rawname)*2+2;
414 stde->pps_type = 5;
415 stde->pps_dir = -1;
416 stde->pps_next = -1;
417 stde->pps_prev = -1;
418 stde->pps_sb = 0xffffffff;
419 stde->pps_size = 0;
420 assert(BIGSIZE==_lwrite32(hf,block,BIGSIZE));
421 return TRUE;
424 /******************************************************************************
425 * STORAGE_set_big_chain [Internal]
427 static BOOL32
428 STORAGE_set_big_chain(HFILE32 hf,int blocknr,INT32 type) {
429 BYTE block[BIGSIZE];
430 LPINT32 bbd = (LPINT32)block;
431 int nextblocknr,bigblocknr;
432 struct storage_header sth;
434 READ_HEADER;
435 assert(blocknr!=type);
436 while (blocknr>=0) {
437 bigblocknr = sth.bbd_list[blocknr/128];
438 assert(bigblocknr>=0);
439 assert(STORAGE_get_big_block(hf,bigblocknr,block));
441 nextblocknr = bbd[blocknr&(128-1)];
442 bbd[blocknr&(128-1)] = type;
443 if (type>=0)
444 return TRUE;
445 assert(STORAGE_put_big_block(hf,bigblocknr,block));
446 type = STORAGE_CHAINENTRY_FREE;
447 blocknr = nextblocknr;
449 return TRUE;
452 /******************************************************************************
453 * STORAGE_set_small_chain [Internal]
455 static BOOL32
456 STORAGE_set_small_chain(HFILE32 hf,int blocknr,INT32 type) {
457 BYTE block[BIGSIZE];
458 LPINT32 sbd = (LPINT32)block;
459 int lastblocknr,nextsmallblocknr,bigblocknr;
460 struct storage_header sth;
462 READ_HEADER;
464 assert(blocknr!=type);
465 lastblocknr=-129;bigblocknr=-2;
466 while (blocknr>=0) {
467 /* cache block ... */
468 if (lastblocknr/128!=blocknr/128) {
469 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
470 assert(bigblocknr>=0);
471 assert(STORAGE_get_big_block(hf,bigblocknr,block));
473 lastblocknr = blocknr;
474 nextsmallblocknr = sbd[blocknr&(128-1)];
475 sbd[blocknr&(128-1)] = type;
476 assert(STORAGE_put_big_block(hf,bigblocknr,block));
477 if (type>=0)
478 return TRUE;
479 type = STORAGE_CHAINENTRY_FREE;
480 blocknr = nextsmallblocknr;
482 return TRUE;
485 /******************************************************************************
486 * STORAGE_get_free_big_blocknr [Internal]
488 static int
489 STORAGE_get_free_big_blocknr(HFILE32 hf) {
490 BYTE block[BIGSIZE];
491 LPINT32 sbd = (LPINT32)block;
492 int lastbigblocknr,i,curblock,bigblocknr;
493 struct storage_header sth;
495 READ_HEADER;
496 curblock = 0;
497 lastbigblocknr = -1;
498 bigblocknr = sth.bbd_list[curblock];
499 while (curblock<sth.num_of_bbd_blocks) {
500 assert(bigblocknr>=0);
501 assert(STORAGE_get_big_block(hf,bigblocknr,block));
502 for (i=0;i<128;i++)
503 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
504 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
505 assert(STORAGE_put_big_block(hf,bigblocknr,block));
506 memset(block,0x42,sizeof(block));
507 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
508 return i+curblock*128;
510 lastbigblocknr = bigblocknr;
511 bigblocknr = sth.bbd_list[++curblock];
513 bigblocknr = curblock*128;
514 /* since we have marked all blocks from 0 up to curblock*128-1
515 * the next free one is curblock*128, where we happily put our
516 * next large block depot.
518 memset(block,0xff,sizeof(block));
519 /* mark the block allocated and returned by this function */
520 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
521 assert(STORAGE_put_big_block(hf,bigblocknr,block));
523 /* if we had a bbd block already (mostlikely) we need
524 * to link the new one into the chain
526 if (lastbigblocknr!=-1)
527 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
528 sth.bbd_list[curblock]=bigblocknr;
529 sth.num_of_bbd_blocks++;
530 assert(sth.num_of_bbd_blocks==curblock+1);
531 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
533 /* Set the end of the chain for the bigblockdepots */
534 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
535 /* add 1, for the first entry is used for the additional big block
536 * depot. (means we already used bigblocknr) */
537 memset(block,0x42,sizeof(block));
538 /* allocate this block (filled with 0x42) */
539 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
540 return bigblocknr+1;
544 /******************************************************************************
545 * STORAGE_get_free_small_blocknr [Internal]
547 static int
548 STORAGE_get_free_small_blocknr(HFILE32 hf) {
549 BYTE block[BIGSIZE];
550 LPINT32 sbd = (LPINT32)block;
551 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
552 struct storage_pps_entry root;
553 struct storage_header sth;
555 READ_HEADER;
556 bigblocknr = sth.sbd_startblock;
557 curblock = 0;
558 lastbigblocknr = -1;
559 newblocknr = -1;
560 while (bigblocknr>=0) {
561 if (!STORAGE_get_big_block(hf,bigblocknr,block))
562 return -1;
563 for (i=0;i<128;i++)
564 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
565 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
566 newblocknr = i+curblock*128;
567 break;
569 if (i!=128)
570 break;
571 lastbigblocknr = bigblocknr;
572 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
573 curblock++;
575 if (newblocknr==-1) {
576 bigblocknr = STORAGE_get_free_big_blocknr(hf);
577 if (bigblocknr<0)
578 return -1;
579 READ_HEADER;
580 memset(block,0xff,sizeof(block));
581 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
582 if (!STORAGE_put_big_block(hf,bigblocknr,block))
583 return -1;
584 if (lastbigblocknr==-1) {
585 sth.sbd_startblock = bigblocknr;
586 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
587 return -1;
588 } else {
589 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
590 return -1;
592 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
593 return -1;
594 newblocknr = curblock*128;
596 /* allocate enough big blocks for storing the allocated small block */
597 if (!STORAGE_get_root_pps_entry(hf,&root))
598 return -1;
599 if (root.pps_sb==-1)
600 lastbigblocknr = -1;
601 else
602 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
603 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
604 /* we need to allocate more stuff */
605 bigblocknr = STORAGE_get_free_big_blocknr(hf);
606 if (bigblocknr<0)
607 return -1;
608 READ_HEADER;
609 if (root.pps_sb==-1) {
610 root.pps_sb = bigblocknr;
611 root.pps_size += BIGSIZE;
612 } else {
613 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
614 return -1;
615 root.pps_size += BIGSIZE;
617 lastbigblocknr = bigblocknr;
619 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
620 return -1;
621 if (!STORAGE_put_pps_entry(hf,0,&root))
622 return -1;
623 return newblocknr;
626 /******************************************************************************
627 * STORAGE_get_free_pps_entry [Internal]
629 static int
630 STORAGE_get_free_pps_entry(HFILE32 hf) {
631 int blocknr,i,curblock,lastblocknr;
632 BYTE block[BIGSIZE];
633 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
634 struct storage_header sth;
636 READ_HEADER;
637 blocknr = sth.root_startblock;
638 assert(blocknr>=0);
639 curblock=0;
640 while (blocknr>=0) {
641 if (!STORAGE_get_big_block(hf,blocknr,block))
642 return -1;
643 for (i=0;i<4;i++)
644 if (stde[i].pps_sizeofname==0) /* free */
645 return curblock*4+i;
646 lastblocknr = blocknr;
647 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
648 curblock++;
650 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
651 blocknr = STORAGE_get_free_big_blocknr(hf);
652 /* sth invalidated */
653 if (blocknr<0)
654 return -1;
656 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
657 return -1;
658 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
659 return -1;
660 memset(block,0,sizeof(block));
661 STORAGE_put_big_block(hf,blocknr,block);
662 return curblock*4;
665 /* --- IStream16 implementation */
667 typedef struct _IStream16 {
668 /* IUnknown fields */
669 ICOM_VTABLE(IStream16)* lpvtbl;
670 DWORD ref;
671 /* IStream16 fields */
672 SEGPTR thisptr; /* pointer to this struct as segmented */
673 struct storage_pps_entry stde;
674 int ppsent;
675 HFILE32 hf;
676 ULARGE_INTEGER offset;
677 } _IStream16;
679 /******************************************************************************
680 * IStream16_QueryInterface [STORAGE.518]
682 HRESULT WINAPI IStream16_fnQueryInterface(
683 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
685 ICOM_THIS(IStream16,iface);
686 char xrefiid[50];
687 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
688 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
689 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
690 *obj = this;
691 return 0;
693 return OLE_E_ENUM_NOMORE;
697 /******************************************************************************
698 * IStream16_AddRef [STORAGE.519]
700 ULONG WINAPI IStream16_fnAddRef(LPUNKNOWN iface) {
701 ICOM_THIS(IStream16,iface);
702 return ++(this->ref);
705 /******************************************************************************
706 * IStream16_Release [STORAGE.520]
708 ULONG WINAPI IStream16_fnRelease(LPUNKNOWN iface) {
709 ICOM_THIS(IStream16,iface);
710 FlushFileBuffers(this->hf);
711 this->ref--;
712 if (!this->ref) {
713 CloseHandle(this->hf);
714 SEGPTR_FREE(this);
715 return 0;
717 return this->ref;
720 /******************************************************************************
721 * IStream16_Seek [STORAGE.523]
723 * FIXME
724 * Does not handle 64 bits
726 HRESULT WINAPI IStream16_fnSeek(
727 LPSTREAM16 iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
729 ICOM_THIS(IStream16,iface);
730 TRACE(relay,"(%p)->([%ld.%ld],%ld,%p)\n",this,offset.HighPart,offset.LowPart,whence,newpos);
732 switch (whence) {
733 /* unix SEEK_xx should be the same as win95 ones */
734 case SEEK_SET:
735 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
736 * right now.
738 assert(offset.HighPart==0);
739 this->offset.HighPart = offset.HighPart;
740 this->offset.LowPart = offset.LowPart;
741 break;
742 case SEEK_CUR:
743 if (offset.HighPart < 0) {
744 /* FIXME: is this negation correct ? */
745 offset.HighPart = -offset.HighPart;
746 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
748 assert(offset.HighPart==0);
749 assert(this->offset.LowPart >= offset.LowPart);
750 this->offset.LowPart -= offset.LowPart;
751 } else {
752 assert(offset.HighPart==0);
753 this->offset.LowPart+= offset.LowPart;
755 break;
756 case SEEK_END:
757 assert(offset.HighPart==0);
758 this->offset.LowPart = this->stde.pps_size-offset.LowPart;
759 break;
761 if (this->offset.LowPart>this->stde.pps_size)
762 this->offset.LowPart=this->stde.pps_size;
763 if (newpos) *newpos = this->offset;
764 return S_OK;
767 /******************************************************************************
768 * IStream16_Read [STORAGE.521]
770 HRESULT WINAPI IStream16_fnRead(
771 LPSEQUENTIALSTREAM iface,void *pv,ULONG cb,ULONG *pcbRead
773 ICOM_THIS(IStream16,iface);
774 BYTE block[BIGSIZE];
775 ULONG *bytesread=pcbRead,xxread;
776 int blocknr;
778 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbRead);
779 if (!pcbRead) bytesread=&xxread;
780 *bytesread = 0;
782 if (cb>this->stde.pps_size-this->offset.LowPart)
783 cb=this->stde.pps_size-this->offset.LowPart;
784 if (this->stde.pps_size < 0x1000) {
785 /* use small block reader */
786 blocknr = STORAGE_get_nth_next_small_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
787 while (cb) {
788 int cc;
790 if (!STORAGE_get_small_block(this->hf,blocknr,block)) {
791 WARN(ole,"small block read failed!!!\n");
792 return E_FAIL;
794 cc = cb;
795 if (cc>SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1)))
796 cc=SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
797 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(SMALLSIZE-1)),cc);
798 this->offset.LowPart+=cc;
799 (LPBYTE)pv+=cc;
800 *bytesread+=cc;
801 cb-=cc;
802 blocknr = STORAGE_get_next_small_blocknr(this->hf,blocknr);
804 } else {
805 /* use big block reader */
806 blocknr = STORAGE_get_nth_next_big_blocknr(this->hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
807 while (cb) {
808 int cc;
810 if (!STORAGE_get_big_block(this->hf,blocknr,block)) {
811 WARN(ole,"big block read failed!!!\n");
812 return E_FAIL;
814 cc = cb;
815 if (cc>BIGSIZE-(this->offset.LowPart&(BIGSIZE-1)))
816 cc=BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
817 memcpy((LPBYTE)pv,block+(this->offset.LowPart&(BIGSIZE-1)),cc);
818 this->offset.LowPart+=cc;
819 (LPBYTE)pv+=cc;
820 *bytesread+=cc;
821 cb-=cc;
822 blocknr=STORAGE_get_next_big_blocknr(this->hf,blocknr);
825 return S_OK;
828 /******************************************************************************
829 * IStream16_Write [STORAGE.522]
831 HRESULT WINAPI IStream16_fnWrite(
832 LPSEQUENTIALSTREAM iface,const void *pv,ULONG cb,ULONG *pcbWrite
834 ICOM_THIS(IStream16,iface);
835 BYTE block[BIGSIZE];
836 ULONG *byteswritten=pcbWrite,xxwritten;
837 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
838 HFILE32 hf = this->hf;
840 if (!pcbWrite) byteswritten=&xxwritten;
841 *byteswritten = 0;
843 TRACE(relay,"(%p)->(%p,%ld,%p)\n",this,pv,cb,pcbWrite);
844 /* do we need to junk some blocks? */
845 newsize = this->offset.LowPart+cb;
846 oldsize = this->stde.pps_size;
847 if (newsize < oldsize) {
848 if (oldsize < 0x1000) {
849 /* only small blocks */
850 blocknr=STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,newsize/SMALLSIZE);
852 assert(blocknr>=0);
854 /* will set the rest of the chain to 'free' */
855 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
856 return E_FAIL;
857 } else {
858 if (newsize >= 0x1000) {
859 blocknr=STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,newsize/BIGSIZE);
860 assert(blocknr>=0);
862 /* will set the rest of the chain to 'free' */
863 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
864 return E_FAIL;
865 } else {
866 /* Migrate large blocks to small blocks
867 * (we just migrate newsize bytes)
869 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
870 cc = newsize;
871 blocknr = this->stde.pps_sb;
872 curdata = data;
873 while (cc>0) {
874 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
875 HeapFree(GetProcessHeap(),0,data);
876 return E_FAIL;
878 curdata += BIGSIZE;
879 cc -= BIGSIZE;
880 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
882 /* frees complete chain for this stream */
883 if (!STORAGE_set_big_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
884 return E_FAIL;
885 curdata = data;
886 blocknr = this->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
887 if (blocknr<0)
888 return E_FAIL;
889 cc = newsize;
890 while (cc>0) {
891 if (!STORAGE_put_small_block(hf,blocknr,curdata))
892 return E_FAIL;
893 cc -= SMALLSIZE;
894 if (cc<=0) {
895 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
896 return E_FAIL;
897 break;
898 } else {
899 int newblocknr = STORAGE_get_free_small_blocknr(hf);
900 if (newblocknr<0)
901 return E_FAIL;
902 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
903 return E_FAIL;
904 blocknr = newblocknr;
906 curdata += SMALLSIZE;
908 HeapFree(GetProcessHeap(),0,data);
911 this->stde.pps_size = newsize;
914 if (newsize > oldsize) {
915 if (oldsize >= 0x1000) {
916 /* should return the block right before the 'endofchain' */
917 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/BIGSIZE);
918 assert(blocknr>=0);
919 lastblocknr = blocknr;
920 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
921 blocknr = STORAGE_get_free_big_blocknr(hf);
922 if (blocknr<0)
923 return E_FAIL;
924 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
925 return E_FAIL;
926 lastblocknr = blocknr;
928 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
929 return E_FAIL;
930 } else {
931 if (newsize < 0x1000) {
932 /* find startblock */
933 if (!oldsize)
934 this->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
935 else
936 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->stde.pps_size/SMALLSIZE);
937 if (blocknr<0)
938 return E_FAIL;
940 /* allocate required new small blocks */
941 lastblocknr = blocknr;
942 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
943 blocknr = STORAGE_get_free_small_blocknr(hf);
944 if (blocknr<0)
945 return E_FAIL;
946 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
947 return E_FAIL;
948 lastblocknr = blocknr;
950 /* and terminate the chain */
951 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
952 return E_FAIL;
953 } else {
954 if (!oldsize) {
955 /* no single block allocated yet */
956 blocknr=STORAGE_get_free_big_blocknr(hf);
957 if (blocknr<0)
958 return E_FAIL;
959 this->stde.pps_sb = blocknr;
960 } else {
961 /* Migrate small blocks to big blocks */
962 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
963 cc = oldsize;
964 blocknr = this->stde.pps_sb;
965 curdata = data;
966 /* slurp in */
967 while (cc>0) {
968 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
969 HeapFree(GetProcessHeap(),0,data);
970 return E_FAIL;
972 curdata += SMALLSIZE;
973 cc -= SMALLSIZE;
974 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
976 /* free small block chain */
977 if (!STORAGE_set_small_chain(hf,this->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
978 return E_FAIL;
979 curdata = data;
980 blocknr = this->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
981 if (blocknr<0)
982 return E_FAIL;
983 /* put the data into the big blocks */
984 cc = this->stde.pps_size;
985 while (cc>0) {
986 if (!STORAGE_put_big_block(hf,blocknr,curdata))
987 return E_FAIL;
988 cc -= BIGSIZE;
989 if (cc<=0) {
990 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
991 return E_FAIL;
992 break;
993 } else {
994 int newblocknr = STORAGE_get_free_big_blocknr(hf);
995 if (newblocknr<0)
996 return E_FAIL;
997 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
998 return E_FAIL;
999 blocknr = newblocknr;
1001 curdata += BIGSIZE;
1003 HeapFree(GetProcessHeap(),0,data);
1005 /* generate big blocks to fit the new data */
1006 lastblocknr = blocknr;
1007 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1008 blocknr = STORAGE_get_free_big_blocknr(hf);
1009 if (blocknr<0)
1010 return E_FAIL;
1011 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1012 return E_FAIL;
1013 lastblocknr = blocknr;
1015 /* terminate chain */
1016 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1017 return E_FAIL;
1020 this->stde.pps_size = newsize;
1023 /* There are just some cases where we didn't modify it, we write it out
1024 * everytime
1026 if (!STORAGE_put_pps_entry(hf,this->ppsent,&(this->stde)))
1027 return E_FAIL;
1029 /* finally the write pass */
1030 if (this->stde.pps_size < 0x1000) {
1031 blocknr = STORAGE_get_nth_next_small_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/SMALLSIZE);
1032 assert(blocknr>=0);
1033 while (cb>0) {
1034 /* we ensured that it is allocated above */
1035 assert(blocknr>=0);
1036 /* Read old block everytime, since we can have
1037 * overlapping data at START and END of the write
1039 if (!STORAGE_get_small_block(hf,blocknr,block))
1040 return E_FAIL;
1042 cc = SMALLSIZE-(this->offset.LowPart&(SMALLSIZE-1));
1043 if (cc>cb)
1044 cc=cb;
1045 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(SMALLSIZE-1)),
1046 (LPBYTE)(pv+curoffset),
1049 if (!STORAGE_put_small_block(hf,blocknr,block))
1050 return E_FAIL;
1051 cb -= cc;
1052 curoffset += cc;
1053 (LPBYTE)pv += cc;
1054 this->offset.LowPart += cc;
1055 *byteswritten += cc;
1056 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1058 } else {
1059 blocknr = STORAGE_get_nth_next_big_blocknr(hf,this->stde.pps_sb,this->offset.LowPart/BIGSIZE);
1060 assert(blocknr>=0);
1061 while (cb>0) {
1062 /* we ensured that it is allocated above, so it better is */
1063 assert(blocknr>=0);
1064 /* read old block everytime, since we can have
1065 * overlapping data at START and END of the write
1067 if (!STORAGE_get_big_block(hf,blocknr,block))
1068 return E_FAIL;
1070 cc = BIGSIZE-(this->offset.LowPart&(BIGSIZE-1));
1071 if (cc>cb)
1072 cc=cb;
1073 memcpy( ((LPBYTE)block)+(this->offset.LowPart&(BIGSIZE-1)),
1074 (LPBYTE)(pv+curoffset),
1077 if (!STORAGE_put_big_block(hf,blocknr,block))
1078 return E_FAIL;
1079 cb -= cc;
1080 curoffset += cc;
1081 (LPBYTE)pv += cc;
1082 this->offset.LowPart += cc;
1083 *byteswritten += cc;
1084 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1087 return S_OK;
1090 /******************************************************************************
1091 * _create_istream16 [Internal]
1093 static void _create_istream16(LPSTREAM16 *str) {
1094 _IStream16* lpst;
1096 if (!strvt16.bvt.bvt.fnQueryInterface) {
1097 HMODULE16 wp = GetModuleHandle16("STORAGE");
1098 if (wp>=32) {
1099 /* FIXME: what is this WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1100 #define VTENT(xfn) strvt16.bvt.bvt.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.bvt.bvt.fn##xfn)
1101 VTENT(QueryInterface);
1102 VTENT(AddRef);
1103 VTENT(Release);
1104 #undef VTENT
1105 #define VTENT(xfn) strvt16.bvt.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.bvt.fn##xfn)
1106 VTENT(Read);
1107 VTENT(Write);
1108 #undef VTENT
1109 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1110 VTENT(Seek);
1111 VTENT(SetSize);
1112 VTENT(CopyTo);
1113 VTENT(Commit);
1114 VTENT(Revert);
1115 VTENT(LockRegion);
1116 VTENT(UnlockRegion);
1117 VTENT(Stat);
1118 VTENT(Clone);
1119 #undef VTENT
1120 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1121 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1122 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1123 } else {
1124 #define VTENT(xfn) strvt16.bvt.bvt.fn##xfn = IStream16_fn##xfn;
1125 VTENT(QueryInterface);
1126 VTENT(AddRef);
1127 VTENT(Release);
1128 #undef VTENT
1129 #define VTENT(xfn) strvt16.bvt.fn##xfn = IStream16_fn##xfn;
1130 VTENT(Read);
1131 VTENT(Write);
1132 #undef VTENT
1133 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1134 VTENT(Seek);
1136 VTENT(CopyTo);
1137 VTENT(Commit);
1138 VTENT(SetSize);
1139 VTENT(Revert);
1140 VTENT(LockRegion);
1141 VTENT(UnlockRegion);
1142 VTENT(Stat);
1143 VTENT(Clone);
1145 #undef VTENT
1146 segstrvt16 = &strvt16;
1149 lpst = SEGPTR_NEW(_IStream16);
1150 lpst->lpvtbl = segstrvt16;
1151 lpst->ref = 1;
1152 lpst->thisptr = SEGPTR_GET(lpst);
1153 *str = (void*)lpst->thisptr;
1157 /* --- IStream32 implementation */
1159 typedef struct _IStream32 {
1160 /* IUnknown fields */
1161 ICOM_VTABLE(IStream32)* lpvtbl;
1162 DWORD ref;
1163 /* IStream32 fields */
1164 struct storage_pps_entry stde;
1165 int ppsent;
1166 HFILE32 hf;
1167 ULARGE_INTEGER offset;
1168 } _IStream32;
1170 /*****************************************************************************
1171 * IStream32_QueryInterface [VTABLE]
1173 HRESULT WINAPI IStream32_fnQueryInterface(
1174 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
1176 ICOM_THIS(IStream32,iface);
1177 char xrefiid[50];
1179 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1180 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1181 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1182 *obj = this;
1183 return 0;
1185 return OLE_E_ENUM_NOMORE;
1189 /******************************************************************************
1190 * IStream32_AddRef [VTABLE]
1192 ULONG WINAPI IStream32_fnAddRef(LPUNKNOWN iface) {
1193 ICOM_THIS(IStream32,iface);
1194 return ++(this->ref);
1197 /******************************************************************************
1198 * IStream32_Release [VTABLE]
1200 ULONG WINAPI IStream32_fnRelease(LPUNKNOWN iface) {
1201 ICOM_THIS(IStream32,iface);
1202 FlushFileBuffers(this->hf);
1203 this->ref--;
1204 if (!this->ref) {
1205 CloseHandle(this->hf);
1206 SEGPTR_FREE(this);
1207 return 0;
1209 return this->ref;
1212 /* --- IStorage16 implementation */
1214 typedef struct _IStorage16 {
1215 /* IUnknown fields */
1216 ICOM_VTABLE(IStorage16)* lpvtbl;
1217 DWORD ref;
1218 /* IStorage16 fields */
1219 SEGPTR thisptr; /* pointer to this struct as segmented */
1220 struct storage_pps_entry stde;
1221 int ppsent;
1222 HFILE32 hf;
1223 } _IStorage16;
1225 /******************************************************************************
1226 * IStorage16_QueryInterface [STORAGE.500]
1228 HRESULT WINAPI IStorage16_fnQueryInterface(
1229 LPUNKNOWN iface,REFIID refiid,LPVOID *obj
1231 ICOM_THIS(IStorage16,iface);
1232 char xrefiid[50];
1234 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1235 TRACE(relay,"(%p)->(%s,%p)\n",this,xrefiid,obj);
1237 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1238 *obj = this;
1239 return 0;
1241 return OLE_E_ENUM_NOMORE;
1244 /******************************************************************************
1245 * IStorage16_AddRef [STORAGE.501]
1247 ULONG WINAPI IStorage16_fnAddRef(LPUNKNOWN iface) {
1248 ICOM_THIS(IStorage16,iface);
1249 return ++(this->ref);
1252 /******************************************************************************
1253 * IStorage16_Release [STORAGE.502]
1255 ULONG WINAPI IStorage16_fnRelease(LPUNKNOWN iface) {
1256 ICOM_THIS(IStorage16,iface);
1257 this->ref--;
1258 if (this->ref)
1259 return this->ref;
1260 SEGPTR_FREE(this);
1261 return 0;
1264 /******************************************************************************
1265 * IStorage16_Stat [STORAGE.517]
1267 HRESULT WINAPI IStorage16_fnStat(
1268 LPSTORAGE16 iface,STATSTG *pstatstg, DWORD grfStatFlag
1270 ICOM_THIS(IStorage16,iface);
1271 TRACE(ole,"(%p)->(%p,0x%08lx)\n",
1272 this,pstatstg,grfStatFlag
1274 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(this->stde.pps_rawname));
1275 pstatstg->type = this->stde.pps_type;
1276 pstatstg->cbSize.LowPart = this->stde.pps_size;
1277 pstatstg->mtime = this->stde.pps_ft1; /* FIXME */ /* why? */
1278 pstatstg->atime = this->stde.pps_ft2; /* FIXME */
1279 pstatstg->ctime = this->stde.pps_ft2; /* FIXME */
1280 pstatstg->grfMode = 0; /* FIXME */
1281 pstatstg->grfLocksSupported = 0; /* FIXME */
1282 pstatstg->clsid = this->stde.pps_guid;
1283 pstatstg->grfStateBits = 0; /* FIXME */
1284 pstatstg->reserved = 0;
1285 return S_OK;
1288 /******************************************************************************
1289 * IStorage16_Commit [STORAGE.509]
1291 HRESULT WINAPI IStorage16_fnCommit(
1292 LPSTORAGE16 iface,DWORD commitflags
1294 ICOM_THIS(IStorage16,iface);
1295 FIXME(ole,"(%p)->(0x%08lx),STUB!\n",
1296 this,commitflags
1298 return S_OK;
1301 /******************************************************************************
1302 * IStorage16_CopyTo [STORAGE.507]
1304 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1305 ICOM_THIS(IStorage16,iface);
1306 char xguid[50];
1308 if (rgiidExclude)
1309 WINE_StringFromCLSID(rgiidExclude,xguid);
1310 else
1311 strcpy(xguid,"<no guid>");
1312 FIXME(ole,"IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1313 this,ciidExclude,xguid,SNB16Exclude,pstgDest
1315 return S_OK;
1319 /******************************************************************************
1320 * IStorage16_CreateStorage [STORAGE.505]
1322 HRESULT WINAPI IStorage16_fnCreateStorage(
1323 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1325 ICOM_THIS(IStorage16,iface);
1326 _IStorage16* lpstg;
1327 int ppsent,x;
1328 struct storage_pps_entry stde;
1329 struct storage_header sth;
1330 HFILE32 hf=this->hf;
1332 READ_HEADER;
1334 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1335 this,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1337 if (grfMode & STGM_TRANSACTED)
1338 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1339 _create_istorage16(ppstg);
1340 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstg);
1341 lpstg->hf = this->hf;
1343 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1344 if (ppsent<0)
1345 return E_FAIL;
1346 stde=this->stde;
1347 if (stde.pps_dir==-1) {
1348 stde.pps_dir = ppsent;
1349 x = this->ppsent;
1350 } else {
1351 FIXME(ole," use prev chain too ?\n");
1352 x=stde.pps_dir;
1353 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1354 return E_FAIL;
1355 while (stde.pps_next!=-1) {
1356 x=stde.pps_next;
1357 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1358 return E_FAIL;
1360 stde.pps_next = ppsent;
1362 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1363 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1364 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1365 lpstg->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1366 lpstg->stde.pps_next = -1;
1367 lpstg->stde.pps_prev = -1;
1368 lpstg->stde.pps_dir = -1;
1369 lpstg->stde.pps_sb = -1;
1370 lpstg->stde.pps_size = 0;
1371 lpstg->stde.pps_type = 1;
1372 lpstg->ppsent = ppsent;
1373 /* FIXME: timestamps? */
1374 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1375 return E_FAIL;
1376 return S_OK;
1379 /******************************************************************************
1380 * IStorage16_CreateStream [STORAGE.503]
1382 HRESULT WINAPI IStorage16_fnCreateStream(
1383 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1385 ICOM_THIS(IStorage16,iface);
1386 _IStream16* lpstr;
1387 int ppsent,x;
1388 struct storage_pps_entry stde;
1390 TRACE(ole,"(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1391 this,pwcsName,grfMode,reserved1,reserved2,ppstm
1393 if (grfMode & STGM_TRANSACTED)
1394 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1395 _create_istream16(ppstm);
1396 lpstr = (_IStream16*)PTR_SEG_TO_LIN(*ppstm);
1397 DuplicateHandle( GetCurrentProcess(), this->hf, GetCurrentProcess(),
1398 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1399 lpstr->offset.LowPart = 0;
1400 lpstr->offset.HighPart = 0;
1402 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1403 if (ppsent<0)
1404 return E_FAIL;
1405 stde=this->stde;
1406 if (stde.pps_next==-1)
1407 x=this->ppsent;
1408 else
1409 while (stde.pps_next!=-1) {
1410 x=stde.pps_next;
1411 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1412 return E_FAIL;
1414 stde.pps_next = ppsent;
1415 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1416 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1417 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1418 lpstr->stde.pps_sizeofname = lstrlen32A(pwcsName)*2+2;
1419 lpstr->stde.pps_next = -1;
1420 lpstr->stde.pps_prev = -1;
1421 lpstr->stde.pps_dir = -1;
1422 lpstr->stde.pps_sb = -1;
1423 lpstr->stde.pps_size = 0;
1424 lpstr->stde.pps_type = 2;
1425 lpstr->ppsent = ppsent;
1426 /* FIXME: timestamps? */
1427 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1428 return E_FAIL;
1429 return S_OK;
1432 /******************************************************************************
1433 * IStorage16_OpenStorage [STORAGE.506]
1435 HRESULT WINAPI IStorage16_fnOpenStorage(
1436 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1438 ICOM_THIS(IStorage16,iface);
1439 _IStream16* lpstg;
1440 WCHAR name[33];
1441 int newpps;
1443 TRACE(relay,"(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1444 this,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1446 if (grfMode & STGM_TRANSACTED)
1447 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1448 _create_istorage16(ppstg);
1449 lpstg = (_IStream16*)PTR_SEG_TO_LIN(*ppstg);
1450 DuplicateHandle( GetCurrentProcess(), this->hf, GetCurrentProcess(),
1451 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1452 lstrcpyAtoW(name,pwcsName);
1453 newpps = STORAGE_look_for_named_pps(lpstg->hf,this->stde.pps_dir,name);
1454 if (newpps==-1) {
1455 IStream16_fnRelease((IUnknown*)lpstg);
1456 return E_FAIL;
1459 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1460 IStream16_fnRelease((IUnknown*)lpstg);
1461 return E_FAIL;
1463 lpstg->ppsent = newpps;
1464 return S_OK;
1467 /******************************************************************************
1468 * IStorage16_OpenStream [STORAGE.504]
1470 HRESULT WINAPI IStorage16_fnOpenStream(
1471 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1473 ICOM_THIS(IStorage16,iface);
1474 _IStream16* lpstr;
1475 WCHAR name[33];
1476 int newpps;
1478 TRACE(relay,"(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1479 this,pwcsName,reserved1,grfMode,reserved2,ppstm
1481 if (grfMode & STGM_TRANSACTED)
1482 FIXME(ole,"We do not support transacted Compound Storage. Using direct mode.\n");
1483 _create_istream16(ppstm);
1484 lpstr = (_IStream16*)PTR_SEG_TO_LIN(*ppstm);
1485 DuplicateHandle( GetCurrentProcess(), this->hf, GetCurrentProcess(),
1486 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1487 lstrcpyAtoW(name,pwcsName);
1488 newpps = STORAGE_look_for_named_pps(lpstr->hf,this->stde.pps_dir,name);
1489 if (newpps==-1) {
1490 IStream16_fnRelease((IUnknown*)lpstr);
1491 return E_FAIL;
1494 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1495 IStream16_fnRelease((IUnknown*)lpstr);
1496 return E_FAIL;
1498 lpstr->offset.LowPart = 0;
1499 lpstr->offset.HighPart = 0;
1500 lpstr->ppsent = newpps;
1501 return S_OK;
1504 /******************************************************************************
1505 * _create_istorage16 [INTERNAL]
1507 static void _create_istorage16(LPSTORAGE16 *stg) {
1508 _IStorage16* lpst;
1510 if (!stvt16.bvt.fnQueryInterface) {
1511 HMODULE16 wp = GetModuleHandle16("STORAGE");
1512 if (wp>=32) {
1513 #define VTENT(xfn) stvt16.bvt.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1514 VTENT(QueryInterface)
1515 VTENT(AddRef)
1516 VTENT(Release)
1517 #undef VTENT
1518 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1519 VTENT(CreateStream)
1520 VTENT(OpenStream)
1521 VTENT(CreateStorage)
1522 VTENT(OpenStorage)
1523 VTENT(CopyTo)
1524 VTENT(MoveElementTo)
1525 VTENT(Commit)
1526 VTENT(Revert)
1527 VTENT(EnumElements)
1528 VTENT(DestroyElement)
1529 VTENT(RenameElement)
1530 VTENT(SetElementTimes)
1531 VTENT(SetClass)
1532 VTENT(SetStateBits)
1533 VTENT(Stat)
1534 #undef VTENT
1535 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1536 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1537 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1538 } else {
1539 #define VTENT(xfn) stvt16.bvt.fn##xfn = IStorage16_fn##xfn;
1540 VTENT(QueryInterface)
1541 VTENT(AddRef)
1542 VTENT(Release)
1543 #undef VTENT
1544 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1545 VTENT(CreateStream)
1546 VTENT(OpenStream)
1547 VTENT(CreateStorage)
1548 VTENT(OpenStorage)
1549 VTENT(CopyTo)
1550 VTENT(Commit)
1551 /* not (yet) implemented ...
1552 VTENT(MoveElementTo)
1553 VTENT(Revert)
1554 VTENT(EnumElements)
1555 VTENT(DestroyElement)
1556 VTENT(RenameElement)
1557 VTENT(SetElementTimes)
1558 VTENT(SetClass)
1559 VTENT(SetStateBits)
1560 VTENT(Stat)
1562 #undef VTENT
1563 segstvt16 = &stvt16;
1566 lpst = SEGPTR_NEW(_IStorage16);
1567 lpst->lpvtbl = segstvt16;
1568 lpst->ref = 1;
1569 lpst->thisptr = SEGPTR_GET(lpst);
1570 *stg = (void*)lpst->thisptr;
1573 /******************************************************************************
1574 * Storage API functions
1577 /******************************************************************************
1578 * StgCreateDocFile16 [STORAGE.1]
1580 HRESULT WINAPI StgCreateDocFile16(
1581 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1583 HFILE32 hf;
1584 int i,ret;
1585 _IStorage16* lpstg;
1586 struct storage_pps_entry stde;
1588 TRACE(ole,"(%s,0x%08lx,0x%08lx,%p)\n",
1589 pwcsName,grfMode,reserved,ppstgOpen
1591 _create_istorage16(ppstgOpen);
1592 hf = CreateFile32A(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1593 if (hf==INVALID_HANDLE_VALUE32) {
1594 WARN(ole,"couldn't open file for storage:%ld\n",GetLastError());
1595 return E_FAIL;
1597 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstgOpen);
1598 lpstg->hf = hf;
1599 /* FIXME: check for existance before overwriting? */
1600 if (!STORAGE_init_storage(hf)) {
1601 CloseHandle(hf);
1602 return E_FAIL;
1604 i=0;ret=0;
1605 while (!ret) { /* neither 1 nor <0 */
1606 ret=STORAGE_get_pps_entry(hf,i,&stde);
1607 if ((ret==1) && (stde.pps_type==5)) {
1608 lpstg->stde = stde;
1609 lpstg->ppsent = i;
1610 break;
1612 i++;
1614 if (ret!=1) {
1615 IStorage16_fnRelease((IUnknown*)lpstg); /* will remove it */
1616 return E_FAIL;
1619 return S_OK;
1622 /******************************************************************************
1623 * StgIsStorageFile16 [STORAGE.5]
1625 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1626 HFILE32 hf;
1627 OFSTRUCT ofs;
1628 BYTE magic[24];
1630 TRACE(ole,"(\'%s\')\n",fn);
1631 hf = OpenFile32(fn,&ofs,OF_SHARE_DENY_NONE);
1632 if (hf==HFILE_ERROR32)
1633 return STG_E_FILENOTFOUND;
1634 if (24!=_lread32(hf,magic,24)) {
1635 WARN(ole," too short\n");
1636 _lclose32(hf);
1637 return S_FALSE;
1639 if (!memcmp(magic,STORAGE_magic,8)) {
1640 WARN(ole," -> YES\n");
1641 _lclose32(hf);
1642 return S_OK;
1644 if (!memcmp(magic,STORAGE_notmagic,8)) {
1645 WARN(ole," -> NO\n");
1646 _lclose32(hf);
1647 return S_FALSE;
1649 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1650 WARN(ole," -> old format\n");
1651 _lclose32(hf);
1652 return STG_E_OLDFORMAT;
1654 WARN(ole," -> Invalid header.\n");
1655 _lclose32(hf);
1656 return STG_E_INVALIDHEADER;
1659 /******************************************************************************
1660 * StgIsStorageFile32 [OLE32.146]
1662 HRESULT WINAPI
1663 StgIsStorageFile32(LPCOLESTR32 fn)
1665 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1666 OLESTATUS ret = StgIsStorageFile16(xfn);
1668 HeapFree(GetProcessHeap(),0,xfn);
1669 return ret;
1673 /******************************************************************************
1674 * StgOpenStorage16 [STORAGE.3]
1676 HRESULT WINAPI StgOpenStorage16(
1677 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1678 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1680 HFILE32 hf;
1681 int ret,i;
1682 _IStorage16* lpstg;
1683 struct storage_pps_entry stde;
1685 TRACE(ole,"(%s,%p,0x%08lx,%p,%ld,%p)\n",
1686 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1688 _create_istorage16(ppstgOpen);
1689 hf = CreateFile32A(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1690 if (hf==INVALID_HANDLE_VALUE32) {
1691 WARN(ole,"Couldn't open file for storage\n");
1692 return E_FAIL;
1694 lpstg = (_IStorage16*)PTR_SEG_TO_LIN(*ppstgOpen);
1695 lpstg->hf = hf;
1697 i=0;ret=0;
1698 while (!ret) { /* neither 1 nor <0 */
1699 ret=STORAGE_get_pps_entry(hf,i,&stde);
1700 if ((ret==1) && (stde.pps_type==5)) {
1701 lpstg->stde=stde;
1702 break;
1704 i++;
1706 if (ret!=1) {
1707 IStorage16_fnRelease((IUnknown*)lpstg); /* will remove it */
1708 return E_FAIL;
1710 return S_OK;