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