Got rid of the Wine internal lstrcpy* functions and of winestring.h.
[wine/gsoc_dplay.git] / dlls / ole32 / storage.c
blobe576182f38961314569a3b223516e8e39dc62921
1 /* Compound Storage
3 * Implemented using the documentation of the LAOLA project at
4 * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
5 * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
7 * Copyright 1998 Marcus Meissner
8 */
10 #include <assert.h>
11 #include <time.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include "windef.h"
16 #include "ntddk.h"
17 #include "winerror.h"
18 #include "wine/winbase16.h"
19 #include "wingdi.h"
20 #include "wtypes.h"
21 #include "wine/obj_base.h"
22 #include "wine/obj_storage.h"
23 #include "heap.h"
24 #include "module.h"
25 #include "ldt.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(ole);
29 DECLARE_DEBUG_CHANNEL(relay);
31 struct storage_header {
32 BYTE magic[8]; /* 00: magic */
33 BYTE unknown1[36]; /* 08: unknown */
34 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
35 DWORD root_startblock;/* 30: root storage first big block */
36 DWORD unknown2[2]; /* 34: unknown */
37 DWORD sbd_startblock; /* 3C: small block depot first big block */
38 DWORD unknown3[3]; /* 40: unknown */
39 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
41 struct storage_pps_entry {
42 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
43 WORD pps_sizeofname; /* 40: namelength in bytes */
44 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
45 BYTE pps_unknown0; /* 43: unknown */
46 DWORD pps_prev; /* 44: previous pps */
47 DWORD pps_next; /* 48: next pps */
48 DWORD pps_dir; /* 4C: directory pps */
49 GUID pps_guid; /* 50: class ID */
50 DWORD pps_unknown1; /* 60: unknown */
51 FILETIME pps_ft1; /* 64: filetime1 */
52 FILETIME pps_ft2; /* 70: filetime2 */
53 DWORD pps_sb; /* 74: data startblock */
54 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
55 DWORD pps_unknown2; /* 7C: unknown */
58 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
59 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
60 #define STORAGE_CHAINENTRY_FREE 0xffffffff
63 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
64 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
65 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
67 #define BIGSIZE 512
68 #define SMALLSIZE 64
70 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
72 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
73 static ICOM_VTABLE(IStorage16) stvt16;
74 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
75 static ICOM_VTABLE(IStream16) strvt16;
76 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
78 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
79 static void _create_istorage16(LPSTORAGE16 *stg);
80 static void _create_istream16(LPSTREAM16 *str);
82 #define IMPLEMENTED 1
85 /******************************************************************************
86 * STORAGE_get_big_block [Internal]
88 * Reading OLE compound storage
90 static BOOL
91 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
92 assert(n>=-1);
93 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
94 WARN(" seek failed (%ld)\n",GetLastError());
95 return FALSE;
97 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
98 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
99 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
100 assert(0);
101 return FALSE;
103 return TRUE;
106 /******************************************************************************
107 * STORAGE_put_big_block [INTERNAL]
109 static BOOL
110 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
111 assert(n>=-1);
112 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
113 WARN(" seek failed (%ld)\n",GetLastError());
114 return FALSE;
116 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
117 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
118 WARN(" write failed (%ld)\n",GetLastError());
119 return FALSE;
121 return TRUE;
124 /******************************************************************************
125 * STORAGE_get_next_big_blocknr [INTERNAL]
127 static int
128 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
129 INT bbs[BIGSIZE/sizeof(INT)];
130 struct storage_header sth;
132 READ_HEADER;
134 assert(blocknr>>7<sth.num_of_bbd_blocks);
135 if (sth.bbd_list[blocknr>>7]==0xffffffff)
136 return -5;
137 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
138 return -5;
139 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
140 return bbs[blocknr&0x7f];
143 /******************************************************************************
144 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
146 static int
147 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
148 INT bbs[BIGSIZE/sizeof(INT)];
149 int lastblock = -1;
150 struct storage_header sth;
152 READ_HEADER;
154 assert(blocknr>=0);
155 while (nr--) {
156 assert((blocknr>>7)<sth.num_of_bbd_blocks);
157 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
159 /* simple caching... */
160 if (lastblock!=sth.bbd_list[blocknr>>7]) {
161 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
162 lastblock = sth.bbd_list[blocknr>>7];
164 blocknr = bbs[blocknr&0x7f];
166 return blocknr;
169 /******************************************************************************
170 * STORAGE_get_root_pps_entry [Internal]
172 static BOOL
173 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
174 int blocknr,i;
175 BYTE block[BIGSIZE];
176 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
177 struct storage_header sth;
179 READ_HEADER;
180 blocknr = sth.root_startblock;
181 while (blocknr>=0) {
182 assert(STORAGE_get_big_block(hf,blocknr,block));
183 for (i=0;i<4;i++) {
184 if (!stde[i].pps_sizeofname)
185 continue;
186 if (stde[i].pps_type==5) {
187 *pstde=stde[i];
188 return TRUE;
191 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
193 return FALSE;
196 /******************************************************************************
197 * STORAGE_get_small_block [INTERNAL]
199 static BOOL
200 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
201 BYTE block[BIGSIZE];
202 int bigblocknr;
203 struct storage_pps_entry root;
205 assert(blocknr>=0);
206 assert(STORAGE_get_root_pps_entry(hf,&root));
207 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
208 assert(bigblocknr>=0);
209 assert(STORAGE_get_big_block(hf,bigblocknr,block));
211 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
212 return TRUE;
215 /******************************************************************************
216 * STORAGE_put_small_block [INTERNAL]
218 static BOOL
219 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
220 BYTE block[BIGSIZE];
221 int bigblocknr;
222 struct storage_pps_entry root;
224 assert(blocknr>=0);
226 assert(STORAGE_get_root_pps_entry(hf,&root));
227 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
228 assert(bigblocknr>=0);
229 assert(STORAGE_get_big_block(hf,bigblocknr,block));
231 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
232 assert(STORAGE_put_big_block(hf,bigblocknr,block));
233 return TRUE;
236 /******************************************************************************
237 * STORAGE_get_next_small_blocknr [INTERNAL]
239 static int
240 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
241 BYTE block[BIGSIZE];
242 LPINT sbd = (LPINT)block;
243 int bigblocknr;
244 struct storage_header sth;
246 READ_HEADER;
247 assert(blocknr>=0);
248 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
249 assert(bigblocknr>=0);
250 assert(STORAGE_get_big_block(hf,bigblocknr,block));
251 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
252 return sbd[blocknr & (128-1)];
255 /******************************************************************************
256 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
258 static int
259 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
260 int lastblocknr;
261 BYTE block[BIGSIZE];
262 LPINT sbd = (LPINT)block;
263 struct storage_header sth;
265 READ_HEADER;
266 lastblocknr=-1;
267 assert(blocknr>=0);
268 while ((nr--) && (blocknr>=0)) {
269 if (lastblocknr/128!=blocknr/128) {
270 int bigblocknr;
271 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
272 assert(bigblocknr>=0);
273 assert(STORAGE_get_big_block(hf,bigblocknr,block));
274 lastblocknr = blocknr;
276 assert(lastblocknr>=0);
277 lastblocknr=blocknr;
278 blocknr=sbd[blocknr & (128-1)];
279 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
281 return blocknr;
284 /******************************************************************************
285 * STORAGE_get_pps_entry [INTERNAL]
287 static int
288 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
289 int blocknr;
290 BYTE block[BIGSIZE];
291 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
292 struct storage_header sth;
294 READ_HEADER;
295 /* we have 4 pps entries per big block */
296 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
297 assert(blocknr>=0);
298 assert(STORAGE_get_big_block(hf,blocknr,block));
300 *pstde=*stde;
301 return 1;
304 /******************************************************************************
305 * STORAGE_put_pps_entry [Internal]
307 static int
308 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
309 int blocknr;
310 BYTE block[BIGSIZE];
311 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
312 struct storage_header sth;
314 READ_HEADER;
316 /* we have 4 pps entries per big block */
317 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
318 assert(blocknr>=0);
319 assert(STORAGE_get_big_block(hf,blocknr,block));
320 *stde=*pstde;
321 assert(STORAGE_put_big_block(hf,blocknr,block));
322 return 1;
325 /******************************************************************************
326 * STORAGE_look_for_named_pps [Internal]
328 static int
329 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
330 struct storage_pps_entry stde;
331 int ret;
333 if (n==-1)
334 return -1;
335 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
336 return -1;
338 if (!lstrcmpW(name,stde.pps_rawname))
339 return n;
340 if (stde.pps_prev != -1) {
341 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
342 if (ret!=-1)
343 return ret;
345 if (stde.pps_next != -1) {
346 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
347 if (ret!=-1)
348 return ret;
350 return -1;
353 /******************************************************************************
354 * STORAGE_dump_pps_entry [Internal]
356 * FIXME
357 * Function is unused
359 void
360 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
361 char name[33];
363 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
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",debugstr_guid(&(stde->pps_guid)));
372 if (stde->pps_type !=2) {
373 time_t t;
374 DWORD dw;
375 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
376 t = dw;
377 DPRINTF("ts1: %s\n",ctime(&t));
378 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
379 t = dw;
380 DPRINTF("ts2: %s\n",ctime(&t));
382 DPRINTF("startblock: %ld\n",stde->pps_sb);
383 DPRINTF("size: %ld\n",stde->pps_size);
386 /******************************************************************************
387 * STORAGE_init_storage [INTERNAL]
389 static BOOL
390 STORAGE_init_storage(HFILE hf) {
391 BYTE block[BIGSIZE];
392 LPDWORD bbs;
393 struct storage_header *sth;
394 struct storage_pps_entry *stde;
396 assert(-1!=_llseek(hf,0,SEEK_SET));
397 /* block -1 is the storage header */
398 sth = (struct storage_header*)block;
399 memcpy(sth->magic,STORAGE_magic,8);
400 memset(sth->unknown1,0,sizeof(sth->unknown1));
401 memset(sth->unknown2,0,sizeof(sth->unknown2));
402 memset(sth->unknown3,0,sizeof(sth->unknown3));
403 sth->num_of_bbd_blocks = 1;
404 sth->root_startblock = 1;
405 sth->sbd_startblock = 0xffffffff;
406 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
407 sth->bbd_list[0] = 0;
408 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
409 /* block 0 is the big block directory */
410 bbs=(LPDWORD)block;
411 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
412 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
413 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
414 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
415 /* block 1 is the root directory entry */
416 memset(block,0x00,sizeof(block));
417 stde = (struct storage_pps_entry*)block;
418 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
419 sizeof(stde->pps_rawname)/sizeof(WCHAR));
420 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
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 GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1106 #define VTENT(xfn) strvt16.fn##xfn = (void*)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 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1355 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1356 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1357 lpstg->stde.pps_next = -1;
1358 lpstg->stde.pps_prev = -1;
1359 lpstg->stde.pps_dir = -1;
1360 lpstg->stde.pps_sb = -1;
1361 lpstg->stde.pps_size = 0;
1362 lpstg->stde.pps_type = 1;
1363 lpstg->ppsent = ppsent;
1364 /* FIXME: timestamps? */
1365 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1366 return E_FAIL;
1367 return S_OK;
1370 /******************************************************************************
1371 * IStorage16_CreateStream [STORAGE.503]
1373 HRESULT WINAPI IStorage16_fnCreateStream(
1374 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1376 ICOM_THIS(IStorage16Impl,iface);
1377 IStream16Impl* lpstr;
1378 int ppsent,x;
1379 struct storage_pps_entry stde;
1381 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1382 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1384 if (grfMode & STGM_TRANSACTED)
1385 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1386 _create_istream16(ppstm);
1387 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1388 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1389 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1390 lpstr->offset.s.LowPart = 0;
1391 lpstr->offset.s.HighPart = 0;
1393 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1394 if (ppsent<0)
1395 return E_FAIL;
1396 stde=This->stde;
1397 if (stde.pps_next==-1)
1398 x=This->ppsent;
1399 else
1400 while (stde.pps_next!=-1) {
1401 x=stde.pps_next;
1402 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1403 return E_FAIL;
1405 stde.pps_next = ppsent;
1406 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1407 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1408 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1409 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1410 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1411 lpstr->stde.pps_next = -1;
1412 lpstr->stde.pps_prev = -1;
1413 lpstr->stde.pps_dir = -1;
1414 lpstr->stde.pps_sb = -1;
1415 lpstr->stde.pps_size = 0;
1416 lpstr->stde.pps_type = 2;
1417 lpstr->ppsent = ppsent;
1418 /* FIXME: timestamps? */
1419 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1420 return E_FAIL;
1421 return S_OK;
1424 /******************************************************************************
1425 * IStorage16_OpenStorage [STORAGE.506]
1427 HRESULT WINAPI IStorage16_fnOpenStorage(
1428 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1430 ICOM_THIS(IStorage16Impl,iface);
1431 IStream16Impl* lpstg;
1432 WCHAR name[33];
1433 int newpps;
1435 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1436 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1438 if (grfMode & STGM_TRANSACTED)
1439 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1440 _create_istorage16(ppstg);
1441 lpstg = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstg);
1442 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1443 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1444 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1445 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1446 if (newpps==-1) {
1447 IStream16_fnRelease((IStream16*)lpstg);
1448 return E_FAIL;
1451 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1452 IStream16_fnRelease((IStream16*)lpstg);
1453 return E_FAIL;
1455 lpstg->ppsent = newpps;
1456 return S_OK;
1459 /******************************************************************************
1460 * IStorage16_OpenStream [STORAGE.504]
1462 HRESULT WINAPI IStorage16_fnOpenStream(
1463 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1465 ICOM_THIS(IStorage16Impl,iface);
1466 IStream16Impl* lpstr;
1467 WCHAR name[33];
1468 int newpps;
1470 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1471 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1473 if (grfMode & STGM_TRANSACTED)
1474 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1475 _create_istream16(ppstm);
1476 lpstr = (IStream16Impl*)PTR_SEG_TO_LIN(*ppstm);
1477 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1478 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1479 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1480 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1481 if (newpps==-1) {
1482 IStream16_fnRelease((IStream16*)lpstr);
1483 return E_FAIL;
1486 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1487 IStream16_fnRelease((IStream16*)lpstr);
1488 return E_FAIL;
1490 lpstr->offset.s.LowPart = 0;
1491 lpstr->offset.s.HighPart = 0;
1492 lpstr->ppsent = newpps;
1493 return S_OK;
1496 /******************************************************************************
1497 * _create_istorage16 [INTERNAL]
1499 static void _create_istorage16(LPSTORAGE16 *stg) {
1500 IStorage16Impl* lpst;
1502 if (!stvt16.fnQueryInterface) {
1503 HMODULE16 wp = GetModuleHandle16("STORAGE");
1504 if (wp>=32) {
1505 #define VTENT(xfn) stvt16.fn##xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1506 VTENT(QueryInterface)
1507 VTENT(AddRef)
1508 VTENT(Release)
1509 VTENT(CreateStream)
1510 VTENT(OpenStream)
1511 VTENT(CreateStorage)
1512 VTENT(OpenStorage)
1513 VTENT(CopyTo)
1514 VTENT(MoveElementTo)
1515 VTENT(Commit)
1516 VTENT(Revert)
1517 VTENT(EnumElements)
1518 VTENT(DestroyElement)
1519 VTENT(RenameElement)
1520 VTENT(SetElementTimes)
1521 VTENT(SetClass)
1522 VTENT(SetStateBits)
1523 VTENT(Stat)
1524 #undef VTENT
1525 segstvt16 = SEGPTR_NEW(ICOM_VTABLE(IStorage16));
1526 memcpy(segstvt16,&stvt16,sizeof(stvt16));
1527 segstvt16 = (ICOM_VTABLE(IStorage16)*)SEGPTR_GET(segstvt16);
1528 } else {
1529 #define VTENT(xfn) stvt16.fn##xfn = IStorage16_fn##xfn;
1530 VTENT(QueryInterface)
1531 VTENT(AddRef)
1532 VTENT(Release)
1533 VTENT(CreateStream)
1534 VTENT(OpenStream)
1535 VTENT(CreateStorage)
1536 VTENT(OpenStorage)
1537 VTENT(CopyTo)
1538 VTENT(Commit)
1539 /* not (yet) implemented ...
1540 VTENT(MoveElementTo)
1541 VTENT(Revert)
1542 VTENT(EnumElements)
1543 VTENT(DestroyElement)
1544 VTENT(RenameElement)
1545 VTENT(SetElementTimes)
1546 VTENT(SetClass)
1547 VTENT(SetStateBits)
1548 VTENT(Stat)
1550 #undef VTENT
1551 segstvt16 = &stvt16;
1554 lpst = SEGPTR_NEW(IStorage16Impl);
1555 ICOM_VTBL(lpst) = segstvt16;
1556 lpst->ref = 1;
1557 lpst->thisptr = SEGPTR_GET(lpst);
1558 *stg = (void*)lpst->thisptr;
1561 /******************************************************************************
1562 * Storage API functions
1565 /******************************************************************************
1566 * StgCreateDocFile16 [STORAGE.1]
1568 HRESULT WINAPI StgCreateDocFile16(
1569 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1571 HFILE hf;
1572 int i,ret;
1573 IStorage16Impl* lpstg;
1574 struct storage_pps_entry stde;
1576 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1577 pwcsName,grfMode,reserved,ppstgOpen
1579 _create_istorage16(ppstgOpen);
1580 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1581 if (hf==INVALID_HANDLE_VALUE) {
1582 WARN("couldn't open file for storage:%ld\n",GetLastError());
1583 return E_FAIL;
1585 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1586 lpstg->hf = hf;
1587 /* FIXME: check for existance before overwriting? */
1588 if (!STORAGE_init_storage(hf)) {
1589 CloseHandle(hf);
1590 return E_FAIL;
1592 i=0;ret=0;
1593 while (!ret) { /* neither 1 nor <0 */
1594 ret=STORAGE_get_pps_entry(hf,i,&stde);
1595 if ((ret==1) && (stde.pps_type==5)) {
1596 lpstg->stde = stde;
1597 lpstg->ppsent = i;
1598 break;
1600 i++;
1602 if (ret!=1) {
1603 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1604 return E_FAIL;
1607 return S_OK;
1610 /******************************************************************************
1611 * StgIsStorageFile16 [STORAGE.5]
1613 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1614 HFILE hf;
1615 OFSTRUCT ofs;
1616 BYTE magic[24];
1618 TRACE("(\'%s\')\n",fn);
1619 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1620 if (hf==HFILE_ERROR)
1621 return STG_E_FILENOTFOUND;
1622 if (24!=_lread(hf,magic,24)) {
1623 WARN(" too short\n");
1624 _lclose(hf);
1625 return S_FALSE;
1627 if (!memcmp(magic,STORAGE_magic,8)) {
1628 WARN(" -> YES\n");
1629 _lclose(hf);
1630 return S_OK;
1632 if (!memcmp(magic,STORAGE_notmagic,8)) {
1633 WARN(" -> NO\n");
1634 _lclose(hf);
1635 return S_FALSE;
1637 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1638 WARN(" -> old format\n");
1639 _lclose(hf);
1640 return STG_E_OLDFORMAT;
1642 WARN(" -> Invalid header.\n");
1643 _lclose(hf);
1644 return STG_E_INVALIDHEADER;
1647 /******************************************************************************
1648 * StgIsStorageFile [OLE32.146]
1650 HRESULT WINAPI
1651 StgIsStorageFile(LPCOLESTR fn)
1653 LPOLESTR16 xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
1654 HRESULT ret = StgIsStorageFile16(xfn);
1656 HeapFree(GetProcessHeap(),0,xfn);
1657 return ret;
1661 /******************************************************************************
1662 * StgOpenStorage16 [STORAGE.3]
1664 HRESULT WINAPI StgOpenStorage16(
1665 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1666 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1668 HFILE hf;
1669 int ret,i;
1670 IStorage16Impl* lpstg;
1671 struct storage_pps_entry stde;
1673 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1674 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1676 _create_istorage16(ppstgOpen);
1677 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1678 if (hf==INVALID_HANDLE_VALUE) {
1679 WARN("Couldn't open file for storage\n");
1680 return E_FAIL;
1682 lpstg = (IStorage16Impl*)PTR_SEG_TO_LIN(*ppstgOpen);
1683 lpstg->hf = hf;
1685 i=0;ret=0;
1686 while (!ret) { /* neither 1 nor <0 */
1687 ret=STORAGE_get_pps_entry(hf,i,&stde);
1688 if ((ret==1) && (stde.pps_type==5)) {
1689 lpstg->stde=stde;
1690 break;
1692 i++;
1694 if (ret!=1) {
1695 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1696 return E_FAIL;
1698 return S_OK;