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