Handle the %f case in wsprintf.
[wine.git] / dlls / ole32 / storage.c
blob6f75a99db919a3da38adae66ff6482723afb7c7a
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 "wingdi.h"
20 #include "wtypes.h"
21 #include "wine/obj_base.h"
22 #include "wine/obj_storage.h"
23 #include "heap.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 SEGPTR_FREE(This);
719 return 0;
721 return This->ref;
724 /******************************************************************************
725 * IStream16_Seek [STORAGE.523]
727 * FIXME
728 * Does not handle 64 bits
730 HRESULT WINAPI IStream16_fnSeek(
731 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
733 ICOM_THIS(IStream16Impl,iface);
734 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
736 switch (whence) {
737 /* unix SEEK_xx should be the same as win95 ones */
738 case SEEK_SET:
739 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
740 * right now.
742 assert(offset.s.HighPart==0);
743 This->offset.s.HighPart = offset.s.HighPart;
744 This->offset.s.LowPart = offset.s.LowPart;
745 break;
746 case SEEK_CUR:
747 if (offset.s.HighPart < 0) {
748 /* FIXME: is this negation correct ? */
749 offset.s.HighPart = -offset.s.HighPart;
750 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
752 assert(offset.s.HighPart==0);
753 assert(This->offset.s.LowPart >= offset.s.LowPart);
754 This->offset.s.LowPart -= offset.s.LowPart;
755 } else {
756 assert(offset.s.HighPart==0);
757 This->offset.s.LowPart+= offset.s.LowPart;
759 break;
760 case SEEK_END:
761 assert(offset.s.HighPart==0);
762 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
763 break;
765 if (This->offset.s.LowPart>This->stde.pps_size)
766 This->offset.s.LowPart=This->stde.pps_size;
767 if (newpos) *newpos = This->offset;
768 return S_OK;
771 /******************************************************************************
772 * IStream16_Read [STORAGE.521]
774 HRESULT WINAPI IStream16_fnRead(
775 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
777 ICOM_THIS(IStream16Impl,iface);
778 BYTE block[BIGSIZE];
779 ULONG *bytesread=pcbRead,xxread;
780 int blocknr;
782 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
783 if (!pcbRead) bytesread=&xxread;
784 *bytesread = 0;
786 if (cb>This->stde.pps_size-This->offset.s.LowPart)
787 cb=This->stde.pps_size-This->offset.s.LowPart;
788 if (This->stde.pps_size < 0x1000) {
789 /* use small block reader */
790 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
791 while (cb) {
792 int cc;
794 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
795 WARN("small block read failed!!!\n");
796 return E_FAIL;
798 cc = cb;
799 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
800 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
801 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
802 This->offset.s.LowPart+=cc;
803 (LPBYTE)pv+=cc;
804 *bytesread+=cc;
805 cb-=cc;
806 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
808 } else {
809 /* use big block reader */
810 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
811 while (cb) {
812 int cc;
814 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
815 WARN("big block read failed!!!\n");
816 return E_FAIL;
818 cc = cb;
819 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
820 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
821 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
822 This->offset.s.LowPart+=cc;
823 (LPBYTE)pv+=cc;
824 *bytesread+=cc;
825 cb-=cc;
826 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
829 return S_OK;
832 /******************************************************************************
833 * IStream16_Write [STORAGE.522]
835 HRESULT WINAPI IStream16_fnWrite(
836 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
838 ICOM_THIS(IStream16Impl,iface);
839 BYTE block[BIGSIZE];
840 ULONG *byteswritten=pcbWrite,xxwritten;
841 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
842 HFILE hf = This->hf;
844 if (!pcbWrite) byteswritten=&xxwritten;
845 *byteswritten = 0;
847 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
848 /* do we need to junk some blocks? */
849 newsize = This->offset.s.LowPart+cb;
850 oldsize = This->stde.pps_size;
851 if (newsize < oldsize) {
852 if (oldsize < 0x1000) {
853 /* only small blocks */
854 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
856 assert(blocknr>=0);
858 /* will set the rest of the chain to 'free' */
859 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
860 return E_FAIL;
861 } else {
862 if (newsize >= 0x1000) {
863 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
864 assert(blocknr>=0);
866 /* will set the rest of the chain to 'free' */
867 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
868 return E_FAIL;
869 } else {
870 /* Migrate large blocks to small blocks
871 * (we just migrate newsize bytes)
873 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
874 cc = newsize;
875 blocknr = This->stde.pps_sb;
876 curdata = data;
877 while (cc>0) {
878 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
879 HeapFree(GetProcessHeap(),0,data);
880 return E_FAIL;
882 curdata += BIGSIZE;
883 cc -= BIGSIZE;
884 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
886 /* frees complete chain for this stream */
887 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
888 return E_FAIL;
889 curdata = data;
890 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
891 if (blocknr<0)
892 return E_FAIL;
893 cc = newsize;
894 while (cc>0) {
895 if (!STORAGE_put_small_block(hf,blocknr,curdata))
896 return E_FAIL;
897 cc -= SMALLSIZE;
898 if (cc<=0) {
899 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
900 return E_FAIL;
901 break;
902 } else {
903 int newblocknr = STORAGE_get_free_small_blocknr(hf);
904 if (newblocknr<0)
905 return E_FAIL;
906 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
907 return E_FAIL;
908 blocknr = newblocknr;
910 curdata += SMALLSIZE;
912 HeapFree(GetProcessHeap(),0,data);
915 This->stde.pps_size = newsize;
918 if (newsize > oldsize) {
919 if (oldsize >= 0x1000) {
920 /* should return the block right before the 'endofchain' */
921 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
922 assert(blocknr>=0);
923 lastblocknr = blocknr;
924 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
925 blocknr = STORAGE_get_free_big_blocknr(hf);
926 if (blocknr<0)
927 return E_FAIL;
928 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
929 return E_FAIL;
930 lastblocknr = blocknr;
932 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
933 return E_FAIL;
934 } else {
935 if (newsize < 0x1000) {
936 /* find startblock */
937 if (!oldsize)
938 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
939 else
940 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
941 if (blocknr<0)
942 return E_FAIL;
944 /* allocate required new small blocks */
945 lastblocknr = blocknr;
946 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
947 blocknr = STORAGE_get_free_small_blocknr(hf);
948 if (blocknr<0)
949 return E_FAIL;
950 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
951 return E_FAIL;
952 lastblocknr = blocknr;
954 /* and terminate the chain */
955 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
956 return E_FAIL;
957 } else {
958 if (!oldsize) {
959 /* no single block allocated yet */
960 blocknr=STORAGE_get_free_big_blocknr(hf);
961 if (blocknr<0)
962 return E_FAIL;
963 This->stde.pps_sb = blocknr;
964 } else {
965 /* Migrate small blocks to big blocks */
966 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
967 cc = oldsize;
968 blocknr = This->stde.pps_sb;
969 curdata = data;
970 /* slurp in */
971 while (cc>0) {
972 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
973 HeapFree(GetProcessHeap(),0,data);
974 return E_FAIL;
976 curdata += SMALLSIZE;
977 cc -= SMALLSIZE;
978 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
980 /* free small block chain */
981 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
982 return E_FAIL;
983 curdata = data;
984 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
985 if (blocknr<0)
986 return E_FAIL;
987 /* put the data into the big blocks */
988 cc = This->stde.pps_size;
989 while (cc>0) {
990 if (!STORAGE_put_big_block(hf,blocknr,curdata))
991 return E_FAIL;
992 cc -= BIGSIZE;
993 if (cc<=0) {
994 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
995 return E_FAIL;
996 break;
997 } else {
998 int newblocknr = STORAGE_get_free_big_blocknr(hf);
999 if (newblocknr<0)
1000 return E_FAIL;
1001 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1002 return E_FAIL;
1003 blocknr = newblocknr;
1005 curdata += BIGSIZE;
1007 HeapFree(GetProcessHeap(),0,data);
1009 /* generate big blocks to fit the new data */
1010 lastblocknr = blocknr;
1011 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1012 blocknr = STORAGE_get_free_big_blocknr(hf);
1013 if (blocknr<0)
1014 return E_FAIL;
1015 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1016 return E_FAIL;
1017 lastblocknr = blocknr;
1019 /* terminate chain */
1020 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1021 return E_FAIL;
1024 This->stde.pps_size = newsize;
1027 /* There are just some cases where we didn't modify it, we write it out
1028 * everytime
1030 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1031 return E_FAIL;
1033 /* finally the write pass */
1034 if (This->stde.pps_size < 0x1000) {
1035 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1036 assert(blocknr>=0);
1037 while (cb>0) {
1038 /* we ensured that it is allocated above */
1039 assert(blocknr>=0);
1040 /* Read old block everytime, since we can have
1041 * overlapping data at START and END of the write
1043 if (!STORAGE_get_small_block(hf,blocknr,block))
1044 return E_FAIL;
1046 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1047 if (cc>cb)
1048 cc=cb;
1049 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1050 (LPBYTE)((char *) pv+curoffset),
1053 if (!STORAGE_put_small_block(hf,blocknr,block))
1054 return E_FAIL;
1055 cb -= cc;
1056 curoffset += cc;
1057 (LPBYTE)pv += cc;
1058 This->offset.s.LowPart += cc;
1059 *byteswritten += cc;
1060 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1062 } else {
1063 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1064 assert(blocknr>=0);
1065 while (cb>0) {
1066 /* we ensured that it is allocated above, so it better is */
1067 assert(blocknr>=0);
1068 /* read old block everytime, since we can have
1069 * overlapping data at START and END of the write
1071 if (!STORAGE_get_big_block(hf,blocknr,block))
1072 return E_FAIL;
1074 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1075 if (cc>cb)
1076 cc=cb;
1077 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1078 (LPBYTE)((char *) pv+curoffset),
1081 if (!STORAGE_put_big_block(hf,blocknr,block))
1082 return E_FAIL;
1083 cb -= cc;
1084 curoffset += cc;
1085 (LPBYTE)pv += cc;
1086 This->offset.s.LowPart += cc;
1087 *byteswritten += cc;
1088 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1091 return S_OK;
1094 /******************************************************************************
1095 * _create_istream16 [Internal]
1097 static void _create_istream16(LPSTREAM16 *str) {
1098 IStream16Impl* lpst;
1100 if (!strvt16.QueryInterface) {
1101 HMODULE16 wp = GetModuleHandle16("STORAGE");
1102 if (wp>=32) {
1103 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1104 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1105 VTENT(QueryInterface);
1106 VTENT(AddRef);
1107 VTENT(Release);
1108 VTENT(Read);
1109 VTENT(Write);
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.xfn = IStream16_fn##xfn;
1125 VTENT(QueryInterface);
1126 VTENT(AddRef);
1127 VTENT(Release);
1128 VTENT(Read);
1129 VTENT(Write);
1130 VTENT(Seek);
1132 VTENT(CopyTo);
1133 VTENT(Commit);
1134 VTENT(SetSize);
1135 VTENT(Revert);
1136 VTENT(LockRegion);
1137 VTENT(UnlockRegion);
1138 VTENT(Stat);
1139 VTENT(Clone);
1141 #undef VTENT
1142 segstrvt16 = &strvt16;
1145 lpst = SEGPTR_NEW(IStream16Impl);
1146 ICOM_VTBL(lpst) = segstrvt16;
1147 lpst->ref = 1;
1148 lpst->thisptr = SEGPTR_GET(lpst);
1149 *str = (void*)lpst->thisptr;
1153 /* --- IStream32 implementation */
1155 typedef struct
1157 /* IUnknown fields */
1158 ICOM_VFIELD(IStream);
1159 DWORD ref;
1160 /* IStream32 fields */
1161 struct storage_pps_entry stde;
1162 int ppsent;
1163 HFILE hf;
1164 ULARGE_INTEGER offset;
1165 } IStream32Impl;
1167 /*****************************************************************************
1168 * IStream32_QueryInterface [VTABLE]
1170 HRESULT WINAPI IStream_fnQueryInterface(
1171 IStream* iface,REFIID refiid,LPVOID *obj
1173 ICOM_THIS(IStream32Impl,iface);
1175 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1176 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1177 *obj = This;
1178 return 0;
1180 return OLE_E_ENUM_NOMORE;
1184 /******************************************************************************
1185 * IStream32_AddRef [VTABLE]
1187 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1188 ICOM_THIS(IStream32Impl,iface);
1189 return ++(This->ref);
1192 /******************************************************************************
1193 * IStream32_Release [VTABLE]
1195 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1196 ICOM_THIS(IStream32Impl,iface);
1197 FlushFileBuffers(This->hf);
1198 This->ref--;
1199 if (!This->ref) {
1200 CloseHandle(This->hf);
1201 SEGPTR_FREE(This);
1202 return 0;
1204 return This->ref;
1207 /* --- IStorage16 implementation */
1209 typedef struct
1211 /* IUnknown fields */
1212 ICOM_VFIELD(IStorage16);
1213 DWORD ref;
1214 /* IStorage16 fields */
1215 SEGPTR thisptr; /* pointer to this struct as segmented */
1216 struct storage_pps_entry stde;
1217 int ppsent;
1218 HFILE hf;
1219 } IStorage16Impl;
1221 /******************************************************************************
1222 * IStorage16_QueryInterface [STORAGE.500]
1224 HRESULT WINAPI IStorage16_fnQueryInterface(
1225 IStorage16* iface,REFIID refiid,LPVOID *obj
1227 ICOM_THIS(IStorage16Impl,iface);
1229 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1231 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1232 *obj = This;
1233 return 0;
1235 return OLE_E_ENUM_NOMORE;
1238 /******************************************************************************
1239 * IStorage16_AddRef [STORAGE.501]
1241 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1242 ICOM_THIS(IStorage16Impl,iface);
1243 return ++(This->ref);
1246 /******************************************************************************
1247 * IStorage16_Release [STORAGE.502]
1249 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1250 ICOM_THIS(IStorage16Impl,iface);
1251 This->ref--;
1252 if (This->ref)
1253 return This->ref;
1254 SEGPTR_FREE(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 TRACE("(%p)->(%p,0x%08lx)\n",
1266 This,pstatstg,grfStatFlag
1268 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1269 pstatstg->type = This->stde.pps_type;
1270 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1271 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1272 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1273 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1274 pstatstg->grfMode = 0; /* FIXME */
1275 pstatstg->grfLocksSupported = 0; /* FIXME */
1276 pstatstg->clsid = This->stde.pps_guid;
1277 pstatstg->grfStateBits = 0; /* FIXME */
1278 pstatstg->reserved = 0;
1279 return S_OK;
1282 /******************************************************************************
1283 * IStorage16_Commit [STORAGE.509]
1285 HRESULT WINAPI IStorage16_fnCommit(
1286 LPSTORAGE16 iface,DWORD commitflags
1288 ICOM_THIS(IStorage16Impl,iface);
1289 FIXME("(%p)->(0x%08lx),STUB!\n",
1290 This,commitflags
1292 return S_OK;
1295 /******************************************************************************
1296 * IStorage16_CopyTo [STORAGE.507]
1298 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1299 ICOM_THIS(IStorage16Impl,iface);
1300 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1301 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1303 return S_OK;
1307 /******************************************************************************
1308 * IStorage16_CreateStorage [STORAGE.505]
1310 HRESULT WINAPI IStorage16_fnCreateStorage(
1311 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1313 ICOM_THIS(IStorage16Impl,iface);
1314 IStorage16Impl* lpstg;
1315 int ppsent,x;
1316 struct storage_pps_entry stde;
1317 struct storage_header sth;
1318 HFILE hf=This->hf;
1320 READ_HEADER;
1322 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1323 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1325 if (grfMode & STGM_TRANSACTED)
1326 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1327 _create_istorage16(ppstg);
1328 lpstg = MapSL((SEGPTR)*ppstg);
1329 lpstg->hf = This->hf;
1331 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1332 if (ppsent<0)
1333 return E_FAIL;
1334 stde=This->stde;
1335 if (stde.pps_dir==-1) {
1336 stde.pps_dir = ppsent;
1337 x = This->ppsent;
1338 } else {
1339 FIXME(" use prev chain too ?\n");
1340 x=stde.pps_dir;
1341 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1342 return E_FAIL;
1343 while (stde.pps_next!=-1) {
1344 x=stde.pps_next;
1345 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1346 return E_FAIL;
1348 stde.pps_next = ppsent;
1350 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1351 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1352 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1353 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1354 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1355 lpstg->stde.pps_next = -1;
1356 lpstg->stde.pps_prev = -1;
1357 lpstg->stde.pps_dir = -1;
1358 lpstg->stde.pps_sb = -1;
1359 lpstg->stde.pps_size = 0;
1360 lpstg->stde.pps_type = 1;
1361 lpstg->ppsent = ppsent;
1362 /* FIXME: timestamps? */
1363 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1364 return E_FAIL;
1365 return S_OK;
1368 /******************************************************************************
1369 * IStorage16_CreateStream [STORAGE.503]
1371 HRESULT WINAPI IStorage16_fnCreateStream(
1372 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1374 ICOM_THIS(IStorage16Impl,iface);
1375 IStream16Impl* lpstr;
1376 int ppsent,x;
1377 struct storage_pps_entry stde;
1379 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1380 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1382 if (grfMode & STGM_TRANSACTED)
1383 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1384 _create_istream16(ppstm);
1385 lpstr = MapSL((SEGPTR)*ppstm);
1386 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1387 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1388 lpstr->offset.s.LowPart = 0;
1389 lpstr->offset.s.HighPart = 0;
1391 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1392 if (ppsent<0)
1393 return E_FAIL;
1394 stde=This->stde;
1395 if (stde.pps_next==-1)
1396 x=This->ppsent;
1397 else
1398 while (stde.pps_next!=-1) {
1399 x=stde.pps_next;
1400 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1401 return E_FAIL;
1403 stde.pps_next = ppsent;
1404 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1405 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1406 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1407 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1408 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1409 lpstr->stde.pps_next = -1;
1410 lpstr->stde.pps_prev = -1;
1411 lpstr->stde.pps_dir = -1;
1412 lpstr->stde.pps_sb = -1;
1413 lpstr->stde.pps_size = 0;
1414 lpstr->stde.pps_type = 2;
1415 lpstr->ppsent = ppsent;
1416 /* FIXME: timestamps? */
1417 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1418 return E_FAIL;
1419 return S_OK;
1422 /******************************************************************************
1423 * IStorage16_OpenStorage [STORAGE.506]
1425 HRESULT WINAPI IStorage16_fnOpenStorage(
1426 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1428 ICOM_THIS(IStorage16Impl,iface);
1429 IStream16Impl* lpstg;
1430 WCHAR name[33];
1431 int newpps;
1433 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1434 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1436 if (grfMode & STGM_TRANSACTED)
1437 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1438 _create_istorage16(ppstg);
1439 lpstg = MapSL((SEGPTR)*ppstg);
1440 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1441 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1442 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1443 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1444 if (newpps==-1) {
1445 IStream16_fnRelease((IStream16*)lpstg);
1446 return E_FAIL;
1449 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1450 IStream16_fnRelease((IStream16*)lpstg);
1451 return E_FAIL;
1453 lpstg->ppsent = newpps;
1454 return S_OK;
1457 /******************************************************************************
1458 * IStorage16_OpenStream [STORAGE.504]
1460 HRESULT WINAPI IStorage16_fnOpenStream(
1461 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1463 ICOM_THIS(IStorage16Impl,iface);
1464 IStream16Impl* lpstr;
1465 WCHAR name[33];
1466 int newpps;
1468 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1469 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1471 if (grfMode & STGM_TRANSACTED)
1472 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1473 _create_istream16(ppstm);
1474 lpstr = MapSL((SEGPTR)*ppstm);
1475 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1476 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1477 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1478 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1479 if (newpps==-1) {
1480 IStream16_fnRelease((IStream16*)lpstr);
1481 return E_FAIL;
1484 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1485 IStream16_fnRelease((IStream16*)lpstr);
1486 return E_FAIL;
1488 lpstr->offset.s.LowPart = 0;
1489 lpstr->offset.s.HighPart = 0;
1490 lpstr->ppsent = newpps;
1491 return S_OK;
1494 /******************************************************************************
1495 * _create_istorage16 [INTERNAL]
1497 static void _create_istorage16(LPSTORAGE16 *stg) {
1498 IStorage16Impl* lpst;
1500 if (!stvt16.QueryInterface) {
1501 HMODULE16 wp = GetModuleHandle16("STORAGE");
1502 if (wp>=32) {
1503 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1504 VTENT(QueryInterface)
1505 VTENT(AddRef)
1506 VTENT(Release)
1507 VTENT(CreateStream)
1508 VTENT(OpenStream)
1509 VTENT(CreateStorage)
1510 VTENT(OpenStorage)
1511 VTENT(CopyTo)
1512 VTENT(MoveElementTo)
1513 VTENT(Commit)
1514 VTENT(Revert)
1515 VTENT(EnumElements)
1516 VTENT(DestroyElement)
1517 VTENT(RenameElement)
1518 VTENT(SetElementTimes)
1519 VTENT(SetClass)
1520 VTENT(SetStateBits)
1521 VTENT(Stat)
1522 #undef VTENT
1523 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1524 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1525 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1526 } else {
1527 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1528 VTENT(QueryInterface)
1529 VTENT(AddRef)
1530 VTENT(Release)
1531 VTENT(CreateStream)
1532 VTENT(OpenStream)
1533 VTENT(CreateStorage)
1534 VTENT(OpenStorage)
1535 VTENT(CopyTo)
1536 VTENT(Commit)
1537 /* not (yet) implemented ...
1538 VTENT(MoveElementTo)
1539 VTENT(Revert)
1540 VTENT(EnumElements)
1541 VTENT(DestroyElement)
1542 VTENT(RenameElement)
1543 VTENT(SetElementTimes)
1544 VTENT(SetClass)
1545 VTENT(SetStateBits)
1546 VTENT(Stat)
1548 #undef VTENT
1549 segstvt16 = &stvt16;
1552 lpst = SEGPTR_NEW(IStorage16Impl);
1553 ICOM_VTBL(lpst) = segstvt16;
1554 lpst->ref = 1;
1555 lpst->thisptr = SEGPTR_GET(lpst);
1556 *stg = (void*)lpst->thisptr;
1559 /******************************************************************************
1560 * Storage API functions
1563 /******************************************************************************
1564 * StgCreateDocFile16 [STORAGE.1]
1566 HRESULT WINAPI StgCreateDocFile16(
1567 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1569 HFILE hf;
1570 int i,ret;
1571 IStorage16Impl* lpstg;
1572 struct storage_pps_entry stde;
1574 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1575 pwcsName,grfMode,reserved,ppstgOpen
1577 _create_istorage16(ppstgOpen);
1578 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1579 if (hf==INVALID_HANDLE_VALUE) {
1580 WARN("couldn't open file for storage:%ld\n",GetLastError());
1581 return E_FAIL;
1583 lpstg = MapSL((SEGPTR)*ppstgOpen);
1584 lpstg->hf = hf;
1585 /* FIXME: check for existence before overwriting? */
1586 if (!STORAGE_init_storage(hf)) {
1587 CloseHandle(hf);
1588 return E_FAIL;
1590 i=0;ret=0;
1591 while (!ret) { /* neither 1 nor <0 */
1592 ret=STORAGE_get_pps_entry(hf,i,&stde);
1593 if ((ret==1) && (stde.pps_type==5)) {
1594 lpstg->stde = stde;
1595 lpstg->ppsent = i;
1596 break;
1598 i++;
1600 if (ret!=1) {
1601 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1602 return E_FAIL;
1605 return S_OK;
1608 /******************************************************************************
1609 * StgIsStorageFile16 [STORAGE.5]
1611 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1612 HFILE hf;
1613 OFSTRUCT ofs;
1614 BYTE magic[24];
1616 TRACE("(\'%s\')\n",fn);
1617 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1618 if (hf==HFILE_ERROR)
1619 return STG_E_FILENOTFOUND;
1620 if (24!=_lread(hf,magic,24)) {
1621 WARN(" too short\n");
1622 _lclose(hf);
1623 return S_FALSE;
1625 if (!memcmp(magic,STORAGE_magic,8)) {
1626 WARN(" -> YES\n");
1627 _lclose(hf);
1628 return S_OK;
1630 if (!memcmp(magic,STORAGE_notmagic,8)) {
1631 WARN(" -> NO\n");
1632 _lclose(hf);
1633 return S_FALSE;
1635 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1636 WARN(" -> old format\n");
1637 _lclose(hf);
1638 return STG_E_OLDFORMAT;
1640 WARN(" -> Invalid header.\n");
1641 _lclose(hf);
1642 return STG_E_INVALIDHEADER;
1645 /******************************************************************************
1646 * StgIsStorageFile [OLE32.146]
1648 HRESULT WINAPI
1649 StgIsStorageFile(LPCOLESTR fn)
1651 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1652 HRESULT ret = StgIsStorageFile16(xfn);
1654 HeapFree(GetProcessHeap(),0,xfn);
1655 return ret;
1659 /******************************************************************************
1660 * StgOpenStorage16 [STORAGE.3]
1662 HRESULT WINAPI StgOpenStorage16(
1663 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1664 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1666 HFILE hf;
1667 int ret,i;
1668 IStorage16Impl* lpstg;
1669 struct storage_pps_entry stde;
1671 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1672 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1674 _create_istorage16(ppstgOpen);
1675 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1676 if (hf==INVALID_HANDLE_VALUE) {
1677 WARN("Couldn't open file for storage\n");
1678 return E_FAIL;
1680 lpstg = MapSL((SEGPTR)*ppstgOpen);
1681 lpstg->hf = hf;
1683 i=0;ret=0;
1684 while (!ret) { /* neither 1 nor <0 */
1685 ret=STORAGE_get_pps_entry(hf,i,&stde);
1686 if ((ret==1) && (stde.pps_type==5)) {
1687 lpstg->stde=stde;
1688 break;
1690 i++;
1692 if (ret!=1) {
1693 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1694 return E_FAIL;
1696 return S_OK;