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