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