LVS_OWNERDRAWFIXED should only take effect in REPORT mode.
[wine/multimedia.git] / dlls / ole32 / storage.c
blobb6e841d886c14f4a20b34eaa802db296ea276a65
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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
26 #include <assert.h>
27 #include <time.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include "windef.h"
34 #include "winternl.h"
35 #include "winerror.h"
36 #include "wine/winbase16.h"
37 #include "wine/unicode.h"
38 #include "wtypes.h"
39 #include "wine/obj_base.h"
40 #include "wine/obj_storage.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 WINE_DECLARE_DEBUG_CHANNEL(relay);
46 struct storage_header {
47 BYTE magic[8]; /* 00: magic */
48 BYTE unknown1[36]; /* 08: unknown */
49 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
50 DWORD root_startblock;/* 30: root storage first big block */
51 DWORD unknown2[2]; /* 34: unknown */
52 DWORD sbd_startblock; /* 3C: small block depot first big block */
53 DWORD unknown3[3]; /* 40: unknown */
54 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
56 struct storage_pps_entry {
57 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
58 WORD pps_sizeofname; /* 40: namelength in bytes */
59 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
60 BYTE pps_unknown0; /* 43: unknown */
61 DWORD pps_prev; /* 44: previous pps */
62 DWORD pps_next; /* 48: next pps */
63 DWORD pps_dir; /* 4C: directory pps */
64 GUID pps_guid; /* 50: class ID */
65 DWORD pps_unknown1; /* 60: unknown */
66 FILETIME pps_ft1; /* 64: filetime1 */
67 FILETIME pps_ft2; /* 70: filetime2 */
68 DWORD pps_sb; /* 74: data startblock */
69 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
70 DWORD pps_unknown2; /* 7C: unknown */
73 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
74 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
75 #define STORAGE_CHAINENTRY_FREE 0xffffffff
78 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
79 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
80 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
82 #define BIGSIZE 512
83 #define SMALLSIZE 64
85 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
87 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
88 static ICOM_VTABLE(IStorage16) stvt16;
89 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
90 static ICOM_VTABLE(IStream16) strvt16;
91 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
93 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
94 static void _create_istorage16(LPSTORAGE16 *stg);
95 static void _create_istream16(LPSTREAM16 *str);
97 #define IMPLEMENTED 1
100 /******************************************************************************
101 * STORAGE_get_big_block [Internal]
103 * Reading OLE compound storage
105 static BOOL
106 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
107 assert(n>=-1);
108 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
109 WARN(" seek failed (%ld)\n",GetLastError());
110 return FALSE;
112 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
113 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
114 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
115 assert(0);
116 return FALSE;
118 return TRUE;
121 /******************************************************************************
122 * STORAGE_put_big_block [INTERNAL]
124 static BOOL
125 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
126 assert(n>=-1);
127 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
128 WARN(" seek failed (%ld)\n",GetLastError());
129 return FALSE;
131 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
132 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
133 WARN(" write failed (%ld)\n",GetLastError());
134 return FALSE;
136 return TRUE;
139 /******************************************************************************
140 * STORAGE_get_next_big_blocknr [INTERNAL]
142 static int
143 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
144 INT bbs[BIGSIZE/sizeof(INT)];
145 struct storage_header sth;
147 READ_HEADER;
149 assert(blocknr>>7<sth.num_of_bbd_blocks);
150 if (sth.bbd_list[blocknr>>7]==0xffffffff)
151 return -5;
152 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
153 return -5;
154 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
155 return bbs[blocknr&0x7f];
158 /******************************************************************************
159 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
161 static int
162 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
163 INT bbs[BIGSIZE/sizeof(INT)];
164 int lastblock = -1;
165 struct storage_header sth;
167 READ_HEADER;
169 assert(blocknr>=0);
170 while (nr--) {
171 assert((blocknr>>7)<sth.num_of_bbd_blocks);
172 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
174 /* simple caching... */
175 if (lastblock!=sth.bbd_list[blocknr>>7]) {
176 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
177 lastblock = sth.bbd_list[blocknr>>7];
179 blocknr = bbs[blocknr&0x7f];
181 return blocknr;
184 /******************************************************************************
185 * STORAGE_get_root_pps_entry [Internal]
187 static BOOL
188 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
189 int blocknr,i;
190 BYTE block[BIGSIZE];
191 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
192 struct storage_header sth;
194 READ_HEADER;
195 blocknr = sth.root_startblock;
196 while (blocknr>=0) {
197 assert(STORAGE_get_big_block(hf,blocknr,block));
198 for (i=0;i<4;i++) {
199 if (!stde[i].pps_sizeofname)
200 continue;
201 if (stde[i].pps_type==5) {
202 *pstde=stde[i];
203 return TRUE;
206 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
208 return FALSE;
211 /******************************************************************************
212 * STORAGE_get_small_block [INTERNAL]
214 static BOOL
215 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
216 BYTE block[BIGSIZE];
217 int bigblocknr;
218 struct storage_pps_entry root;
220 assert(blocknr>=0);
221 assert(STORAGE_get_root_pps_entry(hf,&root));
222 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
223 assert(bigblocknr>=0);
224 assert(STORAGE_get_big_block(hf,bigblocknr,block));
226 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
227 return TRUE;
230 /******************************************************************************
231 * STORAGE_put_small_block [INTERNAL]
233 static BOOL
234 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
235 BYTE block[BIGSIZE];
236 int bigblocknr;
237 struct storage_pps_entry root;
239 assert(blocknr>=0);
241 assert(STORAGE_get_root_pps_entry(hf,&root));
242 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
243 assert(bigblocknr>=0);
244 assert(STORAGE_get_big_block(hf,bigblocknr,block));
246 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
247 assert(STORAGE_put_big_block(hf,bigblocknr,block));
248 return TRUE;
251 /******************************************************************************
252 * STORAGE_get_next_small_blocknr [INTERNAL]
254 static int
255 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
256 BYTE block[BIGSIZE];
257 LPINT sbd = (LPINT)block;
258 int bigblocknr;
259 struct storage_header sth;
261 READ_HEADER;
262 assert(blocknr>=0);
263 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
264 assert(bigblocknr>=0);
265 assert(STORAGE_get_big_block(hf,bigblocknr,block));
266 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
267 return sbd[blocknr & (128-1)];
270 /******************************************************************************
271 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
273 static int
274 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
275 int lastblocknr;
276 BYTE block[BIGSIZE];
277 LPINT sbd = (LPINT)block;
278 struct storage_header sth;
280 READ_HEADER;
281 lastblocknr=-1;
282 assert(blocknr>=0);
283 while ((nr--) && (blocknr>=0)) {
284 if (lastblocknr/128!=blocknr/128) {
285 int bigblocknr;
286 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
287 assert(bigblocknr>=0);
288 assert(STORAGE_get_big_block(hf,bigblocknr,block));
289 lastblocknr = blocknr;
291 assert(lastblocknr>=0);
292 lastblocknr=blocknr;
293 blocknr=sbd[blocknr & (128-1)];
294 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
296 return blocknr;
299 /******************************************************************************
300 * STORAGE_get_pps_entry [INTERNAL]
302 static int
303 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
304 int blocknr;
305 BYTE block[BIGSIZE];
306 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
307 struct storage_header sth;
309 READ_HEADER;
310 /* we have 4 pps entries per big block */
311 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
312 assert(blocknr>=0);
313 assert(STORAGE_get_big_block(hf,blocknr,block));
315 *pstde=*stde;
316 return 1;
319 /******************************************************************************
320 * STORAGE_put_pps_entry [Internal]
322 static int
323 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
324 int blocknr;
325 BYTE block[BIGSIZE];
326 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
327 struct storage_header sth;
329 READ_HEADER;
331 /* we have 4 pps entries per big block */
332 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
333 assert(blocknr>=0);
334 assert(STORAGE_get_big_block(hf,blocknr,block));
335 *stde=*pstde;
336 assert(STORAGE_put_big_block(hf,blocknr,block));
337 return 1;
340 /******************************************************************************
341 * STORAGE_look_for_named_pps [Internal]
343 static int
344 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
345 struct storage_pps_entry stde;
346 int ret;
348 if (n==-1)
349 return -1;
350 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
351 return -1;
353 if (!lstrcmpW(name,stde.pps_rawname))
354 return n;
355 if (stde.pps_prev != -1) {
356 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
357 if (ret!=-1)
358 return ret;
360 if (stde.pps_next != -1) {
361 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
362 if (ret!=-1)
363 return ret;
365 return -1;
368 /******************************************************************************
369 * STORAGE_dump_pps_entry [Internal]
371 * FIXME
372 * Function is unused
374 void
375 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
376 char name[33];
378 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
379 if (!stde->pps_sizeofname)
380 return;
381 DPRINTF("name: %s\n",name);
382 DPRINTF("type: %d\n",stde->pps_type);
383 DPRINTF("prev pps: %ld\n",stde->pps_prev);
384 DPRINTF("next pps: %ld\n",stde->pps_next);
385 DPRINTF("dir pps: %ld\n",stde->pps_dir);
386 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
387 if (stde->pps_type !=2) {
388 time_t t;
389 DWORD dw;
390 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
391 t = dw;
392 DPRINTF("ts1: %s\n",ctime(&t));
393 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
394 t = dw;
395 DPRINTF("ts2: %s\n",ctime(&t));
397 DPRINTF("startblock: %ld\n",stde->pps_sb);
398 DPRINTF("size: %ld\n",stde->pps_size);
401 /******************************************************************************
402 * STORAGE_init_storage [INTERNAL]
404 static BOOL
405 STORAGE_init_storage(HFILE hf) {
406 BYTE block[BIGSIZE];
407 LPDWORD bbs;
408 struct storage_header *sth;
409 struct storage_pps_entry *stde;
411 assert(-1!=_llseek(hf,0,SEEK_SET));
412 /* block -1 is the storage header */
413 sth = (struct storage_header*)block;
414 memcpy(sth->magic,STORAGE_magic,8);
415 memset(sth->unknown1,0,sizeof(sth->unknown1));
416 memset(sth->unknown2,0,sizeof(sth->unknown2));
417 memset(sth->unknown3,0,sizeof(sth->unknown3));
418 sth->num_of_bbd_blocks = 1;
419 sth->root_startblock = 1;
420 sth->sbd_startblock = 0xffffffff;
421 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
422 sth->bbd_list[0] = 0;
423 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
424 /* block 0 is the big block directory */
425 bbs=(LPDWORD)block;
426 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
427 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
428 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
429 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
430 /* block 1 is the root directory entry */
431 memset(block,0x00,sizeof(block));
432 stde = (struct storage_pps_entry*)block;
433 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
434 sizeof(stde->pps_rawname)/sizeof(WCHAR));
435 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
436 stde->pps_type = 5;
437 stde->pps_dir = -1;
438 stde->pps_next = -1;
439 stde->pps_prev = -1;
440 stde->pps_sb = 0xffffffff;
441 stde->pps_size = 0;
442 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
443 return TRUE;
446 /******************************************************************************
447 * STORAGE_set_big_chain [Internal]
449 static BOOL
450 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
451 BYTE block[BIGSIZE];
452 LPINT bbd = (LPINT)block;
453 int nextblocknr,bigblocknr;
454 struct storage_header sth;
456 READ_HEADER;
457 assert(blocknr!=type);
458 while (blocknr>=0) {
459 bigblocknr = sth.bbd_list[blocknr/128];
460 assert(bigblocknr>=0);
461 assert(STORAGE_get_big_block(hf,bigblocknr,block));
463 nextblocknr = bbd[blocknr&(128-1)];
464 bbd[blocknr&(128-1)] = type;
465 if (type>=0)
466 return TRUE;
467 assert(STORAGE_put_big_block(hf,bigblocknr,block));
468 type = STORAGE_CHAINENTRY_FREE;
469 blocknr = nextblocknr;
471 return TRUE;
474 /******************************************************************************
475 * STORAGE_set_small_chain [Internal]
477 static BOOL
478 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
479 BYTE block[BIGSIZE];
480 LPINT sbd = (LPINT)block;
481 int lastblocknr,nextsmallblocknr,bigblocknr;
482 struct storage_header sth;
484 READ_HEADER;
486 assert(blocknr!=type);
487 lastblocknr=-129;bigblocknr=-2;
488 while (blocknr>=0) {
489 /* cache block ... */
490 if (lastblocknr/128!=blocknr/128) {
491 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
492 assert(bigblocknr>=0);
493 assert(STORAGE_get_big_block(hf,bigblocknr,block));
495 lastblocknr = blocknr;
496 nextsmallblocknr = sbd[blocknr&(128-1)];
497 sbd[blocknr&(128-1)] = type;
498 assert(STORAGE_put_big_block(hf,bigblocknr,block));
499 if (type>=0)
500 return TRUE;
501 type = STORAGE_CHAINENTRY_FREE;
502 blocknr = nextsmallblocknr;
504 return TRUE;
507 /******************************************************************************
508 * STORAGE_get_free_big_blocknr [Internal]
510 static int
511 STORAGE_get_free_big_blocknr(HFILE hf) {
512 BYTE block[BIGSIZE];
513 LPINT sbd = (LPINT)block;
514 int lastbigblocknr,i,curblock,bigblocknr;
515 struct storage_header sth;
517 READ_HEADER;
518 curblock = 0;
519 lastbigblocknr = -1;
520 bigblocknr = sth.bbd_list[curblock];
521 while (curblock<sth.num_of_bbd_blocks) {
522 assert(bigblocknr>=0);
523 assert(STORAGE_get_big_block(hf,bigblocknr,block));
524 for (i=0;i<128;i++)
525 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
526 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
527 assert(STORAGE_put_big_block(hf,bigblocknr,block));
528 memset(block,0x42,sizeof(block));
529 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
530 return i+curblock*128;
532 lastbigblocknr = bigblocknr;
533 bigblocknr = sth.bbd_list[++curblock];
535 bigblocknr = curblock*128;
536 /* since we have marked all blocks from 0 up to curblock*128-1
537 * the next free one is curblock*128, where we happily put our
538 * next large block depot.
540 memset(block,0xff,sizeof(block));
541 /* mark the block allocated and returned by this function */
542 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
543 assert(STORAGE_put_big_block(hf,bigblocknr,block));
545 /* if we had a bbd block already (mostlikely) we need
546 * to link the new one into the chain
548 if (lastbigblocknr!=-1)
549 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
550 sth.bbd_list[curblock]=bigblocknr;
551 sth.num_of_bbd_blocks++;
552 assert(sth.num_of_bbd_blocks==curblock+1);
553 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
555 /* Set the end of the chain for the bigblockdepots */
556 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
557 /* add 1, for the first entry is used for the additional big block
558 * depot. (means we already used bigblocknr) */
559 memset(block,0x42,sizeof(block));
560 /* allocate this block (filled with 0x42) */
561 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
562 return bigblocknr+1;
566 /******************************************************************************
567 * STORAGE_get_free_small_blocknr [Internal]
569 static int
570 STORAGE_get_free_small_blocknr(HFILE hf) {
571 BYTE block[BIGSIZE];
572 LPINT sbd = (LPINT)block;
573 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
574 struct storage_pps_entry root;
575 struct storage_header sth;
577 READ_HEADER;
578 bigblocknr = sth.sbd_startblock;
579 curblock = 0;
580 lastbigblocknr = -1;
581 newblocknr = -1;
582 while (bigblocknr>=0) {
583 if (!STORAGE_get_big_block(hf,bigblocknr,block))
584 return -1;
585 for (i=0;i<128;i++)
586 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
587 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
588 newblocknr = i+curblock*128;
589 break;
591 if (i!=128)
592 break;
593 lastbigblocknr = bigblocknr;
594 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
595 curblock++;
597 if (newblocknr==-1) {
598 bigblocknr = STORAGE_get_free_big_blocknr(hf);
599 if (bigblocknr<0)
600 return -1;
601 READ_HEADER;
602 memset(block,0xff,sizeof(block));
603 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
604 if (!STORAGE_put_big_block(hf,bigblocknr,block))
605 return -1;
606 if (lastbigblocknr==-1) {
607 sth.sbd_startblock = bigblocknr;
608 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
609 return -1;
610 } else {
611 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
612 return -1;
614 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
615 return -1;
616 newblocknr = curblock*128;
618 /* allocate enough big blocks for storing the allocated small block */
619 if (!STORAGE_get_root_pps_entry(hf,&root))
620 return -1;
621 if (root.pps_sb==-1)
622 lastbigblocknr = -1;
623 else
624 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
625 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
626 /* we need to allocate more stuff */
627 bigblocknr = STORAGE_get_free_big_blocknr(hf);
628 if (bigblocknr<0)
629 return -1;
630 READ_HEADER;
631 if (root.pps_sb==-1) {
632 root.pps_sb = bigblocknr;
633 root.pps_size += BIGSIZE;
634 } else {
635 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
636 return -1;
637 root.pps_size += BIGSIZE;
639 lastbigblocknr = bigblocknr;
641 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
642 return -1;
643 if (!STORAGE_put_pps_entry(hf,0,&root))
644 return -1;
645 return newblocknr;
648 /******************************************************************************
649 * STORAGE_get_free_pps_entry [Internal]
651 static int
652 STORAGE_get_free_pps_entry(HFILE hf) {
653 int blocknr,i,curblock,lastblocknr;
654 BYTE block[BIGSIZE];
655 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
656 struct storage_header sth;
658 READ_HEADER;
659 blocknr = sth.root_startblock;
660 assert(blocknr>=0);
661 curblock=0;
662 while (blocknr>=0) {
663 if (!STORAGE_get_big_block(hf,blocknr,block))
664 return -1;
665 for (i=0;i<4;i++)
666 if (stde[i].pps_sizeofname==0) /* free */
667 return curblock*4+i;
668 lastblocknr = blocknr;
669 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
670 curblock++;
672 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
673 blocknr = STORAGE_get_free_big_blocknr(hf);
674 /* sth invalidated */
675 if (blocknr<0)
676 return -1;
678 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
679 return -1;
680 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
681 return -1;
682 memset(block,0,sizeof(block));
683 STORAGE_put_big_block(hf,blocknr,block);
684 return curblock*4;
687 /* --- IStream16 implementation */
689 typedef struct
691 /* IUnknown fields */
692 ICOM_VFIELD(IStream16);
693 DWORD ref;
694 /* IStream16 fields */
695 SEGPTR thisptr; /* pointer to this struct as segmented */
696 struct storage_pps_entry stde;
697 int ppsent;
698 HFILE hf;
699 ULARGE_INTEGER offset;
700 } IStream16Impl;
702 /******************************************************************************
703 * IStream16_QueryInterface [STORAGE.518]
705 HRESULT WINAPI IStream16_fnQueryInterface(
706 IStream16* iface,REFIID refiid,LPVOID *obj
708 ICOM_THIS(IStream16Impl,iface);
709 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
710 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
711 *obj = This;
712 return 0;
714 return OLE_E_ENUM_NOMORE;
718 /******************************************************************************
719 * IStream16_AddRef [STORAGE.519]
721 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
722 ICOM_THIS(IStream16Impl,iface);
723 return ++(This->ref);
726 /******************************************************************************
727 * IStream16_Release [STORAGE.520]
729 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
730 ICOM_THIS(IStream16Impl,iface);
731 FlushFileBuffers(This->hf);
732 This->ref--;
733 if (!This->ref) {
734 CloseHandle(This->hf);
735 UnMapLS( This->thisptr );
736 HeapFree( GetProcessHeap(), 0, This );
737 return 0;
739 return This->ref;
742 /******************************************************************************
743 * IStream16_Seek [STORAGE.523]
745 * FIXME
746 * Does not handle 64 bits
748 HRESULT WINAPI IStream16_fnSeek(
749 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
751 ICOM_THIS(IStream16Impl,iface);
752 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
754 switch (whence) {
755 /* unix SEEK_xx should be the same as win95 ones */
756 case SEEK_SET:
757 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
758 * right now.
760 assert(offset.s.HighPart==0);
761 This->offset.s.HighPart = offset.s.HighPart;
762 This->offset.s.LowPart = offset.s.LowPart;
763 break;
764 case SEEK_CUR:
765 if (offset.s.HighPart < 0) {
766 /* FIXME: is this negation correct ? */
767 offset.s.HighPart = -offset.s.HighPart;
768 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
770 assert(offset.s.HighPart==0);
771 assert(This->offset.s.LowPart >= offset.s.LowPart);
772 This->offset.s.LowPart -= offset.s.LowPart;
773 } else {
774 assert(offset.s.HighPart==0);
775 This->offset.s.LowPart+= offset.s.LowPart;
777 break;
778 case SEEK_END:
779 assert(offset.s.HighPart==0);
780 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
781 break;
783 if (This->offset.s.LowPart>This->stde.pps_size)
784 This->offset.s.LowPart=This->stde.pps_size;
785 if (newpos) *newpos = This->offset;
786 return S_OK;
789 /******************************************************************************
790 * IStream16_Read [STORAGE.521]
792 HRESULT WINAPI IStream16_fnRead(
793 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
795 ICOM_THIS(IStream16Impl,iface);
796 BYTE block[BIGSIZE];
797 ULONG *bytesread=pcbRead,xxread;
798 int blocknr;
800 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
801 if (!pcbRead) bytesread=&xxread;
802 *bytesread = 0;
804 if (cb>This->stde.pps_size-This->offset.s.LowPart)
805 cb=This->stde.pps_size-This->offset.s.LowPart;
806 if (This->stde.pps_size < 0x1000) {
807 /* use small block reader */
808 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
809 while (cb) {
810 int cc;
812 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
813 WARN("small block read failed!!!\n");
814 return E_FAIL;
816 cc = cb;
817 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
818 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
819 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
820 This->offset.s.LowPart+=cc;
821 (LPBYTE)pv+=cc;
822 *bytesread+=cc;
823 cb-=cc;
824 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
826 } else {
827 /* use big block reader */
828 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
829 while (cb) {
830 int cc;
832 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
833 WARN("big block read failed!!!\n");
834 return E_FAIL;
836 cc = cb;
837 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
838 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
839 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
840 This->offset.s.LowPart+=cc;
841 (LPBYTE)pv+=cc;
842 *bytesread+=cc;
843 cb-=cc;
844 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
847 return S_OK;
850 /******************************************************************************
851 * IStream16_Write [STORAGE.522]
853 HRESULT WINAPI IStream16_fnWrite(
854 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
856 ICOM_THIS(IStream16Impl,iface);
857 BYTE block[BIGSIZE];
858 ULONG *byteswritten=pcbWrite,xxwritten;
859 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
860 HFILE hf = This->hf;
862 if (!pcbWrite) byteswritten=&xxwritten;
863 *byteswritten = 0;
865 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
866 /* do we need to junk some blocks? */
867 newsize = This->offset.s.LowPart+cb;
868 oldsize = This->stde.pps_size;
869 if (newsize < oldsize) {
870 if (oldsize < 0x1000) {
871 /* only small blocks */
872 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
874 assert(blocknr>=0);
876 /* will set the rest of the chain to 'free' */
877 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
878 return E_FAIL;
879 } else {
880 if (newsize >= 0x1000) {
881 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
882 assert(blocknr>=0);
884 /* will set the rest of the chain to 'free' */
885 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
886 return E_FAIL;
887 } else {
888 /* Migrate large blocks to small blocks
889 * (we just migrate newsize bytes)
891 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
892 HRESULT r = E_FAIL;
894 cc = newsize;
895 blocknr = This->stde.pps_sb;
896 curdata = data;
897 while (cc>0) {
898 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
899 HeapFree(GetProcessHeap(),0,data);
900 return E_FAIL;
902 curdata += BIGSIZE;
903 cc -= BIGSIZE;
904 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
906 /* frees complete chain for this stream */
907 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
908 goto err;
909 curdata = data;
910 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
911 if (blocknr<0)
912 goto err;
913 cc = newsize;
914 while (cc>0) {
915 if (!STORAGE_put_small_block(hf,blocknr,curdata))
916 goto err;
917 cc -= SMALLSIZE;
918 if (cc<=0) {
919 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
920 goto err;
921 break;
922 } else {
923 int newblocknr = STORAGE_get_free_small_blocknr(hf);
924 if (newblocknr<0)
925 goto err;
926 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
927 goto err;
928 blocknr = newblocknr;
930 curdata += SMALLSIZE;
932 r = S_OK;
933 err:
934 HeapFree(GetProcessHeap(),0,data);
935 if(r != S_OK)
936 return r;
939 This->stde.pps_size = newsize;
942 if (newsize > oldsize) {
943 if (oldsize >= 0x1000) {
944 /* should return the block right before the 'endofchain' */
945 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
946 assert(blocknr>=0);
947 lastblocknr = blocknr;
948 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
949 blocknr = STORAGE_get_free_big_blocknr(hf);
950 if (blocknr<0)
951 return E_FAIL;
952 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
953 return E_FAIL;
954 lastblocknr = blocknr;
956 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
957 return E_FAIL;
958 } else {
959 if (newsize < 0x1000) {
960 /* find startblock */
961 if (!oldsize)
962 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
963 else
964 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
965 if (blocknr<0)
966 return E_FAIL;
968 /* allocate required new small blocks */
969 lastblocknr = blocknr;
970 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
971 blocknr = STORAGE_get_free_small_blocknr(hf);
972 if (blocknr<0)
973 return E_FAIL;
974 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
975 return E_FAIL;
976 lastblocknr = blocknr;
978 /* and terminate the chain */
979 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
980 return E_FAIL;
981 } else {
982 if (!oldsize) {
983 /* no single block allocated yet */
984 blocknr=STORAGE_get_free_big_blocknr(hf);
985 if (blocknr<0)
986 return E_FAIL;
987 This->stde.pps_sb = blocknr;
988 } else {
989 /* Migrate small blocks to big blocks */
990 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
991 HRESULT r = E_FAIL;
993 cc = oldsize;
994 blocknr = This->stde.pps_sb;
995 curdata = data;
996 /* slurp in */
997 while (cc>0) {
998 if (!STORAGE_get_small_block(hf,blocknr,curdata))
999 goto err2;
1000 curdata += SMALLSIZE;
1001 cc -= SMALLSIZE;
1002 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1004 /* free small block chain */
1005 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1006 goto err2;
1007 curdata = data;
1008 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1009 if (blocknr<0)
1010 goto err2;
1011 /* put the data into the big blocks */
1012 cc = This->stde.pps_size;
1013 while (cc>0) {
1014 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1015 goto err2;
1016 cc -= BIGSIZE;
1017 if (cc<=0) {
1018 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1019 goto err2;
1020 break;
1021 } else {
1022 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1023 if (newblocknr<0)
1024 goto err2;
1025 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1026 goto err2;
1027 blocknr = newblocknr;
1029 curdata += BIGSIZE;
1031 r = S_OK;
1032 err2:
1033 HeapFree(GetProcessHeap(),0,data);
1034 if(r != S_OK)
1035 return r;
1037 /* generate big blocks to fit the new data */
1038 lastblocknr = blocknr;
1039 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1040 blocknr = STORAGE_get_free_big_blocknr(hf);
1041 if (blocknr<0)
1042 return E_FAIL;
1043 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1044 return E_FAIL;
1045 lastblocknr = blocknr;
1047 /* terminate chain */
1048 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1049 return E_FAIL;
1052 This->stde.pps_size = newsize;
1055 /* There are just some cases where we didn't modify it, we write it out
1056 * everytime
1058 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1059 return E_FAIL;
1061 /* finally the write pass */
1062 if (This->stde.pps_size < 0x1000) {
1063 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1064 assert(blocknr>=0);
1065 while (cb>0) {
1066 /* we ensured that it is allocated above */
1067 assert(blocknr>=0);
1068 /* Read old block everytime, since we can have
1069 * overlapping data at START and END of the write
1071 if (!STORAGE_get_small_block(hf,blocknr,block))
1072 return E_FAIL;
1074 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1075 if (cc>cb)
1076 cc=cb;
1077 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1078 (LPBYTE)((char *) pv+curoffset),
1081 if (!STORAGE_put_small_block(hf,blocknr,block))
1082 return E_FAIL;
1083 cb -= cc;
1084 curoffset += cc;
1085 (LPBYTE)pv += cc;
1086 This->offset.s.LowPart += cc;
1087 *byteswritten += cc;
1088 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1090 } else {
1091 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1092 assert(blocknr>=0);
1093 while (cb>0) {
1094 /* we ensured that it is allocated above, so it better is */
1095 assert(blocknr>=0);
1096 /* read old block everytime, since we can have
1097 * overlapping data at START and END of the write
1099 if (!STORAGE_get_big_block(hf,blocknr,block))
1100 return E_FAIL;
1102 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1103 if (cc>cb)
1104 cc=cb;
1105 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1106 (LPBYTE)((char *) pv+curoffset),
1109 if (!STORAGE_put_big_block(hf,blocknr,block))
1110 return E_FAIL;
1111 cb -= cc;
1112 curoffset += cc;
1113 (LPBYTE)pv += cc;
1114 This->offset.s.LowPart += cc;
1115 *byteswritten += cc;
1116 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1119 return S_OK;
1122 /******************************************************************************
1123 * _create_istream16 [Internal]
1125 static void _create_istream16(LPSTREAM16 *str) {
1126 IStream16Impl* lpst;
1128 if (!strvt16.QueryInterface) {
1129 HMODULE16 wp = GetModuleHandle16("STORAGE");
1130 if (wp>=32) {
1131 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1132 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1133 VTENT(QueryInterface);
1134 VTENT(AddRef);
1135 VTENT(Release);
1136 VTENT(Read);
1137 VTENT(Write);
1138 VTENT(Seek);
1139 VTENT(SetSize);
1140 VTENT(CopyTo);
1141 VTENT(Commit);
1142 VTENT(Revert);
1143 VTENT(LockRegion);
1144 VTENT(UnlockRegion);
1145 VTENT(Stat);
1146 VTENT(Clone);
1147 #undef VTENT
1148 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1149 } else {
1150 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1151 VTENT(QueryInterface);
1152 VTENT(AddRef);
1153 VTENT(Release);
1154 VTENT(Read);
1155 VTENT(Write);
1156 VTENT(Seek);
1158 VTENT(CopyTo);
1159 VTENT(Commit);
1160 VTENT(SetSize);
1161 VTENT(Revert);
1162 VTENT(LockRegion);
1163 VTENT(UnlockRegion);
1164 VTENT(Stat);
1165 VTENT(Clone);
1167 #undef VTENT
1168 segstrvt16 = &strvt16;
1171 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1172 ICOM_VTBL(lpst) = segstrvt16;
1173 lpst->ref = 1;
1174 lpst->thisptr = MapLS( lpst );
1175 *str = (void*)lpst->thisptr;
1179 /* --- IStream32 implementation */
1181 typedef struct
1183 /* IUnknown fields */
1184 ICOM_VFIELD(IStream);
1185 DWORD ref;
1186 /* IStream32 fields */
1187 struct storage_pps_entry stde;
1188 int ppsent;
1189 HFILE hf;
1190 ULARGE_INTEGER offset;
1191 } IStream32Impl;
1193 /*****************************************************************************
1194 * IStream32_QueryInterface [VTABLE]
1196 HRESULT WINAPI IStream_fnQueryInterface(
1197 IStream* iface,REFIID refiid,LPVOID *obj
1199 ICOM_THIS(IStream32Impl,iface);
1201 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1202 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1203 *obj = This;
1204 return 0;
1206 return OLE_E_ENUM_NOMORE;
1210 /******************************************************************************
1211 * IStream32_AddRef [VTABLE]
1213 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1214 ICOM_THIS(IStream32Impl,iface);
1215 return ++(This->ref);
1218 /******************************************************************************
1219 * IStream32_Release [VTABLE]
1221 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1222 ICOM_THIS(IStream32Impl,iface);
1223 FlushFileBuffers(This->hf);
1224 This->ref--;
1225 if (!This->ref) {
1226 CloseHandle(This->hf);
1227 HeapFree( GetProcessHeap(), 0, This );
1228 return 0;
1230 return This->ref;
1233 /* --- IStorage16 implementation */
1235 typedef struct
1237 /* IUnknown fields */
1238 ICOM_VFIELD(IStorage16);
1239 DWORD ref;
1240 /* IStorage16 fields */
1241 SEGPTR thisptr; /* pointer to this struct as segmented */
1242 struct storage_pps_entry stde;
1243 int ppsent;
1244 HFILE hf;
1245 } IStorage16Impl;
1247 /******************************************************************************
1248 * IStorage16_QueryInterface [STORAGE.500]
1250 HRESULT WINAPI IStorage16_fnQueryInterface(
1251 IStorage16* iface,REFIID refiid,LPVOID *obj
1253 ICOM_THIS(IStorage16Impl,iface);
1255 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1257 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1258 *obj = This;
1259 return 0;
1261 return OLE_E_ENUM_NOMORE;
1264 /******************************************************************************
1265 * IStorage16_AddRef [STORAGE.501]
1267 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1268 ICOM_THIS(IStorage16Impl,iface);
1269 return ++(This->ref);
1272 /******************************************************************************
1273 * IStorage16_Release [STORAGE.502]
1275 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1276 ICOM_THIS(IStorage16Impl,iface);
1277 This->ref--;
1278 if (This->ref)
1279 return This->ref;
1280 UnMapLS( This->thisptr );
1281 HeapFree( GetProcessHeap(), 0, This );
1282 return 0;
1285 /******************************************************************************
1286 * IStorage16_Stat [STORAGE.517]
1288 HRESULT WINAPI IStorage16_fnStat(
1289 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1291 ICOM_THIS(IStorage16Impl,iface);
1292 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1293 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1295 TRACE("(%p)->(%p,0x%08lx)\n",
1296 This,pstatstg,grfStatFlag
1298 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1299 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1300 pstatstg->type = This->stde.pps_type;
1301 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1302 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1303 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1304 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1305 pstatstg->grfMode = 0; /* FIXME */
1306 pstatstg->grfLocksSupported = 0; /* FIXME */
1307 pstatstg->clsid = This->stde.pps_guid;
1308 pstatstg->grfStateBits = 0; /* FIXME */
1309 pstatstg->reserved = 0;
1310 return S_OK;
1313 /******************************************************************************
1314 * IStorage16_Commit [STORAGE.509]
1316 HRESULT WINAPI IStorage16_fnCommit(
1317 LPSTORAGE16 iface,DWORD commitflags
1319 ICOM_THIS(IStorage16Impl,iface);
1320 FIXME("(%p)->(0x%08lx),STUB!\n",
1321 This,commitflags
1323 return S_OK;
1326 /******************************************************************************
1327 * IStorage16_CopyTo [STORAGE.507]
1329 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1330 ICOM_THIS(IStorage16Impl,iface);
1331 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1332 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1334 return S_OK;
1338 /******************************************************************************
1339 * IStorage16_CreateStorage [STORAGE.505]
1341 HRESULT WINAPI IStorage16_fnCreateStorage(
1342 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1344 ICOM_THIS(IStorage16Impl,iface);
1345 IStorage16Impl* lpstg;
1346 int ppsent,x;
1347 struct storage_pps_entry stde;
1348 struct storage_header sth;
1349 HFILE hf=This->hf;
1351 READ_HEADER;
1353 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1354 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1356 if (grfMode & STGM_TRANSACTED)
1357 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1358 _create_istorage16(ppstg);
1359 lpstg = MapSL((SEGPTR)*ppstg);
1360 lpstg->hf = This->hf;
1362 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1363 if (ppsent<0)
1364 return E_FAIL;
1365 stde=This->stde;
1366 if (stde.pps_dir==-1) {
1367 stde.pps_dir = ppsent;
1368 x = This->ppsent;
1369 } else {
1370 FIXME(" use prev chain too ?\n");
1371 x=stde.pps_dir;
1372 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1373 return E_FAIL;
1374 while (stde.pps_next!=-1) {
1375 x=stde.pps_next;
1376 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1377 return E_FAIL;
1379 stde.pps_next = ppsent;
1381 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1382 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1383 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1384 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1385 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1386 lpstg->stde.pps_next = -1;
1387 lpstg->stde.pps_prev = -1;
1388 lpstg->stde.pps_dir = -1;
1389 lpstg->stde.pps_sb = -1;
1390 lpstg->stde.pps_size = 0;
1391 lpstg->stde.pps_type = 1;
1392 lpstg->ppsent = ppsent;
1393 /* FIXME: timestamps? */
1394 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1395 return E_FAIL;
1396 return S_OK;
1399 /******************************************************************************
1400 * IStorage16_CreateStream [STORAGE.503]
1402 HRESULT WINAPI IStorage16_fnCreateStream(
1403 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1405 ICOM_THIS(IStorage16Impl,iface);
1406 IStream16Impl* lpstr;
1407 int ppsent,x;
1408 struct storage_pps_entry stde;
1410 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1411 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1413 if (grfMode & STGM_TRANSACTED)
1414 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1415 _create_istream16(ppstm);
1416 lpstr = MapSL((SEGPTR)*ppstm);
1417 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1418 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1419 lpstr->offset.s.LowPart = 0;
1420 lpstr->offset.s.HighPart = 0;
1422 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1423 if (ppsent<0)
1424 return E_FAIL;
1425 stde=This->stde;
1426 if (stde.pps_next==-1)
1427 x=This->ppsent;
1428 else
1429 while (stde.pps_next!=-1) {
1430 x=stde.pps_next;
1431 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1432 return E_FAIL;
1434 stde.pps_next = ppsent;
1435 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1436 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1437 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1438 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1439 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1440 lpstr->stde.pps_next = -1;
1441 lpstr->stde.pps_prev = -1;
1442 lpstr->stde.pps_dir = -1;
1443 lpstr->stde.pps_sb = -1;
1444 lpstr->stde.pps_size = 0;
1445 lpstr->stde.pps_type = 2;
1446 lpstr->ppsent = ppsent;
1447 /* FIXME: timestamps? */
1448 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1449 return E_FAIL;
1450 return S_OK;
1453 /******************************************************************************
1454 * IStorage16_OpenStorage [STORAGE.506]
1456 HRESULT WINAPI IStorage16_fnOpenStorage(
1457 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1459 ICOM_THIS(IStorage16Impl,iface);
1460 IStream16Impl* lpstg;
1461 WCHAR name[33];
1462 int newpps;
1464 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1465 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1467 if (grfMode & STGM_TRANSACTED)
1468 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1469 _create_istorage16(ppstg);
1470 lpstg = MapSL((SEGPTR)*ppstg);
1471 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1472 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1473 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1474 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1475 if (newpps==-1) {
1476 IStream16_fnRelease((IStream16*)lpstg);
1477 return E_FAIL;
1480 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1481 IStream16_fnRelease((IStream16*)lpstg);
1482 return E_FAIL;
1484 lpstg->ppsent = newpps;
1485 return S_OK;
1488 /******************************************************************************
1489 * IStorage16_OpenStream [STORAGE.504]
1491 HRESULT WINAPI IStorage16_fnOpenStream(
1492 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1494 ICOM_THIS(IStorage16Impl,iface);
1495 IStream16Impl* lpstr;
1496 WCHAR name[33];
1497 int newpps;
1499 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1500 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1502 if (grfMode & STGM_TRANSACTED)
1503 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1504 _create_istream16(ppstm);
1505 lpstr = MapSL((SEGPTR)*ppstm);
1506 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1507 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1508 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1509 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1510 if (newpps==-1) {
1511 IStream16_fnRelease((IStream16*)lpstr);
1512 return E_FAIL;
1515 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1516 IStream16_fnRelease((IStream16*)lpstr);
1517 return E_FAIL;
1519 lpstr->offset.s.LowPart = 0;
1520 lpstr->offset.s.HighPart = 0;
1521 lpstr->ppsent = newpps;
1522 return S_OK;
1525 /******************************************************************************
1526 * _create_istorage16 [INTERNAL]
1528 static void _create_istorage16(LPSTORAGE16 *stg) {
1529 IStorage16Impl* lpst;
1531 if (!stvt16.QueryInterface) {
1532 HMODULE16 wp = GetModuleHandle16("STORAGE");
1533 if (wp>=32) {
1534 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1535 VTENT(QueryInterface)
1536 VTENT(AddRef)
1537 VTENT(Release)
1538 VTENT(CreateStream)
1539 VTENT(OpenStream)
1540 VTENT(CreateStorage)
1541 VTENT(OpenStorage)
1542 VTENT(CopyTo)
1543 VTENT(MoveElementTo)
1544 VTENT(Commit)
1545 VTENT(Revert)
1546 VTENT(EnumElements)
1547 VTENT(DestroyElement)
1548 VTENT(RenameElement)
1549 VTENT(SetElementTimes)
1550 VTENT(SetClass)
1551 VTENT(SetStateBits)
1552 VTENT(Stat)
1553 #undef VTENT
1554 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1555 } else {
1556 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1557 VTENT(QueryInterface)
1558 VTENT(AddRef)
1559 VTENT(Release)
1560 VTENT(CreateStream)
1561 VTENT(OpenStream)
1562 VTENT(CreateStorage)
1563 VTENT(OpenStorage)
1564 VTENT(CopyTo)
1565 VTENT(Commit)
1566 /* not (yet) implemented ...
1567 VTENT(MoveElementTo)
1568 VTENT(Revert)
1569 VTENT(EnumElements)
1570 VTENT(DestroyElement)
1571 VTENT(RenameElement)
1572 VTENT(SetElementTimes)
1573 VTENT(SetClass)
1574 VTENT(SetStateBits)
1575 VTENT(Stat)
1577 #undef VTENT
1578 segstvt16 = &stvt16;
1581 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1582 ICOM_VTBL(lpst) = segstvt16;
1583 lpst->ref = 1;
1584 lpst->thisptr = MapLS(lpst);
1585 *stg = (void*)lpst->thisptr;
1588 /******************************************************************************
1589 * Storage API functions
1592 /******************************************************************************
1593 * StgCreateDocFileA [STORAGE.1]
1595 HRESULT WINAPI StgCreateDocFile16(
1596 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1598 HFILE hf;
1599 int i,ret;
1600 IStorage16Impl* lpstg;
1601 struct storage_pps_entry stde;
1603 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1604 pwcsName,grfMode,reserved,ppstgOpen
1606 _create_istorage16(ppstgOpen);
1607 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1608 if (hf==INVALID_HANDLE_VALUE) {
1609 WARN("couldn't open file for storage:%ld\n",GetLastError());
1610 return E_FAIL;
1612 lpstg = MapSL((SEGPTR)*ppstgOpen);
1613 lpstg->hf = hf;
1614 /* FIXME: check for existence before overwriting? */
1615 if (!STORAGE_init_storage(hf)) {
1616 CloseHandle(hf);
1617 return E_FAIL;
1619 i=0;ret=0;
1620 while (!ret) { /* neither 1 nor <0 */
1621 ret=STORAGE_get_pps_entry(hf,i,&stde);
1622 if ((ret==1) && (stde.pps_type==5)) {
1623 lpstg->stde = stde;
1624 lpstg->ppsent = i;
1625 break;
1627 i++;
1629 if (ret!=1) {
1630 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1631 return E_FAIL;
1634 return S_OK;
1637 /******************************************************************************
1638 * StgIsStorageFile [STORAGE.5]
1640 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1641 HFILE hf;
1642 OFSTRUCT ofs;
1643 BYTE magic[24];
1645 TRACE("(\'%s\')\n",fn);
1646 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1647 if (hf==HFILE_ERROR)
1648 return STG_E_FILENOTFOUND;
1649 if (24!=_lread(hf,magic,24)) {
1650 WARN(" too short\n");
1651 _lclose(hf);
1652 return S_FALSE;
1654 if (!memcmp(magic,STORAGE_magic,8)) {
1655 WARN(" -> YES\n");
1656 _lclose(hf);
1657 return S_OK;
1659 if (!memcmp(magic,STORAGE_notmagic,8)) {
1660 WARN(" -> NO\n");
1661 _lclose(hf);
1662 return S_FALSE;
1664 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1665 WARN(" -> old format\n");
1666 _lclose(hf);
1667 return STG_E_OLDFORMAT;
1669 WARN(" -> Invalid header.\n");
1670 _lclose(hf);
1671 return STG_E_INVALIDHEADER;
1674 /******************************************************************************
1675 * StgIsStorageFile [OLE32.146]
1677 HRESULT WINAPI
1678 StgIsStorageFile(LPCOLESTR fn)
1680 HRESULT ret;
1681 DWORD len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL );
1682 LPSTR strA = HeapAlloc( GetProcessHeap(), 0, len );
1684 WideCharToMultiByte( CP_ACP, 0, fn, -1, strA, len, NULL, NULL );
1685 ret = StgIsStorageFile16(strA);
1686 HeapFree( GetProcessHeap(), 0, strA );
1687 return ret;
1691 /******************************************************************************
1692 * StgOpenStorage [STORAGE.3]
1694 HRESULT WINAPI StgOpenStorage16(
1695 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1696 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1698 HFILE hf;
1699 int ret,i;
1700 IStorage16Impl* lpstg;
1701 struct storage_pps_entry stde;
1703 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1704 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1706 _create_istorage16(ppstgOpen);
1707 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1708 if (hf==INVALID_HANDLE_VALUE) {
1709 WARN("Couldn't open file for storage\n");
1710 return E_FAIL;
1712 lpstg = MapSL((SEGPTR)*ppstgOpen);
1713 lpstg->hf = hf;
1715 i=0;ret=0;
1716 while (!ret) { /* neither 1 nor <0 */
1717 ret=STORAGE_get_pps_entry(hf,i,&stde);
1718 if ((ret==1) && (stde.pps_type==5)) {
1719 lpstg->stde=stde;
1720 break;
1722 i++;
1724 if (ret!=1) {
1725 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1726 return E_FAIL;
1728 return S_OK;