Fixed cut&paste typo.
[wine/hacks.git] / dlls / ole32 / storage.c
blob62b45bb8d4cbacf8487056660febeb8878694857
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/winestring.h"
19 #include "wine/winbase16.h"
20 #include "wingdi.h"
21 #include "wtypes.h"
22 #include "wine/obj_base.h"
23 #include "wine/obj_storage.h"
24 #include "heap.h"
25 #include "module.h"
26 #include "ldt.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(ole);
30 DECLARE_DEBUG_CHANNEL(relay);
32 struct storage_header {
33 BYTE magic[8]; /* 00: magic */
34 BYTE unknown1[36]; /* 08: unknown */
35 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
36 DWORD root_startblock;/* 30: root storage first big block */
37 DWORD unknown2[2]; /* 34: unknown */
38 DWORD sbd_startblock; /* 3C: small block depot first big block */
39 DWORD unknown3[3]; /* 40: unknown */
40 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
42 struct storage_pps_entry {
43 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
44 WORD pps_sizeofname; /* 40: namelength in bytes */
45 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
46 BYTE pps_unknown0; /* 43: unknown */
47 DWORD pps_prev; /* 44: previous pps */
48 DWORD pps_next; /* 48: next pps */
49 DWORD pps_dir; /* 4C: directory pps */
50 GUID pps_guid; /* 50: class ID */
51 DWORD pps_unknown1; /* 60: unknown */
52 FILETIME pps_ft1; /* 64: filetime1 */
53 FILETIME pps_ft2; /* 70: filetime2 */
54 DWORD pps_sb; /* 74: data startblock */
55 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
56 DWORD pps_unknown2; /* 7C: unknown */
59 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
60 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
61 #define STORAGE_CHAINENTRY_FREE 0xffffffff
64 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
65 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
66 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
68 #define BIGSIZE 512
69 #define SMALLSIZE 64
71 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
73 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
74 static ICOM_VTABLE(IStorage16) stvt16;
75 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
76 static ICOM_VTABLE(IStream16) strvt16;
77 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
79 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
80 static void _create_istorage16(LPSTORAGE16 *stg);
81 static void _create_istream16(LPSTREAM16 *str);
83 #define IMPLEMENTED 1
86 /******************************************************************************
87 * STORAGE_get_big_block [Internal]
89 * Reading OLE compound storage
91 static BOOL
92 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
93 assert(n>=-1);
94 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
95 WARN(" seek failed (%ld)\n",GetLastError());
96 return FALSE;
98 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
99 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
100 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
101 assert(0);
102 return FALSE;
104 return TRUE;
107 /******************************************************************************
108 * STORAGE_put_big_block [INTERNAL]
110 static BOOL
111 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
112 assert(n>=-1);
113 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
114 WARN(" seek failed (%ld)\n",GetLastError());
115 return FALSE;
117 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
118 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
119 WARN(" write failed (%ld)\n",GetLastError());
120 return FALSE;
122 return TRUE;
125 /******************************************************************************
126 * STORAGE_get_next_big_blocknr [INTERNAL]
128 static int
129 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
130 INT bbs[BIGSIZE/sizeof(INT)];
131 struct storage_header sth;
133 READ_HEADER;
135 assert(blocknr>>7<sth.num_of_bbd_blocks);
136 if (sth.bbd_list[blocknr>>7]==0xffffffff)
137 return -5;
138 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
139 return -5;
140 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
141 return bbs[blocknr&0x7f];
144 /******************************************************************************
145 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
147 static int
148 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
149 INT bbs[BIGSIZE/sizeof(INT)];
150 int lastblock = -1;
151 struct storage_header sth;
153 READ_HEADER;
155 assert(blocknr>=0);
156 while (nr--) {
157 assert((blocknr>>7)<sth.num_of_bbd_blocks);
158 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
160 /* simple caching... */
161 if (lastblock!=sth.bbd_list[blocknr>>7]) {
162 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
163 lastblock = sth.bbd_list[blocknr>>7];
165 blocknr = bbs[blocknr&0x7f];
167 return blocknr;
170 /******************************************************************************
171 * STORAGE_get_root_pps_entry [Internal]
173 static BOOL
174 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
175 int blocknr,i;
176 BYTE block[BIGSIZE];
177 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
178 struct storage_header sth;
180 READ_HEADER;
181 blocknr = sth.root_startblock;
182 while (blocknr>=0) {
183 assert(STORAGE_get_big_block(hf,blocknr,block));
184 for (i=0;i<4;i++) {
185 if (!stde[i].pps_sizeofname)
186 continue;
187 if (stde[i].pps_type==5) {
188 *pstde=stde[i];
189 return TRUE;
192 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
194 return FALSE;
197 /******************************************************************************
198 * STORAGE_get_small_block [INTERNAL]
200 static BOOL
201 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
202 BYTE block[BIGSIZE];
203 int bigblocknr;
204 struct storage_pps_entry root;
206 assert(blocknr>=0);
207 assert(STORAGE_get_root_pps_entry(hf,&root));
208 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
209 assert(bigblocknr>=0);
210 assert(STORAGE_get_big_block(hf,bigblocknr,block));
212 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
213 return TRUE;
216 /******************************************************************************
217 * STORAGE_put_small_block [INTERNAL]
219 static BOOL
220 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
221 BYTE block[BIGSIZE];
222 int bigblocknr;
223 struct storage_pps_entry root;
225 assert(blocknr>=0);
227 assert(STORAGE_get_root_pps_entry(hf,&root));
228 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
229 assert(bigblocknr>=0);
230 assert(STORAGE_get_big_block(hf,bigblocknr,block));
232 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
233 assert(STORAGE_put_big_block(hf,bigblocknr,block));
234 return TRUE;
237 /******************************************************************************
238 * STORAGE_get_next_small_blocknr [INTERNAL]
240 static int
241 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
242 BYTE block[BIGSIZE];
243 LPINT sbd = (LPINT)block;
244 int bigblocknr;
245 struct storage_header sth;
247 READ_HEADER;
248 assert(blocknr>=0);
249 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
250 assert(bigblocknr>=0);
251 assert(STORAGE_get_big_block(hf,bigblocknr,block));
252 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
253 return sbd[blocknr & (128-1)];
256 /******************************************************************************
257 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
259 static int
260 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
261 int lastblocknr;
262 BYTE block[BIGSIZE];
263 LPINT sbd = (LPINT)block;
264 struct storage_header sth;
266 READ_HEADER;
267 lastblocknr=-1;
268 assert(blocknr>=0);
269 while ((nr--) && (blocknr>=0)) {
270 if (lastblocknr/128!=blocknr/128) {
271 int bigblocknr;
272 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
273 assert(bigblocknr>=0);
274 assert(STORAGE_get_big_block(hf,bigblocknr,block));
275 lastblocknr = blocknr;
277 assert(lastblocknr>=0);
278 lastblocknr=blocknr;
279 blocknr=sbd[blocknr & (128-1)];
280 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
282 return blocknr;
285 /******************************************************************************
286 * STORAGE_get_pps_entry [INTERNAL]
288 static int
289 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
290 int blocknr;
291 BYTE block[BIGSIZE];
292 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
293 struct storage_header sth;
295 READ_HEADER;
296 /* we have 4 pps entries per big block */
297 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
298 assert(blocknr>=0);
299 assert(STORAGE_get_big_block(hf,blocknr,block));
301 *pstde=*stde;
302 return 1;
305 /******************************************************************************
306 * STORAGE_put_pps_entry [Internal]
308 static int
309 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
310 int blocknr;
311 BYTE block[BIGSIZE];
312 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
313 struct storage_header sth;
315 READ_HEADER;
317 /* we have 4 pps entries per big block */
318 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
319 assert(blocknr>=0);
320 assert(STORAGE_get_big_block(hf,blocknr,block));
321 *stde=*pstde;
322 assert(STORAGE_put_big_block(hf,blocknr,block));
323 return 1;
326 /******************************************************************************
327 * STORAGE_look_for_named_pps [Internal]
329 static int
330 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
331 struct storage_pps_entry stde;
332 int ret;
334 if (n==-1)
335 return -1;
336 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
337 return -1;
339 if (!lstrcmpW(name,stde.pps_rawname))
340 return n;
341 if (stde.pps_prev != -1) {
342 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
343 if (ret!=-1)
344 return ret;
346 if (stde.pps_next != -1) {
347 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
348 if (ret!=-1)
349 return ret;
351 return -1;
354 /******************************************************************************
355 * STORAGE_dump_pps_entry [Internal]
357 * FIXME
358 * Function is unused
360 void
361 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
362 char name[33];
364 lstrcpyWtoA(name,stde->pps_rawname);
365 if (!stde->pps_sizeofname)
366 return;
367 DPRINTF("name: %s\n",name);
368 DPRINTF("type: %d\n",stde->pps_type);
369 DPRINTF("prev pps: %ld\n",stde->pps_prev);
370 DPRINTF("next pps: %ld\n",stde->pps_next);
371 DPRINTF("dir pps: %ld\n",stde->pps_dir);
372 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
373 if (stde->pps_type !=2) {
374 time_t t;
375 DWORD dw;
376 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
377 t = dw;
378 DPRINTF("ts1: %s\n",ctime(&t));
379 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
380 t = dw;
381 DPRINTF("ts2: %s\n",ctime(&t));
383 DPRINTF("startblock: %ld\n",stde->pps_sb);
384 DPRINTF("size: %ld\n",stde->pps_size);
387 /******************************************************************************
388 * STORAGE_init_storage [INTERNAL]
390 static BOOL
391 STORAGE_init_storage(HFILE hf) {
392 BYTE block[BIGSIZE];
393 LPDWORD bbs;
394 struct storage_header *sth;
395 struct storage_pps_entry *stde;
397 assert(-1!=_llseek(hf,0,SEEK_SET));
398 /* block -1 is the storage header */
399 sth = (struct storage_header*)block;
400 memcpy(sth->magic,STORAGE_magic,8);
401 memset(sth->unknown1,0,sizeof(sth->unknown1));
402 memset(sth->unknown2,0,sizeof(sth->unknown2));
403 memset(sth->unknown3,0,sizeof(sth->unknown3));
404 sth->num_of_bbd_blocks = 1;
405 sth->root_startblock = 1;
406 sth->sbd_startblock = 0xffffffff;
407 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
408 sth->bbd_list[0] = 0;
409 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
410 /* block 0 is the big block directory */
411 bbs=(LPDWORD)block;
412 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
413 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
414 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
415 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
416 /* block 1 is the root directory entry */
417 memset(block,0x00,sizeof(block));
418 stde = (struct storage_pps_entry*)block;
419 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
420 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
421 stde->pps_type = 5;
422 stde->pps_dir = -1;
423 stde->pps_next = -1;
424 stde->pps_prev = -1;
425 stde->pps_sb = 0xffffffff;
426 stde->pps_size = 0;
427 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
428 return TRUE;
431 /******************************************************************************
432 * STORAGE_set_big_chain [Internal]
434 static BOOL
435 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
436 BYTE block[BIGSIZE];
437 LPINT bbd = (LPINT)block;
438 int nextblocknr,bigblocknr;
439 struct storage_header sth;
441 READ_HEADER;
442 assert(blocknr!=type);
443 while (blocknr>=0) {
444 bigblocknr = sth.bbd_list[blocknr/128];
445 assert(bigblocknr>=0);
446 assert(STORAGE_get_big_block(hf,bigblocknr,block));
448 nextblocknr = bbd[blocknr&(128-1)];
449 bbd[blocknr&(128-1)] = type;
450 if (type>=0)
451 return TRUE;
452 assert(STORAGE_put_big_block(hf,bigblocknr,block));
453 type = STORAGE_CHAINENTRY_FREE;
454 blocknr = nextblocknr;
456 return TRUE;
459 /******************************************************************************
460 * STORAGE_set_small_chain [Internal]
462 static BOOL
463 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
464 BYTE block[BIGSIZE];
465 LPINT sbd = (LPINT)block;
466 int lastblocknr,nextsmallblocknr,bigblocknr;
467 struct storage_header sth;
469 READ_HEADER;
471 assert(blocknr!=type);
472 lastblocknr=-129;bigblocknr=-2;
473 while (blocknr>=0) {
474 /* cache block ... */
475 if (lastblocknr/128!=blocknr/128) {
476 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
477 assert(bigblocknr>=0);
478 assert(STORAGE_get_big_block(hf,bigblocknr,block));
480 lastblocknr = blocknr;
481 nextsmallblocknr = sbd[blocknr&(128-1)];
482 sbd[blocknr&(128-1)] = type;
483 assert(STORAGE_put_big_block(hf,bigblocknr,block));
484 if (type>=0)
485 return TRUE;
486 type = STORAGE_CHAINENTRY_FREE;
487 blocknr = nextsmallblocknr;
489 return TRUE;
492 /******************************************************************************
493 * STORAGE_get_free_big_blocknr [Internal]
495 static int
496 STORAGE_get_free_big_blocknr(HFILE hf) {
497 BYTE block[BIGSIZE];
498 LPINT sbd = (LPINT)block;
499 int lastbigblocknr,i,curblock,bigblocknr;
500 struct storage_header sth;
502 READ_HEADER;
503 curblock = 0;
504 lastbigblocknr = -1;
505 bigblocknr = sth.bbd_list[curblock];
506 while (curblock<sth.num_of_bbd_blocks) {
507 assert(bigblocknr>=0);
508 assert(STORAGE_get_big_block(hf,bigblocknr,block));
509 for (i=0;i<128;i++)
510 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
511 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
512 assert(STORAGE_put_big_block(hf,bigblocknr,block));
513 memset(block,0x42,sizeof(block));
514 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
515 return i+curblock*128;
517 lastbigblocknr = bigblocknr;
518 bigblocknr = sth.bbd_list[++curblock];
520 bigblocknr = curblock*128;
521 /* since we have marked all blocks from 0 up to curblock*128-1
522 * the next free one is curblock*128, where we happily put our
523 * next large block depot.
525 memset(block,0xff,sizeof(block));
526 /* mark the block allocated and returned by this function */
527 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
528 assert(STORAGE_put_big_block(hf,bigblocknr,block));
530 /* if we had a bbd block already (mostlikely) we need
531 * to link the new one into the chain
533 if (lastbigblocknr!=-1)
534 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
535 sth.bbd_list[curblock]=bigblocknr;
536 sth.num_of_bbd_blocks++;
537 assert(sth.num_of_bbd_blocks==curblock+1);
538 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
540 /* Set the end of the chain for the bigblockdepots */
541 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
542 /* add 1, for the first entry is used for the additional big block
543 * depot. (means we already used bigblocknr) */
544 memset(block,0x42,sizeof(block));
545 /* allocate this block (filled with 0x42) */
546 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
547 return bigblocknr+1;
551 /******************************************************************************
552 * STORAGE_get_free_small_blocknr [Internal]
554 static int
555 STORAGE_get_free_small_blocknr(HFILE hf) {
556 BYTE block[BIGSIZE];
557 LPINT sbd = (LPINT)block;
558 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
559 struct storage_pps_entry root;
560 struct storage_header sth;
562 READ_HEADER;
563 bigblocknr = sth.sbd_startblock;
564 curblock = 0;
565 lastbigblocknr = -1;
566 newblocknr = -1;
567 while (bigblocknr>=0) {
568 if (!STORAGE_get_big_block(hf,bigblocknr,block))
569 return -1;
570 for (i=0;i<128;i++)
571 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
572 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
573 newblocknr = i+curblock*128;
574 break;
576 if (i!=128)
577 break;
578 lastbigblocknr = bigblocknr;
579 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
580 curblock++;
582 if (newblocknr==-1) {
583 bigblocknr = STORAGE_get_free_big_blocknr(hf);
584 if (bigblocknr<0)
585 return -1;
586 READ_HEADER;
587 memset(block,0xff,sizeof(block));
588 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
589 if (!STORAGE_put_big_block(hf,bigblocknr,block))
590 return -1;
591 if (lastbigblocknr==-1) {
592 sth.sbd_startblock = bigblocknr;
593 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
594 return -1;
595 } else {
596 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
597 return -1;
599 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
600 return -1;
601 newblocknr = curblock*128;
603 /* allocate enough big blocks for storing the allocated small block */
604 if (!STORAGE_get_root_pps_entry(hf,&root))
605 return -1;
606 if (root.pps_sb==-1)
607 lastbigblocknr = -1;
608 else
609 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
610 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
611 /* we need to allocate more stuff */
612 bigblocknr = STORAGE_get_free_big_blocknr(hf);
613 if (bigblocknr<0)
614 return -1;
615 READ_HEADER;
616 if (root.pps_sb==-1) {
617 root.pps_sb = bigblocknr;
618 root.pps_size += BIGSIZE;
619 } else {
620 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
621 return -1;
622 root.pps_size += BIGSIZE;
624 lastbigblocknr = bigblocknr;
626 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
627 return -1;
628 if (!STORAGE_put_pps_entry(hf,0,&root))
629 return -1;
630 return newblocknr;
633 /******************************************************************************
634 * STORAGE_get_free_pps_entry [Internal]
636 static int
637 STORAGE_get_free_pps_entry(HFILE hf) {
638 int blocknr,i,curblock,lastblocknr;
639 BYTE block[BIGSIZE];
640 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
641 struct storage_header sth;
643 READ_HEADER;
644 blocknr = sth.root_startblock;
645 assert(blocknr>=0);
646 curblock=0;
647 while (blocknr>=0) {
648 if (!STORAGE_get_big_block(hf,blocknr,block))
649 return -1;
650 for (i=0;i<4;i++)
651 if (stde[i].pps_sizeofname==0) /* free */
652 return curblock*4+i;
653 lastblocknr = blocknr;
654 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
655 curblock++;
657 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
658 blocknr = STORAGE_get_free_big_blocknr(hf);
659 /* sth invalidated */
660 if (blocknr<0)
661 return -1;
663 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
664 return -1;
665 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
666 return -1;
667 memset(block,0,sizeof(block));
668 STORAGE_put_big_block(hf,blocknr,block);
669 return curblock*4;
672 /* --- IStream16 implementation */
674 typedef struct
676 /* IUnknown fields */
677 ICOM_VFIELD(IStream16);
678 DWORD ref;
679 /* IStream16 fields */
680 SEGPTR thisptr; /* pointer to this struct as segmented */
681 struct storage_pps_entry stde;
682 int ppsent;
683 HFILE hf;
684 ULARGE_INTEGER offset;
685 } IStream16Impl;
687 /******************************************************************************
688 * IStream16_QueryInterface [STORAGE.518]
690 HRESULT WINAPI IStream16_fnQueryInterface(
691 IStream16* iface,REFIID refiid,LPVOID *obj
693 ICOM_THIS(IStream16Impl,iface);
694 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
695 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
696 *obj = This;
697 return 0;
699 return OLE_E_ENUM_NOMORE;
703 /******************************************************************************
704 * IStream16_AddRef [STORAGE.519]
706 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
707 ICOM_THIS(IStream16Impl,iface);
708 return ++(This->ref);
711 /******************************************************************************
712 * IStream16_Release [STORAGE.520]
714 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
715 ICOM_THIS(IStream16Impl,iface);
716 FlushFileBuffers(This->hf);
717 This->ref--;
718 if (!This->ref) {
719 CloseHandle(This->hf);
720 SEGPTR_FREE(This);
721 return 0;
723 return This->ref;
726 /******************************************************************************
727 * IStream16_Seek [STORAGE.523]
729 * FIXME
730 * Does not handle 64 bits
732 HRESULT WINAPI IStream16_fnSeek(
733 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
735 ICOM_THIS(IStream16Impl,iface);
736 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
738 switch (whence) {
739 /* unix SEEK_xx should be the same as win95 ones */
740 case SEEK_SET:
741 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
742 * right now.
744 assert(offset.s.HighPart==0);
745 This->offset.s.HighPart = offset.s.HighPart;
746 This->offset.s.LowPart = offset.s.LowPart;
747 break;
748 case SEEK_CUR:
749 if (offset.s.HighPart < 0) {
750 /* FIXME: is this negation correct ? */
751 offset.s.HighPart = -offset.s.HighPart;
752 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
754 assert(offset.s.HighPart==0);
755 assert(This->offset.s.LowPart >= offset.s.LowPart);
756 This->offset.s.LowPart -= offset.s.LowPart;
757 } else {
758 assert(offset.s.HighPart==0);
759 This->offset.s.LowPart+= offset.s.LowPart;
761 break;
762 case SEEK_END:
763 assert(offset.s.HighPart==0);
764 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
765 break;
767 if (This->offset.s.LowPart>This->stde.pps_size)
768 This->offset.s.LowPart=This->stde.pps_size;
769 if (newpos) *newpos = This->offset;
770 return S_OK;
773 /******************************************************************************
774 * IStream16_Read [STORAGE.521]
776 HRESULT WINAPI IStream16_fnRead(
777 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
779 ICOM_THIS(IStream16Impl,iface);
780 BYTE block[BIGSIZE];
781 ULONG *bytesread=pcbRead,xxread;
782 int blocknr;
784 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
785 if (!pcbRead) bytesread=&xxread;
786 *bytesread = 0;
788 if (cb>This->stde.pps_size-This->offset.s.LowPart)
789 cb=This->stde.pps_size-This->offset.s.LowPart;
790 if (This->stde.pps_size < 0x1000) {
791 /* use small block reader */
792 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
793 while (cb) {
794 int cc;
796 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
797 WARN("small block read failed!!!\n");
798 return E_FAIL;
800 cc = cb;
801 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
802 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
803 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
804 This->offset.s.LowPart+=cc;
805 (LPBYTE)pv+=cc;
806 *bytesread+=cc;
807 cb-=cc;
808 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
810 } else {
811 /* use big block reader */
812 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
813 while (cb) {
814 int cc;
816 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
817 WARN("big block read failed!!!\n");
818 return E_FAIL;
820 cc = cb;
821 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
822 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
823 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
824 This->offset.s.LowPart+=cc;
825 (LPBYTE)pv+=cc;
826 *bytesread+=cc;
827 cb-=cc;
828 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
831 return S_OK;
834 /******************************************************************************
835 * IStream16_Write [STORAGE.522]
837 HRESULT WINAPI IStream16_fnWrite(
838 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
840 ICOM_THIS(IStream16Impl,iface);
841 BYTE block[BIGSIZE];
842 ULONG *byteswritten=pcbWrite,xxwritten;
843 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
844 HFILE hf = This->hf;
846 if (!pcbWrite) byteswritten=&xxwritten;
847 *byteswritten = 0;
849 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
850 /* do we need to junk some blocks? */
851 newsize = This->offset.s.LowPart+cb;
852 oldsize = This->stde.pps_size;
853 if (newsize < oldsize) {
854 if (oldsize < 0x1000) {
855 /* only small blocks */
856 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
858 assert(blocknr>=0);
860 /* will set the rest of the chain to 'free' */
861 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
862 return E_FAIL;
863 } else {
864 if (newsize >= 0x1000) {
865 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
866 assert(blocknr>=0);
868 /* will set the rest of the chain to 'free' */
869 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
870 return E_FAIL;
871 } else {
872 /* Migrate large blocks to small blocks
873 * (we just migrate newsize bytes)
875 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
876 cc = newsize;
877 blocknr = This->stde.pps_sb;
878 curdata = data;
879 while (cc>0) {
880 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
881 HeapFree(GetProcessHeap(),0,data);
882 return E_FAIL;
884 curdata += BIGSIZE;
885 cc -= BIGSIZE;
886 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
888 /* frees complete chain for this stream */
889 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
890 return E_FAIL;
891 curdata = data;
892 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
893 if (blocknr<0)
894 return E_FAIL;
895 cc = newsize;
896 while (cc>0) {
897 if (!STORAGE_put_small_block(hf,blocknr,curdata))
898 return E_FAIL;
899 cc -= SMALLSIZE;
900 if (cc<=0) {
901 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
902 return E_FAIL;
903 break;
904 } else {
905 int newblocknr = STORAGE_get_free_small_blocknr(hf);
906 if (newblocknr<0)
907 return E_FAIL;
908 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
909 return E_FAIL;
910 blocknr = newblocknr;
912 curdata += SMALLSIZE;
914 HeapFree(GetProcessHeap(),0,data);
917 This->stde.pps_size = newsize;
920 if (newsize > oldsize) {
921 if (oldsize >= 0x1000) {
922 /* should return the block right before the 'endofchain' */
923 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
924 assert(blocknr>=0);
925 lastblocknr = blocknr;
926 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
927 blocknr = STORAGE_get_free_big_blocknr(hf);
928 if (blocknr<0)
929 return E_FAIL;
930 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
931 return E_FAIL;
932 lastblocknr = blocknr;
934 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
935 return E_FAIL;
936 } else {
937 if (newsize < 0x1000) {
938 /* find startblock */
939 if (!oldsize)
940 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
941 else
942 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
943 if (blocknr<0)
944 return E_FAIL;
946 /* allocate required new small blocks */
947 lastblocknr = blocknr;
948 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
949 blocknr = STORAGE_get_free_small_blocknr(hf);
950 if (blocknr<0)
951 return E_FAIL;
952 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
953 return E_FAIL;
954 lastblocknr = blocknr;
956 /* and terminate the chain */
957 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
958 return E_FAIL;
959 } else {
960 if (!oldsize) {
961 /* no single block allocated yet */
962 blocknr=STORAGE_get_free_big_blocknr(hf);
963 if (blocknr<0)
964 return E_FAIL;
965 This->stde.pps_sb = blocknr;
966 } else {
967 /* Migrate small blocks to big blocks */
968 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
969 cc = oldsize;
970 blocknr = This->stde.pps_sb;
971 curdata = data;
972 /* slurp in */
973 while (cc>0) {
974 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
975 HeapFree(GetProcessHeap(),0,data);
976 return E_FAIL;
978 curdata += SMALLSIZE;
979 cc -= SMALLSIZE;
980 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
982 /* free small block chain */
983 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
984 return E_FAIL;
985 curdata = data;
986 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
987 if (blocknr<0)
988 return E_FAIL;
989 /* put the data into the big blocks */
990 cc = This->stde.pps_size;
991 while (cc>0) {
992 if (!STORAGE_put_big_block(hf,blocknr,curdata))
993 return E_FAIL;
994 cc -= BIGSIZE;
995 if (cc<=0) {
996 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
997 return E_FAIL;
998 break;
999 } else {
1000 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1001 if (newblocknr<0)
1002 return E_FAIL;
1003 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1004 return E_FAIL;
1005 blocknr = newblocknr;
1007 curdata += BIGSIZE;
1009 HeapFree(GetProcessHeap(),0,data);
1011 /* generate big blocks to fit the new data */
1012 lastblocknr = blocknr;
1013 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1014 blocknr = STORAGE_get_free_big_blocknr(hf);
1015 if (blocknr<0)
1016 return E_FAIL;
1017 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1018 return E_FAIL;
1019 lastblocknr = blocknr;
1021 /* terminate chain */
1022 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1023 return E_FAIL;
1026 This->stde.pps_size = newsize;
1029 /* There are just some cases where we didn't modify it, we write it out
1030 * everytime
1032 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1033 return E_FAIL;
1035 /* finally the write pass */
1036 if (This->stde.pps_size < 0x1000) {
1037 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1038 assert(blocknr>=0);
1039 while (cb>0) {
1040 /* we ensured that it is allocated above */
1041 assert(blocknr>=0);
1042 /* Read old block everytime, since we can have
1043 * overlapping data at START and END of the write
1045 if (!STORAGE_get_small_block(hf,blocknr,block))
1046 return E_FAIL;
1048 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1049 if (cc>cb)
1050 cc=cb;
1051 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1052 (LPBYTE)((char *) pv+curoffset),
1055 if (!STORAGE_put_small_block(hf,blocknr,block))
1056 return E_FAIL;
1057 cb -= cc;
1058 curoffset += cc;
1059 (LPBYTE)pv += cc;
1060 This->offset.s.LowPart += cc;
1061 *byteswritten += cc;
1062 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1064 } else {
1065 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1066 assert(blocknr>=0);
1067 while (cb>0) {
1068 /* we ensured that it is allocated above, so it better is */
1069 assert(blocknr>=0);
1070 /* read old block everytime, since we can have
1071 * overlapping data at START and END of the write
1073 if (!STORAGE_get_big_block(hf,blocknr,block))
1074 return E_FAIL;
1076 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1077 if (cc>cb)
1078 cc=cb;
1079 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1080 (LPBYTE)((char *) pv+curoffset),
1083 if (!STORAGE_put_big_block(hf,blocknr,block))
1084 return E_FAIL;
1085 cb -= cc;
1086 curoffset += cc;
1087 (LPBYTE)pv += cc;
1088 This->offset.s.LowPart += cc;
1089 *byteswritten += cc;
1090 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1093 return S_OK;
1096 /******************************************************************************
1097 * _create_istream16 [Internal]
1099 static void _create_istream16(LPSTREAM16 *str) {
1100 IStream16Impl* lpst;
1102 if (!strvt16.fnQueryInterface) {
1103 HMODULE16 wp = GetModuleHandle16("STORAGE");
1104 if (wp>=32) {
1105 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1106 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1107 VTENT(QueryInterface);
1108 VTENT(AddRef);
1109 VTENT(Release);
1110 VTENT(Read);
1111 VTENT(Write);
1112 VTENT(Seek);
1113 VTENT(SetSize);
1114 VTENT(CopyTo);
1115 VTENT(Commit);
1116 VTENT(Revert);
1117 VTENT(LockRegion);
1118 VTENT(UnlockRegion);
1119 VTENT(Stat);
1120 VTENT(Clone);
1121 #undef VTENT
1122 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1123 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1124 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1125 } else {
1126 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1127 VTENT(QueryInterface);
1128 VTENT(AddRef);
1129 VTENT(Release);
1130 VTENT(Read);
1131 VTENT(Write);
1132 VTENT(Seek);
1134 VTENT(CopyTo);
1135 VTENT(Commit);
1136 VTENT(SetSize);
1137 VTENT(Revert);
1138 VTENT(LockRegion);
1139 VTENT(UnlockRegion);
1140 VTENT(Stat);
1141 VTENT(Clone);
1143 #undef VTENT
1144 segstrvt16 = &strvt16;
1147 lpst = SEGPTR_NEW(IStream16Impl);
1148 ICOM_VTBL(lpst) = segstrvt16;
1149 lpst->ref = 1;
1150 lpst->thisptr = SEGPTR_GET(lpst);
1151 *str = (void*)lpst->thisptr;
1155 /* --- IStream32 implementation */
1157 typedef struct
1159 /* IUnknown fields */
1160 ICOM_VFIELD(IStream);
1161 DWORD ref;
1162 /* IStream32 fields */
1163 struct storage_pps_entry stde;
1164 int ppsent;
1165 HFILE hf;
1166 ULARGE_INTEGER offset;
1167 } IStream32Impl;
1169 /*****************************************************************************
1170 * IStream32_QueryInterface [VTABLE]
1172 HRESULT WINAPI IStream_fnQueryInterface(
1173 IStream* iface,REFIID refiid,LPVOID *obj
1175 ICOM_THIS(IStream32Impl,iface);
1177 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1178 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1179 *obj = This;
1180 return 0;
1182 return OLE_E_ENUM_NOMORE;
1186 /******************************************************************************
1187 * IStream32_AddRef [VTABLE]
1189 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1190 ICOM_THIS(IStream32Impl,iface);
1191 return ++(This->ref);
1194 /******************************************************************************
1195 * IStream32_Release [VTABLE]
1197 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1198 ICOM_THIS(IStream32Impl,iface);
1199 FlushFileBuffers(This->hf);
1200 This->ref--;
1201 if (!This->ref) {
1202 CloseHandle(This->hf);
1203 SEGPTR_FREE(This);
1204 return 0;
1206 return This->ref;
1209 /* --- IStorage16 implementation */
1211 typedef struct
1213 /* IUnknown fields */
1214 ICOM_VFIELD(IStorage16);
1215 DWORD ref;
1216 /* IStorage16 fields */
1217 SEGPTR thisptr; /* pointer to this struct as segmented */
1218 struct storage_pps_entry stde;
1219 int ppsent;
1220 HFILE hf;
1221 } IStorage16Impl;
1223 /******************************************************************************
1224 * IStorage16_QueryInterface [STORAGE.500]
1226 HRESULT WINAPI IStorage16_fnQueryInterface(
1227 IStorage16* iface,REFIID refiid,LPVOID *obj
1229 ICOM_THIS(IStorage16Impl,iface);
1231 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1233 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1234 *obj = This;
1235 return 0;
1237 return OLE_E_ENUM_NOMORE;
1240 /******************************************************************************
1241 * IStorage16_AddRef [STORAGE.501]
1243 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1244 ICOM_THIS(IStorage16Impl,iface);
1245 return ++(This->ref);
1248 /******************************************************************************
1249 * IStorage16_Release [STORAGE.502]
1251 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1252 ICOM_THIS(IStorage16Impl,iface);
1253 This->ref--;
1254 if (This->ref)
1255 return This->ref;
1256 SEGPTR_FREE(This);
1257 return 0;
1260 /******************************************************************************
1261 * IStorage16_Stat [STORAGE.517]
1263 HRESULT WINAPI IStorage16_fnStat(
1264 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1266 ICOM_THIS(IStorage16Impl,iface);
1267 TRACE("(%p)->(%p,0x%08lx)\n",
1268 This,pstatstg,grfStatFlag
1270 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1271 pstatstg->type = This->stde.pps_type;
1272 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1273 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1274 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1275 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1276 pstatstg->grfMode = 0; /* FIXME */
1277 pstatstg->grfLocksSupported = 0; /* FIXME */
1278 pstatstg->clsid = This->stde.pps_guid;
1279 pstatstg->grfStateBits = 0; /* FIXME */
1280 pstatstg->reserved = 0;
1281 return S_OK;
1284 /******************************************************************************
1285 * IStorage16_Commit [STORAGE.509]
1287 HRESULT WINAPI IStorage16_fnCommit(
1288 LPSTORAGE16 iface,DWORD commitflags
1290 ICOM_THIS(IStorage16Impl,iface);
1291 FIXME("(%p)->(0x%08lx),STUB!\n",
1292 This,commitflags
1294 return S_OK;
1297 /******************************************************************************
1298 * IStorage16_CopyTo [STORAGE.507]
1300 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1301 ICOM_THIS(IStorage16Impl,iface);
1302 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1303 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1305 return S_OK;
1309 /******************************************************************************
1310 * IStorage16_CreateStorage [STORAGE.505]
1312 HRESULT WINAPI IStorage16_fnCreateStorage(
1313 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1315 ICOM_THIS(IStorage16Impl,iface);
1316 IStorage16Impl* lpstg;
1317 int ppsent,x;
1318 struct storage_pps_entry stde;
1319 struct storage_header sth;
1320 HFILE hf=This->hf;
1322 READ_HEADER;
1324 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1325 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1327 if (grfMode & STGM_TRANSACTED)
1328 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1329 _create_istorage16(ppstg);
1330 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1331 lpstg->hf = This->hf;
1333 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1334 if (ppsent<0)
1335 return E_FAIL;
1336 stde=This->stde;
1337 if (stde.pps_dir==-1) {
1338 stde.pps_dir = ppsent;
1339 x = This->ppsent;
1340 } else {
1341 FIXME(" use prev chain too ?\n");
1342 x=stde.pps_dir;
1343 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1344 return E_FAIL;
1345 while (stde.pps_next!=-1) {
1346 x=stde.pps_next;
1347 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1348 return E_FAIL;
1350 stde.pps_next = ppsent;
1352 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1353 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1354 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1355 lpstg->stde.pps_sizeofname = strlen(pwcsName)*2+2;
1356 lpstg->stde.pps_next = -1;
1357 lpstg->stde.pps_prev = -1;
1358 lpstg->stde.pps_dir = -1;
1359 lpstg->stde.pps_sb = -1;
1360 lpstg->stde.pps_size = 0;
1361 lpstg->stde.pps_type = 1;
1362 lpstg->ppsent = ppsent;
1363 /* FIXME: timestamps? */
1364 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1365 return E_FAIL;
1366 return S_OK;
1369 /******************************************************************************
1370 * IStorage16_CreateStream [STORAGE.503]
1372 HRESULT WINAPI IStorage16_fnCreateStream(
1373 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1375 ICOM_THIS(IStorage16Impl,iface);
1376 IStream16Impl* lpstr;
1377 int ppsent,x;
1378 struct storage_pps_entry stde;
1380 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1381 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1383 if (grfMode & STGM_TRANSACTED)
1384 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1385 _create_istream16(ppstm);
1386 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1387 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1388 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1389 lpstr->offset.s.LowPart = 0;
1390 lpstr->offset.s.HighPart = 0;
1392 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1393 if (ppsent<0)
1394 return E_FAIL;
1395 stde=This->stde;
1396 if (stde.pps_next==-1)
1397 x=This->ppsent;
1398 else
1399 while (stde.pps_next!=-1) {
1400 x=stde.pps_next;
1401 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1402 return E_FAIL;
1404 stde.pps_next = ppsent;
1405 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1406 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1407 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1408 lpstr->stde.pps_sizeofname = strlen(pwcsName)*2+2;
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 = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1440 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1441 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1442 lstrcpyAtoW(name,pwcsName);
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 = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1475 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1476 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1477 lstrcpyAtoW(name,pwcsName);
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.fnQueryInterface) {
1501 HMODULE16 wp = GetModuleHandle16("STORAGE");
1502 if (wp>=32) {
1503 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_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.fn##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 = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1584 lpstg->hf = hf;
1585 /* FIXME: check for existance 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 = (IStorage16Impl*)PTR_SEG_TO_LIN(*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;