Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine.git] / ole / storage.c
blobd1dcc4a2480e885d2064e3bf345f12da88a57d98
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 "windef.h"
14 #include "winerror.h"
15 #include "wine/winestring.h"
16 #include "wine/winbase16.h"
17 #include "file.h"
18 #include "ole.h"
19 #include "wine/obj_base.h"
20 #include "wine/obj_storage.h"
21 #include "heap.h"
22 #include "module.h"
23 #include "ldt.h"
24 #include "debugtools.h"
26 DECLARE_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_(ole)(" 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_(ole)("(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_(ole)(" 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_(ole)(" 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],xguid[50];
361 WINE_StringFromCLSID(&(stde->pps_guid),xguid);
363 lstrcpyWtoA(name,stde->pps_rawname);
364 if (!stde->pps_sizeofname)
365 return;
366 DPRINTF("name: %s\n",name);
367 DPRINTF("type: %d\n",stde->pps_type);
368 DPRINTF("prev pps: %ld\n",stde->pps_prev);
369 DPRINTF("next pps: %ld\n",stde->pps_next);
370 DPRINTF("dir pps: %ld\n",stde->pps_dir);
371 DPRINTF("guid: %s\n",xguid);
372 if (stde->pps_type !=2) {
373 time_t t;
375 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft1),NULL);
376 DPRINTF("ts1: %s\n",ctime(&t));
377 t = DOSFS_FileTimeToUnixTime(&(stde->pps_ft2),NULL);
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 lstrcpyAtoW(stde->pps_rawname,"RootEntry");
417 stde->pps_sizeofname = lstrlenW(stde->pps_rawname)*2+2;
418 stde->pps_type = 5;
419 stde->pps_dir = -1;
420 stde->pps_next = -1;
421 stde->pps_prev = -1;
422 stde->pps_sb = 0xffffffff;
423 stde->pps_size = 0;
424 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
425 return TRUE;
428 /******************************************************************************
429 * STORAGE_set_big_chain [Internal]
431 static BOOL
432 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
433 BYTE block[BIGSIZE];
434 LPINT bbd = (LPINT)block;
435 int nextblocknr,bigblocknr;
436 struct storage_header sth;
438 READ_HEADER;
439 assert(blocknr!=type);
440 while (blocknr>=0) {
441 bigblocknr = sth.bbd_list[blocknr/128];
442 assert(bigblocknr>=0);
443 assert(STORAGE_get_big_block(hf,bigblocknr,block));
445 nextblocknr = bbd[blocknr&(128-1)];
446 bbd[blocknr&(128-1)] = type;
447 if (type>=0)
448 return TRUE;
449 assert(STORAGE_put_big_block(hf,bigblocknr,block));
450 type = STORAGE_CHAINENTRY_FREE;
451 blocknr = nextblocknr;
453 return TRUE;
456 /******************************************************************************
457 * STORAGE_set_small_chain [Internal]
459 static BOOL
460 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
461 BYTE block[BIGSIZE];
462 LPINT sbd = (LPINT)block;
463 int lastblocknr,nextsmallblocknr,bigblocknr;
464 struct storage_header sth;
466 READ_HEADER;
468 assert(blocknr!=type);
469 lastblocknr=-129;bigblocknr=-2;
470 while (blocknr>=0) {
471 /* cache block ... */
472 if (lastblocknr/128!=blocknr/128) {
473 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
474 assert(bigblocknr>=0);
475 assert(STORAGE_get_big_block(hf,bigblocknr,block));
477 lastblocknr = blocknr;
478 nextsmallblocknr = sbd[blocknr&(128-1)];
479 sbd[blocknr&(128-1)] = type;
480 assert(STORAGE_put_big_block(hf,bigblocknr,block));
481 if (type>=0)
482 return TRUE;
483 type = STORAGE_CHAINENTRY_FREE;
484 blocknr = nextsmallblocknr;
486 return TRUE;
489 /******************************************************************************
490 * STORAGE_get_free_big_blocknr [Internal]
492 static int
493 STORAGE_get_free_big_blocknr(HFILE hf) {
494 BYTE block[BIGSIZE];
495 LPINT sbd = (LPINT)block;
496 int lastbigblocknr,i,curblock,bigblocknr;
497 struct storage_header sth;
499 READ_HEADER;
500 curblock = 0;
501 lastbigblocknr = -1;
502 bigblocknr = sth.bbd_list[curblock];
503 while (curblock<sth.num_of_bbd_blocks) {
504 assert(bigblocknr>=0);
505 assert(STORAGE_get_big_block(hf,bigblocknr,block));
506 for (i=0;i<128;i++)
507 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
508 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
509 assert(STORAGE_put_big_block(hf,bigblocknr,block));
510 memset(block,0x42,sizeof(block));
511 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
512 return i+curblock*128;
514 lastbigblocknr = bigblocknr;
515 bigblocknr = sth.bbd_list[++curblock];
517 bigblocknr = curblock*128;
518 /* since we have marked all blocks from 0 up to curblock*128-1
519 * the next free one is curblock*128, where we happily put our
520 * next large block depot.
522 memset(block,0xff,sizeof(block));
523 /* mark the block allocated and returned by this function */
524 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
525 assert(STORAGE_put_big_block(hf,bigblocknr,block));
527 /* if we had a bbd block already (mostlikely) we need
528 * to link the new one into the chain
530 if (lastbigblocknr!=-1)
531 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
532 sth.bbd_list[curblock]=bigblocknr;
533 sth.num_of_bbd_blocks++;
534 assert(sth.num_of_bbd_blocks==curblock+1);
535 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
537 /* Set the end of the chain for the bigblockdepots */
538 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
539 /* add 1, for the first entry is used for the additional big block
540 * depot. (means we already used bigblocknr) */
541 memset(block,0x42,sizeof(block));
542 /* allocate this block (filled with 0x42) */
543 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
544 return bigblocknr+1;
548 /******************************************************************************
549 * STORAGE_get_free_small_blocknr [Internal]
551 static int
552 STORAGE_get_free_small_blocknr(HFILE hf) {
553 BYTE block[BIGSIZE];
554 LPINT sbd = (LPINT)block;
555 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
556 struct storage_pps_entry root;
557 struct storage_header sth;
559 READ_HEADER;
560 bigblocknr = sth.sbd_startblock;
561 curblock = 0;
562 lastbigblocknr = -1;
563 newblocknr = -1;
564 while (bigblocknr>=0) {
565 if (!STORAGE_get_big_block(hf,bigblocknr,block))
566 return -1;
567 for (i=0;i<128;i++)
568 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
569 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
570 newblocknr = i+curblock*128;
571 break;
573 if (i!=128)
574 break;
575 lastbigblocknr = bigblocknr;
576 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
577 curblock++;
579 if (newblocknr==-1) {
580 bigblocknr = STORAGE_get_free_big_blocknr(hf);
581 if (bigblocknr<0)
582 return -1;
583 READ_HEADER;
584 memset(block,0xff,sizeof(block));
585 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
586 if (!STORAGE_put_big_block(hf,bigblocknr,block))
587 return -1;
588 if (lastbigblocknr==-1) {
589 sth.sbd_startblock = bigblocknr;
590 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
591 return -1;
592 } else {
593 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
594 return -1;
596 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
597 return -1;
598 newblocknr = curblock*128;
600 /* allocate enough big blocks for storing the allocated small block */
601 if (!STORAGE_get_root_pps_entry(hf,&root))
602 return -1;
603 if (root.pps_sb==-1)
604 lastbigblocknr = -1;
605 else
606 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
607 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
608 /* we need to allocate more stuff */
609 bigblocknr = STORAGE_get_free_big_blocknr(hf);
610 if (bigblocknr<0)
611 return -1;
612 READ_HEADER;
613 if (root.pps_sb==-1) {
614 root.pps_sb = bigblocknr;
615 root.pps_size += BIGSIZE;
616 } else {
617 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
618 return -1;
619 root.pps_size += BIGSIZE;
621 lastbigblocknr = bigblocknr;
623 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
624 return -1;
625 if (!STORAGE_put_pps_entry(hf,0,&root))
626 return -1;
627 return newblocknr;
630 /******************************************************************************
631 * STORAGE_get_free_pps_entry [Internal]
633 static int
634 STORAGE_get_free_pps_entry(HFILE hf) {
635 int blocknr,i,curblock,lastblocknr;
636 BYTE block[BIGSIZE];
637 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
638 struct storage_header sth;
640 READ_HEADER;
641 blocknr = sth.root_startblock;
642 assert(blocknr>=0);
643 curblock=0;
644 while (blocknr>=0) {
645 if (!STORAGE_get_big_block(hf,blocknr,block))
646 return -1;
647 for (i=0;i<4;i++)
648 if (stde[i].pps_sizeofname==0) /* free */
649 return curblock*4+i;
650 lastblocknr = blocknr;
651 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
652 curblock++;
654 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
655 blocknr = STORAGE_get_free_big_blocknr(hf);
656 /* sth invalidated */
657 if (blocknr<0)
658 return -1;
660 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
661 return -1;
662 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
663 return -1;
664 memset(block,0,sizeof(block));
665 STORAGE_put_big_block(hf,blocknr,block);
666 return curblock*4;
669 /* --- IStream16 implementation */
671 typedef struct
673 /* IUnknown fields */
674 ICOM_VTABLE(IStream16)* lpvtbl;
675 DWORD ref;
676 /* IStream16 fields */
677 SEGPTR thisptr; /* pointer to this struct as segmented */
678 struct storage_pps_entry stde;
679 int ppsent;
680 HFILE hf;
681 ULARGE_INTEGER offset;
682 } IStream16Impl;
684 /******************************************************************************
685 * IStream16_QueryInterface [STORAGE.518]
687 HRESULT WINAPI IStream16_fnQueryInterface(
688 IStream16* iface,REFIID refiid,LPVOID *obj
690 ICOM_THIS(IStream16Impl,iface);
691 char xrefiid[50];
692 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
693 TRACE_(relay)("(%p)->(%s,%p)\n",This,xrefiid,obj);
694 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
695 *obj = This;
696 return 0;
698 return OLE_E_ENUM_NOMORE;
702 /******************************************************************************
703 * IStream16_AddRef [STORAGE.519]
705 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
706 ICOM_THIS(IStream16Impl,iface);
707 return ++(This->ref);
710 /******************************************************************************
711 * IStream16_Release [STORAGE.520]
713 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
714 ICOM_THIS(IStream16Impl,iface);
715 FlushFileBuffers(This->hf);
716 This->ref--;
717 if (!This->ref) {
718 CloseHandle(This->hf);
719 SEGPTR_FREE(This);
720 return 0;
722 return This->ref;
725 /******************************************************************************
726 * IStream16_Seek [STORAGE.523]
728 * FIXME
729 * Does not handle 64 bits
731 HRESULT WINAPI IStream16_fnSeek(
732 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
734 ICOM_THIS(IStream16Impl,iface);
735 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.HighPart,offset.LowPart,whence,newpos);
737 switch (whence) {
738 /* unix SEEK_xx should be the same as win95 ones */
739 case SEEK_SET:
740 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
741 * right now.
743 assert(offset.HighPart==0);
744 This->offset.HighPart = offset.HighPart;
745 This->offset.LowPart = offset.LowPart;
746 break;
747 case SEEK_CUR:
748 if (offset.HighPart < 0) {
749 /* FIXME: is this negation correct ? */
750 offset.HighPart = -offset.HighPart;
751 offset.LowPart = (0xffffffff ^ offset.LowPart)+1;
753 assert(offset.HighPart==0);
754 assert(This->offset.LowPart >= offset.LowPart);
755 This->offset.LowPart -= offset.LowPart;
756 } else {
757 assert(offset.HighPart==0);
758 This->offset.LowPart+= offset.LowPart;
760 break;
761 case SEEK_END:
762 assert(offset.HighPart==0);
763 This->offset.LowPart = This->stde.pps_size-offset.LowPart;
764 break;
766 if (This->offset.LowPart>This->stde.pps_size)
767 This->offset.LowPart=This->stde.pps_size;
768 if (newpos) *newpos = This->offset;
769 return S_OK;
772 /******************************************************************************
773 * IStream16_Read [STORAGE.521]
775 HRESULT WINAPI IStream16_fnRead(
776 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
778 ICOM_THIS(IStream16Impl,iface);
779 BYTE block[BIGSIZE];
780 ULONG *bytesread=pcbRead,xxread;
781 int blocknr;
783 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
784 if (!pcbRead) bytesread=&xxread;
785 *bytesread = 0;
787 if (cb>This->stde.pps_size-This->offset.LowPart)
788 cb=This->stde.pps_size-This->offset.LowPart;
789 if (This->stde.pps_size < 0x1000) {
790 /* use small block reader */
791 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
792 while (cb) {
793 int cc;
795 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
796 WARN_(ole)("small block read failed!!!\n");
797 return E_FAIL;
799 cc = cb;
800 if (cc>SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1)))
801 cc=SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
802 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(SMALLSIZE-1)),cc);
803 This->offset.LowPart+=cc;
804 (LPBYTE)pv+=cc;
805 *bytesread+=cc;
806 cb-=cc;
807 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
809 } else {
810 /* use big block reader */
811 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
812 while (cb) {
813 int cc;
815 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
816 WARN_(ole)("big block read failed!!!\n");
817 return E_FAIL;
819 cc = cb;
820 if (cc>BIGSIZE-(This->offset.LowPart&(BIGSIZE-1)))
821 cc=BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
822 memcpy((LPBYTE)pv,block+(This->offset.LowPart&(BIGSIZE-1)),cc);
823 This->offset.LowPart+=cc;
824 (LPBYTE)pv+=cc;
825 *bytesread+=cc;
826 cb-=cc;
827 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
830 return S_OK;
833 /******************************************************************************
834 * IStream16_Write [STORAGE.522]
836 HRESULT WINAPI IStream16_fnWrite(
837 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
839 ICOM_THIS(IStream16Impl,iface);
840 BYTE block[BIGSIZE];
841 ULONG *byteswritten=pcbWrite,xxwritten;
842 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
843 HFILE hf = This->hf;
845 if (!pcbWrite) byteswritten=&xxwritten;
846 *byteswritten = 0;
848 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
849 /* do we need to junk some blocks? */
850 newsize = This->offset.LowPart+cb;
851 oldsize = This->stde.pps_size;
852 if (newsize < oldsize) {
853 if (oldsize < 0x1000) {
854 /* only small blocks */
855 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
857 assert(blocknr>=0);
859 /* will set the rest of the chain to 'free' */
860 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
861 return E_FAIL;
862 } else {
863 if (newsize >= 0x1000) {
864 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
865 assert(blocknr>=0);
867 /* will set the rest of the chain to 'free' */
868 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
869 return E_FAIL;
870 } else {
871 /* Migrate large blocks to small blocks
872 * (we just migrate newsize bytes)
874 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
875 cc = newsize;
876 blocknr = This->stde.pps_sb;
877 curdata = data;
878 while (cc>0) {
879 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
880 HeapFree(GetProcessHeap(),0,data);
881 return E_FAIL;
883 curdata += BIGSIZE;
884 cc -= BIGSIZE;
885 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
887 /* frees complete chain for this stream */
888 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
889 return E_FAIL;
890 curdata = data;
891 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
892 if (blocknr<0)
893 return E_FAIL;
894 cc = newsize;
895 while (cc>0) {
896 if (!STORAGE_put_small_block(hf,blocknr,curdata))
897 return E_FAIL;
898 cc -= SMALLSIZE;
899 if (cc<=0) {
900 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
901 return E_FAIL;
902 break;
903 } else {
904 int newblocknr = STORAGE_get_free_small_blocknr(hf);
905 if (newblocknr<0)
906 return E_FAIL;
907 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
908 return E_FAIL;
909 blocknr = newblocknr;
911 curdata += SMALLSIZE;
913 HeapFree(GetProcessHeap(),0,data);
916 This->stde.pps_size = newsize;
919 if (newsize > oldsize) {
920 if (oldsize >= 0x1000) {
921 /* should return the block right before the 'endofchain' */
922 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
923 assert(blocknr>=0);
924 lastblocknr = blocknr;
925 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
926 blocknr = STORAGE_get_free_big_blocknr(hf);
927 if (blocknr<0)
928 return E_FAIL;
929 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
930 return E_FAIL;
931 lastblocknr = blocknr;
933 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
934 return E_FAIL;
935 } else {
936 if (newsize < 0x1000) {
937 /* find startblock */
938 if (!oldsize)
939 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
940 else
941 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
942 if (blocknr<0)
943 return E_FAIL;
945 /* allocate required new small blocks */
946 lastblocknr = blocknr;
947 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
948 blocknr = STORAGE_get_free_small_blocknr(hf);
949 if (blocknr<0)
950 return E_FAIL;
951 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
952 return E_FAIL;
953 lastblocknr = blocknr;
955 /* and terminate the chain */
956 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
957 return E_FAIL;
958 } else {
959 if (!oldsize) {
960 /* no single block allocated yet */
961 blocknr=STORAGE_get_free_big_blocknr(hf);
962 if (blocknr<0)
963 return E_FAIL;
964 This->stde.pps_sb = blocknr;
965 } else {
966 /* Migrate small blocks to big blocks */
967 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
968 cc = oldsize;
969 blocknr = This->stde.pps_sb;
970 curdata = data;
971 /* slurp in */
972 while (cc>0) {
973 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
974 HeapFree(GetProcessHeap(),0,data);
975 return E_FAIL;
977 curdata += SMALLSIZE;
978 cc -= SMALLSIZE;
979 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
981 /* free small block chain */
982 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
983 return E_FAIL;
984 curdata = data;
985 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
986 if (blocknr<0)
987 return E_FAIL;
988 /* put the data into the big blocks */
989 cc = This->stde.pps_size;
990 while (cc>0) {
991 if (!STORAGE_put_big_block(hf,blocknr,curdata))
992 return E_FAIL;
993 cc -= BIGSIZE;
994 if (cc<=0) {
995 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
996 return E_FAIL;
997 break;
998 } else {
999 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1000 if (newblocknr<0)
1001 return E_FAIL;
1002 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1003 return E_FAIL;
1004 blocknr = newblocknr;
1006 curdata += BIGSIZE;
1008 HeapFree(GetProcessHeap(),0,data);
1010 /* generate big blocks to fit the new data */
1011 lastblocknr = blocknr;
1012 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1013 blocknr = STORAGE_get_free_big_blocknr(hf);
1014 if (blocknr<0)
1015 return E_FAIL;
1016 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1017 return E_FAIL;
1018 lastblocknr = blocknr;
1020 /* terminate chain */
1021 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1022 return E_FAIL;
1025 This->stde.pps_size = newsize;
1028 /* There are just some cases where we didn't modify it, we write it out
1029 * everytime
1031 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1032 return E_FAIL;
1034 /* finally the write pass */
1035 if (This->stde.pps_size < 0x1000) {
1036 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/SMALLSIZE);
1037 assert(blocknr>=0);
1038 while (cb>0) {
1039 /* we ensured that it is allocated above */
1040 assert(blocknr>=0);
1041 /* Read old block everytime, since we can have
1042 * overlapping data at START and END of the write
1044 if (!STORAGE_get_small_block(hf,blocknr,block))
1045 return E_FAIL;
1047 cc = SMALLSIZE-(This->offset.LowPart&(SMALLSIZE-1));
1048 if (cc>cb)
1049 cc=cb;
1050 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(SMALLSIZE-1)),
1051 (LPBYTE)((char *) pv+curoffset),
1054 if (!STORAGE_put_small_block(hf,blocknr,block))
1055 return E_FAIL;
1056 cb -= cc;
1057 curoffset += cc;
1058 (LPBYTE)pv += cc;
1059 This->offset.LowPart += cc;
1060 *byteswritten += cc;
1061 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1063 } else {
1064 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.LowPart/BIGSIZE);
1065 assert(blocknr>=0);
1066 while (cb>0) {
1067 /* we ensured that it is allocated above, so it better is */
1068 assert(blocknr>=0);
1069 /* read old block everytime, since we can have
1070 * overlapping data at START and END of the write
1072 if (!STORAGE_get_big_block(hf,blocknr,block))
1073 return E_FAIL;
1075 cc = BIGSIZE-(This->offset.LowPart&(BIGSIZE-1));
1076 if (cc>cb)
1077 cc=cb;
1078 memcpy( ((LPBYTE)block)+(This->offset.LowPart&(BIGSIZE-1)),
1079 (LPBYTE)((char *) pv+curoffset),
1082 if (!STORAGE_put_big_block(hf,blocknr,block))
1083 return E_FAIL;
1084 cb -= cc;
1085 curoffset += cc;
1086 (LPBYTE)pv += cc;
1087 This->offset.LowPart += cc;
1088 *byteswritten += cc;
1089 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1092 return S_OK;
1095 /******************************************************************************
1096 * _create_istream16 [Internal]
1098 static void _create_istream16(LPSTREAM16 *str) {
1099 IStream16Impl* lpst;
1101 if (!strvt16.fnQueryInterface) {
1102 HMODULE16 wp = GetModuleHandle16("STORAGE");
1103 if (wp>=32) {
1104 /* FIXME: what is This WIN32_GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1105 #define VTENT(xfn) strvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.fn##xfn)
1106 VTENT(QueryInterface);
1107 VTENT(AddRef);
1108 VTENT(Release);
1109 VTENT(Read);
1110 VTENT(Write);
1111 VTENT(Seek);
1112 VTENT(SetSize);
1113 VTENT(CopyTo);
1114 VTENT(Commit);
1115 VTENT(Revert);
1116 VTENT(LockRegion);
1117 VTENT(UnlockRegion);
1118 VTENT(Stat);
1119 VTENT(Clone);
1120 #undef VTENT
1121 segstrvt16 = SEGPTR_NEW(ICOM_VTABLE(IStream16));
1122 memcpy(segstrvt16,&strvt16,sizeof(strvt16));
1123 segstrvt16 = (ICOM_VTABLE(IStream16)*)SEGPTR_GET(segstrvt16);
1124 } else {
1125 #define VTENT(xfn) strvt16.fn##xfn = IStream16_fn##xfn;
1126 VTENT(QueryInterface);
1127 VTENT(AddRef);
1128 VTENT(Release);
1129 VTENT(Read);
1130 VTENT(Write);
1131 VTENT(Seek);
1133 VTENT(CopyTo);
1134 VTENT(Commit);
1135 VTENT(SetSize);
1136 VTENT(Revert);
1137 VTENT(LockRegion);
1138 VTENT(UnlockRegion);
1139 VTENT(Stat);
1140 VTENT(Clone);
1142 #undef VTENT
1143 segstrvt16 = &strvt16;
1146 lpst = SEGPTR_NEW(IStream16Impl);
1147 lpst->lpvtbl = segstrvt16;
1148 lpst->ref = 1;
1149 lpst->thisptr = SEGPTR_GET(lpst);
1150 *str = (void*)lpst->thisptr;
1154 /* --- IStream32 implementation */
1156 typedef struct
1158 /* IUnknown fields */
1159 ICOM_VTABLE(IStream)* lpvtbl;
1160 DWORD ref;
1161 /* IStream32 fields */
1162 struct storage_pps_entry stde;
1163 int ppsent;
1164 HFILE hf;
1165 ULARGE_INTEGER offset;
1166 } IStream32Impl;
1168 /*****************************************************************************
1169 * IStream32_QueryInterface [VTABLE]
1171 HRESULT WINAPI IStream_fnQueryInterface(
1172 IStream* iface,REFIID refiid,LPVOID *obj
1174 ICOM_THIS(IStream32Impl,iface);
1175 char xrefiid[50];
1177 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1178 TRACE_(relay)("(%p)->(%s,%p)\n",This,xrefiid,obj);
1179 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1180 *obj = This;
1181 return 0;
1183 return OLE_E_ENUM_NOMORE;
1187 /******************************************************************************
1188 * IStream32_AddRef [VTABLE]
1190 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1191 ICOM_THIS(IStream32Impl,iface);
1192 return ++(This->ref);
1195 /******************************************************************************
1196 * IStream32_Release [VTABLE]
1198 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1199 ICOM_THIS(IStream32Impl,iface);
1200 FlushFileBuffers(This->hf);
1201 This->ref--;
1202 if (!This->ref) {
1203 CloseHandle(This->hf);
1204 SEGPTR_FREE(This);
1205 return 0;
1207 return This->ref;
1210 /* --- IStorage16 implementation */
1212 typedef struct
1214 /* IUnknown fields */
1215 ICOM_VTABLE(IStorage16)* lpvtbl;
1216 DWORD ref;
1217 /* IStorage16 fields */
1218 SEGPTR thisptr; /* pointer to this struct as segmented */
1219 struct storage_pps_entry stde;
1220 int ppsent;
1221 HFILE hf;
1222 } IStorage16Impl;
1224 /******************************************************************************
1225 * IStorage16_QueryInterface [STORAGE.500]
1227 HRESULT WINAPI IStorage16_fnQueryInterface(
1228 IStorage16* iface,REFIID refiid,LPVOID *obj
1230 ICOM_THIS(IStorage16Impl,iface);
1231 char xrefiid[50];
1233 WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
1234 TRACE_(relay)("(%p)->(%s,%p)\n",This,xrefiid,obj);
1236 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1237 *obj = This;
1238 return 0;
1240 return OLE_E_ENUM_NOMORE;
1243 /******************************************************************************
1244 * IStorage16_AddRef [STORAGE.501]
1246 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1247 ICOM_THIS(IStorage16Impl,iface);
1248 return ++(This->ref);
1251 /******************************************************************************
1252 * IStorage16_Release [STORAGE.502]
1254 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1255 ICOM_THIS(IStorage16Impl,iface);
1256 This->ref--;
1257 if (This->ref)
1258 return This->ref;
1259 SEGPTR_FREE(This);
1260 return 0;
1263 /******************************************************************************
1264 * IStorage16_Stat [STORAGE.517]
1266 HRESULT WINAPI IStorage16_fnStat(
1267 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1269 ICOM_THIS(IStorage16Impl,iface);
1270 TRACE_(ole)("(%p)->(%p,0x%08lx)\n",
1271 This,pstatstg,grfStatFlag
1273 pstatstg->pwcsName=(LPOLESTR16)SEGPTR_GET(SEGPTR_STRDUP_WtoA(This->stde.pps_rawname));
1274 pstatstg->type = This->stde.pps_type;
1275 pstatstg->cbSize.LowPart = This->stde.pps_size;
1276 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1277 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1278 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1279 pstatstg->grfMode = 0; /* FIXME */
1280 pstatstg->grfLocksSupported = 0; /* FIXME */
1281 pstatstg->clsid = This->stde.pps_guid;
1282 pstatstg->grfStateBits = 0; /* FIXME */
1283 pstatstg->reserved = 0;
1284 return S_OK;
1287 /******************************************************************************
1288 * IStorage16_Commit [STORAGE.509]
1290 HRESULT WINAPI IStorage16_fnCommit(
1291 LPSTORAGE16 iface,DWORD commitflags
1293 ICOM_THIS(IStorage16Impl,iface);
1294 FIXME_(ole)("(%p)->(0x%08lx),STUB!\n",
1295 This,commitflags
1297 return S_OK;
1300 /******************************************************************************
1301 * IStorage16_CopyTo [STORAGE.507]
1303 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1304 ICOM_THIS(IStorage16Impl,iface);
1305 char xguid[50];
1307 if (rgiidExclude)
1308 WINE_StringFromCLSID(rgiidExclude,xguid);
1309 else
1310 strcpy(xguid,"<no guid>");
1311 FIXME_(ole)("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1312 This,ciidExclude,xguid,SNB16Exclude,pstgDest
1314 return S_OK;
1318 /******************************************************************************
1319 * IStorage16_CreateStorage [STORAGE.505]
1321 HRESULT WINAPI IStorage16_fnCreateStorage(
1322 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1324 ICOM_THIS(IStorage16Impl,iface);
1325 IStorage16Impl* lpstg;
1326 int ppsent,x;
1327 struct storage_pps_entry stde;
1328 struct storage_header sth;
1329 HFILE hf=This->hf;
1331 READ_HEADER;
1333 TRACE_(ole)("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1334 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1336 if (grfMode & STGM_TRANSACTED)
1337 FIXME_(ole)("We do not support transacted Compound Storage. Using direct mode.\n");
1338 _create_istorage16(ppstg);
1339 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstg);
1340 lpstg->hf = This->hf;
1342 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1343 if (ppsent<0)
1344 return E_FAIL;
1345 stde=This->stde;
1346 if (stde.pps_dir==-1) {
1347 stde.pps_dir = ppsent;
1348 x = This->ppsent;
1349 } else {
1350 FIXME_(ole)(" use prev chain too ?\n");
1351 x=stde.pps_dir;
1352 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1353 return E_FAIL;
1354 while (stde.pps_next!=-1) {
1355 x=stde.pps_next;
1356 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1357 return E_FAIL;
1359 stde.pps_next = ppsent;
1361 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1362 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1363 lstrcpyAtoW(lpstg->stde.pps_rawname,pwcsName);
1364 lpstg->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1365 lpstg->stde.pps_next = -1;
1366 lpstg->stde.pps_prev = -1;
1367 lpstg->stde.pps_dir = -1;
1368 lpstg->stde.pps_sb = -1;
1369 lpstg->stde.pps_size = 0;
1370 lpstg->stde.pps_type = 1;
1371 lpstg->ppsent = ppsent;
1372 /* FIXME: timestamps? */
1373 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1374 return E_FAIL;
1375 return S_OK;
1378 /******************************************************************************
1379 * IStorage16_CreateStream [STORAGE.503]
1381 HRESULT WINAPI IStorage16_fnCreateStream(
1382 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1384 ICOM_THIS(IStorage16Impl,iface);
1385 IStream16Impl* lpstr;
1386 int ppsent,x;
1387 struct storage_pps_entry stde;
1389 TRACE_(ole)("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1390 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1392 if (grfMode & STGM_TRANSACTED)
1393 FIXME_(ole)("We do not support transacted Compound Storage. Using direct mode.\n");
1394 _create_istream16(ppstm);
1395 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1396 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1397 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1398 lpstr->offset.LowPart = 0;
1399 lpstr->offset.HighPart = 0;
1401 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1402 if (ppsent<0)
1403 return E_FAIL;
1404 stde=This->stde;
1405 if (stde.pps_next==-1)
1406 x=This->ppsent;
1407 else
1408 while (stde.pps_next!=-1) {
1409 x=stde.pps_next;
1410 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1411 return E_FAIL;
1413 stde.pps_next = ppsent;
1414 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1415 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1416 lstrcpyAtoW(lpstr->stde.pps_rawname,pwcsName);
1417 lpstr->stde.pps_sizeofname = lstrlenA(pwcsName)*2+2;
1418 lpstr->stde.pps_next = -1;
1419 lpstr->stde.pps_prev = -1;
1420 lpstr->stde.pps_dir = -1;
1421 lpstr->stde.pps_sb = -1;
1422 lpstr->stde.pps_size = 0;
1423 lpstr->stde.pps_type = 2;
1424 lpstr->ppsent = ppsent;
1425 /* FIXME: timestamps? */
1426 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1427 return E_FAIL;
1428 return S_OK;
1431 /******************************************************************************
1432 * IStorage16_OpenStorage [STORAGE.506]
1434 HRESULT WINAPI IStorage16_fnOpenStorage(
1435 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1437 ICOM_THIS(IStorage16Impl,iface);
1438 IStream16Impl* lpstg;
1439 WCHAR name[33];
1440 int newpps;
1442 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1443 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1445 if (grfMode & STGM_TRANSACTED)
1446 FIXME_(ole)("We do not support transacted Compound Storage. Using direct mode.\n");
1447 _create_istorage16(ppstg);
1448 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1449 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1450 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1451 lstrcpyAtoW(name,pwcsName);
1452 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1453 if (newpps==-1) {
1454 IStream16_fnRelease((IStream16*)lpstg);
1455 return E_FAIL;
1458 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1459 IStream16_fnRelease((IStream16*)lpstg);
1460 return E_FAIL;
1462 lpstg->ppsent = newpps;
1463 return S_OK;
1466 /******************************************************************************
1467 * IStorage16_OpenStream [STORAGE.504]
1469 HRESULT WINAPI IStorage16_fnOpenStream(
1470 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1472 ICOM_THIS(IStorage16Impl,iface);
1473 IStream16Impl* lpstr;
1474 WCHAR name[33];
1475 int newpps;
1477 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1478 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1480 if (grfMode & STGM_TRANSACTED)
1481 FIXME_(ole)("We do not support transacted Compound Storage. Using direct mode.\n");
1482 _create_istream16(ppstm);
1483 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1484 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1485 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1486 lstrcpyAtoW(name,pwcsName);
1487 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1488 if (newpps==-1) {
1489 IStream16_fnRelease((IStream16*)lpstr);
1490 return E_FAIL;
1493 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1494 IStream16_fnRelease((IStream16*)lpstr);
1495 return E_FAIL;
1497 lpstr->offset.LowPart = 0;
1498 lpstr->offset.HighPart = 0;
1499 lpstr->ppsent = newpps;
1500 return S_OK;
1503 /******************************************************************************
1504 * _create_istorage16 [INTERNAL]
1506 static void _create_istorage16(LPSTORAGE16 *stg) {
1507 IStorage16Impl* lpst;
1509 if (!stvt16.fnQueryInterface) {
1510 HMODULE16 wp = GetModuleHandle16("STORAGE");
1511 if (wp>=32) {
1512 #define VTENT(xfn) stvt16.fn##xfn = (void*)WIN32_GetProcAddress16(wp,"IStorage16_"#xfn);
1513 VTENT(QueryInterface)
1514 VTENT(AddRef)
1515 VTENT(Release)
1516 VTENT(CreateStream)
1517 VTENT(OpenStream)
1518 VTENT(CreateStorage)
1519 VTENT(OpenStorage)
1520 VTENT(CopyTo)
1521 VTENT(MoveElementTo)
1522 VTENT(Commit)
1523 VTENT(Revert)
1524 VTENT(EnumElements)
1525 VTENT(DestroyElement)
1526 VTENT(RenameElement)
1527 VTENT(SetElementTimes)
1528 VTENT(SetClass)
1529 VTENT(SetStateBits)
1530 VTENT(Stat)
1531 #undef VTENT
1532 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1533 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1534 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1535 } else {
1536 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1537 VTENT(QueryInterface)
1538 VTENT(AddRef)
1539 VTENT(Release)
1540 VTENT(CreateStream)
1541 VTENT(OpenStream)
1542 VTENT(CreateStorage)
1543 VTENT(OpenStorage)
1544 VTENT(CopyTo)
1545 VTENT(Commit)
1546 /* not (yet) implemented ...
1547 VTENT(MoveElementTo)
1548 VTENT(Revert)
1549 VTENT(EnumElements)
1550 VTENT(DestroyElement)
1551 VTENT(RenameElement)
1552 VTENT(SetElementTimes)
1553 VTENT(SetClass)
1554 VTENT(SetStateBits)
1555 VTENT(Stat)
1557 #undef VTENT
1558 segstvt16 = &stvt16;
1561 lpst = SEGPTR_NEW(IStorage16Impl);
1562 lpst->lpvtbl = segstvt16;
1563 lpst->ref = 1;
1564 lpst->thisptr = SEGPTR_GET(lpst);
1565 *stg = (void*)lpst->thisptr;
1568 /******************************************************************************
1569 * Storage API functions
1572 /******************************************************************************
1573 * StgCreateDocFile16 [STORAGE.1]
1575 HRESULT WINAPI StgCreateDocFile16(
1576 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1578 HFILE hf;
1579 int i,ret;
1580 IStorage16Impl* lpstg;
1581 struct storage_pps_entry stde;
1583 TRACE_(ole)("(%s,0x%08lx,0x%08lx,%p)\n",
1584 pwcsName,grfMode,reserved,ppstgOpen
1586 _create_istorage16(ppstgOpen);
1587 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1588 if (hf==INVALID_HANDLE_VALUE) {
1589 WARN_(ole)("couldn't open file for storage:%ld\n",GetLastError());
1590 return E_FAIL;
1592 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1593 lpstg->hf = hf;
1594 /* FIXME: check for existance before overwriting? */
1595 if (!STORAGE_init_storage(hf)) {
1596 CloseHandle(hf);
1597 return E_FAIL;
1599 i=0;ret=0;
1600 while (!ret) { /* neither 1 nor <0 */
1601 ret=STORAGE_get_pps_entry(hf,i,&stde);
1602 if ((ret==1) && (stde.pps_type==5)) {
1603 lpstg->stde = stde;
1604 lpstg->ppsent = i;
1605 break;
1607 i++;
1609 if (ret!=1) {
1610 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1611 return E_FAIL;
1614 return S_OK;
1617 /******************************************************************************
1618 * StgIsStorageFile16 [STORAGE.5]
1620 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1621 HFILE hf;
1622 OFSTRUCT ofs;
1623 BYTE magic[24];
1625 TRACE_(ole)("(\'%s\')\n",fn);
1626 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1627 if (hf==HFILE_ERROR)
1628 return STG_E_FILENOTFOUND;
1629 if (24!=_lread(hf,magic,24)) {
1630 WARN_(ole)(" too short\n");
1631 _lclose(hf);
1632 return S_FALSE;
1634 if (!memcmp(magic,STORAGE_magic,8)) {
1635 WARN_(ole)(" -> YES\n");
1636 _lclose(hf);
1637 return S_OK;
1639 if (!memcmp(magic,STORAGE_notmagic,8)) {
1640 WARN_(ole)(" -> NO\n");
1641 _lclose(hf);
1642 return S_FALSE;
1644 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1645 WARN_(ole)(" -> old format\n");
1646 _lclose(hf);
1647 return STG_E_OLDFORMAT;
1649 WARN_(ole)(" -> Invalid header.\n");
1650 _lclose(hf);
1651 return STG_E_INVALIDHEADER;
1654 /******************************************************************************
1655 * StgIsStorageFile32 [OLE32.146]
1657 HRESULT WINAPI
1658 StgIsStorageFile(LPCOLESTR fn)
1660 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1661 OLESTATUS ret = StgIsStorageFile16(xfn);
1663 HeapFree(GetProcessHeap(),0,xfn);
1664 return ret;
1668 /******************************************************************************
1669 * StgOpenStorage16 [STORAGE.3]
1671 HRESULT WINAPI StgOpenStorage16(
1672 const OLECHAR16 * pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1673 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1675 HFILE hf;
1676 int ret,i;
1677 IStorage16Impl* lpstg;
1678 struct storage_pps_entry stde;
1680 TRACE_(ole)("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1681 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1683 _create_istorage16(ppstgOpen);
1684 hf = CreateFileA(pwcsName,GENERIC_READ,0,NULL,0,0,0);
1685 if (hf==INVALID_HANDLE_VALUE) {
1686 WARN_(ole)("Couldn't open file for storage\n");
1687 return E_FAIL;
1689 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1690 lpstg->hf = hf;
1692 i=0;ret=0;
1693 while (!ret) { /* neither 1 nor <0 */
1694 ret=STORAGE_get_pps_entry(hf,i,&stde);
1695 if ((ret==1) && (stde.pps_type==5)) {
1696 lpstg->stde=stde;
1697 break;
1699 i++;
1701 if (ret!=1) {
1702 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1703 return E_FAIL;
1705 return S_OK;