Avoid compiler warning in STORAGE_get_free_pps_entry().
[wine/multimedia.git] / dlls / ole32 / storage.c
blobfb56b3e77b347f3798b62c80527581ec9ad12789
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
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
36 #include "windef.h"
37 #include "winternl.h"
38 #include "winerror.h"
39 #include "wine/winbase16.h"
40 #include "wownt32.h"
41 #include "wine/unicode.h"
42 #include "objbase.h"
43 #include "wine/debug.h"
45 #include "ifs.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48 WINE_DECLARE_DEBUG_CHANNEL(relay);
50 struct storage_header {
51 BYTE magic[8]; /* 00: magic */
52 BYTE unknown1[36]; /* 08: unknown */
53 DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */
54 DWORD root_startblock;/* 30: root storage first big block */
55 DWORD unknown2[2]; /* 34: unknown */
56 DWORD sbd_startblock; /* 3C: small block depot first big block */
57 DWORD unknown3[3]; /* 40: unknown */
58 DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/
60 struct storage_pps_entry {
61 WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */
62 WORD pps_sizeofname; /* 40: namelength in bytes */
63 BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */
64 BYTE pps_unknown0; /* 43: unknown */
65 DWORD pps_prev; /* 44: previous pps */
66 DWORD pps_next; /* 48: next pps */
67 DWORD pps_dir; /* 4C: directory pps */
68 GUID pps_guid; /* 50: class ID */
69 DWORD pps_unknown1; /* 60: unknown */
70 FILETIME pps_ft1; /* 64: filetime1 */
71 FILETIME pps_ft2; /* 70: filetime2 */
72 DWORD pps_sb; /* 74: data startblock */
73 DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/
74 DWORD pps_unknown2; /* 7C: unknown */
77 #define STORAGE_CHAINENTRY_FAT 0xfffffffd
78 #define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe
79 #define STORAGE_CHAINENTRY_FREE 0xffffffff
82 static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
84 #define BIGSIZE 512
85 #define SMALLSIZE 64
87 #define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE)
89 #define READ_HEADER assert(STORAGE_get_big_block(hf,-1,(LPBYTE)&sth));assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
90 static ICOM_VTABLE(IStorage16) stvt16;
91 static ICOM_VTABLE(IStorage16) *segstvt16 = NULL;
92 static ICOM_VTABLE(IStream16) strvt16;
93 static ICOM_VTABLE(IStream16) *segstrvt16 = NULL;
95 /*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
96 static void _create_istorage16(LPSTORAGE16 *stg);
97 static void _create_istream16(LPSTREAM16 *str);
99 #define IMPLEMENTED 1
102 /******************************************************************************
103 * STORAGE_get_big_block [Internal]
105 * Reading OLE compound storage
107 static BOOL
108 STORAGE_get_big_block(HANDLE hf,int n,BYTE *block)
110 DWORD result;
112 assert(n>=-1);
113 if (!SetFilePointer( hf, (n+1)*BIGSIZE, NULL, SEEK_SET ))
115 WARN(" seek failed (%ld)\n",GetLastError());
116 return FALSE;
118 if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
120 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
121 return FALSE;
123 return TRUE;
126 /******************************************************************************
127 * STORAGE_put_big_block [INTERNAL]
129 static BOOL
130 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
132 DWORD result;
134 assert(n>=-1);
135 if (!SetFilePointer( hf, (n+1)*BIGSIZE, NULL, SEEK_SET ))
137 WARN(" seek failed (%ld)\n",GetLastError());
138 return FALSE;
140 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
142 WARN(" write failed (%ld)\n",GetLastError());
143 return FALSE;
145 return TRUE;
148 /******************************************************************************
149 * STORAGE_get_next_big_blocknr [INTERNAL]
151 static int
152 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
153 INT bbs[BIGSIZE/sizeof(INT)];
154 struct storage_header sth;
156 READ_HEADER;
158 assert(blocknr>>7<sth.num_of_bbd_blocks);
159 if (sth.bbd_list[blocknr>>7]==0xffffffff)
160 return -5;
161 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
162 return -5;
163 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
164 return bbs[blocknr&0x7f];
167 /******************************************************************************
168 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
170 static int
171 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
172 INT bbs[BIGSIZE/sizeof(INT)];
173 int lastblock = -1;
174 struct storage_header sth;
176 READ_HEADER;
178 assert(blocknr>=0);
179 while (nr--) {
180 assert((blocknr>>7)<sth.num_of_bbd_blocks);
181 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
183 /* simple caching... */
184 if (lastblock!=sth.bbd_list[blocknr>>7]) {
185 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
186 lastblock = sth.bbd_list[blocknr>>7];
188 blocknr = bbs[blocknr&0x7f];
190 return blocknr;
193 /******************************************************************************
194 * STORAGE_get_root_pps_entry [Internal]
196 static BOOL
197 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
198 int blocknr,i;
199 BYTE block[BIGSIZE];
200 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
201 struct storage_header sth;
203 READ_HEADER;
204 blocknr = sth.root_startblock;
205 while (blocknr>=0) {
206 assert(STORAGE_get_big_block(hf,blocknr,block));
207 for (i=0;i<4;i++) {
208 if (!stde[i].pps_sizeofname)
209 continue;
210 if (stde[i].pps_type==5) {
211 *pstde=stde[i];
212 return TRUE;
215 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
217 return FALSE;
220 /******************************************************************************
221 * STORAGE_get_small_block [INTERNAL]
223 static BOOL
224 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
225 BYTE block[BIGSIZE];
226 int bigblocknr;
227 struct storage_pps_entry root;
229 assert(blocknr>=0);
230 assert(STORAGE_get_root_pps_entry(hf,&root));
231 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
232 assert(bigblocknr>=0);
233 assert(STORAGE_get_big_block(hf,bigblocknr,block));
235 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
236 return TRUE;
239 /******************************************************************************
240 * STORAGE_put_small_block [INTERNAL]
242 static BOOL
243 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
244 BYTE block[BIGSIZE];
245 int bigblocknr;
246 struct storage_pps_entry root;
248 assert(blocknr>=0);
250 assert(STORAGE_get_root_pps_entry(hf,&root));
251 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
252 assert(bigblocknr>=0);
253 assert(STORAGE_get_big_block(hf,bigblocknr,block));
255 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
256 assert(STORAGE_put_big_block(hf,bigblocknr,block));
257 return TRUE;
260 /******************************************************************************
261 * STORAGE_get_next_small_blocknr [INTERNAL]
263 static int
264 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
265 BYTE block[BIGSIZE];
266 LPINT sbd = (LPINT)block;
267 int bigblocknr;
268 struct storage_header sth;
270 READ_HEADER;
271 assert(blocknr>=0);
272 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
273 assert(bigblocknr>=0);
274 assert(STORAGE_get_big_block(hf,bigblocknr,block));
275 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
276 return sbd[blocknr & (128-1)];
279 /******************************************************************************
280 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
282 static int
283 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
284 int lastblocknr=-1;
285 BYTE block[BIGSIZE];
286 LPINT sbd = (LPINT)block;
287 struct storage_header sth;
289 READ_HEADER;
290 assert(blocknr>=0);
291 while ((nr--) && (blocknr>=0)) {
292 if (lastblocknr/128!=blocknr/128) {
293 int bigblocknr;
294 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
295 assert(bigblocknr>=0);
296 assert(STORAGE_get_big_block(hf,bigblocknr,block));
297 lastblocknr = blocknr;
299 assert(lastblocknr>=0);
300 lastblocknr=blocknr;
301 blocknr=sbd[blocknr & (128-1)];
302 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
304 return blocknr;
307 /******************************************************************************
308 * STORAGE_get_pps_entry [INTERNAL]
310 static int
311 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
312 int blocknr;
313 BYTE block[BIGSIZE];
314 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
315 struct storage_header sth;
317 READ_HEADER;
318 /* we have 4 pps entries per big block */
319 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
320 assert(blocknr>=0);
321 assert(STORAGE_get_big_block(hf,blocknr,block));
323 *pstde=*stde;
324 return 1;
327 /******************************************************************************
328 * STORAGE_put_pps_entry [Internal]
330 static int
331 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
332 int blocknr;
333 BYTE block[BIGSIZE];
334 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
335 struct storage_header sth;
337 READ_HEADER;
339 /* we have 4 pps entries per big block */
340 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
341 assert(blocknr>=0);
342 assert(STORAGE_get_big_block(hf,blocknr,block));
343 *stde=*pstde;
344 assert(STORAGE_put_big_block(hf,blocknr,block));
345 return 1;
348 /******************************************************************************
349 * STORAGE_look_for_named_pps [Internal]
351 static int
352 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
353 struct storage_pps_entry stde;
354 int ret;
356 if (n==-1)
357 return -1;
358 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
359 return -1;
361 if (!lstrcmpW(name,stde.pps_rawname))
362 return n;
363 if (stde.pps_prev != -1) {
364 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
365 if (ret!=-1)
366 return ret;
368 if (stde.pps_next != -1) {
369 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
370 if (ret!=-1)
371 return ret;
373 return -1;
376 /******************************************************************************
377 * STORAGE_dump_pps_entry [Internal]
379 * FIXME
380 * Function is unused
382 void
383 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
384 char name[33];
386 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
387 if (!stde->pps_sizeofname)
388 return;
389 DPRINTF("name: %s\n",name);
390 DPRINTF("type: %d\n",stde->pps_type);
391 DPRINTF("prev pps: %ld\n",stde->pps_prev);
392 DPRINTF("next pps: %ld\n",stde->pps_next);
393 DPRINTF("dir pps: %ld\n",stde->pps_dir);
394 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
395 if (stde->pps_type !=2) {
396 time_t t;
397 DWORD dw;
398 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
399 t = dw;
400 DPRINTF("ts1: %s\n",ctime(&t));
401 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
402 t = dw;
403 DPRINTF("ts2: %s\n",ctime(&t));
405 DPRINTF("startblock: %ld\n",stde->pps_sb);
406 DPRINTF("size: %ld\n",stde->pps_size);
409 /******************************************************************************
410 * STORAGE_init_storage [INTERNAL]
412 static BOOL
413 STORAGE_init_storage(HANDLE hf) {
414 BYTE block[BIGSIZE];
415 LPDWORD bbs;
416 struct storage_header *sth;
417 struct storage_pps_entry *stde;
418 DWORD result;
420 SetFilePointer( hf, 0, NULL, SEEK_SET );
421 /* block -1 is the storage header */
422 sth = (struct storage_header*)block;
423 memcpy(sth->magic,STORAGE_magic,8);
424 memset(sth->unknown1,0,sizeof(sth->unknown1));
425 memset(sth->unknown2,0,sizeof(sth->unknown2));
426 memset(sth->unknown3,0,sizeof(sth->unknown3));
427 sth->num_of_bbd_blocks = 1;
428 sth->root_startblock = 1;
429 sth->sbd_startblock = 0xffffffff;
430 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
431 sth->bbd_list[0] = 0;
432 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
433 /* block 0 is the big block directory */
434 bbs=(LPDWORD)block;
435 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
436 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
437 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
438 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
439 /* block 1 is the root directory entry */
440 memset(block,0x00,sizeof(block));
441 stde = (struct storage_pps_entry*)block;
442 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
443 sizeof(stde->pps_rawname)/sizeof(WCHAR));
444 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
445 stde->pps_type = 5;
446 stde->pps_dir = -1;
447 stde->pps_next = -1;
448 stde->pps_prev = -1;
449 stde->pps_sb = 0xffffffff;
450 stde->pps_size = 0;
451 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
454 /******************************************************************************
455 * STORAGE_set_big_chain [Internal]
457 static BOOL
458 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
459 BYTE block[BIGSIZE];
460 LPINT bbd = (LPINT)block;
461 int nextblocknr,bigblocknr;
462 struct storage_header sth;
464 READ_HEADER;
465 assert(blocknr!=type);
466 while (blocknr>=0) {
467 bigblocknr = sth.bbd_list[blocknr/128];
468 assert(bigblocknr>=0);
469 assert(STORAGE_get_big_block(hf,bigblocknr,block));
471 nextblocknr = bbd[blocknr&(128-1)];
472 bbd[blocknr&(128-1)] = type;
473 if (type>=0)
474 return TRUE;
475 assert(STORAGE_put_big_block(hf,bigblocknr,block));
476 type = STORAGE_CHAINENTRY_FREE;
477 blocknr = nextblocknr;
479 return TRUE;
482 /******************************************************************************
483 * STORAGE_set_small_chain [Internal]
485 static BOOL
486 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
487 BYTE block[BIGSIZE];
488 LPINT sbd = (LPINT)block;
489 int lastblocknr,nextsmallblocknr,bigblocknr;
490 struct storage_header sth;
492 READ_HEADER;
494 assert(blocknr!=type);
495 lastblocknr=-129;bigblocknr=-2;
496 while (blocknr>=0) {
497 /* cache block ... */
498 if (lastblocknr/128!=blocknr/128) {
499 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
500 assert(bigblocknr>=0);
501 assert(STORAGE_get_big_block(hf,bigblocknr,block));
503 lastblocknr = blocknr;
504 nextsmallblocknr = sbd[blocknr&(128-1)];
505 sbd[blocknr&(128-1)] = type;
506 assert(STORAGE_put_big_block(hf,bigblocknr,block));
507 if (type>=0)
508 return TRUE;
509 type = STORAGE_CHAINENTRY_FREE;
510 blocknr = nextsmallblocknr;
512 return TRUE;
515 /******************************************************************************
516 * STORAGE_get_free_big_blocknr [Internal]
518 static int
519 STORAGE_get_free_big_blocknr(HANDLE hf) {
520 BYTE block[BIGSIZE];
521 LPINT sbd = (LPINT)block;
522 int lastbigblocknr,i,curblock,bigblocknr;
523 struct storage_header sth;
525 READ_HEADER;
526 curblock = 0;
527 lastbigblocknr = -1;
528 bigblocknr = sth.bbd_list[curblock];
529 while (curblock<sth.num_of_bbd_blocks) {
530 assert(bigblocknr>=0);
531 assert(STORAGE_get_big_block(hf,bigblocknr,block));
532 for (i=0;i<128;i++)
533 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
534 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
535 assert(STORAGE_put_big_block(hf,bigblocknr,block));
536 memset(block,0x42,sizeof(block));
537 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
538 return i+curblock*128;
540 lastbigblocknr = bigblocknr;
541 bigblocknr = sth.bbd_list[++curblock];
543 bigblocknr = curblock*128;
544 /* since we have marked all blocks from 0 up to curblock*128-1
545 * the next free one is curblock*128, where we happily put our
546 * next large block depot.
548 memset(block,0xff,sizeof(block));
549 /* mark the block allocated and returned by this function */
550 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
551 assert(STORAGE_put_big_block(hf,bigblocknr,block));
553 /* if we had a bbd block already (mostlikely) we need
554 * to link the new one into the chain
556 if (lastbigblocknr!=-1)
557 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
558 sth.bbd_list[curblock]=bigblocknr;
559 sth.num_of_bbd_blocks++;
560 assert(sth.num_of_bbd_blocks==curblock+1);
561 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
563 /* Set the end of the chain for the bigblockdepots */
564 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
565 /* add 1, for the first entry is used for the additional big block
566 * depot. (means we already used bigblocknr) */
567 memset(block,0x42,sizeof(block));
568 /* allocate this block (filled with 0x42) */
569 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
570 return bigblocknr+1;
574 /******************************************************************************
575 * STORAGE_get_free_small_blocknr [Internal]
577 static int
578 STORAGE_get_free_small_blocknr(HANDLE hf) {
579 BYTE block[BIGSIZE];
580 LPINT sbd = (LPINT)block;
581 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
582 struct storage_pps_entry root;
583 struct storage_header sth;
585 READ_HEADER;
586 bigblocknr = sth.sbd_startblock;
587 curblock = 0;
588 lastbigblocknr = -1;
589 newblocknr = -1;
590 while (bigblocknr>=0) {
591 if (!STORAGE_get_big_block(hf,bigblocknr,block))
592 return -1;
593 for (i=0;i<128;i++)
594 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
595 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
596 newblocknr = i+curblock*128;
597 break;
599 if (i!=128)
600 break;
601 lastbigblocknr = bigblocknr;
602 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
603 curblock++;
605 if (newblocknr==-1) {
606 bigblocknr = STORAGE_get_free_big_blocknr(hf);
607 if (bigblocknr<0)
608 return -1;
609 READ_HEADER;
610 memset(block,0xff,sizeof(block));
611 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
612 if (!STORAGE_put_big_block(hf,bigblocknr,block))
613 return -1;
614 if (lastbigblocknr==-1) {
615 sth.sbd_startblock = bigblocknr;
616 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
617 return -1;
618 } else {
619 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
620 return -1;
622 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
623 return -1;
624 newblocknr = curblock*128;
626 /* allocate enough big blocks for storing the allocated small block */
627 if (!STORAGE_get_root_pps_entry(hf,&root))
628 return -1;
629 if (root.pps_sb==-1)
630 lastbigblocknr = -1;
631 else
632 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
633 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
634 /* we need to allocate more stuff */
635 bigblocknr = STORAGE_get_free_big_blocknr(hf);
636 if (bigblocknr<0)
637 return -1;
638 READ_HEADER;
639 if (root.pps_sb==-1) {
640 root.pps_sb = bigblocknr;
641 root.pps_size += BIGSIZE;
642 } else {
643 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
644 return -1;
645 root.pps_size += BIGSIZE;
647 lastbigblocknr = bigblocknr;
649 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
650 return -1;
651 if (!STORAGE_put_pps_entry(hf,0,&root))
652 return -1;
653 return newblocknr;
656 /******************************************************************************
657 * STORAGE_get_free_pps_entry [Internal]
659 static int
660 STORAGE_get_free_pps_entry(HANDLE hf) {
661 int blocknr, i, curblock, lastblocknr=-1;
662 BYTE block[BIGSIZE];
663 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
664 struct storage_header sth;
666 READ_HEADER;
667 blocknr = sth.root_startblock;
668 assert(blocknr>=0);
669 curblock=0;
670 while (blocknr>=0) {
671 if (!STORAGE_get_big_block(hf,blocknr,block))
672 return -1;
673 for (i=0;i<4;i++)
674 if (stde[i].pps_sizeofname==0) /* free */
675 return curblock*4+i;
676 lastblocknr = blocknr;
677 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
678 curblock++;
680 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
681 blocknr = STORAGE_get_free_big_blocknr(hf);
682 /* sth invalidated */
683 if (blocknr<0)
684 return -1;
686 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
687 return -1;
688 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
689 return -1;
690 memset(block,0,sizeof(block));
691 STORAGE_put_big_block(hf,blocknr,block);
692 return curblock*4;
695 /* --- IStream16 implementation */
697 typedef struct
699 /* IUnknown fields */
700 ICOM_VFIELD(IStream16);
701 DWORD ref;
702 /* IStream16 fields */
703 SEGPTR thisptr; /* pointer to this struct as segmented */
704 struct storage_pps_entry stde;
705 int ppsent;
706 HANDLE hf;
707 ULARGE_INTEGER offset;
708 } IStream16Impl;
710 /******************************************************************************
711 * IStream16_QueryInterface [STORAGE.518]
713 HRESULT WINAPI IStream16_fnQueryInterface(
714 IStream16* iface,REFIID refiid,LPVOID *obj
716 ICOM_THIS(IStream16Impl,iface);
717 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
718 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
719 *obj = This;
720 return 0;
722 return OLE_E_ENUM_NOMORE;
726 /******************************************************************************
727 * IStream16_AddRef [STORAGE.519]
729 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
730 ICOM_THIS(IStream16Impl,iface);
731 return ++(This->ref);
734 /******************************************************************************
735 * IStream16_Release [STORAGE.520]
737 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
738 ICOM_THIS(IStream16Impl,iface);
739 FlushFileBuffers(This->hf);
740 This->ref--;
741 if (!This->ref) {
742 CloseHandle(This->hf);
743 UnMapLS( This->thisptr );
744 HeapFree( GetProcessHeap(), 0, This );
745 return 0;
747 return This->ref;
750 /******************************************************************************
751 * IStream16_Seek [STORAGE.523]
753 * FIXME
754 * Does not handle 64 bits
756 HRESULT WINAPI IStream16_fnSeek(
757 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
759 ICOM_THIS(IStream16Impl,iface);
760 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
762 switch (whence) {
763 /* unix SEEK_xx should be the same as win95 ones */
764 case SEEK_SET:
765 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
766 * right now.
768 assert(offset.s.HighPart==0);
769 This->offset.s.HighPart = offset.s.HighPart;
770 This->offset.s.LowPart = offset.s.LowPart;
771 break;
772 case SEEK_CUR:
773 if (offset.s.HighPart < 0) {
774 /* FIXME: is this negation correct ? */
775 offset.s.HighPart = -offset.s.HighPart;
776 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
778 assert(offset.s.HighPart==0);
779 assert(This->offset.s.LowPart >= offset.s.LowPart);
780 This->offset.s.LowPart -= offset.s.LowPart;
781 } else {
782 assert(offset.s.HighPart==0);
783 This->offset.s.LowPart+= offset.s.LowPart;
785 break;
786 case SEEK_END:
787 assert(offset.s.HighPart==0);
788 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
789 break;
791 if (This->offset.s.LowPart>This->stde.pps_size)
792 This->offset.s.LowPart=This->stde.pps_size;
793 if (newpos) *newpos = This->offset;
794 return S_OK;
797 /******************************************************************************
798 * IStream16_Read [STORAGE.521]
800 HRESULT WINAPI IStream16_fnRead(
801 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
803 ICOM_THIS(IStream16Impl,iface);
804 BYTE block[BIGSIZE];
805 ULONG *bytesread=pcbRead,xxread;
806 int blocknr;
808 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
809 if (!pcbRead) bytesread=&xxread;
810 *bytesread = 0;
812 if (cb>This->stde.pps_size-This->offset.s.LowPart)
813 cb=This->stde.pps_size-This->offset.s.LowPart;
814 if (This->stde.pps_size < 0x1000) {
815 /* use small block reader */
816 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
817 while (cb) {
818 int cc;
820 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
821 WARN("small block read failed!!!\n");
822 return E_FAIL;
824 cc = cb;
825 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
826 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
827 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
828 This->offset.s.LowPart+=cc;
829 (LPBYTE)pv+=cc;
830 *bytesread+=cc;
831 cb-=cc;
832 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
834 } else {
835 /* use big block reader */
836 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
837 while (cb) {
838 int cc;
840 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
841 WARN("big block read failed!!!\n");
842 return E_FAIL;
844 cc = cb;
845 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
846 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
847 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
848 This->offset.s.LowPart+=cc;
849 (LPBYTE)pv+=cc;
850 *bytesread+=cc;
851 cb-=cc;
852 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
855 return S_OK;
858 /******************************************************************************
859 * IStream16_Write [STORAGE.522]
861 HRESULT WINAPI IStream16_fnWrite(
862 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
864 ICOM_THIS(IStream16Impl,iface);
865 BYTE block[BIGSIZE];
866 ULONG *byteswritten=pcbWrite,xxwritten;
867 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
868 HANDLE hf = This->hf;
870 if (!pcbWrite) byteswritten=&xxwritten;
871 *byteswritten = 0;
873 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
874 /* do we need to junk some blocks? */
875 newsize = This->offset.s.LowPart+cb;
876 oldsize = This->stde.pps_size;
877 if (newsize < oldsize) {
878 if (oldsize < 0x1000) {
879 /* only small blocks */
880 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
882 assert(blocknr>=0);
884 /* will set the rest of the chain to 'free' */
885 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
886 return E_FAIL;
887 } else {
888 if (newsize >= 0x1000) {
889 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
890 assert(blocknr>=0);
892 /* will set the rest of the chain to 'free' */
893 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
894 return E_FAIL;
895 } else {
896 /* Migrate large blocks to small blocks
897 * (we just migrate newsize bytes)
899 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
900 HRESULT r = E_FAIL;
902 cc = newsize;
903 blocknr = This->stde.pps_sb;
904 curdata = data;
905 while (cc>0) {
906 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
907 HeapFree(GetProcessHeap(),0,data);
908 return E_FAIL;
910 curdata += BIGSIZE;
911 cc -= BIGSIZE;
912 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
914 /* frees complete chain for this stream */
915 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
916 goto err;
917 curdata = data;
918 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
919 if (blocknr<0)
920 goto err;
921 cc = newsize;
922 while (cc>0) {
923 if (!STORAGE_put_small_block(hf,blocknr,curdata))
924 goto err;
925 cc -= SMALLSIZE;
926 if (cc<=0) {
927 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
928 goto err;
929 break;
930 } else {
931 int newblocknr = STORAGE_get_free_small_blocknr(hf);
932 if (newblocknr<0)
933 goto err;
934 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
935 goto err;
936 blocknr = newblocknr;
938 curdata += SMALLSIZE;
940 r = S_OK;
941 err:
942 HeapFree(GetProcessHeap(),0,data);
943 if(r != S_OK)
944 return r;
947 This->stde.pps_size = newsize;
950 if (newsize > oldsize) {
951 if (oldsize >= 0x1000) {
952 /* should return the block right before the 'endofchain' */
953 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
954 assert(blocknr>=0);
955 lastblocknr = blocknr;
956 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
957 blocknr = STORAGE_get_free_big_blocknr(hf);
958 if (blocknr<0)
959 return E_FAIL;
960 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
961 return E_FAIL;
962 lastblocknr = blocknr;
964 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
965 return E_FAIL;
966 } else {
967 if (newsize < 0x1000) {
968 /* find startblock */
969 if (!oldsize)
970 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
971 else
972 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
973 if (blocknr<0)
974 return E_FAIL;
976 /* allocate required new small blocks */
977 lastblocknr = blocknr;
978 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
979 blocknr = STORAGE_get_free_small_blocknr(hf);
980 if (blocknr<0)
981 return E_FAIL;
982 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
983 return E_FAIL;
984 lastblocknr = blocknr;
986 /* and terminate the chain */
987 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
988 return E_FAIL;
989 } else {
990 if (!oldsize) {
991 /* no single block allocated yet */
992 blocknr=STORAGE_get_free_big_blocknr(hf);
993 if (blocknr<0)
994 return E_FAIL;
995 This->stde.pps_sb = blocknr;
996 } else {
997 /* Migrate small blocks to big blocks */
998 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
999 HRESULT r = E_FAIL;
1001 cc = oldsize;
1002 blocknr = This->stde.pps_sb;
1003 curdata = data;
1004 /* slurp in */
1005 while (cc>0) {
1006 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1007 goto err2;
1008 curdata += SMALLSIZE;
1009 cc -= SMALLSIZE;
1010 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1012 /* free small block chain */
1013 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1014 goto err2;
1015 curdata = data;
1016 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1017 if (blocknr<0)
1018 goto err2;
1019 /* put the data into the big blocks */
1020 cc = This->stde.pps_size;
1021 while (cc>0) {
1022 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1023 goto err2;
1024 cc -= BIGSIZE;
1025 if (cc<=0) {
1026 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1027 goto err2;
1028 break;
1029 } else {
1030 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1031 if (newblocknr<0)
1032 goto err2;
1033 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1034 goto err2;
1035 blocknr = newblocknr;
1037 curdata += BIGSIZE;
1039 r = S_OK;
1040 err2:
1041 HeapFree(GetProcessHeap(),0,data);
1042 if(r != S_OK)
1043 return r;
1045 /* generate big blocks to fit the new data */
1046 lastblocknr = blocknr;
1047 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1048 blocknr = STORAGE_get_free_big_blocknr(hf);
1049 if (blocknr<0)
1050 return E_FAIL;
1051 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1052 return E_FAIL;
1053 lastblocknr = blocknr;
1055 /* terminate chain */
1056 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1057 return E_FAIL;
1060 This->stde.pps_size = newsize;
1063 /* There are just some cases where we didn't modify it, we write it out
1064 * everytime
1066 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1067 return E_FAIL;
1069 /* finally the write pass */
1070 if (This->stde.pps_size < 0x1000) {
1071 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1072 assert(blocknr>=0);
1073 while (cb>0) {
1074 /* we ensured that it is allocated above */
1075 assert(blocknr>=0);
1076 /* Read old block everytime, since we can have
1077 * overlapping data at START and END of the write
1079 if (!STORAGE_get_small_block(hf,blocknr,block))
1080 return E_FAIL;
1082 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1083 if (cc>cb)
1084 cc=cb;
1085 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1086 (LPBYTE)((char *) pv+curoffset),
1089 if (!STORAGE_put_small_block(hf,blocknr,block))
1090 return E_FAIL;
1091 cb -= cc;
1092 curoffset += cc;
1093 (LPBYTE)pv += cc;
1094 This->offset.s.LowPart += cc;
1095 *byteswritten += cc;
1096 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1098 } else {
1099 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1100 assert(blocknr>=0);
1101 while (cb>0) {
1102 /* we ensured that it is allocated above, so it better is */
1103 assert(blocknr>=0);
1104 /* read old block everytime, since we can have
1105 * overlapping data at START and END of the write
1107 if (!STORAGE_get_big_block(hf,blocknr,block))
1108 return E_FAIL;
1110 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1111 if (cc>cb)
1112 cc=cb;
1113 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1114 (LPBYTE)((char *) pv+curoffset),
1117 if (!STORAGE_put_big_block(hf,blocknr,block))
1118 return E_FAIL;
1119 cb -= cc;
1120 curoffset += cc;
1121 (LPBYTE)pv += cc;
1122 This->offset.s.LowPart += cc;
1123 *byteswritten += cc;
1124 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1127 return S_OK;
1130 /******************************************************************************
1131 * _create_istream16 [Internal]
1133 static void _create_istream16(LPSTREAM16 *str) {
1134 IStream16Impl* lpst;
1136 if (!strvt16.QueryInterface) {
1137 HMODULE16 wp = GetModuleHandle16("STORAGE");
1138 if (wp>=32) {
1139 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1140 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1141 VTENT(QueryInterface);
1142 VTENT(AddRef);
1143 VTENT(Release);
1144 VTENT(Read);
1145 VTENT(Write);
1146 VTENT(Seek);
1147 VTENT(SetSize);
1148 VTENT(CopyTo);
1149 VTENT(Commit);
1150 VTENT(Revert);
1151 VTENT(LockRegion);
1152 VTENT(UnlockRegion);
1153 VTENT(Stat);
1154 VTENT(Clone);
1155 #undef VTENT
1156 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1157 } else {
1158 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1159 VTENT(QueryInterface);
1160 VTENT(AddRef);
1161 VTENT(Release);
1162 VTENT(Read);
1163 VTENT(Write);
1164 VTENT(Seek);
1166 VTENT(CopyTo);
1167 VTENT(Commit);
1168 VTENT(SetSize);
1169 VTENT(Revert);
1170 VTENT(LockRegion);
1171 VTENT(UnlockRegion);
1172 VTENT(Stat);
1173 VTENT(Clone);
1175 #undef VTENT
1176 segstrvt16 = &strvt16;
1179 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1180 ICOM_VTBL(lpst) = segstrvt16;
1181 lpst->ref = 1;
1182 lpst->thisptr = MapLS( lpst );
1183 *str = (void*)lpst->thisptr;
1187 /* --- IStream32 implementation */
1189 typedef struct
1191 /* IUnknown fields */
1192 ICOM_VFIELD(IStream);
1193 DWORD ref;
1194 /* IStream32 fields */
1195 struct storage_pps_entry stde;
1196 int ppsent;
1197 HANDLE hf;
1198 ULARGE_INTEGER offset;
1199 } IStream32Impl;
1201 /*****************************************************************************
1202 * IStream32_QueryInterface [VTABLE]
1204 HRESULT WINAPI IStream_fnQueryInterface(
1205 IStream* iface,REFIID refiid,LPVOID *obj
1207 ICOM_THIS(IStream32Impl,iface);
1209 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1210 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1211 *obj = This;
1212 return 0;
1214 return OLE_E_ENUM_NOMORE;
1218 /******************************************************************************
1219 * IStream32_AddRef [VTABLE]
1221 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1222 ICOM_THIS(IStream32Impl,iface);
1223 return ++(This->ref);
1226 /******************************************************************************
1227 * IStream32_Release [VTABLE]
1229 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1230 ICOM_THIS(IStream32Impl,iface);
1231 FlushFileBuffers(This->hf);
1232 This->ref--;
1233 if (!This->ref) {
1234 CloseHandle(This->hf);
1235 HeapFree( GetProcessHeap(), 0, This );
1236 return 0;
1238 return This->ref;
1241 /* --- IStorage16 implementation */
1243 typedef struct
1245 /* IUnknown fields */
1246 ICOM_VFIELD(IStorage16);
1247 DWORD ref;
1248 /* IStorage16 fields */
1249 SEGPTR thisptr; /* pointer to this struct as segmented */
1250 struct storage_pps_entry stde;
1251 int ppsent;
1252 HANDLE hf;
1253 } IStorage16Impl;
1255 /******************************************************************************
1256 * IStorage16_QueryInterface [STORAGE.500]
1258 HRESULT WINAPI IStorage16_fnQueryInterface(
1259 IStorage16* iface,REFIID refiid,LPVOID *obj
1261 ICOM_THIS(IStorage16Impl,iface);
1263 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1265 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1266 *obj = This;
1267 return 0;
1269 return OLE_E_ENUM_NOMORE;
1272 /******************************************************************************
1273 * IStorage16_AddRef [STORAGE.501]
1275 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1276 ICOM_THIS(IStorage16Impl,iface);
1277 return ++(This->ref);
1280 /******************************************************************************
1281 * IStorage16_Release [STORAGE.502]
1283 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1284 ICOM_THIS(IStorage16Impl,iface);
1285 This->ref--;
1286 if (This->ref)
1287 return This->ref;
1288 UnMapLS( This->thisptr );
1289 HeapFree( GetProcessHeap(), 0, This );
1290 return 0;
1293 /******************************************************************************
1294 * IStorage16_Stat [STORAGE.517]
1296 HRESULT WINAPI IStorage16_fnStat(
1297 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1299 ICOM_THIS(IStorage16Impl,iface);
1300 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1301 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1303 TRACE("(%p)->(%p,0x%08lx)\n",
1304 This,pstatstg,grfStatFlag
1306 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1307 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1308 pstatstg->type = This->stde.pps_type;
1309 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1310 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1311 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1312 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1313 pstatstg->grfMode = 0; /* FIXME */
1314 pstatstg->grfLocksSupported = 0; /* FIXME */
1315 pstatstg->clsid = This->stde.pps_guid;
1316 pstatstg->grfStateBits = 0; /* FIXME */
1317 pstatstg->reserved = 0;
1318 return S_OK;
1321 /******************************************************************************
1322 * IStorage16_Commit [STORAGE.509]
1324 HRESULT WINAPI IStorage16_fnCommit(
1325 LPSTORAGE16 iface,DWORD commitflags
1327 ICOM_THIS(IStorage16Impl,iface);
1328 FIXME("(%p)->(0x%08lx),STUB!\n",
1329 This,commitflags
1331 return S_OK;
1334 /******************************************************************************
1335 * IStorage16_CopyTo [STORAGE.507]
1337 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1338 ICOM_THIS(IStorage16Impl,iface);
1339 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1340 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1342 return S_OK;
1346 /******************************************************************************
1347 * IStorage16_CreateStorage [STORAGE.505]
1349 HRESULT WINAPI IStorage16_fnCreateStorage(
1350 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1352 ICOM_THIS(IStorage16Impl,iface);
1353 IStorage16Impl* lpstg;
1354 int ppsent,x;
1355 struct storage_pps_entry stde;
1356 struct storage_header sth;
1357 HANDLE hf=This->hf;
1359 READ_HEADER;
1361 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1362 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1364 if (grfMode & STGM_TRANSACTED)
1365 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1366 _create_istorage16(ppstg);
1367 lpstg = MapSL((SEGPTR)*ppstg);
1368 lpstg->hf = This->hf;
1370 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1371 if (ppsent<0)
1372 return E_FAIL;
1373 stde=This->stde;
1374 if (stde.pps_dir==-1) {
1375 stde.pps_dir = ppsent;
1376 x = This->ppsent;
1377 } else {
1378 FIXME(" use prev chain too ?\n");
1379 x=stde.pps_dir;
1380 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1381 return E_FAIL;
1382 while (stde.pps_next!=-1) {
1383 x=stde.pps_next;
1384 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1385 return E_FAIL;
1387 stde.pps_next = ppsent;
1389 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1390 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1391 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1392 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1393 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1394 lpstg->stde.pps_next = -1;
1395 lpstg->stde.pps_prev = -1;
1396 lpstg->stde.pps_dir = -1;
1397 lpstg->stde.pps_sb = -1;
1398 lpstg->stde.pps_size = 0;
1399 lpstg->stde.pps_type = 1;
1400 lpstg->ppsent = ppsent;
1401 /* FIXME: timestamps? */
1402 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1403 return E_FAIL;
1404 return S_OK;
1407 /******************************************************************************
1408 * IStorage16_CreateStream [STORAGE.503]
1410 HRESULT WINAPI IStorage16_fnCreateStream(
1411 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1413 ICOM_THIS(IStorage16Impl,iface);
1414 IStream16Impl* lpstr;
1415 int ppsent,x;
1416 struct storage_pps_entry stde;
1418 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1419 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1421 if (grfMode & STGM_TRANSACTED)
1422 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1423 _create_istream16(ppstm);
1424 lpstr = MapSL((SEGPTR)*ppstm);
1425 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1426 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1427 lpstr->offset.s.LowPart = 0;
1428 lpstr->offset.s.HighPart = 0;
1430 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1431 if (ppsent<0)
1432 return E_FAIL;
1433 stde=This->stde;
1434 if (stde.pps_next==-1)
1435 x=This->ppsent;
1436 else
1437 while (stde.pps_next!=-1) {
1438 x=stde.pps_next;
1439 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1440 return E_FAIL;
1442 stde.pps_next = ppsent;
1443 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1444 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1445 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1446 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1447 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1448 lpstr->stde.pps_next = -1;
1449 lpstr->stde.pps_prev = -1;
1450 lpstr->stde.pps_dir = -1;
1451 lpstr->stde.pps_sb = -1;
1452 lpstr->stde.pps_size = 0;
1453 lpstr->stde.pps_type = 2;
1454 lpstr->ppsent = ppsent;
1455 /* FIXME: timestamps? */
1456 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1457 return E_FAIL;
1458 return S_OK;
1461 /******************************************************************************
1462 * IStorage16_OpenStorage [STORAGE.506]
1464 HRESULT WINAPI IStorage16_fnOpenStorage(
1465 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1467 ICOM_THIS(IStorage16Impl,iface);
1468 IStream16Impl* lpstg;
1469 WCHAR name[33];
1470 int newpps;
1472 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1473 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1475 if (grfMode & STGM_TRANSACTED)
1476 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1477 _create_istorage16(ppstg);
1478 lpstg = MapSL((SEGPTR)*ppstg);
1479 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1480 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1481 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1482 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1483 if (newpps==-1) {
1484 IStream16_fnRelease((IStream16*)lpstg);
1485 return E_FAIL;
1488 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1489 IStream16_fnRelease((IStream16*)lpstg);
1490 return E_FAIL;
1492 lpstg->ppsent = newpps;
1493 return S_OK;
1496 /******************************************************************************
1497 * IStorage16_OpenStream [STORAGE.504]
1499 HRESULT WINAPI IStorage16_fnOpenStream(
1500 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1502 ICOM_THIS(IStorage16Impl,iface);
1503 IStream16Impl* lpstr;
1504 WCHAR name[33];
1505 int newpps;
1507 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1508 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1510 if (grfMode & STGM_TRANSACTED)
1511 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1512 _create_istream16(ppstm);
1513 lpstr = MapSL((SEGPTR)*ppstm);
1514 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1515 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1516 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1517 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1518 if (newpps==-1) {
1519 IStream16_fnRelease((IStream16*)lpstr);
1520 return E_FAIL;
1523 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1524 IStream16_fnRelease((IStream16*)lpstr);
1525 return E_FAIL;
1527 lpstr->offset.s.LowPart = 0;
1528 lpstr->offset.s.HighPart = 0;
1529 lpstr->ppsent = newpps;
1530 return S_OK;
1533 /******************************************************************************
1534 * _create_istorage16 [INTERNAL]
1536 static void _create_istorage16(LPSTORAGE16 *stg) {
1537 IStorage16Impl* lpst;
1539 if (!stvt16.QueryInterface) {
1540 HMODULE16 wp = GetModuleHandle16("STORAGE");
1541 if (wp>=32) {
1542 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#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(MoveElementTo)
1552 VTENT(Commit)
1553 VTENT(Revert)
1554 VTENT(EnumElements)
1555 VTENT(DestroyElement)
1556 VTENT(RenameElement)
1557 VTENT(SetElementTimes)
1558 VTENT(SetClass)
1559 VTENT(SetStateBits)
1560 VTENT(Stat)
1561 #undef VTENT
1562 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1563 } else {
1564 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1565 VTENT(QueryInterface)
1566 VTENT(AddRef)
1567 VTENT(Release)
1568 VTENT(CreateStream)
1569 VTENT(OpenStream)
1570 VTENT(CreateStorage)
1571 VTENT(OpenStorage)
1572 VTENT(CopyTo)
1573 VTENT(Commit)
1574 /* not (yet) implemented ...
1575 VTENT(MoveElementTo)
1576 VTENT(Revert)
1577 VTENT(EnumElements)
1578 VTENT(DestroyElement)
1579 VTENT(RenameElement)
1580 VTENT(SetElementTimes)
1581 VTENT(SetClass)
1582 VTENT(SetStateBits)
1583 VTENT(Stat)
1585 #undef VTENT
1586 segstvt16 = &stvt16;
1589 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1590 ICOM_VTBL(lpst) = segstvt16;
1591 lpst->ref = 1;
1592 lpst->thisptr = MapLS(lpst);
1593 *stg = (void*)lpst->thisptr;
1596 /******************************************************************************
1597 * Storage API functions
1600 /******************************************************************************
1601 * StgCreateDocFileA [STORAGE.1]
1603 HRESULT WINAPI StgCreateDocFile16(
1604 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1606 HANDLE hf;
1607 int i,ret;
1608 IStorage16Impl* lpstg;
1609 struct storage_pps_entry stde;
1611 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1612 pwcsName,grfMode,reserved,ppstgOpen
1614 _create_istorage16(ppstgOpen);
1615 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1616 if (hf==INVALID_HANDLE_VALUE) {
1617 WARN("couldn't open file for storage:%ld\n",GetLastError());
1618 return E_FAIL;
1620 lpstg = MapSL((SEGPTR)*ppstgOpen);
1621 lpstg->hf = hf;
1622 /* FIXME: check for existence before overwriting? */
1623 if (!STORAGE_init_storage(hf)) {
1624 CloseHandle(hf);
1625 return E_FAIL;
1627 i=0;ret=0;
1628 while (!ret) { /* neither 1 nor <0 */
1629 ret=STORAGE_get_pps_entry(hf,i,&stde);
1630 if ((ret==1) && (stde.pps_type==5)) {
1631 lpstg->stde = stde;
1632 lpstg->ppsent = i;
1633 break;
1635 i++;
1637 if (ret!=1) {
1638 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1639 return E_FAIL;
1642 return S_OK;
1645 /******************************************************************************
1646 * StgIsStorageFile [STORAGE.5]
1648 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1649 UNICODE_STRING strW;
1650 HRESULT ret;
1652 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1653 ret = StgIsStorageFile( strW.Buffer );
1654 RtlFreeUnicodeString( &strW );
1656 return ret;
1659 /******************************************************************************
1660 * StgOpenStorage [STORAGE.3]
1662 HRESULT WINAPI StgOpenStorage16(
1663 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1664 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1666 HANDLE hf;
1667 int ret,i;
1668 IStorage16Impl* lpstg;
1669 struct storage_pps_entry stde;
1671 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1672 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1674 _create_istorage16(ppstgOpen);
1675 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1676 if (hf==INVALID_HANDLE_VALUE) {
1677 WARN("Couldn't open file for storage\n");
1678 return E_FAIL;
1680 lpstg = MapSL((SEGPTR)*ppstgOpen);
1681 lpstg->hf = hf;
1683 i=0;ret=0;
1684 while (!ret) { /* neither 1 nor <0 */
1685 ret=STORAGE_get_pps_entry(hf,i,&stde);
1686 if ((ret==1) && (stde.pps_type==5)) {
1687 lpstg->stde=stde;
1688 break;
1690 i++;
1692 if (ret!=1) {
1693 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1694 return E_FAIL;
1696 return S_OK;
1700 /******************************************************************************
1701 * StgIsStorageILockBytes [STORAGE.6]
1703 * Determines if the ILockBytes contains a storage object.
1705 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1707 DWORD args[6];
1708 HRESULT hres;
1709 HANDLE16 hsig;
1711 args[0] = (DWORD)plkbyt; /* iface */
1712 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1713 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1714 args[4] = 8;
1715 args[5] = 0;
1717 if (!K32WOWCallback16Ex(
1718 (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1719 (SEGPTR)ICOM_VTBL(((LPLOCKBYTES16)MapSL(plkbyt))))
1720 )->ReadAt,
1721 WCB16_PASCAL,
1722 6*sizeof(DWORD),
1723 (LPVOID)args,
1724 (LPDWORD)&hres
1725 )) {
1726 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1727 return hres;
1729 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1730 K32WOWGlobalUnlockFree16(args[3]);
1731 return S_OK;
1733 K32WOWGlobalUnlockFree16(args[3]);
1734 return S_FALSE;
1737 /******************************************************************************
1738 * StgOpenStorageOnILockBytes [STORAGE.4]
1740 HRESULT WINAPI StgOpenStorageOnILockBytes16(
1741 ILockBytes16 *plkbyt,
1742 IStorage16 *pstgPriority,
1743 DWORD grfMode,
1744 SNB16 snbExclude,
1745 DWORD reserved,
1746 IStorage16 **ppstgOpen)
1748 IStorage16Impl* lpstg;
1750 if ((plkbyt == 0) || (ppstgOpen == 0))
1751 return STG_E_INVALIDPOINTER;
1753 *ppstgOpen = 0;
1755 _create_istorage16(ppstgOpen);
1756 lpstg = MapSL((SEGPTR)*ppstgOpen);
1758 /* just teach it to use HANDLE instead of ilockbytes :/ */
1760 return S_OK;