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