Convert MRULists to Unicode.
[wine/testsucceed.git] / dlls / ole32 / storage.c
blob53c9fede2f14c9791302acb69bd063ea1fc37073
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 <sys/types.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "ntddk.h"
17 #include "winerror.h"
18 #include "wine/winbase16.h"
19 #include "wine/unicode.h"
20 #include "wingdi.h"
21 #include "wtypes.h"
22 #include "wine/obj_base.h"
23 #include "wine/obj_storage.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(ole);
27 DECLARE_DEBUG_CHANNEL(relay);
29 struct storage_header {
30 BYTE magic[8]; /* 00: magic */
31 BYTE unknown1[36]; /* 08: unknown */
32 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
33 DWORD root_startblock;/* 30: root storage first big block */
34 DWORD unknown2[2]; /* 34: unknown */
35 DWORD sbd_startblock; /* 3C: small block depot first big block */
36 DWORD unknown3[3]; /* 40: unknown */
37 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
39 struct storage_pps_entry {
40 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
41 WORD pps_sizeofname; /* 40: namelength in bytes */
42 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
43 BYTE pps_unknown0; /* 43: unknown */
44 DWORD pps_prev; /* 44: previous pps */
45 DWORD pps_next; /* 48: next pps */
46 DWORD pps_dir; /* 4C: directory pps */
47 GUID pps_guid; /* 50: class ID */
48 DWORD pps_unknown1; /* 60: unknown */
49 FILETIME pps_ft1; /* 64: filetime1 */
50 FILETIME pps_ft2; /* 70: filetime2 */
51 DWORD pps_sb; /* 74: data startblock */
52 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
53 DWORD pps_unknown2; /* 7C: unknown */
56 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
57 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
58 #define STORAGE_CHAINENTRY_FREE 0xffffffff
61 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
62 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
63 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
65 #define BIGSIZE 512
66 #define SMALLSIZE 64
68 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
70 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
71 static ICOM_VTABLE(IStorage16) stvt16;
72 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
73 static ICOM_VTABLE(IStream16) strvt16;
74 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
76 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
77 static void _create_istorage16(LPSTORAGE16 *stg);
78 static void _create_istream16(LPSTREAM16 *str);
80 #define IMPLEMENTED 1
83 /******************************************************************************
84 * STORAGE_get_big_block [Internal]
86 * Reading OLE compound storage
88 static BOOL
89 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
90 assert(n>=-1);
91 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
92 WARN(" seek failed (%ld)\n",GetLastError());
93 return FALSE;
95 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
96 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
97 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
98 assert(0);
99 return FALSE;
101 return TRUE;
104 /******************************************************************************
105 * STORAGE_put_big_block [INTERNAL]
107 static BOOL
108 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
109 assert(n>=-1);
110 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
111 WARN(" seek failed (%ld)\n",GetLastError());
112 return FALSE;
114 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
115 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
116 WARN(" write failed (%ld)\n",GetLastError());
117 return FALSE;
119 return TRUE;
122 /******************************************************************************
123 * STORAGE_get_next_big_blocknr [INTERNAL]
125 static int
126 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
127 INT bbs[BIGSIZE/sizeof(INT)];
128 struct storage_header sth;
130 READ_HEADER;
132 assert(blocknr>>7<sth.num_of_bbd_blocks);
133 if (sth.bbd_list[blocknr>>7]==0xffffffff)
134 return -5;
135 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
136 return -5;
137 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
138 return bbs[blocknr&0x7f];
141 /******************************************************************************
142 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
144 static int
145 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
146 INT bbs[BIGSIZE/sizeof(INT)];
147 int lastblock = -1;
148 struct storage_header sth;
150 READ_HEADER;
152 assert(blocknr>=0);
153 while (nr--) {
154 assert((blocknr>>7)<sth.num_of_bbd_blocks);
155 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
157 /* simple caching... */
158 if (lastblock!=sth.bbd_list[blocknr>>7]) {
159 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
160 lastblock = sth.bbd_list[blocknr>>7];
162 blocknr = bbs[blocknr&0x7f];
164 return blocknr;
167 /******************************************************************************
168 * STORAGE_get_root_pps_entry [Internal]
170 static BOOL
171 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
172 int blocknr,i;
173 BYTE block[BIGSIZE];
174 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
175 struct storage_header sth;
177 READ_HEADER;
178 blocknr = sth.root_startblock;
179 while (blocknr>=0) {
180 assert(STORAGE_get_big_block(hf,blocknr,block));
181 for (i=0;i<4;i++) {
182 if (!stde[i].pps_sizeofname)
183 continue;
184 if (stde[i].pps_type==5) {
185 *pstde=stde[i];
186 return TRUE;
189 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
191 return FALSE;
194 /******************************************************************************
195 * STORAGE_get_small_block [INTERNAL]
197 static BOOL
198 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
199 BYTE block[BIGSIZE];
200 int bigblocknr;
201 struct storage_pps_entry root;
203 assert(blocknr>=0);
204 assert(STORAGE_get_root_pps_entry(hf,&root));
205 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
206 assert(bigblocknr>=0);
207 assert(STORAGE_get_big_block(hf,bigblocknr,block));
209 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
210 return TRUE;
213 /******************************************************************************
214 * STORAGE_put_small_block [INTERNAL]
216 static BOOL
217 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
218 BYTE block[BIGSIZE];
219 int bigblocknr;
220 struct storage_pps_entry root;
222 assert(blocknr>=0);
224 assert(STORAGE_get_root_pps_entry(hf,&root));
225 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
226 assert(bigblocknr>=0);
227 assert(STORAGE_get_big_block(hf,bigblocknr,block));
229 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
230 assert(STORAGE_put_big_block(hf,bigblocknr,block));
231 return TRUE;
234 /******************************************************************************
235 * STORAGE_get_next_small_blocknr [INTERNAL]
237 static int
238 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
239 BYTE block[BIGSIZE];
240 LPINT sbd = (LPINT)block;
241 int bigblocknr;
242 struct storage_header sth;
244 READ_HEADER;
245 assert(blocknr>=0);
246 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
247 assert(bigblocknr>=0);
248 assert(STORAGE_get_big_block(hf,bigblocknr,block));
249 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
250 return sbd[blocknr & (128-1)];
253 /******************************************************************************
254 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
256 static int
257 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
258 int lastblocknr;
259 BYTE block[BIGSIZE];
260 LPINT sbd = (LPINT)block;
261 struct storage_header sth;
263 READ_HEADER;
264 lastblocknr=-1;
265 assert(blocknr>=0);
266 while ((nr--) && (blocknr>=0)) {
267 if (lastblocknr/128!=blocknr/128) {
268 int bigblocknr;
269 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
270 assert(bigblocknr>=0);
271 assert(STORAGE_get_big_block(hf,bigblocknr,block));
272 lastblocknr = blocknr;
274 assert(lastblocknr>=0);
275 lastblocknr=blocknr;
276 blocknr=sbd[blocknr & (128-1)];
277 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
279 return blocknr;
282 /******************************************************************************
283 * STORAGE_get_pps_entry [INTERNAL]
285 static int
286 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
287 int blocknr;
288 BYTE block[BIGSIZE];
289 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
290 struct storage_header sth;
292 READ_HEADER;
293 /* we have 4 pps entries per big block */
294 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
295 assert(blocknr>=0);
296 assert(STORAGE_get_big_block(hf,blocknr,block));
298 *pstde=*stde;
299 return 1;
302 /******************************************************************************
303 * STORAGE_put_pps_entry [Internal]
305 static int
306 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
307 int blocknr;
308 BYTE block[BIGSIZE];
309 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
310 struct storage_header sth;
312 READ_HEADER;
314 /* we have 4 pps entries per big block */
315 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
316 assert(blocknr>=0);
317 assert(STORAGE_get_big_block(hf,blocknr,block));
318 *stde=*pstde;
319 assert(STORAGE_put_big_block(hf,blocknr,block));
320 return 1;
323 /******************************************************************************
324 * STORAGE_look_for_named_pps [Internal]
326 static int
327 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
328 struct storage_pps_entry stde;
329 int ret;
331 if (n==-1)
332 return -1;
333 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
334 return -1;
336 if (!lstrcmpW(name,stde.pps_rawname))
337 return n;
338 if (stde.pps_prev != -1) {
339 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
340 if (ret!=-1)
341 return ret;
343 if (stde.pps_next != -1) {
344 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
345 if (ret!=-1)
346 return ret;
348 return -1;
351 /******************************************************************************
352 * STORAGE_dump_pps_entry [Internal]
354 * FIXME
355 * Function is unused
357 void
358 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
359 char name[33];
361 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
362 if (!stde->pps_sizeofname)
363 return;
364 DPRINTF("name: %s\n",name);
365 DPRINTF("type: %d\n",stde->pps_type);
366 DPRINTF("prev pps: %ld\n",stde->pps_prev);
367 DPRINTF("next pps: %ld\n",stde->pps_next);
368 DPRINTF("dir pps: %ld\n",stde->pps_dir);
369 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
370 if (stde->pps_type !=2) {
371 time_t t;
372 DWORD dw;
373 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
374 t = dw;
375 DPRINTF("ts1: %s\n",ctime(&t));
376 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
377 t = dw;
378 DPRINTF("ts2: %s\n",ctime(&t));
380 DPRINTF("startblock: %ld\n",stde->pps_sb);
381 DPRINTF("size: %ld\n",stde->pps_size);
384 /******************************************************************************
385 * STORAGE_init_storage [INTERNAL]
387 static BOOL
388 STORAGE_init_storage(HFILE hf) {
389 BYTE block[BIGSIZE];
390 LPDWORD bbs;
391 struct storage_header *sth;
392 struct storage_pps_entry *stde;
394 assert(-1!=_llseek(hf,0,SEEK_SET));
395 /* block -1 is the storage header */
396 sth = (struct storage_header*)block;
397 memcpy(sth->magic,STORAGE_magic,8);
398 memset(sth->unknown1,0,sizeof(sth->unknown1));
399 memset(sth->unknown2,0,sizeof(sth->unknown2));
400 memset(sth->unknown3,0,sizeof(sth->unknown3));
401 sth->num_of_bbd_blocks = 1;
402 sth->root_startblock = 1;
403 sth->sbd_startblock = 0xffffffff;
404 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
405 sth->bbd_list[0] = 0;
406 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
407 /* block 0 is the big block directory */
408 bbs=(LPDWORD)block;
409 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
410 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
411 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
412 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
413 /* block 1 is the root directory entry */
414 memset(block,0x00,sizeof(block));
415 stde = (struct storage_pps_entry*)block;
416 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
417 sizeof(stde->pps_rawname)/sizeof(WCHAR));
418 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
419 stde->pps_type = 5;
420 stde->pps_dir = -1;
421 stde->pps_next = -1;
422 stde->pps_prev = -1;
423 stde->pps_sb = 0xffffffff;
424 stde->pps_size = 0;
425 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
426 return TRUE;
429 /******************************************************************************
430 * STORAGE_set_big_chain [Internal]
432 static BOOL
433 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
434 BYTE block[BIGSIZE];
435 LPINT bbd = (LPINT)block;
436 int nextblocknr,bigblocknr;
437 struct storage_header sth;
439 READ_HEADER;
440 assert(blocknr!=type);
441 while (blocknr>=0) {
442 bigblocknr = sth.bbd_list[blocknr/128];
443 assert(bigblocknr>=0);
444 assert(STORAGE_get_big_block(hf,bigblocknr,block));
446 nextblocknr = bbd[blocknr&(128-1)];
447 bbd[blocknr&(128-1)] = type;
448 if (type>=0)
449 return TRUE;
450 assert(STORAGE_put_big_block(hf,bigblocknr,block));
451 type = STORAGE_CHAINENTRY_FREE;
452 blocknr = nextblocknr;
454 return TRUE;
457 /******************************************************************************
458 * STORAGE_set_small_chain [Internal]
460 static BOOL
461 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
462 BYTE block[BIGSIZE];
463 LPINT sbd = (LPINT)block;
464 int lastblocknr,nextsmallblocknr,bigblocknr;
465 struct storage_header sth;
467 READ_HEADER;
469 assert(blocknr!=type);
470 lastblocknr=-129;bigblocknr=-2;
471 while (blocknr>=0) {
472 /* cache block ... */
473 if (lastblocknr/128!=blocknr/128) {
474 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
475 assert(bigblocknr>=0);
476 assert(STORAGE_get_big_block(hf,bigblocknr,block));
478 lastblocknr = blocknr;
479 nextsmallblocknr = sbd[blocknr&(128-1)];
480 sbd[blocknr&(128-1)] = type;
481 assert(STORAGE_put_big_block(hf,bigblocknr,block));
482 if (type>=0)
483 return TRUE;
484 type = STORAGE_CHAINENTRY_FREE;
485 blocknr = nextsmallblocknr;
487 return TRUE;
490 /******************************************************************************
491 * STORAGE_get_free_big_blocknr [Internal]
493 static int
494 STORAGE_get_free_big_blocknr(HFILE hf) {
495 BYTE block[BIGSIZE];
496 LPINT sbd = (LPINT)block;
497 int lastbigblocknr,i,curblock,bigblocknr;
498 struct storage_header sth;
500 READ_HEADER;
501 curblock = 0;
502 lastbigblocknr = -1;
503 bigblocknr = sth.bbd_list[curblock];
504 while (curblock<sth.num_of_bbd_blocks) {
505 assert(bigblocknr>=0);
506 assert(STORAGE_get_big_block(hf,bigblocknr,block));
507 for (i=0;i<128;i++)
508 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
509 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
510 assert(STORAGE_put_big_block(hf,bigblocknr,block));
511 memset(block,0x42,sizeof(block));
512 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
513 return i+curblock*128;
515 lastbigblocknr = bigblocknr;
516 bigblocknr = sth.bbd_list[++curblock];
518 bigblocknr = curblock*128;
519 /* since we have marked all blocks from 0 up to curblock*128-1
520 * the next free one is curblock*128, where we happily put our
521 * next large block depot.
523 memset(block,0xff,sizeof(block));
524 /* mark the block allocated and returned by this function */
525 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
526 assert(STORAGE_put_big_block(hf,bigblocknr,block));
528 /* if we had a bbd block already (mostlikely) we need
529 * to link the new one into the chain
531 if (lastbigblocknr!=-1)
532 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
533 sth.bbd_list[curblock]=bigblocknr;
534 sth.num_of_bbd_blocks++;
535 assert(sth.num_of_bbd_blocks==curblock+1);
536 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
538 /* Set the end of the chain for the bigblockdepots */
539 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
540 /* add 1, for the first entry is used for the additional big block
541 * depot. (means we already used bigblocknr) */
542 memset(block,0x42,sizeof(block));
543 /* allocate this block (filled with 0x42) */
544 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
545 return bigblocknr+1;
549 /******************************************************************************
550 * STORAGE_get_free_small_blocknr [Internal]
552 static int
553 STORAGE_get_free_small_blocknr(HFILE hf) {
554 BYTE block[BIGSIZE];
555 LPINT sbd = (LPINT)block;
556 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
557 struct storage_pps_entry root;
558 struct storage_header sth;
560 READ_HEADER;
561 bigblocknr = sth.sbd_startblock;
562 curblock = 0;
563 lastbigblocknr = -1;
564 newblocknr = -1;
565 while (bigblocknr>=0) {
566 if (!STORAGE_get_big_block(hf,bigblocknr,block))
567 return -1;
568 for (i=0;i<128;i++)
569 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
570 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
571 newblocknr = i+curblock*128;
572 break;
574 if (i!=128)
575 break;
576 lastbigblocknr = bigblocknr;
577 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
578 curblock++;
580 if (newblocknr==-1) {
581 bigblocknr = STORAGE_get_free_big_blocknr(hf);
582 if (bigblocknr<0)
583 return -1;
584 READ_HEADER;
585 memset(block,0xff,sizeof(block));
586 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
587 if (!STORAGE_put_big_block(hf,bigblocknr,block))
588 return -1;
589 if (lastbigblocknr==-1) {
590 sth.sbd_startblock = bigblocknr;
591 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
592 return -1;
593 } else {
594 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
595 return -1;
597 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
598 return -1;
599 newblocknr = curblock*128;
601 /* allocate enough big blocks for storing the allocated small block */
602 if (!STORAGE_get_root_pps_entry(hf,&root))
603 return -1;
604 if (root.pps_sb==-1)
605 lastbigblocknr = -1;
606 else
607 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
608 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
609 /* we need to allocate more stuff */
610 bigblocknr = STORAGE_get_free_big_blocknr(hf);
611 if (bigblocknr<0)
612 return -1;
613 READ_HEADER;
614 if (root.pps_sb==-1) {
615 root.pps_sb = bigblocknr;
616 root.pps_size += BIGSIZE;
617 } else {
618 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
619 return -1;
620 root.pps_size += BIGSIZE;
622 lastbigblocknr = bigblocknr;
624 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
625 return -1;
626 if (!STORAGE_put_pps_entry(hf,0,&root))
627 return -1;
628 return newblocknr;
631 /******************************************************************************
632 * STORAGE_get_free_pps_entry [Internal]
634 static int
635 STORAGE_get_free_pps_entry(HFILE hf) {
636 int blocknr,i,curblock,lastblocknr;
637 BYTE block[BIGSIZE];
638 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
639 struct storage_header sth;
641 READ_HEADER;
642 blocknr = sth.root_startblock;
643 assert(blocknr>=0);
644 curblock=0;
645 while (blocknr>=0) {
646 if (!STORAGE_get_big_block(hf,blocknr,block))
647 return -1;
648 for (i=0;i<4;i++)
649 if (stde[i].pps_sizeofname==0) /* free */
650 return curblock*4+i;
651 lastblocknr = blocknr;
652 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
653 curblock++;
655 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
656 blocknr = STORAGE_get_free_big_blocknr(hf);
657 /* sth invalidated */
658 if (blocknr<0)
659 return -1;
661 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
662 return -1;
663 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
664 return -1;
665 memset(block,0,sizeof(block));
666 STORAGE_put_big_block(hf,blocknr,block);
667 return curblock*4;
670 /* --- IStream16 implementation */
672 typedef struct
674 /* IUnknown fields */
675 ICOM_VFIELD(IStream16);
676 DWORD ref;
677 /* IStream16 fields */
678 SEGPTR thisptr; /* pointer to this struct as segmented */
679 struct storage_pps_entry stde;
680 int ppsent;
681 HFILE hf;
682 ULARGE_INTEGER offset;
683 } IStream16Impl;
685 /******************************************************************************
686 * IStream16_QueryInterface [STORAGE.518]
688 HRESULT WINAPI IStream16_fnQueryInterface(
689 IStream16* iface,REFIID refiid,LPVOID *obj
691 ICOM_THIS(IStream16Impl,iface);
692 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
693 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
694 *obj = This;
695 return 0;
697 return OLE_E_ENUM_NOMORE;
701 /******************************************************************************
702 * IStream16_AddRef [STORAGE.519]
704 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
705 ICOM_THIS(IStream16Impl,iface);
706 return ++(This->ref);
709 /******************************************************************************
710 * IStream16_Release [STORAGE.520]
712 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
713 ICOM_THIS(IStream16Impl,iface);
714 FlushFileBuffers(This->hf);
715 This->ref--;
716 if (!This->ref) {
717 CloseHandle(This->hf);
718 UnMapLS( This->thisptr );
719 HeapFree( GetProcessHeap(), 0, This );
720 return 0;
722 return This->ref;
725 /******************************************************************************
726 * IStream16_Seek [STORAGE.523]
728 * FIXME
729 * Does not handle 64 bits
731 HRESULT WINAPI IStream16_fnSeek(
732 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
734 ICOM_THIS(IStream16Impl,iface);
735 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
737 switch (whence) {
738 /* unix SEEK_xx should be the same as win95 ones */
739 case SEEK_SET:
740 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
741 * right now.
743 assert(offset.s.HighPart==0);
744 This->offset.s.HighPart = offset.s.HighPart;
745 This->offset.s.LowPart = offset.s.LowPart;
746 break;
747 case SEEK_CUR:
748 if (offset.s.HighPart < 0) {
749 /* FIXME: is this negation correct ? */
750 offset.s.HighPart = -offset.s.HighPart;
751 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
753 assert(offset.s.HighPart==0);
754 assert(This->offset.s.LowPart >= offset.s.LowPart);
755 This->offset.s.LowPart -= offset.s.LowPart;
756 } else {
757 assert(offset.s.HighPart==0);
758 This->offset.s.LowPart+= offset.s.LowPart;
760 break;
761 case SEEK_END:
762 assert(offset.s.HighPart==0);
763 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
764 break;
766 if (This->offset.s.LowPart>This->stde.pps_size)
767 This->offset.s.LowPart=This->stde.pps_size;
768 if (newpos) *newpos = This->offset;
769 return S_OK;
772 /******************************************************************************
773 * IStream16_Read [STORAGE.521]
775 HRESULT WINAPI IStream16_fnRead(
776 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
778 ICOM_THIS(IStream16Impl,iface);
779 BYTE block[BIGSIZE];
780 ULONG *bytesread=pcbRead,xxread;
781 int blocknr;
783 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
784 if (!pcbRead) bytesread=&xxread;
785 *bytesread = 0;
787 if (cb>This->stde.pps_size-This->offset.s.LowPart)
788 cb=This->stde.pps_size-This->offset.s.LowPart;
789 if (This->stde.pps_size < 0x1000) {
790 /* use small block reader */
791 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
792 while (cb) {
793 int cc;
795 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
796 WARN("small block read failed!!!\n");
797 return E_FAIL;
799 cc = cb;
800 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
801 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
802 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
803 This->offset.s.LowPart+=cc;
804 (LPBYTE)pv+=cc;
805 *bytesread+=cc;
806 cb-=cc;
807 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
809 } else {
810 /* use big block reader */
811 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
812 while (cb) {
813 int cc;
815 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
816 WARN("big block read failed!!!\n");
817 return E_FAIL;
819 cc = cb;
820 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
821 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
822 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
823 This->offset.s.LowPart+=cc;
824 (LPBYTE)pv+=cc;
825 *bytesread+=cc;
826 cb-=cc;
827 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
830 return S_OK;
833 /******************************************************************************
834 * IStream16_Write [STORAGE.522]
836 HRESULT WINAPI IStream16_fnWrite(
837 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
839 ICOM_THIS(IStream16Impl,iface);
840 BYTE block[BIGSIZE];
841 ULONG *byteswritten=pcbWrite,xxwritten;
842 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
843 HFILE hf = This->hf;
845 if (!pcbWrite) byteswritten=&xxwritten;
846 *byteswritten = 0;
848 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
849 /* do we need to junk some blocks? */
850 newsize = This->offset.s.LowPart+cb;
851 oldsize = This->stde.pps_size;
852 if (newsize < oldsize) {
853 if (oldsize < 0x1000) {
854 /* only small blocks */
855 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
857 assert(blocknr>=0);
859 /* will set the rest of the chain to 'free' */
860 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
861 return E_FAIL;
862 } else {
863 if (newsize >= 0x1000) {
864 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
865 assert(blocknr>=0);
867 /* will set the rest of the chain to 'free' */
868 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
869 return E_FAIL;
870 } else {
871 /* Migrate large blocks to small blocks
872 * (we just migrate newsize bytes)
874 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
875 cc = newsize;
876 blocknr = This->stde.pps_sb;
877 curdata = data;
878 while (cc>0) {
879 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
880 HeapFree(GetProcessHeap(),0,data);
881 return E_FAIL;
883 curdata += BIGSIZE;
884 cc -= BIGSIZE;
885 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
887 /* frees complete chain for this stream */
888 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
889 return E_FAIL;
890 curdata = data;
891 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
892 if (blocknr<0)
893 return E_FAIL;
894 cc = newsize;
895 while (cc>0) {
896 if (!STORAGE_put_small_block(hf,blocknr,curdata))
897 return E_FAIL;
898 cc -= SMALLSIZE;
899 if (cc<=0) {
900 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
901 return E_FAIL;
902 break;
903 } else {
904 int newblocknr = STORAGE_get_free_small_blocknr(hf);
905 if (newblocknr<0)
906 return E_FAIL;
907 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
908 return E_FAIL;
909 blocknr = newblocknr;
911 curdata += SMALLSIZE;
913 HeapFree(GetProcessHeap(),0,data);
916 This->stde.pps_size = newsize;
919 if (newsize > oldsize) {
920 if (oldsize >= 0x1000) {
921 /* should return the block right before the 'endofchain' */
922 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
923 assert(blocknr>=0);
924 lastblocknr = blocknr;
925 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
926 blocknr = STORAGE_get_free_big_blocknr(hf);
927 if (blocknr<0)
928 return E_FAIL;
929 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
930 return E_FAIL;
931 lastblocknr = blocknr;
933 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
934 return E_FAIL;
935 } else {
936 if (newsize < 0x1000) {
937 /* find startblock */
938 if (!oldsize)
939 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
940 else
941 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
942 if (blocknr<0)
943 return E_FAIL;
945 /* allocate required new small blocks */
946 lastblocknr = blocknr;
947 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
948 blocknr = STORAGE_get_free_small_blocknr(hf);
949 if (blocknr<0)
950 return E_FAIL;
951 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
952 return E_FAIL;
953 lastblocknr = blocknr;
955 /* and terminate the chain */
956 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
957 return E_FAIL;
958 } else {
959 if (!oldsize) {
960 /* no single block allocated yet */
961 blocknr=STORAGE_get_free_big_blocknr(hf);
962 if (blocknr<0)
963 return E_FAIL;
964 This->stde.pps_sb = blocknr;
965 } else {
966 /* Migrate small blocks to big blocks */
967 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
968 cc = oldsize;
969 blocknr = This->stde.pps_sb;
970 curdata = data;
971 /* slurp in */
972 while (cc>0) {
973 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
974 HeapFree(GetProcessHeap(),0,data);
975 return E_FAIL;
977 curdata += SMALLSIZE;
978 cc -= SMALLSIZE;
979 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
981 /* free small block chain */
982 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
983 return E_FAIL;
984 curdata = data;
985 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
986 if (blocknr<0)
987 return E_FAIL;
988 /* put the data into the big blocks */
989 cc = This->stde.pps_size;
990 while (cc>0) {
991 if (!STORAGE_put_big_block(hf,blocknr,curdata))
992 return E_FAIL;
993 cc -= BIGSIZE;
994 if (cc<=0) {
995 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
996 return E_FAIL;
997 break;
998 } else {
999 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1000 if (newblocknr<0)
1001 return E_FAIL;
1002 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1003 return E_FAIL;
1004 blocknr = newblocknr;
1006 curdata += BIGSIZE;
1008 HeapFree(GetProcessHeap(),0,data);
1010 /* generate big blocks to fit the new data */
1011 lastblocknr = blocknr;
1012 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1013 blocknr = STORAGE_get_free_big_blocknr(hf);
1014 if (blocknr<0)
1015 return E_FAIL;
1016 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1017 return E_FAIL;
1018 lastblocknr = blocknr;
1020 /* terminate chain */
1021 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1022 return E_FAIL;
1025 This->stde.pps_size = newsize;
1028 /* There are just some cases where we didn't modify it, we write it out
1029 * everytime
1031 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1032 return E_FAIL;
1034 /* finally the write pass */
1035 if (This->stde.pps_size < 0x1000) {
1036 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1037 assert(blocknr>=0);
1038 while (cb>0) {
1039 /* we ensured that it is allocated above */
1040 assert(blocknr>=0);
1041 /* Read old block everytime, since we can have
1042 * overlapping data at START and END of the write
1044 if (!STORAGE_get_small_block(hf,blocknr,block))
1045 return E_FAIL;
1047 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1048 if (cc>cb)
1049 cc=cb;
1050 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1051 (LPBYTE)((char *) pv+curoffset),
1054 if (!STORAGE_put_small_block(hf,blocknr,block))
1055 return E_FAIL;
1056 cb -= cc;
1057 curoffset += cc;
1058 (LPBYTE)pv += cc;
1059 This->offset.s.LowPart += cc;
1060 *byteswritten += cc;
1061 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1063 } else {
1064 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1065 assert(blocknr>=0);
1066 while (cb>0) {
1067 /* we ensured that it is allocated above, so it better is */
1068 assert(blocknr>=0);
1069 /* read old block everytime, since we can have
1070 * overlapping data at START and END of the write
1072 if (!STORAGE_get_big_block(hf,blocknr,block))
1073 return E_FAIL;
1075 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1076 if (cc>cb)
1077 cc=cb;
1078 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1079 (LPBYTE)((char *) pv+curoffset),
1082 if (!STORAGE_put_big_block(hf,blocknr,block))
1083 return E_FAIL;
1084 cb -= cc;
1085 curoffset += cc;
1086 (LPBYTE)pv += cc;
1087 This->offset.s.LowPart += cc;
1088 *byteswritten += cc;
1089 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1092 return S_OK;
1095 /******************************************************************************
1096 * _create_istream16 [Internal]
1098 static void _create_istream16(LPSTREAM16 *str) {
1099 IStream16Impl* lpst;
1101 if (!strvt16.QueryInterface) {
1102 HMODULE16 wp = GetModuleHandle16("STORAGE");
1103 if (wp>=32) {
1104 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1105 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1106 VTENT(QueryInterface);
1107 VTENT(AddRef);
1108 VTENT(Release);
1109 VTENT(Read);
1110 VTENT(Write);
1111 VTENT(Seek);
1112 VTENT(SetSize);
1113 VTENT(CopyTo);
1114 VTENT(Commit);
1115 VTENT(Revert);
1116 VTENT(LockRegion);
1117 VTENT(UnlockRegion);
1118 VTENT(Stat);
1119 VTENT(Clone);
1120 #undef VTENT
1121 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1122 } else {
1123 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1124 VTENT(QueryInterface);
1125 VTENT(AddRef);
1126 VTENT(Release);
1127 VTENT(Read);
1128 VTENT(Write);
1129 VTENT(Seek);
1131 VTENT(CopyTo);
1132 VTENT(Commit);
1133 VTENT(SetSize);
1134 VTENT(Revert);
1135 VTENT(LockRegion);
1136 VTENT(UnlockRegion);
1137 VTENT(Stat);
1138 VTENT(Clone);
1140 #undef VTENT
1141 segstrvt16 = &strvt16;
1144 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1145 ICOM_VTBL(lpst) = segstrvt16;
1146 lpst->ref = 1;
1147 lpst->thisptr = MapLS( lpst );
1148 *str = (void*)lpst->thisptr;
1152 /* --- IStream32 implementation */
1154 typedef struct
1156 /* IUnknown fields */
1157 ICOM_VFIELD(IStream);
1158 DWORD ref;
1159 /* IStream32 fields */
1160 struct storage_pps_entry stde;
1161 int ppsent;
1162 HFILE hf;
1163 ULARGE_INTEGER offset;
1164 } IStream32Impl;
1166 /*****************************************************************************
1167 * IStream32_QueryInterface [VTABLE]
1169 HRESULT WINAPI IStream_fnQueryInterface(
1170 IStream* iface,REFIID refiid,LPVOID *obj
1172 ICOM_THIS(IStream32Impl,iface);
1174 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1175 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1176 *obj = This;
1177 return 0;
1179 return OLE_E_ENUM_NOMORE;
1183 /******************************************************************************
1184 * IStream32_AddRef [VTABLE]
1186 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1187 ICOM_THIS(IStream32Impl,iface);
1188 return ++(This->ref);
1191 /******************************************************************************
1192 * IStream32_Release [VTABLE]
1194 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1195 ICOM_THIS(IStream32Impl,iface);
1196 FlushFileBuffers(This->hf);
1197 This->ref--;
1198 if (!This->ref) {
1199 CloseHandle(This->hf);
1200 HeapFree( GetProcessHeap(), 0, This );
1201 return 0;
1203 return This->ref;
1206 /* --- IStorage16 implementation */
1208 typedef struct
1210 /* IUnknown fields */
1211 ICOM_VFIELD(IStorage16);
1212 DWORD ref;
1213 /* IStorage16 fields */
1214 SEGPTR thisptr; /* pointer to this struct as segmented */
1215 struct storage_pps_entry stde;
1216 int ppsent;
1217 HFILE hf;
1218 } IStorage16Impl;
1220 /******************************************************************************
1221 * IStorage16_QueryInterface [STORAGE.500]
1223 HRESULT WINAPI IStorage16_fnQueryInterface(
1224 IStorage16* iface,REFIID refiid,LPVOID *obj
1226 ICOM_THIS(IStorage16Impl,iface);
1228 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1230 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1231 *obj = This;
1232 return 0;
1234 return OLE_E_ENUM_NOMORE;
1237 /******************************************************************************
1238 * IStorage16_AddRef [STORAGE.501]
1240 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1241 ICOM_THIS(IStorage16Impl,iface);
1242 return ++(This->ref);
1245 /******************************************************************************
1246 * IStorage16_Release [STORAGE.502]
1248 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1249 ICOM_THIS(IStorage16Impl,iface);
1250 This->ref--;
1251 if (This->ref)
1252 return This->ref;
1253 UnMapLS( This->thisptr );
1254 HeapFree( GetProcessHeap(), 0, This );
1255 return 0;
1258 /******************************************************************************
1259 * IStorage16_Stat [STORAGE.517]
1261 HRESULT WINAPI IStorage16_fnStat(
1262 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1264 ICOM_THIS(IStorage16Impl,iface);
1265 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1266 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1268 TRACE("(%p)->(%p,0x%08lx)\n",
1269 This,pstatstg,grfStatFlag
1271 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1272 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1273 pstatstg->type = This->stde.pps_type;
1274 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1275 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1276 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1277 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1278 pstatstg->grfMode = 0; /* FIXME */
1279 pstatstg->grfLocksSupported = 0; /* FIXME */
1280 pstatstg->clsid = This->stde.pps_guid;
1281 pstatstg->grfStateBits = 0; /* FIXME */
1282 pstatstg->reserved = 0;
1283 return S_OK;
1286 /******************************************************************************
1287 * IStorage16_Commit [STORAGE.509]
1289 HRESULT WINAPI IStorage16_fnCommit(
1290 LPSTORAGE16 iface,DWORD commitflags
1292 ICOM_THIS(IStorage16Impl,iface);
1293 FIXME("(%p)->(0x%08lx),STUB!\n",
1294 This,commitflags
1296 return S_OK;
1299 /******************************************************************************
1300 * IStorage16_CopyTo [STORAGE.507]
1302 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1303 ICOM_THIS(IStorage16Impl,iface);
1304 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1305 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1307 return S_OK;
1311 /******************************************************************************
1312 * IStorage16_CreateStorage [STORAGE.505]
1314 HRESULT WINAPI IStorage16_fnCreateStorage(
1315 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1317 ICOM_THIS(IStorage16Impl,iface);
1318 IStorage16Impl* lpstg;
1319 int ppsent,x;
1320 struct storage_pps_entry stde;
1321 struct storage_header sth;
1322 HFILE hf=This->hf;
1324 READ_HEADER;
1326 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1327 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1329 if (grfMode & STGM_TRANSACTED)
1330 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1331 _create_istorage16(ppstg);
1332 lpstg = MapSL((SEGPTR)*ppstg);
1333 lpstg->hf = This->hf;
1335 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1336 if (ppsent<0)
1337 return E_FAIL;
1338 stde=This->stde;
1339 if (stde.pps_dir==-1) {
1340 stde.pps_dir = ppsent;
1341 x = This->ppsent;
1342 } else {
1343 FIXME(" use prev chain too ?\n");
1344 x=stde.pps_dir;
1345 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1346 return E_FAIL;
1347 while (stde.pps_next!=-1) {
1348 x=stde.pps_next;
1349 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1350 return E_FAIL;
1352 stde.pps_next = ppsent;
1354 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1355 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1356 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1357 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1358 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1359 lpstg->stde.pps_next = -1;
1360 lpstg->stde.pps_prev = -1;
1361 lpstg->stde.pps_dir = -1;
1362 lpstg->stde.pps_sb = -1;
1363 lpstg->stde.pps_size = 0;
1364 lpstg->stde.pps_type = 1;
1365 lpstg->ppsent = ppsent;
1366 /* FIXME: timestamps? */
1367 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1368 return E_FAIL;
1369 return S_OK;
1372 /******************************************************************************
1373 * IStorage16_CreateStream [STORAGE.503]
1375 HRESULT WINAPI IStorage16_fnCreateStream(
1376 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1378 ICOM_THIS(IStorage16Impl,iface);
1379 IStream16Impl* lpstr;
1380 int ppsent,x;
1381 struct storage_pps_entry stde;
1383 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1384 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1386 if (grfMode & STGM_TRANSACTED)
1387 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1388 _create_istream16(ppstm);
1389 lpstr = MapSL((SEGPTR)*ppstm);
1390 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1391 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1392 lpstr->offset.s.LowPart = 0;
1393 lpstr->offset.s.HighPart = 0;
1395 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1396 if (ppsent<0)
1397 return E_FAIL;
1398 stde=This->stde;
1399 if (stde.pps_next==-1)
1400 x=This->ppsent;
1401 else
1402 while (stde.pps_next!=-1) {
1403 x=stde.pps_next;
1404 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1405 return E_FAIL;
1407 stde.pps_next = ppsent;
1408 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1409 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1410 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1411 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1412 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1413 lpstr->stde.pps_next = -1;
1414 lpstr->stde.pps_prev = -1;
1415 lpstr->stde.pps_dir = -1;
1416 lpstr->stde.pps_sb = -1;
1417 lpstr->stde.pps_size = 0;
1418 lpstr->stde.pps_type = 2;
1419 lpstr->ppsent = ppsent;
1420 /* FIXME: timestamps? */
1421 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1422 return E_FAIL;
1423 return S_OK;
1426 /******************************************************************************
1427 * IStorage16_OpenStorage [STORAGE.506]
1429 HRESULT WINAPI IStorage16_fnOpenStorage(
1430 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1432 ICOM_THIS(IStorage16Impl,iface);
1433 IStream16Impl* lpstg;
1434 WCHAR name[33];
1435 int newpps;
1437 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1438 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1440 if (grfMode & STGM_TRANSACTED)
1441 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1442 _create_istorage16(ppstg);
1443 lpstg = MapSL((SEGPTR)*ppstg);
1444 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1445 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1446 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1447 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1448 if (newpps==-1) {
1449 IStream16_fnRelease((IStream16*)lpstg);
1450 return E_FAIL;
1453 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1454 IStream16_fnRelease((IStream16*)lpstg);
1455 return E_FAIL;
1457 lpstg->ppsent = newpps;
1458 return S_OK;
1461 /******************************************************************************
1462 * IStorage16_OpenStream [STORAGE.504]
1464 HRESULT WINAPI IStorage16_fnOpenStream(
1465 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1467 ICOM_THIS(IStorage16Impl,iface);
1468 IStream16Impl* lpstr;
1469 WCHAR name[33];
1470 int newpps;
1472 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1473 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1475 if (grfMode & STGM_TRANSACTED)
1476 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1477 _create_istream16(ppstm);
1478 lpstr = MapSL((SEGPTR)*ppstm);
1479 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1480 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1481 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1482 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1483 if (newpps==-1) {
1484 IStream16_fnRelease((IStream16*)lpstr);
1485 return E_FAIL;
1488 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1489 IStream16_fnRelease((IStream16*)lpstr);
1490 return E_FAIL;
1492 lpstr->offset.s.LowPart = 0;
1493 lpstr->offset.s.HighPart = 0;
1494 lpstr->ppsent = newpps;
1495 return S_OK;
1498 /******************************************************************************
1499 * _create_istorage16 [INTERNAL]
1501 static void _create_istorage16(LPSTORAGE16 *stg) {
1502 IStorage16Impl* lpst;
1504 if (!stvt16.QueryInterface) {
1505 HMODULE16 wp = GetModuleHandle16("STORAGE");
1506 if (wp>=32) {
1507 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1508 VTENT(QueryInterface)
1509 VTENT(AddRef)
1510 VTENT(Release)
1511 VTENT(CreateStream)
1512 VTENT(OpenStream)
1513 VTENT(CreateStorage)
1514 VTENT(OpenStorage)
1515 VTENT(CopyTo)
1516 VTENT(MoveElementTo)
1517 VTENT(Commit)
1518 VTENT(Revert)
1519 VTENT(EnumElements)
1520 VTENT(DestroyElement)
1521 VTENT(RenameElement)
1522 VTENT(SetElementTimes)
1523 VTENT(SetClass)
1524 VTENT(SetStateBits)
1525 VTENT(Stat)
1526 #undef VTENT
1527 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1528 } else {
1529 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1530 VTENT(QueryInterface)
1531 VTENT(AddRef)
1532 VTENT(Release)
1533 VTENT(CreateStream)
1534 VTENT(OpenStream)
1535 VTENT(CreateStorage)
1536 VTENT(OpenStorage)
1537 VTENT(CopyTo)
1538 VTENT(Commit)
1539 /* not (yet) implemented ...
1540 VTENT(MoveElementTo)
1541 VTENT(Revert)
1542 VTENT(EnumElements)
1543 VTENT(DestroyElement)
1544 VTENT(RenameElement)
1545 VTENT(SetElementTimes)
1546 VTENT(SetClass)
1547 VTENT(SetStateBits)
1548 VTENT(Stat)
1550 #undef VTENT
1551 segstvt16 = &stvt16;
1554 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1555 ICOM_VTBL(lpst) = segstvt16;
1556 lpst->ref = 1;
1557 lpst->thisptr = MapLS(lpst);
1558 *stg = (void*)lpst->thisptr;
1561 /******************************************************************************
1562 * Storage API functions
1565 /******************************************************************************
1566 * StgCreateDocFileA [STORAGE.1]
1568 HRESULT WINAPI StgCreateDocFile16(
1569 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1571 HFILE hf;
1572 int i,ret;
1573 IStorage16Impl* lpstg;
1574 struct storage_pps_entry stde;
1576 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1577 pwcsName,grfMode,reserved,ppstgOpen
1579 _create_istorage16(ppstgOpen);
1580 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1581 if (hf==INVALID_HANDLE_VALUE) {
1582 WARN("couldn't open file for storage:%ld\n",GetLastError());
1583 return E_FAIL;
1585 lpstg = MapSL((SEGPTR)*ppstgOpen);
1586 lpstg->hf = hf;
1587 /* FIXME: check for existence before overwriting? */
1588 if (!STORAGE_init_storage(hf)) {
1589 CloseHandle(hf);
1590 return E_FAIL;
1592 i=0;ret=0;
1593 while (!ret) { /* neither 1 nor <0 */
1594 ret=STORAGE_get_pps_entry(hf,i,&stde);
1595 if ((ret==1) && (stde.pps_type==5)) {
1596 lpstg->stde = stde;
1597 lpstg->ppsent = i;
1598 break;
1600 i++;
1602 if (ret!=1) {
1603 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1604 return E_FAIL;
1607 return S_OK;
1610 /******************************************************************************
1611 * StgIsStorageFile [STORAGE.5]
1613 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1614 HFILE hf;
1615 OFSTRUCT ofs;
1616 BYTE magic[24];
1618 TRACE("(\'%s\')\n",fn);
1619 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1620 if (hf==HFILE_ERROR)
1621 return STG_E_FILENOTFOUND;
1622 if (24!=_lread(hf,magic,24)) {
1623 WARN(" too short\n");
1624 _lclose(hf);
1625 return S_FALSE;
1627 if (!memcmp(magic,STORAGE_magic,8)) {
1628 WARN(" -> YES\n");
1629 _lclose(hf);
1630 return S_OK;
1632 if (!memcmp(magic,STORAGE_notmagic,8)) {
1633 WARN(" -> NO\n");
1634 _lclose(hf);
1635 return S_FALSE;
1637 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1638 WARN(" -> old format\n");
1639 _lclose(hf);
1640 return STG_E_OLDFORMAT;
1642 WARN(" -> Invalid header.\n");
1643 _lclose(hf);
1644 return STG_E_INVALIDHEADER;
1647 /******************************************************************************
1648 * StgIsStorageFile [OLE32.146]
1650 HRESULT WINAPI
1651 StgIsStorageFile(LPCOLESTR fn)
1653 HRESULT ret;
1654 DWORD len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL );
1655 LPSTR strA = HeapAlloc( GetProcessHeap(), 0, len );
1657 WideCharToMultiByte( CP_ACP, 0, fn, -1, strA, len, NULL, NULL );
1658 ret = StgIsStorageFile16(strA);
1659 HeapFree( GetProcessHeap(), 0, strA );
1660 return ret;
1664 /******************************************************************************
1665 * StgOpenStorage [STORAGE.3]
1667 HRESULT WINAPI StgOpenStorage16(
1668 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1669 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1671 HFILE hf;
1672 int ret,i;
1673 IStorage16Impl* lpstg;
1674 struct storage_pps_entry stde;
1676 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1677 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1679 _create_istorage16(ppstgOpen);
1680 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1681 if (hf==INVALID_HANDLE_VALUE) {
1682 WARN("Couldn't open file for storage\n");
1683 return E_FAIL;
1685 lpstg = MapSL((SEGPTR)*ppstgOpen);
1686 lpstg->hf = hf;
1688 i=0;ret=0;
1689 while (!ret) { /* neither 1 nor <0 */
1690 ret=STORAGE_get_pps_entry(hf,i,&stde);
1691 if ((ret==1) && (stde.pps_type==5)) {
1692 lpstg->stde=stde;
1693 break;
1695 i++;
1697 if (ret!=1) {
1698 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1699 return E_FAIL;
1701 return S_OK;