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