Changed wsock32 to use the new iphlpapi for interface and route
[wine/wine64.git] / dlls / ole32 / storage.c
blob086d6b025fd4a1510455b9a62f22fc6aa1431712
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,
114 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
116 WARN(" seek failed (%ld)\n",GetLastError());
117 return FALSE;
119 if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
121 WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError());
122 return FALSE;
124 return TRUE;
127 /******************************************************************************
128 * STORAGE_put_big_block [INTERNAL]
130 static BOOL
131 STORAGE_put_big_block(HANDLE hf,int n,BYTE *block)
133 DWORD result;
135 assert(n>=-1);
136 if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL,
137 SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
139 WARN("seek failed (%ld)\n",GetLastError());
140 return FALSE;
142 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
144 WARN(" write failed (%ld)\n",GetLastError());
145 return FALSE;
147 return TRUE;
150 /******************************************************************************
151 * STORAGE_get_next_big_blocknr [INTERNAL]
153 static int
154 STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) {
155 INT bbs[BIGSIZE/sizeof(INT)];
156 struct storage_header sth;
158 READ_HEADER;
160 assert(blocknr>>7<sth.num_of_bbd_blocks);
161 if (sth.bbd_list[blocknr>>7]==0xffffffff)
162 return -5;
163 if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
164 return -5;
165 assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
166 return bbs[blocknr&0x7f];
169 /******************************************************************************
170 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
172 static int
173 STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) {
174 INT bbs[BIGSIZE/sizeof(INT)];
175 int lastblock = -1;
176 struct storage_header sth;
178 READ_HEADER;
180 assert(blocknr>=0);
181 while (nr--) {
182 assert((blocknr>>7)<sth.num_of_bbd_blocks);
183 assert(sth.bbd_list[blocknr>>7]!=0xffffffff);
185 /* simple caching... */
186 if (lastblock!=sth.bbd_list[blocknr>>7]) {
187 assert(STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs));
188 lastblock = sth.bbd_list[blocknr>>7];
190 blocknr = bbs[blocknr&0x7f];
192 return blocknr;
195 /******************************************************************************
196 * STORAGE_get_root_pps_entry [Internal]
198 static BOOL
199 STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) {
200 int blocknr,i;
201 BYTE block[BIGSIZE];
202 struct storage_pps_entry *stde=(struct storage_pps_entry*)block;
203 struct storage_header sth;
205 READ_HEADER;
206 blocknr = sth.root_startblock;
207 while (blocknr>=0) {
208 assert(STORAGE_get_big_block(hf,blocknr,block));
209 for (i=0;i<4;i++) {
210 if (!stde[i].pps_sizeofname)
211 continue;
212 if (stde[i].pps_type==5) {
213 *pstde=stde[i];
214 return TRUE;
217 blocknr=STORAGE_get_next_big_blocknr(hf,blocknr);
219 return FALSE;
222 /******************************************************************************
223 * STORAGE_get_small_block [INTERNAL]
225 static BOOL
226 STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
227 BYTE block[BIGSIZE];
228 int bigblocknr;
229 struct storage_pps_entry root;
231 assert(blocknr>=0);
232 assert(STORAGE_get_root_pps_entry(hf,&root));
233 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
234 assert(bigblocknr>=0);
235 assert(STORAGE_get_big_block(hf,bigblocknr,block));
237 memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
238 return TRUE;
241 /******************************************************************************
242 * STORAGE_put_small_block [INTERNAL]
244 static BOOL
245 STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) {
246 BYTE block[BIGSIZE];
247 int bigblocknr;
248 struct storage_pps_entry root;
250 assert(blocknr>=0);
252 assert(STORAGE_get_root_pps_entry(hf,&root));
253 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
254 assert(bigblocknr>=0);
255 assert(STORAGE_get_big_block(hf,bigblocknr,block));
257 memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
258 assert(STORAGE_put_big_block(hf,bigblocknr,block));
259 return TRUE;
262 /******************************************************************************
263 * STORAGE_get_next_small_blocknr [INTERNAL]
265 static int
266 STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) {
267 BYTE block[BIGSIZE];
268 LPINT sbd = (LPINT)block;
269 int bigblocknr;
270 struct storage_header sth;
272 READ_HEADER;
273 assert(blocknr>=0);
274 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
275 assert(bigblocknr>=0);
276 assert(STORAGE_get_big_block(hf,bigblocknr,block));
277 assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
278 return sbd[blocknr & (128-1)];
281 /******************************************************************************
282 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
284 static int
285 STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) {
286 int lastblocknr=-1;
287 BYTE block[BIGSIZE];
288 LPINT sbd = (LPINT)block;
289 struct storage_header sth;
291 READ_HEADER;
292 assert(blocknr>=0);
293 while ((nr--) && (blocknr>=0)) {
294 if (lastblocknr/128!=blocknr/128) {
295 int bigblocknr;
296 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
297 assert(bigblocknr>=0);
298 assert(STORAGE_get_big_block(hf,bigblocknr,block));
299 lastblocknr = blocknr;
301 assert(lastblocknr>=0);
302 lastblocknr=blocknr;
303 blocknr=sbd[blocknr & (128-1)];
304 assert(blocknr!=STORAGE_CHAINENTRY_FREE);
306 return blocknr;
309 /******************************************************************************
310 * STORAGE_get_pps_entry [INTERNAL]
312 static int
313 STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
314 int blocknr;
315 BYTE block[BIGSIZE];
316 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
317 struct storage_header sth;
319 READ_HEADER;
320 /* we have 4 pps entries per big block */
321 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
322 assert(blocknr>=0);
323 assert(STORAGE_get_big_block(hf,blocknr,block));
325 *pstde=*stde;
326 return 1;
329 /******************************************************************************
330 * STORAGE_put_pps_entry [Internal]
332 static int
333 STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) {
334 int blocknr;
335 BYTE block[BIGSIZE];
336 struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
337 struct storage_header sth;
339 READ_HEADER;
341 /* we have 4 pps entries per big block */
342 blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4);
343 assert(blocknr>=0);
344 assert(STORAGE_get_big_block(hf,blocknr,block));
345 *stde=*pstde;
346 assert(STORAGE_put_big_block(hf,blocknr,block));
347 return 1;
350 /******************************************************************************
351 * STORAGE_look_for_named_pps [Internal]
353 static int
354 STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) {
355 struct storage_pps_entry stde;
356 int ret;
358 if (n==-1)
359 return -1;
360 if (1!=STORAGE_get_pps_entry(hf,n,&stde))
361 return -1;
363 if (!lstrcmpW(name,stde.pps_rawname))
364 return n;
365 if (stde.pps_prev != -1) {
366 ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name);
367 if (ret!=-1)
368 return ret;
370 if (stde.pps_next != -1) {
371 ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name);
372 if (ret!=-1)
373 return ret;
375 return -1;
378 /******************************************************************************
379 * STORAGE_dump_pps_entry [Internal]
381 * FIXME
382 * Function is unused
384 void
385 STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
386 char name[33];
388 WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
389 if (!stde->pps_sizeofname)
390 return;
391 DPRINTF("name: %s\n",name);
392 DPRINTF("type: %d\n",stde->pps_type);
393 DPRINTF("prev pps: %ld\n",stde->pps_prev);
394 DPRINTF("next pps: %ld\n",stde->pps_next);
395 DPRINTF("dir pps: %ld\n",stde->pps_dir);
396 DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
397 if (stde->pps_type !=2) {
398 time_t t;
399 DWORD dw;
400 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
401 t = dw;
402 DPRINTF("ts1: %s\n",ctime(&t));
403 RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
404 t = dw;
405 DPRINTF("ts2: %s\n",ctime(&t));
407 DPRINTF("startblock: %ld\n",stde->pps_sb);
408 DPRINTF("size: %ld\n",stde->pps_size);
411 /******************************************************************************
412 * STORAGE_init_storage [INTERNAL]
414 static BOOL
415 STORAGE_init_storage(HANDLE hf) {
416 BYTE block[BIGSIZE];
417 LPDWORD bbs;
418 struct storage_header *sth;
419 struct storage_pps_entry *stde;
420 DWORD result;
422 SetFilePointer( hf, 0, NULL, SEEK_SET );
423 /* block -1 is the storage header */
424 sth = (struct storage_header*)block;
425 memcpy(sth->magic,STORAGE_magic,8);
426 memset(sth->unknown1,0,sizeof(sth->unknown1));
427 memset(sth->unknown2,0,sizeof(sth->unknown2));
428 memset(sth->unknown3,0,sizeof(sth->unknown3));
429 sth->num_of_bbd_blocks = 1;
430 sth->root_startblock = 1;
431 sth->sbd_startblock = 0xffffffff;
432 memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
433 sth->bbd_list[0] = 0;
434 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
435 /* block 0 is the big block directory */
436 bbs=(LPDWORD)block;
437 memset(block,0xff,sizeof(block)); /* mark all blocks as free */
438 bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
439 bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
440 if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
441 /* block 1 is the root directory entry */
442 memset(block,0x00,sizeof(block));
443 stde = (struct storage_pps_entry*)block;
444 MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
445 sizeof(stde->pps_rawname)/sizeof(WCHAR));
446 stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
447 stde->pps_type = 5;
448 stde->pps_dir = -1;
449 stde->pps_next = -1;
450 stde->pps_prev = -1;
451 stde->pps_sb = 0xffffffff;
452 stde->pps_size = 0;
453 return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
456 /******************************************************************************
457 * STORAGE_set_big_chain [Internal]
459 static BOOL
460 STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) {
461 BYTE block[BIGSIZE];
462 LPINT bbd = (LPINT)block;
463 int nextblocknr,bigblocknr;
464 struct storage_header sth;
466 READ_HEADER;
467 assert(blocknr!=type);
468 while (blocknr>=0) {
469 bigblocknr = sth.bbd_list[blocknr/128];
470 assert(bigblocknr>=0);
471 assert(STORAGE_get_big_block(hf,bigblocknr,block));
473 nextblocknr = bbd[blocknr&(128-1)];
474 bbd[blocknr&(128-1)] = type;
475 if (type>=0)
476 return TRUE;
477 assert(STORAGE_put_big_block(hf,bigblocknr,block));
478 type = STORAGE_CHAINENTRY_FREE;
479 blocknr = nextblocknr;
481 return TRUE;
484 /******************************************************************************
485 * STORAGE_set_small_chain [Internal]
487 static BOOL
488 STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) {
489 BYTE block[BIGSIZE];
490 LPINT sbd = (LPINT)block;
491 int lastblocknr,nextsmallblocknr,bigblocknr;
492 struct storage_header sth;
494 READ_HEADER;
496 assert(blocknr!=type);
497 lastblocknr=-129;bigblocknr=-2;
498 while (blocknr>=0) {
499 /* cache block ... */
500 if (lastblocknr/128!=blocknr/128) {
501 bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128);
502 assert(bigblocknr>=0);
503 assert(STORAGE_get_big_block(hf,bigblocknr,block));
505 lastblocknr = blocknr;
506 nextsmallblocknr = sbd[blocknr&(128-1)];
507 sbd[blocknr&(128-1)] = type;
508 assert(STORAGE_put_big_block(hf,bigblocknr,block));
509 if (type>=0)
510 return TRUE;
511 type = STORAGE_CHAINENTRY_FREE;
512 blocknr = nextsmallblocknr;
514 return TRUE;
517 /******************************************************************************
518 * STORAGE_get_free_big_blocknr [Internal]
520 static int
521 STORAGE_get_free_big_blocknr(HANDLE hf) {
522 BYTE block[BIGSIZE];
523 LPINT sbd = (LPINT)block;
524 int lastbigblocknr,i,curblock,bigblocknr;
525 struct storage_header sth;
527 READ_HEADER;
528 curblock = 0;
529 lastbigblocknr = -1;
530 bigblocknr = sth.bbd_list[curblock];
531 while (curblock<sth.num_of_bbd_blocks) {
532 assert(bigblocknr>=0);
533 assert(STORAGE_get_big_block(hf,bigblocknr,block));
534 for (i=0;i<128;i++)
535 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
536 sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
537 assert(STORAGE_put_big_block(hf,bigblocknr,block));
538 memset(block,0x42,sizeof(block));
539 assert(STORAGE_put_big_block(hf,i+curblock*128,block));
540 return i+curblock*128;
542 lastbigblocknr = bigblocknr;
543 bigblocknr = sth.bbd_list[++curblock];
545 bigblocknr = curblock*128;
546 /* since we have marked all blocks from 0 up to curblock*128-1
547 * the next free one is curblock*128, where we happily put our
548 * next large block depot.
550 memset(block,0xff,sizeof(block));
551 /* mark the block allocated and returned by this function */
552 sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
553 assert(STORAGE_put_big_block(hf,bigblocknr,block));
555 /* if we had a bbd block already (mostlikely) we need
556 * to link the new one into the chain
558 if (lastbigblocknr!=-1)
559 assert(STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr));
560 sth.bbd_list[curblock]=bigblocknr;
561 sth.num_of_bbd_blocks++;
562 assert(sth.num_of_bbd_blocks==curblock+1);
563 assert(STORAGE_put_big_block(hf,-1,(LPBYTE)&sth));
565 /* Set the end of the chain for the bigblockdepots */
566 assert(STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN));
567 /* add 1, for the first entry is used for the additional big block
568 * depot. (means we already used bigblocknr) */
569 memset(block,0x42,sizeof(block));
570 /* allocate this block (filled with 0x42) */
571 assert(STORAGE_put_big_block(hf,bigblocknr+1,block));
572 return bigblocknr+1;
576 /******************************************************************************
577 * STORAGE_get_free_small_blocknr [Internal]
579 static int
580 STORAGE_get_free_small_blocknr(HANDLE hf) {
581 BYTE block[BIGSIZE];
582 LPINT sbd = (LPINT)block;
583 int lastbigblocknr,newblocknr,i,curblock,bigblocknr;
584 struct storage_pps_entry root;
585 struct storage_header sth;
587 READ_HEADER;
588 bigblocknr = sth.sbd_startblock;
589 curblock = 0;
590 lastbigblocknr = -1;
591 newblocknr = -1;
592 while (bigblocknr>=0) {
593 if (!STORAGE_get_big_block(hf,bigblocknr,block))
594 return -1;
595 for (i=0;i<128;i++)
596 if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
597 sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
598 newblocknr = i+curblock*128;
599 break;
601 if (i!=128)
602 break;
603 lastbigblocknr = bigblocknr;
604 bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr);
605 curblock++;
607 if (newblocknr==-1) {
608 bigblocknr = STORAGE_get_free_big_blocknr(hf);
609 if (bigblocknr<0)
610 return -1;
611 READ_HEADER;
612 memset(block,0xff,sizeof(block));
613 sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
614 if (!STORAGE_put_big_block(hf,bigblocknr,block))
615 return -1;
616 if (lastbigblocknr==-1) {
617 sth.sbd_startblock = bigblocknr;
618 if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */
619 return -1;
620 } else {
621 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
622 return -1;
624 if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
625 return -1;
626 newblocknr = curblock*128;
628 /* allocate enough big blocks for storing the allocated small block */
629 if (!STORAGE_get_root_pps_entry(hf,&root))
630 return -1;
631 if (root.pps_sb==-1)
632 lastbigblocknr = -1;
633 else
634 lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE);
635 while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
636 /* we need to allocate more stuff */
637 bigblocknr = STORAGE_get_free_big_blocknr(hf);
638 if (bigblocknr<0)
639 return -1;
640 READ_HEADER;
641 if (root.pps_sb==-1) {
642 root.pps_sb = bigblocknr;
643 root.pps_size += BIGSIZE;
644 } else {
645 if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr))
646 return -1;
647 root.pps_size += BIGSIZE;
649 lastbigblocknr = bigblocknr;
651 if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
652 return -1;
653 if (!STORAGE_put_pps_entry(hf,0,&root))
654 return -1;
655 return newblocknr;
658 /******************************************************************************
659 * STORAGE_get_free_pps_entry [Internal]
661 static int
662 STORAGE_get_free_pps_entry(HANDLE hf) {
663 int blocknr, i, curblock, lastblocknr=-1;
664 BYTE block[BIGSIZE];
665 struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
666 struct storage_header sth;
668 READ_HEADER;
669 blocknr = sth.root_startblock;
670 assert(blocknr>=0);
671 curblock=0;
672 while (blocknr>=0) {
673 if (!STORAGE_get_big_block(hf,blocknr,block))
674 return -1;
675 for (i=0;i<4;i++)
676 if (stde[i].pps_sizeofname==0) /* free */
677 return curblock*4+i;
678 lastblocknr = blocknr;
679 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
680 curblock++;
682 assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
683 blocknr = STORAGE_get_free_big_blocknr(hf);
684 /* sth invalidated */
685 if (blocknr<0)
686 return -1;
688 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
689 return -1;
690 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
691 return -1;
692 memset(block,0,sizeof(block));
693 STORAGE_put_big_block(hf,blocknr,block);
694 return curblock*4;
697 /* --- IStream16 implementation */
699 typedef struct
701 /* IUnknown fields */
702 ICOM_VFIELD(IStream16);
703 DWORD ref;
704 /* IStream16 fields */
705 SEGPTR thisptr; /* pointer to this struct as segmented */
706 struct storage_pps_entry stde;
707 int ppsent;
708 HANDLE hf;
709 ULARGE_INTEGER offset;
710 } IStream16Impl;
712 /******************************************************************************
713 * IStream16_QueryInterface [STORAGE.518]
715 HRESULT WINAPI IStream16_fnQueryInterface(
716 IStream16* iface,REFIID refiid,LPVOID *obj
718 ICOM_THIS(IStream16Impl,iface);
719 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
720 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
721 *obj = This;
722 return 0;
724 return OLE_E_ENUM_NOMORE;
728 /******************************************************************************
729 * IStream16_AddRef [STORAGE.519]
731 ULONG WINAPI IStream16_fnAddRef(IStream16* iface) {
732 ICOM_THIS(IStream16Impl,iface);
733 return ++(This->ref);
736 /******************************************************************************
737 * IStream16_Release [STORAGE.520]
739 ULONG WINAPI IStream16_fnRelease(IStream16* iface) {
740 ICOM_THIS(IStream16Impl,iface);
741 FlushFileBuffers(This->hf);
742 This->ref--;
743 if (!This->ref) {
744 CloseHandle(This->hf);
745 UnMapLS( This->thisptr );
746 HeapFree( GetProcessHeap(), 0, This );
747 return 0;
749 return This->ref;
752 /******************************************************************************
753 * IStream16_Seek [STORAGE.523]
755 * FIXME
756 * Does not handle 64 bits
758 HRESULT WINAPI IStream16_fnSeek(
759 IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
761 ICOM_THIS(IStream16Impl,iface);
762 TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.s.HighPart,offset.s.LowPart,whence,newpos);
764 switch (whence) {
765 /* unix SEEK_xx should be the same as win95 ones */
766 case SEEK_SET:
767 /* offset must be ==0 (<0 is invalid, and >0 cannot be handled
768 * right now.
770 assert(offset.s.HighPart==0);
771 This->offset.s.HighPart = offset.s.HighPart;
772 This->offset.s.LowPart = offset.s.LowPart;
773 break;
774 case SEEK_CUR:
775 if (offset.s.HighPart < 0) {
776 /* FIXME: is this negation correct ? */
777 offset.s.HighPart = -offset.s.HighPart;
778 offset.s.LowPart = (0xffffffff ^ offset.s.LowPart)+1;
780 assert(offset.s.HighPart==0);
781 assert(This->offset.s.LowPart >= offset.s.LowPart);
782 This->offset.s.LowPart -= offset.s.LowPart;
783 } else {
784 assert(offset.s.HighPart==0);
785 This->offset.s.LowPart+= offset.s.LowPart;
787 break;
788 case SEEK_END:
789 assert(offset.s.HighPart==0);
790 This->offset.s.LowPart = This->stde.pps_size-offset.s.LowPart;
791 break;
793 if (This->offset.s.LowPart>This->stde.pps_size)
794 This->offset.s.LowPart=This->stde.pps_size;
795 if (newpos) *newpos = This->offset;
796 return S_OK;
799 /******************************************************************************
800 * IStream16_Read [STORAGE.521]
802 HRESULT WINAPI IStream16_fnRead(
803 IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead
805 ICOM_THIS(IStream16Impl,iface);
806 BYTE block[BIGSIZE];
807 ULONG *bytesread=pcbRead,xxread;
808 int blocknr;
810 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
811 if (!pcbRead) bytesread=&xxread;
812 *bytesread = 0;
814 if (cb>This->stde.pps_size-This->offset.s.LowPart)
815 cb=This->stde.pps_size-This->offset.s.LowPart;
816 if (This->stde.pps_size < 0x1000) {
817 /* use small block reader */
818 blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
819 while (cb) {
820 int cc;
822 if (!STORAGE_get_small_block(This->hf,blocknr,block)) {
823 WARN("small block read failed!!!\n");
824 return E_FAIL;
826 cc = cb;
827 if (cc>SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1)))
828 cc=SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
829 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(SMALLSIZE-1)),cc);
830 This->offset.s.LowPart+=cc;
831 (LPBYTE)pv+=cc;
832 *bytesread+=cc;
833 cb-=cc;
834 blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr);
836 } else {
837 /* use big block reader */
838 blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
839 while (cb) {
840 int cc;
842 if (!STORAGE_get_big_block(This->hf,blocknr,block)) {
843 WARN("big block read failed!!!\n");
844 return E_FAIL;
846 cc = cb;
847 if (cc>BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1)))
848 cc=BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
849 memcpy((LPBYTE)pv,block+(This->offset.s.LowPart&(BIGSIZE-1)),cc);
850 This->offset.s.LowPart+=cc;
851 (LPBYTE)pv+=cc;
852 *bytesread+=cc;
853 cb-=cc;
854 blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr);
857 return S_OK;
860 /******************************************************************************
861 * IStream16_Write [STORAGE.522]
863 HRESULT WINAPI IStream16_fnWrite(
864 IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
866 ICOM_THIS(IStream16Impl,iface);
867 BYTE block[BIGSIZE];
868 ULONG *byteswritten=pcbWrite,xxwritten;
869 int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
870 HANDLE hf = This->hf;
872 if (!pcbWrite) byteswritten=&xxwritten;
873 *byteswritten = 0;
875 TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
876 /* do we need to junk some blocks? */
877 newsize = This->offset.s.LowPart+cb;
878 oldsize = This->stde.pps_size;
879 if (newsize < oldsize) {
880 if (oldsize < 0x1000) {
881 /* only small blocks */
882 blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE);
884 assert(blocknr>=0);
886 /* will set the rest of the chain to 'free' */
887 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
888 return E_FAIL;
889 } else {
890 if (newsize >= 0x1000) {
891 blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE);
892 assert(blocknr>=0);
894 /* will set the rest of the chain to 'free' */
895 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
896 return E_FAIL;
897 } else {
898 /* Migrate large blocks to small blocks
899 * (we just migrate newsize bytes)
901 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
902 HRESULT r = E_FAIL;
904 cc = newsize;
905 blocknr = This->stde.pps_sb;
906 curdata = data;
907 while (cc>0) {
908 if (!STORAGE_get_big_block(hf,blocknr,curdata)) {
909 HeapFree(GetProcessHeap(),0,data);
910 return E_FAIL;
912 curdata += BIGSIZE;
913 cc -= BIGSIZE;
914 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
916 /* frees complete chain for this stream */
917 if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
918 goto err;
919 curdata = data;
920 blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf);
921 if (blocknr<0)
922 goto err;
923 cc = newsize;
924 while (cc>0) {
925 if (!STORAGE_put_small_block(hf,blocknr,curdata))
926 goto err;
927 cc -= SMALLSIZE;
928 if (cc<=0) {
929 if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
930 goto err;
931 break;
932 } else {
933 int newblocknr = STORAGE_get_free_small_blocknr(hf);
934 if (newblocknr<0)
935 goto err;
936 if (!STORAGE_set_small_chain(hf,blocknr,newblocknr))
937 goto err;
938 blocknr = newblocknr;
940 curdata += SMALLSIZE;
942 r = S_OK;
943 err:
944 HeapFree(GetProcessHeap(),0,data);
945 if(r != S_OK)
946 return r;
949 This->stde.pps_size = newsize;
952 if (newsize > oldsize) {
953 if (oldsize >= 0x1000) {
954 /* should return the block right before the 'endofchain' */
955 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
956 assert(blocknr>=0);
957 lastblocknr = blocknr;
958 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
959 blocknr = STORAGE_get_free_big_blocknr(hf);
960 if (blocknr<0)
961 return E_FAIL;
962 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
963 return E_FAIL;
964 lastblocknr = blocknr;
966 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
967 return E_FAIL;
968 } else {
969 if (newsize < 0x1000) {
970 /* find startblock */
971 if (!oldsize)
972 This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf);
973 else
974 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
975 if (blocknr<0)
976 return E_FAIL;
978 /* allocate required new small blocks */
979 lastblocknr = blocknr;
980 for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
981 blocknr = STORAGE_get_free_small_blocknr(hf);
982 if (blocknr<0)
983 return E_FAIL;
984 if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr))
985 return E_FAIL;
986 lastblocknr = blocknr;
988 /* and terminate the chain */
989 if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
990 return E_FAIL;
991 } else {
992 if (!oldsize) {
993 /* no single block allocated yet */
994 blocknr=STORAGE_get_free_big_blocknr(hf);
995 if (blocknr<0)
996 return E_FAIL;
997 This->stde.pps_sb = blocknr;
998 } else {
999 /* Migrate small blocks to big blocks */
1000 LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1001 HRESULT r = E_FAIL;
1003 cc = oldsize;
1004 blocknr = This->stde.pps_sb;
1005 curdata = data;
1006 /* slurp in */
1007 while (cc>0) {
1008 if (!STORAGE_get_small_block(hf,blocknr,curdata))
1009 goto err2;
1010 curdata += SMALLSIZE;
1011 cc -= SMALLSIZE;
1012 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1014 /* free small block chain */
1015 if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1016 goto err2;
1017 curdata = data;
1018 blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf);
1019 if (blocknr<0)
1020 goto err2;
1021 /* put the data into the big blocks */
1022 cc = This->stde.pps_size;
1023 while (cc>0) {
1024 if (!STORAGE_put_big_block(hf,blocknr,curdata))
1025 goto err2;
1026 cc -= BIGSIZE;
1027 if (cc<=0) {
1028 if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1029 goto err2;
1030 break;
1031 } else {
1032 int newblocknr = STORAGE_get_free_big_blocknr(hf);
1033 if (newblocknr<0)
1034 goto err2;
1035 if (!STORAGE_set_big_chain(hf,blocknr,newblocknr))
1036 goto err2;
1037 blocknr = newblocknr;
1039 curdata += BIGSIZE;
1041 r = S_OK;
1042 err2:
1043 HeapFree(GetProcessHeap(),0,data);
1044 if(r != S_OK)
1045 return r;
1047 /* generate big blocks to fit the new data */
1048 lastblocknr = blocknr;
1049 for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1050 blocknr = STORAGE_get_free_big_blocknr(hf);
1051 if (blocknr<0)
1052 return E_FAIL;
1053 if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr))
1054 return E_FAIL;
1055 lastblocknr = blocknr;
1057 /* terminate chain */
1058 if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1059 return E_FAIL;
1062 This->stde.pps_size = newsize;
1065 /* There are just some cases where we didn't modify it, we write it out
1066 * everytime
1068 if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde)))
1069 return E_FAIL;
1071 /* finally the write pass */
1072 if (This->stde.pps_size < 0x1000) {
1073 blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/SMALLSIZE);
1074 assert(blocknr>=0);
1075 while (cb>0) {
1076 /* we ensured that it is allocated above */
1077 assert(blocknr>=0);
1078 /* Read old block everytime, since we can have
1079 * overlapping data at START and END of the write
1081 if (!STORAGE_get_small_block(hf,blocknr,block))
1082 return E_FAIL;
1084 cc = SMALLSIZE-(This->offset.s.LowPart&(SMALLSIZE-1));
1085 if (cc>cb)
1086 cc=cb;
1087 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(SMALLSIZE-1)),
1088 (LPBYTE)((char *) pv+curoffset),
1091 if (!STORAGE_put_small_block(hf,blocknr,block))
1092 return E_FAIL;
1093 cb -= cc;
1094 curoffset += cc;
1095 (LPBYTE)pv += cc;
1096 This->offset.s.LowPart += cc;
1097 *byteswritten += cc;
1098 blocknr = STORAGE_get_next_small_blocknr(hf,blocknr);
1100 } else {
1101 blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.s.LowPart/BIGSIZE);
1102 assert(blocknr>=0);
1103 while (cb>0) {
1104 /* we ensured that it is allocated above, so it better is */
1105 assert(blocknr>=0);
1106 /* read old block everytime, since we can have
1107 * overlapping data at START and END of the write
1109 if (!STORAGE_get_big_block(hf,blocknr,block))
1110 return E_FAIL;
1112 cc = BIGSIZE-(This->offset.s.LowPart&(BIGSIZE-1));
1113 if (cc>cb)
1114 cc=cb;
1115 memcpy( ((LPBYTE)block)+(This->offset.s.LowPart&(BIGSIZE-1)),
1116 (LPBYTE)((char *) pv+curoffset),
1119 if (!STORAGE_put_big_block(hf,blocknr,block))
1120 return E_FAIL;
1121 cb -= cc;
1122 curoffset += cc;
1123 (LPBYTE)pv += cc;
1124 This->offset.s.LowPart += cc;
1125 *byteswritten += cc;
1126 blocknr = STORAGE_get_next_big_blocknr(hf,blocknr);
1129 return S_OK;
1132 /******************************************************************************
1133 * _create_istream16 [Internal]
1135 static void _create_istream16(LPSTREAM16 *str) {
1136 IStream16Impl* lpst;
1138 if (!strvt16.QueryInterface) {
1139 HMODULE16 wp = GetModuleHandle16("STORAGE");
1140 if (wp>=32) {
1141 /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1142 #define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1143 VTENT(QueryInterface);
1144 VTENT(AddRef);
1145 VTENT(Release);
1146 VTENT(Read);
1147 VTENT(Write);
1148 VTENT(Seek);
1149 VTENT(SetSize);
1150 VTENT(CopyTo);
1151 VTENT(Commit);
1152 VTENT(Revert);
1153 VTENT(LockRegion);
1154 VTENT(UnlockRegion);
1155 VTENT(Stat);
1156 VTENT(Clone);
1157 #undef VTENT
1158 segstrvt16 = (ICOM_VTABLE(IStream16)*)MapLS( &strvt16 );
1159 } else {
1160 #define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1161 VTENT(QueryInterface);
1162 VTENT(AddRef);
1163 VTENT(Release);
1164 VTENT(Read);
1165 VTENT(Write);
1166 VTENT(Seek);
1168 VTENT(CopyTo);
1169 VTENT(Commit);
1170 VTENT(SetSize);
1171 VTENT(Revert);
1172 VTENT(LockRegion);
1173 VTENT(UnlockRegion);
1174 VTENT(Stat);
1175 VTENT(Clone);
1177 #undef VTENT
1178 segstrvt16 = &strvt16;
1181 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1182 lpst->lpVtbl = segstrvt16;
1183 lpst->ref = 1;
1184 lpst->thisptr = MapLS( lpst );
1185 *str = (void*)lpst->thisptr;
1189 /* --- IStream32 implementation */
1191 typedef struct
1193 /* IUnknown fields */
1194 ICOM_VFIELD(IStream);
1195 DWORD ref;
1196 /* IStream32 fields */
1197 struct storage_pps_entry stde;
1198 int ppsent;
1199 HANDLE hf;
1200 ULARGE_INTEGER offset;
1201 } IStream32Impl;
1203 /*****************************************************************************
1204 * IStream32_QueryInterface [VTABLE]
1206 HRESULT WINAPI IStream_fnQueryInterface(
1207 IStream* iface,REFIID refiid,LPVOID *obj
1209 ICOM_THIS(IStream32Impl,iface);
1211 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1212 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1213 *obj = This;
1214 return 0;
1216 return OLE_E_ENUM_NOMORE;
1220 /******************************************************************************
1221 * IStream32_AddRef [VTABLE]
1223 ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1224 ICOM_THIS(IStream32Impl,iface);
1225 return ++(This->ref);
1228 /******************************************************************************
1229 * IStream32_Release [VTABLE]
1231 ULONG WINAPI IStream_fnRelease(IStream* iface) {
1232 ICOM_THIS(IStream32Impl,iface);
1233 FlushFileBuffers(This->hf);
1234 This->ref--;
1235 if (!This->ref) {
1236 CloseHandle(This->hf);
1237 HeapFree( GetProcessHeap(), 0, This );
1238 return 0;
1240 return This->ref;
1243 /* --- IStorage16 implementation */
1245 typedef struct
1247 /* IUnknown fields */
1248 ICOM_VFIELD(IStorage16);
1249 DWORD ref;
1250 /* IStorage16 fields */
1251 SEGPTR thisptr; /* pointer to this struct as segmented */
1252 struct storage_pps_entry stde;
1253 int ppsent;
1254 HANDLE hf;
1255 } IStorage16Impl;
1257 /******************************************************************************
1258 * IStorage16_QueryInterface [STORAGE.500]
1260 HRESULT WINAPI IStorage16_fnQueryInterface(
1261 IStorage16* iface,REFIID refiid,LPVOID *obj
1263 ICOM_THIS(IStorage16Impl,iface);
1265 TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
1267 if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1268 *obj = This;
1269 return 0;
1271 return OLE_E_ENUM_NOMORE;
1274 /******************************************************************************
1275 * IStorage16_AddRef [STORAGE.501]
1277 ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) {
1278 ICOM_THIS(IStorage16Impl,iface);
1279 return ++(This->ref);
1282 /******************************************************************************
1283 * IStorage16_Release [STORAGE.502]
1285 ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) {
1286 ICOM_THIS(IStorage16Impl,iface);
1287 This->ref--;
1288 if (This->ref)
1289 return This->ref;
1290 UnMapLS( This->thisptr );
1291 HeapFree( GetProcessHeap(), 0, This );
1292 return 0;
1295 /******************************************************************************
1296 * IStorage16_Stat [STORAGE.517]
1298 HRESULT WINAPI IStorage16_fnStat(
1299 LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
1301 ICOM_THIS(IStorage16Impl,iface);
1302 DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
1303 LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );
1305 TRACE("(%p)->(%p,0x%08lx)\n",
1306 This,pstatstg,grfStatFlag
1308 WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
1309 pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1310 pstatstg->type = This->stde.pps_type;
1311 pstatstg->cbSize.s.LowPart = This->stde.pps_size;
1312 pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
1313 pstatstg->atime = This->stde.pps_ft2; /* FIXME */
1314 pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
1315 pstatstg->grfMode = 0; /* FIXME */
1316 pstatstg->grfLocksSupported = 0; /* FIXME */
1317 pstatstg->clsid = This->stde.pps_guid;
1318 pstatstg->grfStateBits = 0; /* FIXME */
1319 pstatstg->reserved = 0;
1320 return S_OK;
1323 /******************************************************************************
1324 * IStorage16_Commit [STORAGE.509]
1326 HRESULT WINAPI IStorage16_fnCommit(
1327 LPSTORAGE16 iface,DWORD commitflags
1329 ICOM_THIS(IStorage16Impl,iface);
1330 FIXME("(%p)->(0x%08lx),STUB!\n",
1331 This,commitflags
1333 return S_OK;
1336 /******************************************************************************
1337 * IStorage16_CopyTo [STORAGE.507]
1339 HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1340 ICOM_THIS(IStorage16Impl,iface);
1341 FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1342 This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
1344 return S_OK;
1348 /******************************************************************************
1349 * IStorage16_CreateStorage [STORAGE.505]
1351 HRESULT WINAPI IStorage16_fnCreateStorage(
1352 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
1354 ICOM_THIS(IStorage16Impl,iface);
1355 IStorage16Impl* lpstg;
1356 int ppsent,x;
1357 struct storage_pps_entry stde;
1358 struct storage_header sth;
1359 HANDLE hf=This->hf;
1361 READ_HEADER;
1363 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1364 This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
1366 if (grfMode & STGM_TRANSACTED)
1367 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1368 _create_istorage16(ppstg);
1369 lpstg = MapSL((SEGPTR)*ppstg);
1370 lpstg->hf = This->hf;
1372 ppsent=STORAGE_get_free_pps_entry(lpstg->hf);
1373 if (ppsent<0)
1374 return E_FAIL;
1375 stde=This->stde;
1376 if (stde.pps_dir==-1) {
1377 stde.pps_dir = ppsent;
1378 x = This->ppsent;
1379 } else {
1380 FIXME(" use prev chain too ?\n");
1381 x=stde.pps_dir;
1382 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1383 return E_FAIL;
1384 while (stde.pps_next!=-1) {
1385 x=stde.pps_next;
1386 if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde))
1387 return E_FAIL;
1389 stde.pps_next = ppsent;
1391 assert(STORAGE_put_pps_entry(lpstg->hf,x,&stde));
1392 assert(1==STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)));
1393 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
1394 sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
1395 lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
1396 lpstg->stde.pps_next = -1;
1397 lpstg->stde.pps_prev = -1;
1398 lpstg->stde.pps_dir = -1;
1399 lpstg->stde.pps_sb = -1;
1400 lpstg->stde.pps_size = 0;
1401 lpstg->stde.pps_type = 1;
1402 lpstg->ppsent = ppsent;
1403 /* FIXME: timestamps? */
1404 if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)))
1405 return E_FAIL;
1406 return S_OK;
1409 /******************************************************************************
1410 * IStorage16_CreateStream [STORAGE.503]
1412 HRESULT WINAPI IStorage16_fnCreateStream(
1413 LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
1415 ICOM_THIS(IStorage16Impl,iface);
1416 IStream16Impl* lpstr;
1417 int ppsent,x;
1418 struct storage_pps_entry stde;
1420 TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1421 This,pwcsName,grfMode,reserved1,reserved2,ppstm
1423 if (grfMode & STGM_TRANSACTED)
1424 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1425 _create_istream16(ppstm);
1426 lpstr = MapSL((SEGPTR)*ppstm);
1427 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1428 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1429 lpstr->offset.s.LowPart = 0;
1430 lpstr->offset.s.HighPart = 0;
1432 ppsent=STORAGE_get_free_pps_entry(lpstr->hf);
1433 if (ppsent<0)
1434 return E_FAIL;
1435 stde=This->stde;
1436 if (stde.pps_next==-1)
1437 x=This->ppsent;
1438 else
1439 while (stde.pps_next!=-1) {
1440 x=stde.pps_next;
1441 if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde))
1442 return E_FAIL;
1444 stde.pps_next = ppsent;
1445 assert(STORAGE_put_pps_entry(lpstr->hf,x,&stde));
1446 assert(1==STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)));
1447 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
1448 sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
1449 lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
1450 lpstr->stde.pps_next = -1;
1451 lpstr->stde.pps_prev = -1;
1452 lpstr->stde.pps_dir = -1;
1453 lpstr->stde.pps_sb = -1;
1454 lpstr->stde.pps_size = 0;
1455 lpstr->stde.pps_type = 2;
1456 lpstr->ppsent = ppsent;
1457 /* FIXME: timestamps? */
1458 if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)))
1459 return E_FAIL;
1460 return S_OK;
1463 /******************************************************************************
1464 * IStorage16_OpenStorage [STORAGE.506]
1466 HRESULT WINAPI IStorage16_fnOpenStorage(
1467 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
1469 ICOM_THIS(IStorage16Impl,iface);
1470 IStream16Impl* lpstg;
1471 WCHAR name[33];
1472 int newpps;
1474 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1475 This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
1477 if (grfMode & STGM_TRANSACTED)
1478 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1479 _create_istorage16(ppstg);
1480 lpstg = MapSL((SEGPTR)*ppstg);
1481 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1482 &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1483 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1484 newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name);
1485 if (newpps==-1) {
1486 IStream16_fnRelease((IStream16*)lpstg);
1487 return E_FAIL;
1490 if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) {
1491 IStream16_fnRelease((IStream16*)lpstg);
1492 return E_FAIL;
1494 lpstg->ppsent = newpps;
1495 return S_OK;
1498 /******************************************************************************
1499 * IStorage16_OpenStream [STORAGE.504]
1501 HRESULT WINAPI IStorage16_fnOpenStream(
1502 LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
1504 ICOM_THIS(IStorage16Impl,iface);
1505 IStream16Impl* lpstr;
1506 WCHAR name[33];
1507 int newpps;
1509 TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1510 This,pwcsName,reserved1,grfMode,reserved2,ppstm
1512 if (grfMode & STGM_TRANSACTED)
1513 FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
1514 _create_istream16(ppstm);
1515 lpstr = MapSL((SEGPTR)*ppstm);
1516 DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(),
1517 &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
1518 MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1519 newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name);
1520 if (newpps==-1) {
1521 IStream16_fnRelease((IStream16*)lpstr);
1522 return E_FAIL;
1525 if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) {
1526 IStream16_fnRelease((IStream16*)lpstr);
1527 return E_FAIL;
1529 lpstr->offset.s.LowPart = 0;
1530 lpstr->offset.s.HighPart = 0;
1531 lpstr->ppsent = newpps;
1532 return S_OK;
1535 /******************************************************************************
1536 * _create_istorage16 [INTERNAL]
1538 static void _create_istorage16(LPSTORAGE16 *stg) {
1539 IStorage16Impl* lpst;
1541 if (!stvt16.QueryInterface) {
1542 HMODULE16 wp = GetModuleHandle16("STORAGE");
1543 if (wp>=32) {
1544 #define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
1545 VTENT(QueryInterface)
1546 VTENT(AddRef)
1547 VTENT(Release)
1548 VTENT(CreateStream)
1549 VTENT(OpenStream)
1550 VTENT(CreateStorage)
1551 VTENT(OpenStorage)
1552 VTENT(CopyTo)
1553 VTENT(MoveElementTo)
1554 VTENT(Commit)
1555 VTENT(Revert)
1556 VTENT(EnumElements)
1557 VTENT(DestroyElement)
1558 VTENT(RenameElement)
1559 VTENT(SetElementTimes)
1560 VTENT(SetClass)
1561 VTENT(SetStateBits)
1562 VTENT(Stat)
1563 #undef VTENT
1564 segstvt16 = (ICOM_VTABLE(IStorage16)*)MapLS( &stvt16 );
1565 } else {
1566 #define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
1567 VTENT(QueryInterface)
1568 VTENT(AddRef)
1569 VTENT(Release)
1570 VTENT(CreateStream)
1571 VTENT(OpenStream)
1572 VTENT(CreateStorage)
1573 VTENT(OpenStorage)
1574 VTENT(CopyTo)
1575 VTENT(Commit)
1576 /* not (yet) implemented ...
1577 VTENT(MoveElementTo)
1578 VTENT(Revert)
1579 VTENT(EnumElements)
1580 VTENT(DestroyElement)
1581 VTENT(RenameElement)
1582 VTENT(SetElementTimes)
1583 VTENT(SetClass)
1584 VTENT(SetStateBits)
1585 VTENT(Stat)
1587 #undef VTENT
1588 segstvt16 = &stvt16;
1591 lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1592 lpst->lpVtbl = segstvt16;
1593 lpst->ref = 1;
1594 lpst->thisptr = MapLS(lpst);
1595 *stg = (void*)lpst->thisptr;
1598 /******************************************************************************
1599 * Storage API functions
1602 /******************************************************************************
1603 * StgCreateDocFileA [STORAGE.1]
1605 HRESULT WINAPI StgCreateDocFile16(
1606 LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
1608 HANDLE hf;
1609 int i,ret;
1610 IStorage16Impl* lpstg;
1611 struct storage_pps_entry stde;
1613 TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
1614 pwcsName,grfMode,reserved,ppstgOpen
1616 _create_istorage16(ppstgOpen);
1617 hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
1618 if (hf==INVALID_HANDLE_VALUE) {
1619 WARN("couldn't open file for storage:%ld\n",GetLastError());
1620 return E_FAIL;
1622 lpstg = MapSL((SEGPTR)*ppstgOpen);
1623 lpstg->hf = hf;
1624 /* FIXME: check for existence before overwriting? */
1625 if (!STORAGE_init_storage(hf)) {
1626 CloseHandle(hf);
1627 return E_FAIL;
1629 i=0;ret=0;
1630 while (!ret) { /* neither 1 nor <0 */
1631 ret=STORAGE_get_pps_entry(hf,i,&stde);
1632 if ((ret==1) && (stde.pps_type==5)) {
1633 lpstg->stde = stde;
1634 lpstg->ppsent = i;
1635 break;
1637 i++;
1639 if (ret!=1) {
1640 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1641 return E_FAIL;
1644 return S_OK;
1647 /******************************************************************************
1648 * StgIsStorageFile [STORAGE.5]
1650 HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
1651 UNICODE_STRING strW;
1652 HRESULT ret;
1654 RtlCreateUnicodeStringFromAsciiz(&strW, fn);
1655 ret = StgIsStorageFile( strW.Buffer );
1656 RtlFreeUnicodeString( &strW );
1658 return ret;
1661 /******************************************************************************
1662 * StgOpenStorage [STORAGE.3]
1664 HRESULT WINAPI StgOpenStorage16(
1665 LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
1666 SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
1668 HANDLE hf;
1669 int ret,i;
1670 IStorage16Impl* lpstg;
1671 struct storage_pps_entry stde;
1673 TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
1674 pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
1676 _create_istorage16(ppstgOpen);
1677 hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
1678 if (hf==INVALID_HANDLE_VALUE) {
1679 WARN("Couldn't open file for storage\n");
1680 return E_FAIL;
1682 lpstg = MapSL((SEGPTR)*ppstgOpen);
1683 lpstg->hf = hf;
1685 i=0;ret=0;
1686 while (!ret) { /* neither 1 nor <0 */
1687 ret=STORAGE_get_pps_entry(hf,i,&stde);
1688 if ((ret==1) && (stde.pps_type==5)) {
1689 lpstg->stde=stde;
1690 break;
1692 i++;
1694 if (ret!=1) {
1695 IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
1696 return E_FAIL;
1698 return S_OK;
1702 /******************************************************************************
1703 * StgIsStorageILockBytes [STORAGE.6]
1705 * Determines if the ILockBytes contains a storage object.
1707 HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
1709 DWORD args[6];
1710 HRESULT hres;
1711 HANDLE16 hsig;
1713 args[0] = (DWORD)plkbyt; /* iface */
1714 args[1] = args[2] = 0; /* ULARGE_INTEGER offset */
1715 args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
1716 args[4] = 8;
1717 args[5] = 0;
1719 if (!K32WOWCallback16Ex(
1720 (DWORD)((ICOM_VTABLE(ILockBytes16)*)MapSL(
1721 (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
1722 )->ReadAt,
1723 WCB16_PASCAL,
1724 6*sizeof(DWORD),
1725 (LPVOID)args,
1726 (LPDWORD)&hres
1727 )) {
1728 ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
1729 return hres;
1731 if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
1732 K32WOWGlobalUnlockFree16(args[3]);
1733 return S_OK;
1735 K32WOWGlobalUnlockFree16(args[3]);
1736 return S_FALSE;
1739 /******************************************************************************
1740 * StgOpenStorageOnILockBytes [STORAGE.4]
1742 HRESULT WINAPI StgOpenStorageOnILockBytes16(
1743 ILockBytes16 *plkbyt,
1744 IStorage16 *pstgPriority,
1745 DWORD grfMode,
1746 SNB16 snbExclude,
1747 DWORD reserved,
1748 IStorage16 **ppstgOpen)
1750 IStorage16Impl* lpstg;
1752 if ((plkbyt == 0) || (ppstgOpen == 0))
1753 return STG_E_INVALIDPOINTER;
1755 *ppstgOpen = 0;
1757 _create_istorage16(ppstgOpen);
1758 lpstg = MapSL((SEGPTR)*ppstgOpen);
1760 /* just teach it to use HANDLE instead of ilockbytes :/ */
1762 return S_OK;