Added LGPL standard comment, and copyright notices where necessary.
[wine/multimedia.git] / dlls / ole32 / storage.c
blobd861fff2933773b97fb85e387547e86fa2b33c0e
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 <assert.h>
25 #include <time.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include "windef.h"
30 #include "ntddk.h"
31 #include "winerror.h"
32 #include "wine/winbase16.h"
33 #include "wine/unicode.h"
34 #include "wtypes.h"
35 #include "wine/obj_base.h"
36 #include "wine/obj_storage.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 WINE_DECLARE_DEBUG_CHANNEL(relay);
42 struct storage_header {
43 BYTE magic[8]; /* 00: magic */
44 BYTE unknown1[36]; /* 08: unknown */
45 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
46 DWORD root_startblock;/* 30: root storage first big block */
47 DWORD unknown2[2]; /* 34: unknown */
48 DWORD sbd_startblock; /* 3C: small block depot first big block */
49 DWORD unknown3[3]; /* 40: unknown */
50 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
52 struct storage_pps_entry {
53 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
54 WORD pps_sizeofname; /* 40: namelength in bytes */
55 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
56 BYTE pps_unknown0; /* 43: unknown */
57 DWORD pps_prev; /* 44: previous pps */
58 DWORD pps_next; /* 48: next pps */
59 DWORD pps_dir; /* 4C: directory pps */
60 GUID pps_guid; /* 50: class ID */
61 DWORD pps_unknown1; /* 60: unknown */
62 FILETIME pps_ft1; /* 64: filetime1 */
63 FILETIME pps_ft2; /* 70: filetime2 */
64 DWORD pps_sb; /* 74: data startblock */
65 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
66 DWORD pps_unknown2; /* 7C: unknown */
69 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
70 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
71 #define STORAGE_CHAINENTRY_FREE 0xffffffff
74 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
75 static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
76 static const BYTE STORAGE_oldmagic[8]={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
78 #define BIGSIZE 512
79 #define SMALLSIZE 64
81 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
83 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
84 static ICOM_VTABLE(IStorage16) stvt16;
85 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
86 static ICOM_VTABLE(IStream16) strvt16;
87 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
89 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
90 static void _create_istorage16(LPSTORAGE16 *stg);
91 static void _create_istream16(LPSTREAM16 *str);
93 #define IMPLEMENTED 1
96 /******************************************************************************
97 * STORAGE_get_big_block [Internal]
99 * Reading OLE compound storage
101 static BOOL
102 STORAGE_get_big_block(HFILE hf,int n,BYTE *block) {
103 assert(n>=-1);
104 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
105 WARN(" seek failed (%ld)\n",GetLastError());
106 return FALSE;
108 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
109 if (BIGSIZE!=_lread(hf,block,BIGSIZE)) {
110 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
111 assert(0);
112 return FALSE;
114 return TRUE;
117 /******************************************************************************
118 * STORAGE_put_big_block [INTERNAL]
120 static BOOL
121 STORAGE_put_big_block(HFILE hf,int n,BYTE *block) {
122 assert(n>=-1);
123 if (-1==_llseek(hf,(n+1)*BIGSIZE,SEEK_SET)) {
124 WARN(" seek failed (%ld)\n",GetLastError());
125 return FALSE;
127 assert((n+1)*BIGSIZE==_llseek(hf,0,SEEK_CUR));
128 if (BIGSIZE!=_lwrite(hf,block,BIGSIZE)) {
129 WARN(" write failed (%ld)\n",GetLastError());
130 return FALSE;
132 return TRUE;
135 /******************************************************************************
136 * STORAGE_get_next_big_blocknr [INTERNAL]
138 static int
139 STORAGE_get_next_big_blocknr(HFILE hf,int blocknr) {
140 INT bbs[BIGSIZE/sizeof(INT)];
141 struct storage_header sth;
143 READ_HEADER;
145 assert(blocknr>>7<sth.num_of_bbd_blocks);
146 if (sth.bbd_list[blocknr>>7]==0xffffffff)
147 return -5;
148 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
149 return -5;
150 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
151 return bbs[blocknr&0x7f];
154 /******************************************************************************
155 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
157 static int
158 STORAGE_get_nth_next_big_blocknr(HFILE hf,int blocknr,int nr) {
159 INT bbs[BIGSIZE/sizeof(INT)];
160 int lastblock = -1;
161 struct storage_header sth;
163 READ_HEADER;
165 assert(blocknr>=0);
166 while (nr--) {
167 assert((blocknr>>7)<sth.num_of_bbd_blocks);
168 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
170 /* simple caching... */
171 if (lastblock!=sth.bbd_list[blocknr>>7]) {
172 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
173 lastblock = sth.bbd_list[blocknr>>7];
175 blocknr = bbs[blocknr&0x7f];
177 return blocknr;
180 /******************************************************************************
181 * STORAGE_get_root_pps_entry [Internal]
183 static BOOL
184 STORAGE_get_root_pps_entry(HFILE hf,struct storage_pps_entry *pstde) {
185 int blocknr,i;
186 BYTE block[BIGSIZE];
187 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
188 struct storage_header sth;
190 READ_HEADER;
191 blocknr = sth.root_startblock;
192 while (blocknr>=0) {
193 assert(STORAGE_get_big_block(hf,blocknr,block));
194 for (i=0;i<4;i++) {
195 if (!stde[i].pps_sizeofname)
196 continue;
197 if (stde[i].pps_type==5) {
198 *pstde=stde[i];
199 return TRUE;
202 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
204 return FALSE;
207 /******************************************************************************
208 * STORAGE_get_small_block [INTERNAL]
210 static BOOL
211 STORAGE_get_small_block(HFILE hf,int blocknr,BYTE *sblock) {
212 BYTE block[BIGSIZE];
213 int bigblocknr;
214 struct storage_pps_entry root;
216 assert(blocknr>=0);
217 assert(STORAGE_get_root_pps_entry(hf,&root));
218 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
219 assert(bigblocknr>=0);
220 assert(STORAGE_get_big_block(hf,bigblocknr,block));
222 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
223 return TRUE;
226 /******************************************************************************
227 * STORAGE_put_small_block [INTERNAL]
229 static BOOL
230 STORAGE_put_small_block(HFILE hf,int blocknr,BYTE *sblock) {
231 BYTE block[BIGSIZE];
232 int bigblocknr;
233 struct storage_pps_entry root;
235 assert(blocknr>=0);
237 assert(STORAGE_get_root_pps_entry(hf,&root));
238 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
239 assert(bigblocknr>=0);
240 assert(STORAGE_get_big_block(hf,bigblocknr,block));
242 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
243 assert(STORAGE_put_big_block(hf,bigblocknr,block));
244 return TRUE;
247 /******************************************************************************
248 * STORAGE_get_next_small_blocknr [INTERNAL]
250 static int
251 STORAGE_get_next_small_blocknr(HFILE hf,int blocknr) {
252 BYTE block[BIGSIZE];
253 LPINT sbd = (LPINT)block;
254 int bigblocknr;
255 struct storage_header sth;
257 READ_HEADER;
258 assert(blocknr>=0);
259 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
260 assert(bigblocknr>=0);
261 assert(STORAGE_get_big_block(hf,bigblocknr,block));
262 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
263 return sbd[blocknr & (128-1)];
266 /******************************************************************************
267 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
269 static int
270 STORAGE_get_nth_next_small_blocknr(HFILE hf,int blocknr,int nr) {
271 int lastblocknr;
272 BYTE block[BIGSIZE];
273 LPINT sbd = (LPINT)block;
274 struct storage_header sth;
276 READ_HEADER;
277 lastblocknr=-1;
278 assert(blocknr>=0);
279 while ((nr--) && (blocknr>=0)) {
280 if (lastblocknr/128!=blocknr/128) {
281 int bigblocknr;
282 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
283 assert(bigblocknr>=0);
284 assert(STORAGE_get_big_block(hf,bigblocknr,block));
285 lastblocknr = blocknr;
287 assert(lastblocknr>=0);
288 lastblocknr=blocknr;
289 blocknr=sbd[blocknr & (128-1)];
290 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
292 return blocknr;
295 /******************************************************************************
296 * STORAGE_get_pps_entry [INTERNAL]
298 static int
299 STORAGE_get_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
300 int blocknr;
301 BYTE block[BIGSIZE];
302 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
303 struct storage_header sth;
305 READ_HEADER;
306 /* we have 4 pps entries per big block */
307 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
308 assert(blocknr>=0);
309 assert(STORAGE_get_big_block(hf,blocknr,block));
311 *pstde=*stde;
312 return 1;
315 /******************************************************************************
316 * STORAGE_put_pps_entry [Internal]
318 static int
319 STORAGE_put_pps_entry(HFILE hf,int n,struct storage_pps_entry *pstde) {
320 int blocknr;
321 BYTE block[BIGSIZE];
322 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
323 struct storage_header sth;
325 READ_HEADER;
327 /* we have 4 pps entries per big block */
328 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
329 assert(blocknr>=0);
330 assert(STORAGE_get_big_block(hf,blocknr,block));
331 *stde=*pstde;
332 assert(STORAGE_put_big_block(hf,blocknr,block));
333 return 1;
336 /******************************************************************************
337 * STORAGE_look_for_named_pps [Internal]
339 static int
340 STORAGE_look_for_named_pps(HFILE hf,int n,LPOLESTR name) {
341 struct storage_pps_entry stde;
342 int ret;
344 if (n==-1)
345 return -1;
346 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
347 return -1;
349 if (!lstrcmpW(name,stde.pps_rawname))
350 return n;
351 if (stde.pps_prev != -1) {
352 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
353 if (ret!=-1)
354 return ret;
356 if (stde.pps_next != -1) {
357 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
358 if (ret!=-1)
359 return ret;
361 return -1;
364 /******************************************************************************
365 * STORAGE_dump_pps_entry [Internal]
367 * FIXME
368 * Function is unused
370 void
371 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
372 char name[33];
374 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
375 if (!stde->pps_sizeofname)
376 return;
377 DPRINTF("name: %s\n",name);
378 DPRINTF("type: %d\n",stde->pps_type);
379 DPRINTF("prev pps: %ld\n",stde->pps_prev);
380 DPRINTF("next pps: %ld\n",stde->pps_next);
381 DPRINTF("dir pps: %ld\n",stde->pps_dir);
382 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
383 if (stde->pps_type !=2) {
384 time_t t;
385 DWORD dw;
386 RtlTimeToSecondsSince1970(&(stde->pps_ft1),&dw);
387 t = dw;
388 DPRINTF("ts1: %s\n",ctime(&t));
389 RtlTimeToSecondsSince1970(&(stde->pps_ft2),&dw);
390 t = dw;
391 DPRINTF("ts2: %s\n",ctime(&t));
393 DPRINTF("startblock: %ld\n",stde->pps_sb);
394 DPRINTF("size: %ld\n",stde->pps_size);
397 /******************************************************************************
398 * STORAGE_init_storage [INTERNAL]
400 static BOOL
401 STORAGE_init_storage(HFILE hf) {
402 BYTE block[BIGSIZE];
403 LPDWORD bbs;
404 struct storage_header *sth;
405 struct storage_pps_entry *stde;
407 assert(-1!=_llseek(hf,0,SEEK_SET));
408 /* block -1 is the storage header */
409 sth = (struct storage_header*)block;
410 memcpy(sth->magic,STORAGE_magic,8);
411 memset(sth->unknown1,0,sizeof(sth->unknown1));
412 memset(sth->unknown2,0,sizeof(sth->unknown2));
413 memset(sth->unknown3,0,sizeof(sth->unknown3));
414 sth->num_of_bbd_blocks = 1;
415 sth->root_startblock = 1;
416 sth->sbd_startblock = 0xffffffff;
417 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
418 sth->bbd_list[0] = 0;
419 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
420 /* block 0 is the big block directory */
421 bbs=(LPDWORD)block;
422 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
423 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
424 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
425 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
426 /* block 1 is the root directory entry */
427 memset(block,0x00,sizeof(block));
428 stde = (struct storage_pps_entry*)block;
429 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
430 sizeof(stde->pps_rawname)/sizeof(WCHAR));
431 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
432 stde->pps_type = 5;
433 stde->pps_dir = -1;
434 stde->pps_next = -1;
435 stde->pps_prev = -1;
436 stde->pps_sb = 0xffffffff;
437 stde->pps_size = 0;
438 assert(BIGSIZE==_lwrite(hf,block,BIGSIZE));
439 return TRUE;
442 /******************************************************************************
443 * STORAGE_set_big_chain [Internal]
445 static BOOL
446 STORAGE_set_big_chain(HFILE hf,int blocknr,INT type) {
447 BYTE block[BIGSIZE];
448 LPINT bbd = (LPINT)block;
449 int nextblocknr,bigblocknr;
450 struct storage_header sth;
452 READ_HEADER;
453 assert(blocknr!=type);
454 while (blocknr>=0) {
455 bigblocknr = sth.bbd_list[blocknr/128];
456 assert(bigblocknr>=0);
457 assert(STORAGE_get_big_block(hf,bigblocknr,block));
459 nextblocknr = bbd[blocknr&(128-1)];
460 bbd[blocknr&(128-1)] = type;
461 if (type>=0)
462 return TRUE;
463 assert(STORAGE_put_big_block(hf,bigblocknr,block));
464 type = STORAGE_CHAINENTRY_FREE;
465 blocknr = nextblocknr;
467 return TRUE;
470 /******************************************************************************
471 * STORAGE_set_small_chain [Internal]
473 static BOOL
474 STORAGE_set_small_chain(HFILE hf,int blocknr,INT type) {
475 BYTE block[BIGSIZE];
476 LPINT sbd = (LPINT)block;
477 int lastblocknr,nextsmallblocknr,bigblocknr;
478 struct storage_header sth;
480 READ_HEADER;
482 assert(blocknr!=type);
483 lastblocknr=-129;bigblocknr=-2;
484 while (blocknr>=0) {
485 /* cache block ... */
486 if (lastblocknr/128!=blocknr/128) {
487 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
488 assert(bigblocknr>=0);
489 assert(STORAGE_get_big_block(hf,bigblocknr,block));
491 lastblocknr = blocknr;
492 nextsmallblocknr = sbd[blocknr&(128-1)];
493 sbd[blocknr&(128-1)] = type;
494 assert(STORAGE_put_big_block(hf,bigblocknr,block));
495 if (type>=0)
496 return TRUE;
497 type = STORAGE_CHAINENTRY_FREE;
498 blocknr = nextsmallblocknr;
500 return TRUE;
503 /******************************************************************************
504 * STORAGE_get_free_big_blocknr [Internal]
506 static int
507 STORAGE_get_free_big_blocknr(HFILE hf) {
508 BYTE block[BIGSIZE];
509 LPINT sbd = (LPINT)block;
510 int lastbigblocknr,i,curblock,bigblocknr;
511 struct storage_header sth;
513 READ_HEADER;
514 curblock = 0;
515 lastbigblocknr = -1;
516 bigblocknr = sth.bbd_list[curblock];
517 while (curblock<sth.num_of_bbd_blocks) {
518 assert(bigblocknr>=0);
519 assert(STORAGE_get_big_block(hf,bigblocknr,block));
520 for (i=0;i<128;i++)
521 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
522 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
523 assert(STORAGE_put_big_block(hf,bigblocknr,block));
524 memset(block,0x42,sizeof(block));
525 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
526 return i+curblock*128;
528 lastbigblocknr = bigblocknr;
529 bigblocknr = sth.bbd_list[++curblock];
531 bigblocknr = curblock*128;
532 /* since we have marked all blocks from 0 up to curblock*128-1
533 * the next free one is curblock*128, where we happily put our
534 * next large block depot.
536 memset(block,0xff,sizeof(block));
537 /* mark the block allocated and returned by this function */
538 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
539 assert(STORAGE_put_big_block(hf,bigblocknr,block));
541 /* if we had a bbd block already (mostlikely) we need
542 * to link the new one into the chain
544 if (lastbigblocknr!=-1)
545 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
546 sth.bbd_list[curblock]=bigblocknr;
547 sth.num_of_bbd_blocks++;
548 assert(sth.num_of_bbd_blocks==curblock+1);
549 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
551 /* Set the end of the chain for the bigblockdepots */
552 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
553 /* add 1, for the first entry is used for the additional big block
554 * depot. (means we already used bigblocknr) */
555 memset(block,0x42,sizeof(block));
556 /* allocate this block (filled with 0x42) */
557 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
558 return bigblocknr+1;
562 /******************************************************************************
563 * STORAGE_get_free_small_blocknr [Internal]
565 static int
566 STORAGE_get_free_small_blocknr(HFILE hf) {
567 BYTE block[BIGSIZE];
568 LPINT sbd = (LPINT)block;
569 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
570 struct storage_pps_entry root;
571 struct storage_header sth;
573 READ_HEADER;
574 bigblocknr = sth.sbd_startblock;
575 curblock = 0;
576 lastbigblocknr = -1;
577 newblocknr = -1;
578 while (bigblocknr>=0) {
579 if (!STORAGE_get_big_block(hf,bigblocknr,block))
580 return -1;
581 for (i=0;i<128;i++)
582 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
583 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
584 newblocknr = i+curblock*128;
585 break;
587 if (i!=128)
588 break;
589 lastbigblocknr = bigblocknr;
590 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
591 curblock++;
593 if (newblocknr==-1) {
594 bigblocknr = STORAGE_get_free_big_blocknr(hf);
595 if (bigblocknr<0)
596 return -1;
597 READ_HEADER;
598 memset(block,0xff,sizeof(block));
599 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
600 if (!STORAGE_put_big_block(hf,bigblocknr,block))
601 return -1;
602 if (lastbigblocknr==-1) {
603 sth.sbd_startblock = bigblocknr;
604 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
605 return -1;
606 } else {
607 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
608 return -1;
610 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
611 return -1;
612 newblocknr = curblock*128;
614 /* allocate enough big blocks for storing the allocated small block */
615 if (!STORAGE_get_root_pps_entry(hf,&root))
616 return -1;
617 if (root.pps_sb==-1)
618 lastbigblocknr = -1;
619 else
620 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
621 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
622 /* we need to allocate more stuff */
623 bigblocknr = STORAGE_get_free_big_blocknr(hf);
624 if (bigblocknr<0)
625 return -1;
626 READ_HEADER;
627 if (root.pps_sb==-1) {
628 root.pps_sb = bigblocknr;
629 root.pps_size += BIGSIZE;
630 } else {
631 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
632 return -1;
633 root.pps_size += BIGSIZE;
635 lastbigblocknr = bigblocknr;
637 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
638 return -1;
639 if (!STORAGE_put_pps_entry(hf,0,&root))
640 return -1;
641 return newblocknr;
644 /******************************************************************************
645 * STORAGE_get_free_pps_entry [Internal]
647 static int
648 STORAGE_get_free_pps_entry(HFILE hf) {
649 int blocknr,i,curblock,lastblocknr;
650 BYTE block[BIGSIZE];
651 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
652 struct storage_header sth;
654 READ_HEADER;
655 blocknr = sth.root_startblock;
656 assert(blocknr>=0);
657 curblock=0;
658 while (blocknr>=0) {
659 if (!STORAGE_get_big_block(hf,blocknr,block))
660 return -1;
661 for (i=0;i<4;i++)
662 if (stde[i].pps_sizeofname==0) /* free */
663 return curblock*4+i;
664 lastblocknr = blocknr;
665 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
666 curblock++;
668 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
669 blocknr = STORAGE_get_free_big_blocknr(hf);
670 /* sth invalidated */
671 if (blocknr<0)
672 return -1;
674 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
675 return -1;
676 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
677 return -1;
678 memset(block,0,sizeof(block));
679 STORAGE_put_big_block(hf,blocknr,block);
680 return curblock*4;
683 /* --- IStream16 implementation */
685 typedef struct
687 /* IUnknown fields */
688 ICOM_VFIELD(IStream16);
689 DWORD ref;
690 /* IStream16 fields */
691 SEGPTR thisptr; /* pointer to this struct as segmented */
692 struct storage_pps_entry stde;
693 int ppsent;
694 HFILE hf;
695 ULARGE_INTEGER offset;
696 } IStream16Impl;
698 /******************************************************************************
699 * IStream16_QueryInterface [STORAGE.518]
701 HRESULT WINAPI IStream16_fnQueryInterface(
702 IStream16* iface,REFIID refiid,LPVOID *obj
704 ICOM_THIS(IStream16Impl,iface);
705 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
706 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
707 *obj = This;
708 return 0;
710 return OLE_E_ENUM_NOMORE;
714 /******************************************************************************
715 * IStream16_AddRef [STORAGE.519]
717 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
718 ICOM_THIS(IStream16Impl,iface);
719 return ++(This->ref);
722 /******************************************************************************
723 * IStream16_Release [STORAGE.520]
725 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
726 ICOM_THIS(IStream16Impl,iface);
727 FlushFileBuffers(This->hf);
728 This->ref--;
729 if (!This->ref) {
730 CloseHandle(This->hf);
731 UnMapLS( This->thisptr );
732 HeapFree( GetProcessHeap(), 0, This );
733 return 0;
735 return This->ref;
738 /******************************************************************************
739 * IStream16_Seek [STORAGE.523]
741 * FIXME
742 * Does not handle 64 bits
744 HRESULT WINAPI IStream16_fnSeek(
745 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
747 ICOM_THIS(IStream16Impl,iface);
748 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
750 switch (whence) {
751 /* unix SEEK_xx should be the same as win95 ones */
752 case SEEK_SET:
753 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
754 * right now.
756 assert(offset.s.HighPart==0);
757 This->offset.s.HighPart = offset.s.HighPart;
758 This->offset.s.LowPart = offset.s.LowPart;
759 break;
760 case SEEK_CUR:
761 if (offset.s.HighPart < 0) {
762 /* FIXME: is this negation correct ? */
763 offset.s.HighPart = -offset.s.HighPart;
764 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
766 assert(offset.s.HighPart==0);
767 assert(This->offset.s.LowPart >= offset.s.LowPart);
768 This->offset.s.LowPart -= offset.s.LowPart;
769 } else {
770 assert(offset.s.HighPart==0);
771 This->offset.s.LowPart+= offset.s.LowPart;
773 break;
774 case SEEK_END:
775 assert(offset.s.HighPart==0);
776 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
777 break;
779 if (This->offset.s.LowPart>This->stde.pps_size)
780 This->offset.s.LowPart=This->stde.pps_size;
781 if (newpos) *newpos = This->offset;
782 return S_OK;
785 /******************************************************************************
786 * IStream16_Read [STORAGE.521]
788 HRESULT WINAPI IStream16_fnRead(
789 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
791 ICOM_THIS(IStream16Impl,iface);
792 BYTE block[BIGSIZE];
793 ULONG *bytesread=pcbRead,xxread;
794 int blocknr;
796 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
797 if (!pcbRead) bytesread=&xxread;
798 *bytesread = 0;
800 if (cb>This->stde.pps_size-This->offset.s.LowPart)
801 cb=This->stde.pps_size-This->offset.s.LowPart;
802 if (This->stde.pps_size < 0x1000) {
803 /* use small block reader */
804 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
805 while (cb) {
806 int cc;
808 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
809 WARN("small block read failed!!!\n");
810 return E_FAIL;
812 cc = cb;
813 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
814 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
815 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
816 This->offset.s.LowPart+=cc;
817 (LPBYTE)pv+=cc;
818 *bytesread+=cc;
819 cb-=cc;
820 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
822 } else {
823 /* use big block reader */
824 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
825 while (cb) {
826 int cc;
828 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
829 WARN("big block read failed!!!\n");
830 return E_FAIL;
832 cc = cb;
833 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
834 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
835 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
836 This->offset.s.LowPart+=cc;
837 (LPBYTE)pv+=cc;
838 *bytesread+=cc;
839 cb-=cc;
840 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
843 return S_OK;
846 /******************************************************************************
847 * IStream16_Write [STORAGE.522]
849 HRESULT WINAPI IStream16_fnWrite(
850 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
852 ICOM_THIS(IStream16Impl,iface);
853 BYTE block[BIGSIZE];
854 ULONG *byteswritten=pcbWrite,xxwritten;
855 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
856 HFILE hf = This->hf;
858 if (!pcbWrite) byteswritten=&xxwritten;
859 *byteswritten = 0;
861 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
862 /* do we need to junk some blocks? */
863 newsize = This->offset.s.LowPart+cb;
864 oldsize = This->stde.pps_size;
865 if (newsize < oldsize) {
866 if (oldsize < 0x1000) {
867 /* only small blocks */
868 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
870 assert(blocknr>=0);
872 /* will set the rest of the chain to 'free' */
873 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
874 return E_FAIL;
875 } else {
876 if (newsize >= 0x1000) {
877 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
878 assert(blocknr>=0);
880 /* will set the rest of the chain to 'free' */
881 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
882 return E_FAIL;
883 } else {
884 /* Migrate large blocks to small blocks
885 * (we just migrate newsize bytes)
887 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
888 cc = newsize;
889 blocknr = This->stde.pps_sb;
890 curdata = data;
891 while (cc>0) {
892 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
893 HeapFree(GetProcessHeap(),0,data);
894 return E_FAIL;
896 curdata += BIGSIZE;
897 cc -= BIGSIZE;
898 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
900 /* frees complete chain for this stream */
901 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
902 return E_FAIL;
903 curdata = data;
904 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
905 if (blocknr<0)
906 return E_FAIL;
907 cc = newsize;
908 while (cc>0) {
909 if (!STORAGE_put_small_block(hf,blocknr,curdata))
910 return E_FAIL;
911 cc -= SMALLSIZE;
912 if (cc<=0) {
913 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
914 return E_FAIL;
915 break;
916 } else {
917 int newblocknr = STORAGE_get_free_small_blocknr(hf);
918 if (newblocknr<0)
919 return E_FAIL;
920 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
921 return E_FAIL;
922 blocknr = newblocknr;
924 curdata += SMALLSIZE;
926 HeapFree(GetProcessHeap(),0,data);
929 This->stde.pps_size = newsize;
932 if (newsize > oldsize) {
933 if (oldsize >= 0x1000) {
934 /* should return the block right before the 'endofchain' */
935 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
936 assert(blocknr>=0);
937 lastblocknr = blocknr;
938 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
939 blocknr = STORAGE_get_free_big_blocknr(hf);
940 if (blocknr<0)
941 return E_FAIL;
942 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
943 return E_FAIL;
944 lastblocknr = blocknr;
946 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
947 return E_FAIL;
948 } else {
949 if (newsize < 0x1000) {
950 /* find startblock */
951 if (!oldsize)
952 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
953 else
954 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
955 if (blocknr<0)
956 return E_FAIL;
958 /* allocate required new small blocks */
959 lastblocknr = blocknr;
960 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
961 blocknr = STORAGE_get_free_small_blocknr(hf);
962 if (blocknr<0)
963 return E_FAIL;
964 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
965 return E_FAIL;
966 lastblocknr = blocknr;
968 /* and terminate the chain */
969 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
970 return E_FAIL;
971 } else {
972 if (!oldsize) {
973 /* no single block allocated yet */
974 blocknr=STORAGE_get_free_big_blocknr(hf);
975 if (blocknr<0)
976 return E_FAIL;
977 This->stde.pps_sb = blocknr;
978 } else {
979 /* Migrate small blocks to big blocks */
980 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
981 cc = oldsize;
982 blocknr = This->stde.pps_sb;
983 curdata = data;
984 /* slurp in */
985 while (cc>0) {
986 if (!STORAGE_get_small_block(hf,blocknr,curdata)) {
987 HeapFree(GetProcessHeap(),0,data);
988 return E_FAIL;
990 curdata += SMALLSIZE;
991 cc -= SMALLSIZE;
992 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
994 /* free small block chain */
995 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
996 return E_FAIL;
997 curdata = data;
998 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
999 if (blocknr<0)
1000 return E_FAIL;
1001 /* put the data into the big blocks */
1002 cc = This->stde.pps_size;
1003 while (cc>0) {
1004 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1005 return E_FAIL;
1006 cc -= BIGSIZE;
1007 if (cc<=0) {
1008 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1009 return E_FAIL;
1010 break;
1011 } else {
1012 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1013 if (newblocknr<0)
1014 return E_FAIL;
1015 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1016 return E_FAIL;
1017 blocknr = newblocknr;
1019 curdata += BIGSIZE;
1021 HeapFree(GetProcessHeap(),0,data);
1023 /* generate big blocks to fit the new data */
1024 lastblocknr = blocknr;
1025 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1026 blocknr = STORAGE_get_free_big_blocknr(hf);
1027 if (blocknr<0)
1028 return E_FAIL;
1029 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1030 return E_FAIL;
1031 lastblocknr = blocknr;
1033 /* terminate chain */
1034 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1035 return E_FAIL;
1038 This->stde.pps_size = newsize;
1041 /* There are just some cases where we didn't modify it, we write it out
1042 * everytime
1044 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1045 return E_FAIL;
1047 /* finally the write pass */
1048 if (This->stde.pps_size < 0x1000) {
1049 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1050 assert(blocknr>=0);
1051 while (cb>0) {
1052 /* we ensured that it is allocated above */
1053 assert(blocknr>=0);
1054 /* Read old block everytime, since we can have
1055 * overlapping data at START and END of the write
1057 if (!STORAGE_get_small_block(hf,blocknr,block))
1058 return E_FAIL;
1060 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1061 if (cc>cb)
1062 cc=cb;
1063 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1064 (LPBYTE)((char *) pv+curoffset),
1067 if (!STORAGE_put_small_block(hf,blocknr,block))
1068 return E_FAIL;
1069 cb -= cc;
1070 curoffset += cc;
1071 (LPBYTE)pv += cc;
1072 This->offset.s.LowPart += cc;
1073 *byteswritten += cc;
1074 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1076 } else {
1077 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1078 assert(blocknr>=0);
1079 while (cb>0) {
1080 /* we ensured that it is allocated above, so it better is */
1081 assert(blocknr>=0);
1082 /* read old block everytime, since we can have
1083 * overlapping data at START and END of the write
1085 if (!STORAGE_get_big_block(hf,blocknr,block))
1086 return E_FAIL;
1088 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1089 if (cc>cb)
1090 cc=cb;
1091 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1092 (LPBYTE)((char *) pv+curoffset),
1095 if (!STORAGE_put_big_block(hf,blocknr,block))
1096 return E_FAIL;
1097 cb -= cc;
1098 curoffset += cc;
1099 (LPBYTE)pv += cc;
1100 This->offset.s.LowPart += cc;
1101 *byteswritten += cc;
1102 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1105 return S_OK;
1108 /******************************************************************************
1109 * _create_istream16 [Internal]
1111 static void _create_istream16(LPSTREAM16 *str) {
1112 IStream16Impl* lpst;
1114 if (!strvt16.QueryInterface) {
1115 HMODULE16 wp = GetModuleHandle16("STORAGE");
1116 if (wp>=32) {
1117 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1118 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1119 VTENT(QueryInterface);
1120 VTENT(AddRef);
1121 VTENT(Release);
1122 VTENT(Read);
1123 VTENT(Write);
1124 VTENT(Seek);
1125 VTENT(SetSize);
1126 VTENT(CopyTo);
1127 VTENT(Commit);
1128 VTENT(Revert);
1129 VTENT(LockRegion);
1130 VTENT(UnlockRegion);
1131 VTENT(Stat);
1132 VTENT(Clone);
1133 #undef VTENT
1134 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1135 } else {
1136 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1137 VTENT(QueryInterface);
1138 VTENT(AddRef);
1139 VTENT(Release);
1140 VTENT(Read);
1141 VTENT(Write);
1142 VTENT(Seek);
1144 VTENT(CopyTo);
1145 VTENT(Commit);
1146 VTENT(SetSize);
1147 VTENT(Revert);
1148 VTENT(LockRegion);
1149 VTENT(UnlockRegion);
1150 VTENT(Stat);
1151 VTENT(Clone);
1153 #undef VTENT
1154 segstrvt16 = &strvt16;
1157 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1158 ICOM_VTBL(lpst) = segstrvt16;
1159 lpst->ref = 1;
1160 lpst->thisptr = MapLS( lpst );
1161 *str = (void*)lpst->thisptr;
1165 /* --- IStream32 implementation */
1167 typedef struct
1169 /* IUnknown fields */
1170 ICOM_VFIELD(IStream);
1171 DWORD ref;
1172 /* IStream32 fields */
1173 struct storage_pps_entry stde;
1174 int ppsent;
1175 HFILE hf;
1176 ULARGE_INTEGER offset;
1177 } IStream32Impl;
1179 /*****************************************************************************
1180 * IStream32_QueryInterface [VTABLE]
1182 HRESULT WINAPI IStream_fnQueryInterface(
1183 IStream* iface,REFIID refiid,LPVOID *obj
1185 ICOM_THIS(IStream32Impl,iface);
1187 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1188 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1189 *obj = This;
1190 return 0;
1192 return OLE_E_ENUM_NOMORE;
1196 /******************************************************************************
1197 * IStream32_AddRef [VTABLE]
1199 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1200 ICOM_THIS(IStream32Impl,iface);
1201 return ++(This->ref);
1204 /******************************************************************************
1205 * IStream32_Release [VTABLE]
1207 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1208 ICOM_THIS(IStream32Impl,iface);
1209 FlushFileBuffers(This->hf);
1210 This->ref--;
1211 if (!This->ref) {
1212 CloseHandle(This->hf);
1213 HeapFree( GetProcessHeap(), 0, This );
1214 return 0;
1216 return This->ref;
1219 /* --- IStorage16 implementation */
1221 typedef struct
1223 /* IUnknown fields */
1224 ICOM_VFIELD(IStorage16);
1225 DWORD ref;
1226 /* IStorage16 fields */
1227 SEGPTR thisptr; /* pointer to this struct as segmented */
1228 struct storage_pps_entry stde;
1229 int ppsent;
1230 HFILE hf;
1231 } IStorage16Impl;
1233 /******************************************************************************
1234 * IStorage16_QueryInterface [STORAGE.500]
1236 HRESULT WINAPI IStorage16_fnQueryInterface(
1237 IStorage16* iface,REFIID refiid,LPVOID *obj
1239 ICOM_THIS(IStorage16Impl,iface);
1241 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1243 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1244 *obj = This;
1245 return 0;
1247 return OLE_E_ENUM_NOMORE;
1250 /******************************************************************************
1251 * IStorage16_AddRef [STORAGE.501]
1253 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1254 ICOM_THIS(IStorage16Impl,iface);
1255 return ++(This->ref);
1258 /******************************************************************************
1259 * IStorage16_Release [STORAGE.502]
1261 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1262 ICOM_THIS(IStorage16Impl,iface);
1263 This->ref--;
1264 if (This->ref)
1265 return This->ref;
1266 UnMapLS( This->thisptr );
1267 HeapFree( GetProcessHeap(), 0, This );
1268 return 0;
1271 /******************************************************************************
1272 * IStorage16_Stat [STORAGE.517]
1274 HRESULT WINAPI IStorage16_fnStat(
1275 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1277 ICOM_THIS(IStorage16Impl,iface);
1278 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1279 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1281 TRACE("(%p)->(%p,0x%08lx)\n",
1282 This,pstatstg,grfStatFlag
1284 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1285 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1286 pstatstg->type = This->stde.pps_type;
1287 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1288 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1289 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1290 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1291 pstatstg->grfMode = 0; /* FIXME */
1292 pstatstg->grfLocksSupported = 0; /* FIXME */
1293 pstatstg->clsid = This->stde.pps_guid;
1294 pstatstg->grfStateBits = 0; /* FIXME */
1295 pstatstg->reserved = 0;
1296 return S_OK;
1299 /******************************************************************************
1300 * IStorage16_Commit [STORAGE.509]
1302 HRESULT WINAPI IStorage16_fnCommit(
1303 LPSTORAGE16 iface,DWORD commitflags
1305 ICOM_THIS(IStorage16Impl,iface);
1306 FIXME("(%p)->(0x%08lx),STUB!\n",
1307 This,commitflags
1309 return S_OK;
1312 /******************************************************************************
1313 * IStorage16_CopyTo [STORAGE.507]
1315 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1316 ICOM_THIS(IStorage16Impl,iface);
1317 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1318 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1320 return S_OK;
1324 /******************************************************************************
1325 * IStorage16_CreateStorage [STORAGE.505]
1327 HRESULT WINAPI IStorage16_fnCreateStorage(
1328 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1330 ICOM_THIS(IStorage16Impl,iface);
1331 IStorage16Impl* lpstg;
1332 int ppsent,x;
1333 struct storage_pps_entry stde;
1334 struct storage_header sth;
1335 HFILE hf=This->hf;
1337 READ_HEADER;
1339 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1340 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1342 if (grfMode & STGM_TRANSACTED)
1343 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1344 _create_istorage16(ppstg);
1345 lpstg = MapSL((SEGPTR)*ppstg);
1346 lpstg->hf = This->hf;
1348 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1349 if (ppsent<0)
1350 return E_FAIL;
1351 stde=This->stde;
1352 if (stde.pps_dir==-1) {
1353 stde.pps_dir = ppsent;
1354 x = This->ppsent;
1355 } else {
1356 FIXME(" use prev chain too ?\n");
1357 x=stde.pps_dir;
1358 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1359 return E_FAIL;
1360 while (stde.pps_next!=-1) {
1361 x=stde.pps_next;
1362 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1363 return E_FAIL;
1365 stde.pps_next = ppsent;
1367 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1368 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1369 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1370 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1371 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1372 lpstg->stde.pps_next = -1;
1373 lpstg->stde.pps_prev = -1;
1374 lpstg->stde.pps_dir = -1;
1375 lpstg->stde.pps_sb = -1;
1376 lpstg->stde.pps_size = 0;
1377 lpstg->stde.pps_type = 1;
1378 lpstg->ppsent = ppsent;
1379 /* FIXME: timestamps? */
1380 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1381 return E_FAIL;
1382 return S_OK;
1385 /******************************************************************************
1386 * IStorage16_CreateStream [STORAGE.503]
1388 HRESULT WINAPI IStorage16_fnCreateStream(
1389 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1391 ICOM_THIS(IStorage16Impl,iface);
1392 IStream16Impl* lpstr;
1393 int ppsent,x;
1394 struct storage_pps_entry stde;
1396 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1397 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1399 if (grfMode & STGM_TRANSACTED)
1400 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1401 _create_istream16(ppstm);
1402 lpstr = MapSL((SEGPTR)*ppstm);
1403 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1404 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1405 lpstr->offset.s.LowPart = 0;
1406 lpstr->offset.s.HighPart = 0;
1408 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1409 if (ppsent<0)
1410 return E_FAIL;
1411 stde=This->stde;
1412 if (stde.pps_next==-1)
1413 x=This->ppsent;
1414 else
1415 while (stde.pps_next!=-1) {
1416 x=stde.pps_next;
1417 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1418 return E_FAIL;
1420 stde.pps_next = ppsent;
1421 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1422 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1423 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1424 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1425 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1426 lpstr->stde.pps_next = -1;
1427 lpstr->stde.pps_prev = -1;
1428 lpstr->stde.pps_dir = -1;
1429 lpstr->stde.pps_sb = -1;
1430 lpstr->stde.pps_size = 0;
1431 lpstr->stde.pps_type = 2;
1432 lpstr->ppsent = ppsent;
1433 /* FIXME: timestamps? */
1434 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1435 return E_FAIL;
1436 return S_OK;
1439 /******************************************************************************
1440 * IStorage16_OpenStorage [STORAGE.506]
1442 HRESULT WINAPI IStorage16_fnOpenStorage(
1443 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1445 ICOM_THIS(IStorage16Impl,iface);
1446 IStream16Impl* lpstg;
1447 WCHAR name[33];
1448 int newpps;
1450 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1451 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1453 if (grfMode & STGM_TRANSACTED)
1454 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1455 _create_istorage16(ppstg);
1456 lpstg = MapSL((SEGPTR)*ppstg);
1457 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1458 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1459 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1460 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1461 if (newpps==-1) {
1462 IStream16_fnRelease((IStream16*)lpstg);
1463 return E_FAIL;
1466 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1467 IStream16_fnRelease((IStream16*)lpstg);
1468 return E_FAIL;
1470 lpstg->ppsent = newpps;
1471 return S_OK;
1474 /******************************************************************************
1475 * IStorage16_OpenStream [STORAGE.504]
1477 HRESULT WINAPI IStorage16_fnOpenStream(
1478 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1480 ICOM_THIS(IStorage16Impl,iface);
1481 IStream16Impl* lpstr;
1482 WCHAR name[33];
1483 int newpps;
1485 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1486 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1488 if (grfMode & STGM_TRANSACTED)
1489 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1490 _create_istream16(ppstm);
1491 lpstr = MapSL((SEGPTR)*ppstm);
1492 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1493 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1494 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1495 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1496 if (newpps==-1) {
1497 IStream16_fnRelease((IStream16*)lpstr);
1498 return E_FAIL;
1501 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1502 IStream16_fnRelease((IStream16*)lpstr);
1503 return E_FAIL;
1505 lpstr->offset.s.LowPart = 0;
1506 lpstr->offset.s.HighPart = 0;
1507 lpstr->ppsent = newpps;
1508 return S_OK;
1511 /******************************************************************************
1512 * _create_istorage16 [INTERNAL]
1514 static void _create_istorage16(LPSTORAGE16 *stg) {
1515 IStorage16Impl* lpst;
1517 if (!stvt16.QueryInterface) {
1518 HMODULE16 wp = GetModuleHandle16("STORAGE");
1519 if (wp>=32) {
1520 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1521 VTENT(QueryInterface)
1522 VTENT(AddRef)
1523 VTENT(Release)
1524 VTENT(CreateStream)
1525 VTENT(OpenStream)
1526 VTENT(CreateStorage)
1527 VTENT(OpenStorage)
1528 VTENT(CopyTo)
1529 VTENT(MoveElementTo)
1530 VTENT(Commit)
1531 VTENT(Revert)
1532 VTENT(EnumElements)
1533 VTENT(DestroyElement)
1534 VTENT(RenameElement)
1535 VTENT(SetElementTimes)
1536 VTENT(SetClass)
1537 VTENT(SetStateBits)
1538 VTENT(Stat)
1539 #undef VTENT
1540 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1541 } else {
1542 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1543 VTENT(QueryInterface)
1544 VTENT(AddRef)
1545 VTENT(Release)
1546 VTENT(CreateStream)
1547 VTENT(OpenStream)
1548 VTENT(CreateStorage)
1549 VTENT(OpenStorage)
1550 VTENT(CopyTo)
1551 VTENT(Commit)
1552 /* not (yet) implemented ...
1553 VTENT(MoveElementTo)
1554 VTENT(Revert)
1555 VTENT(EnumElements)
1556 VTENT(DestroyElement)
1557 VTENT(RenameElement)
1558 VTENT(SetElementTimes)
1559 VTENT(SetClass)
1560 VTENT(SetStateBits)
1561 VTENT(Stat)
1563 #undef VTENT
1564 segstvt16 = &stvt16;
1567 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1568 ICOM_VTBL(lpst) = segstvt16;
1569 lpst->ref = 1;
1570 lpst->thisptr = MapLS(lpst);
1571 *stg = (void*)lpst->thisptr;
1574 /******************************************************************************
1575 * Storage API functions
1578 /******************************************************************************
1579 * StgCreateDocFileA [STORAGE.1]
1581 HRESULT WINAPI StgCreateDocFile16(
1582 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1584 HFILE hf;
1585 int i,ret;
1586 IStorage16Impl* lpstg;
1587 struct storage_pps_entry stde;
1589 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1590 pwcsName,grfMode,reserved,ppstgOpen
1592 _create_istorage16(ppstgOpen);
1593 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1594 if (hf==INVALID_HANDLE_VALUE) {
1595 WARN("couldn't open file for storage:%ld\n",GetLastError());
1596 return E_FAIL;
1598 lpstg = MapSL((SEGPTR)*ppstgOpen);
1599 lpstg->hf = hf;
1600 /* FIXME: check for existence before overwriting? */
1601 if (!STORAGE_init_storage(hf)) {
1602 CloseHandle(hf);
1603 return E_FAIL;
1605 i=0;ret=0;
1606 while (!ret) { /* neither 1 nor <0 */
1607 ret=STORAGE_get_pps_entry(hf,i,&stde);
1608 if ((ret==1) && (stde.pps_type==5)) {
1609 lpstg->stde = stde;
1610 lpstg->ppsent = i;
1611 break;
1613 i++;
1615 if (ret!=1) {
1616 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1617 return E_FAIL;
1620 return S_OK;
1623 /******************************************************************************
1624 * StgIsStorageFile [STORAGE.5]
1626 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1627 HFILE hf;
1628 OFSTRUCT ofs;
1629 BYTE magic[24];
1631 TRACE("(\'%s\')\n",fn);
1632 hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
1633 if (hf==HFILE_ERROR)
1634 return STG_E_FILENOTFOUND;
1635 if (24!=_lread(hf,magic,24)) {
1636 WARN(" too short\n");
1637 _lclose(hf);
1638 return S_FALSE;
1640 if (!memcmp(magic,STORAGE_magic,8)) {
1641 WARN(" -> YES\n");
1642 _lclose(hf);
1643 return S_OK;
1645 if (!memcmp(magic,STORAGE_notmagic,8)) {
1646 WARN(" -> NO\n");
1647 _lclose(hf);
1648 return S_FALSE;
1650 if (!memcmp(magic,STORAGE_oldmagic,8)) {
1651 WARN(" -> old format\n");
1652 _lclose(hf);
1653 return STG_E_OLDFORMAT;
1655 WARN(" -> Invalid header.\n");
1656 _lclose(hf);
1657 return STG_E_INVALIDHEADER;
1660 /******************************************************************************
1661 * StgIsStorageFile [OLE32.146]
1663 HRESULT WINAPI
1664 StgIsStorageFile(LPCOLESTR fn)
1666 HRESULT ret;
1667 DWORD len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL );
1668 LPSTR strA = HeapAlloc( GetProcessHeap(), 0, len );
1670 WideCharToMultiByte( CP_ACP, 0, fn, -1, strA, len, NULL, NULL );
1671 ret = StgIsStorageFile16(strA);
1672 HeapFree( GetProcessHeap(), 0, strA );
1673 return ret;
1677 /******************************************************************************
1678 * StgOpenStorage [STORAGE.3]
1680 HRESULT WINAPI StgOpenStorage16(
1681 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1682 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1684 HFILE hf;
1685 int ret,i;
1686 IStorage16Impl* lpstg;
1687 struct storage_pps_entry stde;
1689 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1690 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1692 _create_istorage16(ppstgOpen);
1693 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1694 if (hf==INVALID_HANDLE_VALUE) {
1695 WARN("Couldn't open file for storage\n");
1696 return E_FAIL;
1698 lpstg = MapSL((SEGPTR)*ppstgOpen);
1699 lpstg->hf = hf;
1701 i=0;ret=0;
1702 while (!ret) { /* neither 1 nor <0 */
1703 ret=STORAGE_get_pps_entry(hf,i,&stde);
1704 if ((ret==1) && (stde.pps_type==5)) {
1705 lpstg->stde=stde;
1706 break;
1708 i++;
1710 if (ret!=1) {
1711 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1712 return E_FAIL;
1714 return S_OK;