storage.c 67.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5 6 7
/* Compound Storage
 *
 * Implemented using the documentation of the LAOLA project at
 * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
 * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
 *
 * Copyright 1998 Marcus Meissner
8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23
 */

24 25
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
26 27
#include <assert.h>
#include <time.h>
28
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include <string.h>
30
#include <sys/types.h>
31 32 33
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
34 35 36

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
37
#include "windef.h"
38 39
#include "winbase.h"
#include "winreg.h"
40
#include "winternl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
41
#include "winerror.h"
42
#include "wine/winbase16.h"
43
#include "wownt32.h"
44
#include "wine/unicode.h"
45
#include "objbase.h"
46
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
47

48 49
#include "ifs.h"

50 51
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(relay);
52

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
struct storage_header {
	BYTE	magic[8];	/* 00: magic */
	BYTE	unknown1[36];	/* 08: unknown */
	DWORD	num_of_bbd_blocks;/* 2C: length of big datablocks */
	DWORD	root_startblock;/* 30: root storage first big block */
	DWORD	unknown2[2];	/* 34: unknown */
	DWORD	sbd_startblock;	/* 3C: small block depot first big block */
	DWORD	unknown3[3];	/* 40: unknown */
	DWORD	bbd_list[109];	/* 4C: big data block list (up to end of sector)*/
};
struct storage_pps_entry {
	WCHAR	pps_rawname[32];/* 00: \0 terminated widechar name */
	WORD	pps_sizeofname;	/* 40: namelength in bytes */
	BYTE	pps_type;	/* 42: flags, 1 storage/dir, 2 stream, 5 root */
	BYTE	pps_unknown0;	/* 43: unknown */
	DWORD	pps_prev;	/* 44: previous pps */
	DWORD	pps_next;	/* 48: next pps */
	DWORD	pps_dir;	/* 4C: directory pps */
	GUID	pps_guid;	/* 50: class ID */
	DWORD	pps_unknown1;	/* 60: unknown */
	FILETIME pps_ft1;	/* 64: filetime1 */
	FILETIME pps_ft2;	/* 70: filetime2 */
	DWORD	pps_sb;		/* 74: data startblock */
	DWORD	pps_size;	/* 78: datalength. (<0x1000)?small:big blocks*/
	DWORD	pps_unknown2;	/* 7C: unknown */
};

#define STORAGE_CHAINENTRY_FAT		0xfffffffd
#define STORAGE_CHAINENTRY_ENDOFCHAIN	0xfffffffe
#define STORAGE_CHAINENTRY_FREE		0xffffffff


Alexandre Julliard's avatar
Alexandre Julliard committed
85 86 87 88 89 90 91
static const BYTE STORAGE_magic[8]   ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};

#define BIGSIZE		512
#define SMALLSIZE		64

#define SMALLBLOCKS_PER_BIGBLOCK	(BIGSIZE/SMALLSIZE)

92
#define READ_HEADER(str)	STORAGE_get_big_block(str,-1,(LPBYTE)&sth);assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic)));
93
static IStorage16Vtbl stvt16;
94
static const IStorage16Vtbl *segstvt16 = NULL;
95
static IStream16Vtbl strvt16;
96
static const IStream16Vtbl *segstrvt16 = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
97

Matthew Becker's avatar
Matthew Becker committed
98
/*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/
Alexandre Julliard's avatar
Alexandre Julliard committed
99 100 101 102 103
static void _create_istorage16(LPSTORAGE16 *stg);
static void _create_istream16(LPSTREAM16 *str);

#define IMPLEMENTED 1

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
/* The following is taken from the CorVu implementation of docfiles, and
 * documents things about the file format that are not implemented here, and
 * not documented by the LAOLA project. The CorVu implementation was posted
 * to wine-devel in February 2004, and released under the LGPL at the same
 * time. Because that implementation is in C++, it's not directly usable in
 * Wine, but does have documentation value.
 *
 *
 * #define DF_EXT_VTOC		-4
 * #define DF_VTOC_VTOC		-3
 * #define DF_VTOC_EOF		-2
 * #define DF_VTOC_FREE		-1
 * #define DF_NAMELEN	0x20	// Maximum entry name length - 31 characters plus
 * 				// a NUL terminator
 * 
 * #define DF_FT_STORAGE	1
 * #define DF_FT_STREAM		2
 * #define DF_FT_LOCKBYTES	3	// Not used -- How the bloody hell did I manage
 * #define DF_FT_PROPERTY	4	// Not Used -- to figure these two out?
 * #define DF_FT_ROOT		5
 * 
 * #define DF_BLOCK_SIZE	0x200
 * #define DF_VTOC_SIZE		0x80
 * #define DF_DE_PER_BLOCK	4
 * #define DF_STREAM_BLOCK_SIZE	0x40
 * 
 * A DocFile is divided into blocks of 512 bytes.
 * The first block contains the header.
 *
 * The file header contains The first 109 entries in the VTOC of VTOCs.
 *
 * Each block pointed to by a VTOC of VTOCs contains a VTOC, which
 * includes block chains - just like FAT. This is a somewhat poor
 * design for the following reasons:
 *
 *	1. FAT was a poor file system design to begin with, and
 *	   has long been known to be horrendously inefficient
 *	   for day to day operations.
 *
 *	2. The problem is compounded here, since the file
 *	   level streams are generally *not* read sequentially.
 *	   This means that a significant percentage of reads
 *	   require seeking from the start of the chain.
 *
 * Data chains also contain an internal VTOC. The block size for
 * the standard VTOC is 512. The block size for the internal VTOC
 * is 64.
 *
 * Now, the 109 blocks in the VTOC of VTOCs allows for files of
 * up to around 7MB. So what do you think happens if that's
 * exceeded? Well, there's an entry in the header block which
 * points to the first block used as additional storage for
 * the VTOC of VTOCs.
 *
 * Now we can get up to around 15MB. Now, guess how the file
 * format adds in another block to the VTOC of VTOCs. Come on,
 * it's no big surprise. That's right - the last entry in each
 * block extending the VTOC of VTOCs is, you guessed it, the
 * block number of the next block containing an extension to
 * the VTOC of VTOCs. The VTOC of VTOCs is chained!!!!
 *
 * So, to review:
 *
 * 1. If you are using a FAT file system, the location of
 *    your file's blocks is stored in chains.
 *
 * 2. At the abstract level, the file contains a VTOC of VTOCs,
 *    which is stored in the most inefficient possible format for
 *    random access - a chain (AKA list).
 *
 * 3. The VTOC of VTOCs contains descriptions of three file level
 *    streams:
 *
 *    a. The Directory stream
 *    b. The Data stream
 *    c. The Data VTOC stream
 *
 *    These are, of course, represented as chains.
 *
 * 4. The Data VTOC contains data describing the chains of blocks
 *    within the Data stream.
 *
 * That's right - we have a total of four levels of block chains!
 *
 * Now, is that complicated enough for you? No? OK, there's another
 * complication. If an individual stream (ie. an IStream) reaches
 * 4096 bytes in size, it gets moved from the Data Stream to
 * a new file level stream. Now, if the stream then gets truncated
 * back to less than 4096 bytes, it returns to the data stream.
 *
 * The effect of using this format can be seen very easily. Pick
 * an arbitrary application with a grid data representation that
 * can export to both Lotus 123 and Excel 5 or higher. Export
 * a large file to Lotus 123 and time it. Export the same thing
 * to Excel 5 and time that. The difference is the inefficiency
 * of the Microsoft DocFile format.
 *
 *
 * #define TOTAL_SIMPLE_VTOCS	109
 * 
 * struct	DocFile_Header
 * {
 * 	df_byte iMagic1;	// 0xd0 
 * 	df_byte iMagic2;	// 0xcf 
 * 	df_byte iMagic3;	// 0x11 
 * 	df_byte iMagic4;	// 0xe0 - Spells D0CF11E0, or DocFile 
 * 	df_byte iMagic5;	// 161	(igi upside down) 
 * 	df_byte iMagic6;	// 177	(lli upside down - see below 
 * 	df_byte iMagic7;	// 26 (gz upside down) 
 * 	df_byte iMagic8;	// 225 (szz upside down) - see below 
 * 	df_int4 aiUnknown1[4];
 * 	df_int4 iVersion;	// DocFile Version - 0x03003E	
 * 	df_int4 aiUnknown2[4];
 * 	df_int4 nVTOCs;		// Number of VTOCs 
 * 	df_int4 iFirstDirBlock; // First Directory Block 
 * 	df_int4 aiUnknown3[2];
 * 	df_int4 iFirstDataVTOC; // First data VTOC block 
 * 	df_int4 iHasData;	// 1 if there is data in the file - yes, this is important
 * 	df_int4 iExtendedVTOC;	// Extended VTOC location 
 * 	df_int4 iExtendedVTOCSize; // Size of extended VTOC (+1?) 
 * 	df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS];
 * };
 * 
 * struct	DocFile_VTOC
 * {
 * 	df_int4 aiBlocks[DF_VTOC_SIZE];
 * };
 * 
 * 
 * The meaning of the magic numbers
 *
 * 0xd0cf11e0 is DocFile with a zero on the end (sort of)
 *
 * If you key 177161 into a calculator, then turn the calculator
 * upside down, you get igilli, which may be a reference to
 * somebody's name, or to the Hebrew word for "angel".
 *
 * If you key 26225 into a calculator, then turn it upside down, you
 * get szzgz. Microsoft has a tradition of creating nonsense words
 * using the letters s, g, z and y. We think szzgz may be one of the
 * Microsoft placeholder variables, along the lines of foo, bar and baz.
 * Alternatively, it could be 22526, which would be gzszz.
 *
 * 
 * struct	DocFile_DirEnt
 * {
 * 	df_char achEntryName[DF_NAMELEN];	// Entry Name 
 * 	df_int2 iNameLen;			// Name length in bytes, including NUL terminator 
 * 	df_byte iFileType;			// Entry type 
 * 	df_byte iColour;			// 1 = Black, 0 = Red 
 * 	df_int4 iLeftSibling;			// Next Left Sibling Entry - See below 
 * 	df_int4 iRightSibling;			// Next Right Sibling Entry 
 * 	df_int4 iFirstChild;			// First Child Entry 
 * 	df_byte achClassID[16];			// Class ID 
 * 	df_int4 iStateBits;			// [GS]etStateBits value 
 * 	df_int4 iCreatedLow;			// Low DWORD of creation time 
 * 	df_int4 iCreatedHigh;			// High DWORD of creation time 
 * 	df_int4 iModifiedLow;			// Low DWORD of modification time 
 * 	df_int4 iModifiedHigh;			// High DWORD of modification time 
 * 	df_int4 iVTOCPosition;			// VTOC Position 
 * 	df_int4 iFileSize;			// Size of the stream 
 * 	df_int4 iZero;				// We think this is part of the 64 bit stream size - must be 0 
 * };
 * 
 * Siblings
 * ========
 *
 * Siblings are stored in an obscure but incredibly elegant
 * data structure called a red-black tree. This is generally
 * defined as a 2-3-4 tree stored in a binary tree.
 *
 * A red-black tree can always be balanced very easily. The rules
 * for a red-black tree are as follows:
 *
 *	1. The root node is always black.
 *	2. The parent of a red node is always black.
 *
 * There is a Java demo of red-black trees at:
 *
 *	http://langevin.usc.edu/BST/RedBlackTree-Example.html
 *
 * This demo is an excellent tool for learning how red-black
 * trees work, without having to go through the process of
 * learning how they were derived.
 *
 * Within the tree, elements are ordered by the length of the
 * name and within that, ASCII order by name. This causes the
 * apparently bizarre reordering you see when you use dfview.
 *
 * This is a somewhat bizarre choice. It suggests that the
 * designer of the DocFile format was trying to optimise
 * searching through the directory entries. However searching
 * through directory entries is a relatively rare operation.
 * Reading and seeking within a stream are much more common
 * operations, especially within the file level streams, yet
 * these use the horrendously inefficient FAT chains.
 *
 * This suggests that the designer was probably somebody
 * fresh out of university, who had some basic knowledge of
 * basic data structures, but little knowledge of anything
 * more practical. It is bizarre to attempt to optimise
 * directory searches while not using a more efficient file
 * block locating system than FAT (seedling/sapling/tree
 * would result in a massive improvement - in fact we have
 * an alternative to DocFiles that we use internally that
 * uses seedling/sapling/tree and *is* far more efficient).
 *
 * It is worth noting that the MS implementation of red-black
 * trees is incorrect (I can tell you're surprised) and
 * actually causes more operations to occur than are really
 * needed. Fortunately the fact that our implementation is
 * correct will not cause any problems - the MS implementation
 * still appears to cause the tree to satisfy the rules, albeit
 * a sequence of the same insertions in the different
 * implementations may result in a different, and possibly
 * deeper (but never shallower) tree.
 */

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
typedef struct {
	HANDLE		hf;
	SEGPTR		lockbytes;
} stream_access16;
/* --- IStorage16 implementation struct */

typedef struct
{
        /* IUnknown fields */
        const IStorage16Vtbl           *lpVtbl;
        LONG                            ref;
        /* IStorage16 fields */
        SEGPTR                          thisptr; /* pointer to this struct as segmented */
        struct storage_pps_entry        stde;
        int                             ppsent;
	stream_access16			str;
} IStorage16Impl;

340

Alexandre Julliard's avatar
Alexandre Julliard committed
341
/******************************************************************************
342 343
 *		STORAGE_get_big_block	[Internal]
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345
 * Reading OLE compound storage
 */
346
static BOOL
347
STORAGE_get_big_block(stream_access16 *str,int n,BYTE *block)
348 349 350 351
{
    DWORD result;

    assert(n>=-1);
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
    if (str->hf) {
	if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL,
			     SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
	{
	    WARN("(%p,%d,%p), seek failed (%ld)\n",str->hf, n, block, GetLastError());
	    return FALSE;
	}
	if (!ReadFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
	{
	    WARN("(hf=%p, block size %d): read didn't read (%ld)\n",str->hf,n,GetLastError());
	    return FALSE;
	}
    } else {
	DWORD args[6];
	HRESULT hres;
	HANDLE16 hsig;
	
	args[0] = (DWORD)str->lockbytes;	/* iface */
	args[1] = (n+1)*BIGSIZE;
	args[2] = 0;	/* ULARGE_INTEGER offset */
372
	args[3] = WOWGlobalAllocLock16( 0, BIGSIZE, &hsig ); /* sig */
373 374 375
	args[4] = BIGSIZE;
	args[5] = 0;

376
	if (!WOWCallback16Ex(
377 378 379 380 381 382 383 384 385 386 387 388
	    (DWORD)((const ILockBytes16Vtbl*)MapSL(
			(SEGPTR)((LPLOCKBYTES16)MapSL(str->lockbytes))->lpVtbl)
	    )->ReadAt,
	    WCB16_PASCAL,
	    6*sizeof(DWORD),
	    (LPVOID)args,
	    (LPDWORD)&hres
	)) {
	    ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
	    return FALSE;
	}
	memcpy(block, MapSL(args[3]), BIGSIZE);
389
	WOWGlobalUnlockFree16(args[3]);
390
    }
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
    return TRUE;
}

static BOOL
_ilockbytes16_writeat(SEGPTR lockbytes, DWORD offset, DWORD length, void *buffer) {
    DWORD args[6];
    HRESULT hres;

    args[0] = (DWORD)lockbytes;	/* iface */
    args[1] = offset;
    args[2] = 0;	/* ULARGE_INTEGER offset */
    args[3] = (DWORD)MapLS( buffer );
    args[4] = length;
    args[5] = 0;

    /* THIS_ ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, ULONG *pcbWritten); */

408
    if (!WOWCallback16Ex(
409 410 411 412 413 414 415 416 417 418
	(DWORD)((const ILockBytes16Vtbl*)MapSL(
		    (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
	)->WriteAt,
	WCB16_PASCAL,
	6*sizeof(DWORD),
	(LPVOID)args,
	(LPDWORD)&hres
    )) {
	ERR("CallTo16 ILockBytes16::WriteAt() failed, hres %lx\n",hres);
	return FALSE;
419
    }
420
    UnMapLS(args[3]);
421
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
422 423
}

Matthew Becker's avatar
Matthew Becker committed
424 425 426
/******************************************************************************
 * STORAGE_put_big_block [INTERNAL]
 */
427
static BOOL
428
STORAGE_put_big_block(stream_access16 *str,int n,BYTE *block)
429 430 431 432
{
    DWORD result;

    assert(n>=-1);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    if (str->hf) {
	if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL,
			     SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
	{
	    WARN("seek failed (%ld)\n",GetLastError());
	    return FALSE;
	}
	if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
	{
	    WARN(" write failed (%ld)\n",GetLastError());
	    return FALSE;
	}
	return TRUE;
    } else {
	_ilockbytes16_writeat(str->lockbytes, (n+1)*BIGSIZE, BIGSIZE, block);
	return TRUE;
449
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
450 451
}

Matthew Becker's avatar
Matthew Becker committed
452 453 454
/******************************************************************************
 * STORAGE_get_next_big_blocknr [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
455
static int
456
STORAGE_get_next_big_blocknr(stream_access16 *str,int blocknr) {
457
	INT	bbs[BIGSIZE/sizeof(INT)];
Alexandre Julliard's avatar
Alexandre Julliard committed
458 459
	struct	storage_header	sth;

460
	READ_HEADER(str);
461

Alexandre Julliard's avatar
Alexandre Julliard committed
462 463 464
	assert(blocknr>>7<sth.num_of_bbd_blocks);
	if (sth.bbd_list[blocknr>>7]==0xffffffff)
		return -5;
465
	if (!STORAGE_get_big_block(str,sth.bbd_list[blocknr>>7],(LPBYTE)bbs))
Alexandre Julliard's avatar
Alexandre Julliard committed
466 467 468 469 470
		return -5;
	assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE);
	return bbs[blocknr&0x7f];
}

Matthew Becker's avatar
Matthew Becker committed
471 472 473
/******************************************************************************
 * STORAGE_get_nth_next_big_blocknr [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
474
static int
475
STORAGE_get_nth_next_big_blocknr(stream_access16 *str,int blocknr,int nr) {
476
	INT	bbs[BIGSIZE/sizeof(INT)];
Alexandre Julliard's avatar
Alexandre Julliard committed
477 478 479
	int	lastblock = -1;
	struct storage_header sth;

480 481
	TRACE("(blocknr=%d, nr=%d)\n", blocknr, nr);
	READ_HEADER(str);
482

Alexandre Julliard's avatar
Alexandre Julliard committed
483 484 485 486 487 488 489
	assert(blocknr>=0);
	while (nr--) {
		assert((blocknr>>7)<sth.num_of_bbd_blocks);
		assert(sth.bbd_list[blocknr>>7]!=0xffffffff);

		/* simple caching... */
		if (lastblock!=sth.bbd_list[blocknr>>7]) {
490
			BOOL ret = STORAGE_get_big_block(str,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
491
			assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
492 493 494 495 496 497 498
			lastblock = sth.bbd_list[blocknr>>7];
		}
		blocknr = bbs[blocknr&0x7f];
	}
	return blocknr;
}

499 500 501
/******************************************************************************
 *		STORAGE_get_root_pps_entry	[Internal]
 */
502
static BOOL
503
STORAGE_get_root_pps_entry(stream_access16* str,struct storage_pps_entry *pstde) {
Alexandre Julliard's avatar
Alexandre Julliard committed
504 505 506 507 508
	int	blocknr,i;
	BYTE	block[BIGSIZE];
	struct storage_pps_entry	*stde=(struct storage_pps_entry*)block;
	struct storage_header sth;

509
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
510
	blocknr = sth.root_startblock;
511
	TRACE("startblock is %d\n", blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
512
	while (blocknr>=0) {
513
		BOOL ret = STORAGE_get_big_block(str,blocknr,block);
514
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
515 516 517 518 519 520 521 522
		for (i=0;i<4;i++) {
			if (!stde[i].pps_sizeofname)
				continue;
			if (stde[i].pps_type==5) {
				*pstde=stde[i];
				return TRUE;
			}
		}
523 524
		blocknr=STORAGE_get_next_big_blocknr(str,blocknr);
		TRACE("next block is %d\n", blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
525 526 527 528
	}
	return FALSE;
}

Matthew Becker's avatar
Matthew Becker committed
529 530 531
/******************************************************************************
 * STORAGE_get_small_block [INTERNAL]
 */
532
static BOOL
533
STORAGE_get_small_block(stream_access16 *str,int blocknr,BYTE *sblock) {
Alexandre Julliard's avatar
Alexandre Julliard committed
534 535 536
	BYTE				block[BIGSIZE];
	int				bigblocknr;
	struct storage_pps_entry	root;
537
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
538

539
	TRACE("(blocknr=%d)\n", blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
540
	assert(blocknr>=0);
541
	ret = STORAGE_get_root_pps_entry(str,&root);
542
	assert(ret);
543
	bigblocknr = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
Alexandre Julliard's avatar
Alexandre Julliard committed
544
	assert(bigblocknr>=0);
545
	ret = STORAGE_get_big_block(str,bigblocknr,block);
546
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
547 548 549 550 551

	memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE);
	return TRUE;
}

Matthew Becker's avatar
Matthew Becker committed
552 553 554
/******************************************************************************
 * STORAGE_put_small_block [INTERNAL]
 */
555
static BOOL
556
STORAGE_put_small_block(stream_access16 *str,int blocknr,BYTE *sblock) {
Alexandre Julliard's avatar
Alexandre Julliard committed
557 558 559
	BYTE				block[BIGSIZE];
	int				bigblocknr;
	struct storage_pps_entry	root;
560
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
561 562

	assert(blocknr>=0);
563
	TRACE("(blocknr=%d)\n", blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
564

565
	ret = STORAGE_get_root_pps_entry(str,&root);
566
	assert(ret);
567
	bigblocknr = STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK);
Alexandre Julliard's avatar
Alexandre Julliard committed
568
	assert(bigblocknr>=0);
569
	ret = STORAGE_get_big_block(str,bigblocknr,block);
570
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
571 572

	memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE);
573
	ret = STORAGE_put_big_block(str,bigblocknr,block);
574
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
575 576 577
	return TRUE;
}

Matthew Becker's avatar
Matthew Becker committed
578 579 580
/******************************************************************************
 * STORAGE_get_next_small_blocknr [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
581
static int
582
STORAGE_get_next_small_blocknr(stream_access16 *str,int blocknr) {
Alexandre Julliard's avatar
Alexandre Julliard committed
583
	BYTE				block[BIGSIZE];
584
	LPINT				sbd = (LPINT)block;
Alexandre Julliard's avatar
Alexandre Julliard committed
585 586
	int				bigblocknr;
	struct storage_header		sth;
587
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
588

589 590
	TRACE("(blocknr=%d)\n", blocknr);
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
591
	assert(blocknr>=0);
592
	bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
Alexandre Julliard's avatar
Alexandre Julliard committed
593
	assert(bigblocknr>=0);
594
	ret = STORAGE_get_big_block(str,bigblocknr,block);
595
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
596 597 598 599
	assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE);
	return sbd[blocknr & (128-1)];
}

Matthew Becker's avatar
Matthew Becker committed
600 601 602
/******************************************************************************
 * STORAGE_get_nth_next_small_blocknr [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
603
static int
604
STORAGE_get_nth_next_small_blocknr(stream_access16*str,int blocknr,int nr) {
605
	int	lastblocknr=-1;
Alexandre Julliard's avatar
Alexandre Julliard committed
606
	BYTE	block[BIGSIZE];
607
	LPINT	sbd = (LPINT)block;
Alexandre Julliard's avatar
Alexandre Julliard committed
608
	struct storage_header sth;
609
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
610

611 612
	TRACE("(blocknr=%d, nr=%d)\n", blocknr, nr);
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
613 614 615 616
	assert(blocknr>=0);
	while ((nr--) && (blocknr>=0)) {
		if (lastblocknr/128!=blocknr/128) {
			int	bigblocknr;
617
			bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
Alexandre Julliard's avatar
Alexandre Julliard committed
618
			assert(bigblocknr>=0);
619
			ret = STORAGE_get_big_block(str,bigblocknr,block);
620
			assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622 623 624 625 626 627 628 629 630
			lastblocknr = blocknr;
		}
		assert(lastblocknr>=0);
		lastblocknr=blocknr;
		blocknr=sbd[blocknr & (128-1)];
		assert(blocknr!=STORAGE_CHAINENTRY_FREE);
	}
	return blocknr;
}

Matthew Becker's avatar
Matthew Becker committed
631 632 633
/******************************************************************************
 * STORAGE_get_pps_entry [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
634
static int
635
STORAGE_get_pps_entry(stream_access16*str,int n,struct storage_pps_entry *pstde) {
Alexandre Julliard's avatar
Alexandre Julliard committed
636 637 638 639
	int	blocknr;
	BYTE	block[BIGSIZE];
	struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
	struct storage_header sth;
640
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
641

642 643
	TRACE("(n=%d)\n", n);
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
644
	/* we have 4 pps entries per big block */
645
	blocknr = STORAGE_get_nth_next_big_blocknr(str,sth.root_startblock,n/4);
Alexandre Julliard's avatar
Alexandre Julliard committed
646
	assert(blocknr>=0);
647
	ret = STORAGE_get_big_block(str,blocknr,block);
648
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
649 650 651 652 653

	*pstde=*stde;
	return 1;
}

654 655 656
/******************************************************************************
 *		STORAGE_put_pps_entry	[Internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
657
static int
658
STORAGE_put_pps_entry(stream_access16*str,int n,struct storage_pps_entry *pstde) {
Alexandre Julliard's avatar
Alexandre Julliard committed
659 660 661 662
	int	blocknr;
	BYTE	block[BIGSIZE];
	struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
	struct storage_header sth;
663
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
664

665 666
	TRACE("(n=%d)\n", n);
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
667
	/* we have 4 pps entries per big block */
668
	blocknr = STORAGE_get_nth_next_big_blocknr(str,sth.root_startblock,n/4);
Alexandre Julliard's avatar
Alexandre Julliard committed
669
	assert(blocknr>=0);
670
	ret = STORAGE_get_big_block(str,blocknr,block);
671
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
672
	*stde=*pstde;
673
	ret = STORAGE_put_big_block(str,blocknr,block);
674
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
675 676 677
	return 1;
}

678 679 680
/******************************************************************************
 *		STORAGE_look_for_named_pps	[Internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
681
static int
682
STORAGE_look_for_named_pps(stream_access16*str,int n,LPOLESTR name) {
Alexandre Julliard's avatar
Alexandre Julliard committed
683 684 685
	struct storage_pps_entry	stde;
	int				ret;

686
	TRACE("(n=%d,name=%s)\n", n, debugstr_w(name));
Alexandre Julliard's avatar
Alexandre Julliard committed
687 688
	if (n==-1)
		return -1;
689
	if (1!=STORAGE_get_pps_entry(str,n,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
690 691
		return -1;

692
	if (!lstrcmpW(name,stde.pps_rawname))
Alexandre Julliard's avatar
Alexandre Julliard committed
693 694
		return n;
	if (stde.pps_prev != -1) {
695
		ret=STORAGE_look_for_named_pps(str,stde.pps_prev,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
696 697 698 699
		if (ret!=-1)
			return ret;
	}
	if (stde.pps_next != -1) {
700
		ret=STORAGE_look_for_named_pps(str,stde.pps_next,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
701 702 703 704 705 706
		if (ret!=-1)
			return ret;
	}
	return -1;
}

707 708 709 710 711 712
/******************************************************************************
 *		STORAGE_dump_pps_entry	[Internal]
 *
 * FIXME
 *    Function is unused
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
713
void
Alexandre Julliard's avatar
Alexandre Julliard committed
714
STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
715
    char	name[33];
Alexandre Julliard's avatar
Alexandre Julliard committed
716

717
    WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
718 719
	if (!stde->pps_sizeofname)
		return;
720 721 722 723 724
	DPRINTF("name: %s\n",name);
	DPRINTF("type: %d\n",stde->pps_type);
	DPRINTF("prev pps: %ld\n",stde->pps_prev);
	DPRINTF("next pps: %ld\n",stde->pps_next);
	DPRINTF("dir pps: %ld\n",stde->pps_dir);
725
	DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid)));
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727
	if (stde->pps_type !=2) {
		time_t	t;
728
                DWORD dw;
729
		RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw);
730
                t = dw;
731
		DPRINTF("ts1: %s\n",ctime(&t));
732
		RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw);
733
                t = dw;
734
		DPRINTF("ts2: %s\n",ctime(&t));
Alexandre Julliard's avatar
Alexandre Julliard committed
735
	}
736 737
	DPRINTF("startblock: %ld\n",stde->pps_sb);
	DPRINTF("size: %ld\n",stde->pps_size);
Alexandre Julliard's avatar
Alexandre Julliard committed
738 739
}

Matthew Becker's avatar
Matthew Becker committed
740 741 742
/******************************************************************************
 * STORAGE_init_storage [INTERNAL]
 */
743
static BOOL
744
STORAGE_init_storage(stream_access16 *str) {
Alexandre Julliard's avatar
Alexandre Julliard committed
745 746 747 748
	BYTE	block[BIGSIZE];
	LPDWORD	bbs;
	struct storage_header *sth;
	struct storage_pps_entry *stde;
749
        DWORD result;
Alexandre Julliard's avatar
Alexandre Julliard committed
750

751 752
	if (str->hf)
	    SetFilePointer( str->hf, 0, NULL, SEEK_SET );
Alexandre Julliard's avatar
Alexandre Julliard committed
753 754 755 756 757 758 759 760 761 762 763
	/* block -1 is the storage header */
	sth = (struct storage_header*)block;
	memcpy(sth->magic,STORAGE_magic,8);
	memset(sth->unknown1,0,sizeof(sth->unknown1));
	memset(sth->unknown2,0,sizeof(sth->unknown2));
	memset(sth->unknown3,0,sizeof(sth->unknown3));
	sth->num_of_bbd_blocks	= 1;
	sth->root_startblock	= 1;
	sth->sbd_startblock	= 0xffffffff;
	memset(sth->bbd_list,0xff,sizeof(sth->bbd_list));
	sth->bbd_list[0]	= 0;
764 765 766 767 768
	if (str->hf) {
	    if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
	} else {
	    if (!_ilockbytes16_writeat(str->lockbytes, 0, BIGSIZE, block)) return FALSE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
769 770 771 772 773
	/* block 0 is the big block directory */
	bbs=(LPDWORD)block;
	memset(block,0xff,sizeof(block)); /* mark all blocks as free */
	bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */
	bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */
774 775 776 777 778
	if (str->hf) {
	    if (!WriteFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE;
	} else {
	    if (!_ilockbytes16_writeat(str->lockbytes, BIGSIZE, BIGSIZE, block)) return FALSE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
779 780 781
	/* block 1 is the root directory entry */
	memset(block,0x00,sizeof(block));
	stde = (struct storage_pps_entry*)block;
782 783 784
        MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname,
                             sizeof(stde->pps_rawname)/sizeof(WCHAR));
	stde->pps_sizeofname	= (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
785 786 787 788 789 790
	stde->pps_type		= 5;
	stde->pps_dir		= -1;
	stde->pps_next		= -1;
	stde->pps_prev		= -1;
	stde->pps_sb		= 0xffffffff;
	stde->pps_size		= 0;
791 792 793 794 795
	if (str->hf) {
	    return (WriteFile( str->hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE);
	} else {
	    return _ilockbytes16_writeat(str->lockbytes, BIGSIZE, BIGSIZE, block);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
796 797
}

798 799 800
/******************************************************************************
 *		STORAGE_set_big_chain	[Internal]
 */
801
static BOOL
802
STORAGE_set_big_chain(stream_access16*str,int blocknr,INT type) {
Alexandre Julliard's avatar
Alexandre Julliard committed
803
	BYTE	block[BIGSIZE];
804
	LPINT	bbd = (LPINT)block;
Alexandre Julliard's avatar
Alexandre Julliard committed
805 806
	int	nextblocknr,bigblocknr;
	struct storage_header sth;
807
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
808

809
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
810 811 812 813
	assert(blocknr!=type);
	while (blocknr>=0) {
		bigblocknr = sth.bbd_list[blocknr/128];
		assert(bigblocknr>=0);
814
		ret = STORAGE_get_big_block(str,bigblocknr,block);
815
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
816 817 818 819 820

		nextblocknr = bbd[blocknr&(128-1)];
		bbd[blocknr&(128-1)] = type;
		if (type>=0)
			return TRUE;
821
		ret = STORAGE_put_big_block(str,bigblocknr,block);
822
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
823 824 825 826 827 828
		type = STORAGE_CHAINENTRY_FREE;
		blocknr = nextblocknr;
	}
	return TRUE;
}

Matthew Becker's avatar
Matthew Becker committed
829
/******************************************************************************
830
 * STORAGE_set_small_chain [Internal]
Matthew Becker's avatar
Matthew Becker committed
831
 */
832
static BOOL
833
STORAGE_set_small_chain(stream_access16*str,int blocknr,INT type) {
Alexandre Julliard's avatar
Alexandre Julliard committed
834
	BYTE	block[BIGSIZE];
835
	LPINT	sbd = (LPINT)block;
Alexandre Julliard's avatar
Alexandre Julliard committed
836 837
	int	lastblocknr,nextsmallblocknr,bigblocknr;
	struct storage_header sth;
838
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
839

840
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
841 842 843 844 845 846

	assert(blocknr!=type);
	lastblocknr=-129;bigblocknr=-2;
	while (blocknr>=0) {
		/* cache block ... */
		if (lastblocknr/128!=blocknr/128) {
847
			bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
Alexandre Julliard's avatar
Alexandre Julliard committed
848
			assert(bigblocknr>=0);
849
			ret = STORAGE_get_big_block(str,bigblocknr,block);
850
			assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
851 852 853 854
		}
		lastblocknr = blocknr;
		nextsmallblocknr = sbd[blocknr&(128-1)];
		sbd[blocknr&(128-1)] = type;
855
		ret = STORAGE_put_big_block(str,bigblocknr,block);
856
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
857 858 859 860 861 862 863 864
		if (type>=0)
			return TRUE;
		type = STORAGE_CHAINENTRY_FREE;
		blocknr = nextsmallblocknr;
	}
	return TRUE;
}

865 866 867
/******************************************************************************
 *		STORAGE_get_free_big_blocknr	[Internal]
 */
868
static int
869
STORAGE_get_free_big_blocknr(stream_access16 *str) {
Alexandre Julliard's avatar
Alexandre Julliard committed
870
	BYTE	block[BIGSIZE];
871
	LPINT	sbd = (LPINT)block;
872 873
	int	lastbigblocknr,i,bigblocknr;
	unsigned int curblock;
Alexandre Julliard's avatar
Alexandre Julliard committed
874
	struct storage_header sth;
875
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
876

877
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
878 879 880 881 882
	curblock	= 0;
	lastbigblocknr	= -1;
	bigblocknr	= sth.bbd_list[curblock];
	while (curblock<sth.num_of_bbd_blocks) {
		assert(bigblocknr>=0);
883
		ret = STORAGE_get_big_block(str,bigblocknr,block);
884
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
885 886 887
		for (i=0;i<128;i++)
			if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
				sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
888
				ret = STORAGE_put_big_block(str,bigblocknr,block);
889
				assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
890
				memset(block,0x42,sizeof(block));
891
				ret = STORAGE_put_big_block(str,i+curblock*128,block);
892
				assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
893 894 895 896 897 898
				return i+curblock*128;
			}
		lastbigblocknr = bigblocknr;
		bigblocknr = sth.bbd_list[++curblock];
	}
	bigblocknr = curblock*128;
899 900
	/* since we have marked all blocks from 0 up to curblock*128-1
	 * the next free one is curblock*128, where we happily put our
Alexandre Julliard's avatar
Alexandre Julliard committed
901 902 903 904 905
	 * next large block depot.
	 */
	memset(block,0xff,sizeof(block));
	/* mark the block allocated and returned by this function */
	sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
906
	ret = STORAGE_put_big_block(str,bigblocknr,block);
907
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
908 909

	/* if we had a bbd block already (mostlikely) we need
910
	 * to link the new one into the chain
Alexandre Julliard's avatar
Alexandre Julliard committed
911
	 */
912
	if (lastbigblocknr!=-1) {
913
		ret = STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr);
914 915
		assert(ret);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
916 917 918
	sth.bbd_list[curblock]=bigblocknr;
	sth.num_of_bbd_blocks++;
	assert(sth.num_of_bbd_blocks==curblock+1);
919
	ret = STORAGE_put_big_block(str,-1,(LPBYTE)&sth);
920
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
921 922

	/* Set the end of the chain for the bigblockdepots */
923
	ret = STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN);
924
	assert(ret);
925
	/* add 1, for the first entry is used for the additional big block
Alexandre Julliard's avatar
Alexandre Julliard committed
926 927 928
	 * depot. (means we already used bigblocknr) */
	memset(block,0x42,sizeof(block));
	/* allocate this block (filled with 0x42) */
929
	ret = STORAGE_put_big_block(str,bigblocknr+1,block);
930
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
931 932 933 934
	return bigblocknr+1;
}


935 936 937
/******************************************************************************
 *		STORAGE_get_free_small_blocknr	[Internal]
 */
938
static int
939
STORAGE_get_free_small_blocknr(stream_access16 *str) {
Alexandre Julliard's avatar
Alexandre Julliard committed
940
	BYTE	block[BIGSIZE];
941
	LPINT	sbd = (LPINT)block;
Alexandre Julliard's avatar
Alexandre Julliard committed
942 943 944 945
	int	lastbigblocknr,newblocknr,i,curblock,bigblocknr;
	struct storage_pps_entry	root;
	struct storage_header sth;

946
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
947 948 949 950 951
	bigblocknr	= sth.sbd_startblock;
	curblock	= 0;
	lastbigblocknr	= -1;
	newblocknr	= -1;
	while (bigblocknr>=0) {
952
		if (!STORAGE_get_big_block(str,bigblocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954 955 956 957 958 959 960 961 962
			return -1;
		for (i=0;i<128;i++)
			if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
				sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN;
				newblocknr = i+curblock*128;
				break;
			}
		if (i!=128)
			break;
		lastbigblocknr = bigblocknr;
963
		bigblocknr = STORAGE_get_next_big_blocknr(str,bigblocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
964 965 966
		curblock++;
	}
	if (newblocknr==-1) {
967
		bigblocknr = STORAGE_get_free_big_blocknr(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
968 969
		if (bigblocknr<0)
			return -1;
970
		READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
971 972
		memset(block,0xff,sizeof(block));
		sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN;
973
		if (!STORAGE_put_big_block(str,bigblocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
974 975 976
			return -1;
		if (lastbigblocknr==-1) {
			sth.sbd_startblock = bigblocknr;
977
			if (!STORAGE_put_big_block(str,-1,(LPBYTE)&sth)) /* need to write it */
Alexandre Julliard's avatar
Alexandre Julliard committed
978 979
				return -1;
		} else {
980
			if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
981 982
				return -1;
		}
983
		if (!STORAGE_set_big_chain(str,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
984 985 986 987
			return -1;
		newblocknr = curblock*128;
	}
	/* allocate enough big blocks for storing the allocated small block */
988
	if (!STORAGE_get_root_pps_entry(str,&root))
Alexandre Julliard's avatar
Alexandre Julliard committed
989 990 991 992
		return -1;
	if (root.pps_sb==-1)
		lastbigblocknr	= -1;
	else
993
		lastbigblocknr	= STORAGE_get_nth_next_big_blocknr(str,root.pps_sb,(root.pps_size-1)/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995
	while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) {
		/* we need to allocate more stuff */
996
		bigblocknr = STORAGE_get_free_big_blocknr(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
997 998
		if (bigblocknr<0)
			return -1;
999
		READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001 1002 1003
		if (root.pps_sb==-1) {
			root.pps_sb	 = bigblocknr;
			root.pps_size	+= BIGSIZE;
		} else {
1004
			if (!STORAGE_set_big_chain(str,lastbigblocknr,bigblocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006 1007 1008 1009
				return -1;
			root.pps_size	+= BIGSIZE;
		}
		lastbigblocknr = bigblocknr;
	}
1010
	if (!STORAGE_set_big_chain(str,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1011
		return -1;
1012
	if (!STORAGE_put_pps_entry(str,0,&root))
Alexandre Julliard's avatar
Alexandre Julliard committed
1013 1014 1015 1016
		return -1;
	return newblocknr;
}

1017 1018 1019
/******************************************************************************
 *		STORAGE_get_free_pps_entry	[Internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
static int
1021
STORAGE_get_free_pps_entry(stream_access16*str) {
1022
	int	blocknr, i, curblock, lastblocknr=-1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1023 1024 1025 1026
	BYTE	block[BIGSIZE];
	struct storage_pps_entry *stde = (struct storage_pps_entry*)block;
	struct storage_header sth;

1027
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1028 1029 1030 1031
	blocknr = sth.root_startblock;
	assert(blocknr>=0);
	curblock=0;
	while (blocknr>=0) {
1032
		if (!STORAGE_get_big_block(str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1033
			return -1;
1034
		for (i=0;i<4;i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
1035 1036 1037
			if (stde[i].pps_sizeofname==0) /* free */
				return curblock*4+i;
		lastblocknr = blocknr;
1038
		blocknr = STORAGE_get_next_big_blocknr(str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1039 1040 1041
		curblock++;
	}
	assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN);
1042
	blocknr = STORAGE_get_free_big_blocknr(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1043 1044 1045
	/* sth invalidated */
	if (blocknr<0)
		return -1;
1046

1047
	if (!STORAGE_set_big_chain(str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1048
		return -1;
1049
	if (!STORAGE_set_big_chain(str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1050 1051
		return -1;
	memset(block,0,sizeof(block));
1052
	STORAGE_put_big_block(str,blocknr,block);
Alexandre Julliard's avatar
Alexandre Julliard committed
1053 1054 1055
	return curblock*4;
}

1056 1057
/* --- IStream16 implementation */

1058 1059
typedef struct
{
1060
        /* IUnknown fields */
1061
        const IStream16Vtbl            *lpVtbl;
1062
        LONG                            ref;
1063 1064 1065 1066 1067
        /* IStream16 fields */
        SEGPTR                          thisptr; /* pointer to this struct as segmented */
        struct storage_pps_entry        stde;
        int                             ppsent;
        ULARGE_INTEGER                  offset;
1068
	stream_access16			str;
1069
} IStream16Impl;
1070

Alexandre Julliard's avatar
Alexandre Julliard committed
1071
/******************************************************************************
1072
 *		IStream16_QueryInterface	[STORAGE.518]
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
 */
1074
HRESULT IStream16_fnQueryInterface(
1075
	IStream16* iface,REFIID refiid,LPVOID *obj
Alexandre Julliard's avatar
Alexandre Julliard committed
1076
) {
1077
	IStream16Impl *This = (IStream16Impl *)iface;
1078
	TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1079
	if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1080
		*obj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
1081 1082 1083
		return 0;
	}
	return OLE_E_ENUM_NOMORE;
1084

Alexandre Julliard's avatar
Alexandre Julliard committed
1085 1086
}

Matthew Becker's avatar
Matthew Becker committed
1087 1088 1089
/******************************************************************************
 * IStream16_AddRef [STORAGE.519]
 */
1090
ULONG IStream16_fnAddRef(IStream16* iface) {
1091
	IStream16Impl *This = (IStream16Impl *)iface;
1092
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094
}

1095 1096 1097 1098 1099 1100
static void
_ilockbytes16_addref(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
    
    args[0] = (DWORD)lockbytes;	/* iface */
1101
    if (!WOWCallback16Ex(
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
	(DWORD)((const ILockBytes16Vtbl*)MapSL(
		    (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
	)->AddRef,
	WCB16_PASCAL,
	1*sizeof(DWORD),
	(LPVOID)args,
	(LPDWORD)&hres
    ))
	ERR("CallTo16 ILockBytes16::AddRef() failed, hres %lx\n",hres);
}

static void
_ilockbytes16_release(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
    
    args[0] = (DWORD)lockbytes;	/* iface */
1119
    if (!WOWCallback16Ex(
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
	(DWORD)((const ILockBytes16Vtbl*)MapSL(
		    (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
	)->Release,
	WCB16_PASCAL,
	1*sizeof(DWORD),
	(LPVOID)args,
	(LPDWORD)&hres
    ))
	ERR("CallTo16 ILockBytes16::Release() failed, hres %lx\n",hres);
}

static void
_ilockbytes16_flush(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
    
    args[0] = (DWORD)lockbytes;	/* iface */
1137
    if (!WOWCallback16Ex(
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
	(DWORD)((const ILockBytes16Vtbl*)MapSL(
		    (SEGPTR)((LPLOCKBYTES16)MapSL(lockbytes))->lpVtbl)
	)->Flush,
	WCB16_PASCAL,
	1*sizeof(DWORD),
	(LPVOID)args,
	(LPDWORD)&hres
    ))
	ERR("CallTo16 ILockBytes16::Flush() failed, hres %lx\n",hres);
}

Matthew Becker's avatar
Matthew Becker committed
1149 1150 1151
/******************************************************************************
 * IStream16_Release [STORAGE.520]
 */
1152
ULONG IStream16_fnRelease(IStream16* iface) {
1153
	IStream16Impl *This = (IStream16Impl *)iface;
1154
        ULONG ref;
1155 1156 1157 1158 1159

	if (This->str.hf)
	    FlushFileBuffers(This->str.hf);
	else
	    _ilockbytes16_flush(This->str.lockbytes);
1160
        ref = InterlockedDecrement(&This->ref);
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
	if (ref)
	    return ref;

	if (This->str.hf)
	    CloseHandle(This->str.hf);
	else
	    _ilockbytes16_release(This->str.lockbytes);
        UnMapLS( This->thisptr );
	HeapFree( GetProcessHeap(), 0, This );
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172
}

1173 1174 1175 1176 1177 1178
/******************************************************************************
 *		IStream16_Seek	[STORAGE.523]
 *
 * FIXME
 *    Does not handle 64 bits
 */
1179
HRESULT IStream16_fnSeek(
1180
	IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos
Alexandre Julliard's avatar
Alexandre Julliard committed
1181
) {
1182
	IStream16Impl *This = (IStream16Impl *)iface;
1183
	TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185 1186 1187 1188 1189 1190

	switch (whence) {
	/* unix SEEK_xx should be the same as win95 ones */
	case SEEK_SET:
		/* offset must be ==0 (<0 is invalid, and >0 cannot be handled
		 * right now.
		 */
1191 1192 1193
		assert(offset.u.HighPart==0);
		This->offset.u.HighPart = offset.u.HighPart;
		This->offset.u.LowPart = offset.u.LowPart;
Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195
		break;
	case SEEK_CUR:
1196
		if (offset.u.HighPart < 0) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
			/* FIXME: is this negation correct ? */
1198 1199
			offset.u.HighPart = -offset.u.HighPart;
			offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1200

1201 1202 1203
			assert(offset.u.HighPart==0);
			assert(This->offset.u.LowPart >= offset.u.LowPart);
			This->offset.u.LowPart -= offset.u.LowPart;
Alexandre Julliard's avatar
Alexandre Julliard committed
1204
		} else {
1205 1206
			assert(offset.u.HighPart==0);
			This->offset.u.LowPart+= offset.u.LowPart;
Alexandre Julliard's avatar
Alexandre Julliard committed
1207 1208 1209
		}
		break;
	case SEEK_END:
1210 1211
		assert(offset.u.HighPart==0);
		This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart;
Alexandre Julliard's avatar
Alexandre Julliard committed
1212 1213
		break;
	}
1214 1215
	if (This->offset.u.LowPart>This->stde.pps_size)
		This->offset.u.LowPart=This->stde.pps_size;
1216
	if (newpos) *newpos = This->offset;
1217
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1218 1219
}

1220 1221 1222
/******************************************************************************
 *		IStream16_Read	[STORAGE.521]
 */
1223
HRESULT IStream16_fnRead(
1224
        IStream16* iface,void  *pv,ULONG cb,ULONG  *pcbRead
Alexandre Julliard's avatar
Alexandre Julliard committed
1225
) {
1226
	IStream16Impl *This = (IStream16Impl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
1227 1228 1229
	BYTE	block[BIGSIZE];
	ULONG	*bytesread=pcbRead,xxread;
	int	blocknr;
Marcus Meissner's avatar
Marcus Meissner committed
1230
	LPBYTE	pbv = pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1231

1232
	TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead);
Alexandre Julliard's avatar
Alexandre Julliard committed
1233 1234 1235
	if (!pcbRead) bytesread=&xxread;
	*bytesread = 0;

1236 1237
	if (cb>This->stde.pps_size-This->offset.u.LowPart)
		cb=This->stde.pps_size-This->offset.u.LowPart;
1238
	if (This->stde.pps_size < 0x1000) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1239
		/* use small block reader */
1240
		blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1241
		while (cb) {
1242
			unsigned int cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1243

1244
			if (!STORAGE_get_small_block(&This->str,blocknr,block)) {
1245
			   WARN("small block read failed!!!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1246 1247
				return E_FAIL;
			}
1248
			cc = cb;
1249 1250
			if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
				cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
Marcus Meissner's avatar
Marcus Meissner committed
1251
			memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1252
			This->offset.u.LowPart+=cc;
Marcus Meissner's avatar
Marcus Meissner committed
1253
			pbv+=cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1254 1255
			*bytesread+=cc;
			cb-=cc;
1256
			blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1257 1258 1259
		}
	} else {
		/* use big block reader */
1260
		blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1261
		while (cb) {
1262
			unsigned int cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1263

1264
			if (!STORAGE_get_big_block(&This->str,blocknr,block)) {
1265
				WARN("big block read failed!!!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1266 1267
				return E_FAIL;
			}
1268
			cc = cb;
1269 1270
			if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
				cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
Marcus Meissner's avatar
Marcus Meissner committed
1271
			memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1272
			This->offset.u.LowPart+=cc;
Marcus Meissner's avatar
Marcus Meissner committed
1273
			pbv+=cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275
			*bytesread+=cc;
			cb-=cc;
1276
			blocknr=STORAGE_get_next_big_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278
		}
	}
1279
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1280 1281
}

1282 1283 1284
/******************************************************************************
 *		IStream16_Write	[STORAGE.522]
 */
1285
HRESULT IStream16_fnWrite(
1286
        IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite
Alexandre Julliard's avatar
Alexandre Julliard committed
1287
) {
1288
	IStream16Impl *This = (IStream16Impl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
1289 1290 1291
	BYTE	block[BIGSIZE];
	ULONG	*byteswritten=pcbWrite,xxwritten;
	int	oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
Eric Pouech's avatar
Eric Pouech committed
1292
	const BYTE*     pbv = (const BYTE*)pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294 1295 1296

	if (!pcbWrite) byteswritten=&xxwritten;
	*byteswritten = 0;

1297
	TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite);
Alexandre Julliard's avatar
Alexandre Julliard committed
1298
	/* do we need to junk some blocks? */
1299
	newsize	= This->offset.u.LowPart+cb;
1300
	oldsize	= This->stde.pps_size;
Alexandre Julliard's avatar
Alexandre Julliard committed
1301 1302 1303
	if (newsize < oldsize) {
		if (oldsize < 0x1000) {
			/* only small blocks */
1304
			blocknr=STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,newsize/SMALLSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1305 1306 1307 1308

			assert(blocknr>=0);

			/* will set the rest of the chain to 'free' */
1309
			if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1310 1311 1312
				return E_FAIL;
		} else {
			if (newsize >= 0x1000) {
1313
				blocknr=STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,newsize/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1314 1315 1316
				assert(blocknr>=0);

				/* will set the rest of the chain to 'free' */
1317
				if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1318 1319
					return E_FAIL;
			} else {
1320
				/* Migrate large blocks to small blocks
Alexandre Julliard's avatar
Alexandre Julliard committed
1321 1322 1323
				 * (we just migrate newsize bytes)
				 */
				LPBYTE	curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1324 1325
				HRESULT r = E_FAIL;

Alexandre Julliard's avatar
Alexandre Julliard committed
1326
				cc	= newsize;
1327
				blocknr = This->stde.pps_sb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1328 1329
				curdata = data;
				while (cc>0) {
1330
					if (!STORAGE_get_big_block(&This->str,blocknr,curdata)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1331 1332 1333 1334 1335
						HeapFree(GetProcessHeap(),0,data);
						return E_FAIL;
					}
					curdata	+= BIGSIZE;
					cc	-= BIGSIZE;
1336
					blocknr	 = STORAGE_get_next_big_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1337 1338
				}
				/* frees complete chain for this stream */
1339
				if (!STORAGE_set_big_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1340
					goto err;
Alexandre Julliard's avatar
Alexandre Julliard committed
1341
				curdata	= data;
1342
				blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1343
				if (blocknr<0)
1344
					goto err;
Alexandre Julliard's avatar
Alexandre Julliard committed
1345 1346
				cc	= newsize;
				while (cc>0) {
1347
					if (!STORAGE_put_small_block(&This->str,blocknr,curdata))
1348
						goto err;
Alexandre Julliard's avatar
Alexandre Julliard committed
1349 1350
					cc	-= SMALLSIZE;
					if (cc<=0) {
1351
						if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1352
							goto err;
Alexandre Julliard's avatar
Alexandre Julliard committed
1353 1354
						break;
					} else {
1355
						int newblocknr = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1356
						if (newblocknr<0)
1357
							goto err;
1358
						if (!STORAGE_set_small_chain(&This->str,blocknr,newblocknr))
1359
							goto err;
Alexandre Julliard's avatar
Alexandre Julliard committed
1360 1361 1362 1363
						blocknr = newblocknr;
					}
					curdata	+= SMALLSIZE;
				}
1364 1365
				r = S_OK;
			err:
Alexandre Julliard's avatar
Alexandre Julliard committed
1366
				HeapFree(GetProcessHeap(),0,data);
1367 1368
				if(r != S_OK)
					return r;
Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370
			}
		}
1371
		This->stde.pps_size = newsize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1372 1373 1374 1375 1376
	}

	if (newsize > oldsize) {
		if (oldsize >= 0x1000) {
			/* should return the block right before the 'endofchain' */
1377
			blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1378 1379 1380
			assert(blocknr>=0);
			lastblocknr	= blocknr;
			for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1381
				blocknr = STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1382 1383
				if (blocknr<0)
					return E_FAIL;
1384
				if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1385 1386 1387
					return E_FAIL;
				lastblocknr = blocknr;
			}
1388
			if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1389 1390 1391 1392 1393
				return E_FAIL;
		} else {
			if (newsize < 0x1000) {
				/* find startblock */
				if (!oldsize)
1394
					This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1395
				else
1396
					blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1397 1398 1399 1400 1401 1402
				if (blocknr<0)
					return E_FAIL;

				/* allocate required new small blocks */
				lastblocknr = blocknr;
				for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1403
					blocknr = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1404 1405
					if (blocknr<0)
						return E_FAIL;
1406
					if (!STORAGE_set_small_chain(&This->str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1407 1408 1409 1410
						return E_FAIL;
					lastblocknr = blocknr;
				}
				/* and terminate the chain */
1411
				if (!STORAGE_set_small_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1412 1413 1414 1415
					return E_FAIL;
			} else {
				if (!oldsize) {
					/* no single block allocated yet */
1416
					blocknr=STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1417 1418
					if (blocknr<0)
						return E_FAIL;
1419
					This->stde.pps_sb = blocknr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421 1422
				} else {
					/* Migrate small blocks to big blocks */
					LPBYTE	curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1423 1424
					HRESULT r = E_FAIL;

Alexandre Julliard's avatar
Alexandre Julliard committed
1425
					cc	= oldsize;
1426
					blocknr = This->stde.pps_sb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1427 1428 1429
					curdata = data;
					/* slurp in */
					while (cc>0) {
1430
						if (!STORAGE_get_small_block(&This->str,blocknr,curdata))
1431
							goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1432 1433
						curdata	+= SMALLSIZE;
						cc	-= SMALLSIZE;
1434
						blocknr	 = STORAGE_get_next_small_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436
					}
					/* free small block chain */
1437
					if (!STORAGE_set_small_chain(&This->str,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE))
1438
						goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1439
					curdata	= data;
1440
					blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1441
					if (blocknr<0)
1442
						goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1443
					/* put the data into the big blocks */
1444
					cc	= This->stde.pps_size;
Alexandre Julliard's avatar
Alexandre Julliard committed
1445
					while (cc>0) {
1446
						if (!STORAGE_put_big_block(&This->str,blocknr,curdata))
1447
							goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1448 1449
						cc	-= BIGSIZE;
						if (cc<=0) {
1450
							if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
1451
								goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1452 1453
							break;
						} else {
1454
							int newblocknr = STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1455
							if (newblocknr<0)
1456
								goto err2;
1457
							if (!STORAGE_set_big_chain(&This->str,blocknr,newblocknr))
1458
								goto err2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1459 1460 1461 1462
							blocknr = newblocknr;
						}
						curdata	+= BIGSIZE;
					}
1463 1464
					r = S_OK;
				err2:
Alexandre Julliard's avatar
Alexandre Julliard committed
1465
					HeapFree(GetProcessHeap(),0,data);
1466 1467
					if(r != S_OK)
						return r;
Alexandre Julliard's avatar
Alexandre Julliard committed
1468 1469 1470 1471
				}
				/* generate big blocks to fit the new data */
				lastblocknr	= blocknr;
				for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1472
					blocknr = STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474
					if (blocknr<0)
						return E_FAIL;
1475
					if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1476 1477 1478 1479
						return E_FAIL;
					lastblocknr = blocknr;
				}
				/* terminate chain */
1480
				if (!STORAGE_set_big_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1481 1482 1483
					return E_FAIL;
			}
		}
1484
		This->stde.pps_size = newsize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486 1487 1488 1489
	}

	/* There are just some cases where we didn't modify it, we write it out
	 * everytime
	 */
1490
	if (!STORAGE_put_pps_entry(&This->str,This->ppsent,&(This->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1491 1492 1493
		return E_FAIL;

	/* finally the write pass */
1494
	if (This->stde.pps_size < 0x1000) {
1495
		blocknr = STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1496 1497 1498 1499 1500 1501 1502
		assert(blocknr>=0);
		while (cb>0) {
			/* we ensured that it is allocated above */
			assert(blocknr>=0);
			/* Read old block everytime, since we can have
			 * overlapping data at START and END of the write
			 */
1503
			if (!STORAGE_get_small_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1504 1505
				return E_FAIL;

1506
			cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1507 1508
			if (cc>cb)
				cc=cb;
1509
			memcpy(	((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
Marcus Meissner's avatar
Marcus Meissner committed
1510
				pbv+curoffset,
Alexandre Julliard's avatar
Alexandre Julliard committed
1511 1512
				cc
			);
1513
			if (!STORAGE_put_small_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1514 1515 1516
				return E_FAIL;
			cb			-= cc;
			curoffset		+= cc;
Marcus Meissner's avatar
Marcus Meissner committed
1517
			pbv			+= cc;
1518
			This->offset.u.LowPart	+= cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1519
			*byteswritten		+= cc;
1520
			blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1521 1522
		}
	} else {
1523
		blocknr = STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1524 1525 1526 1527 1528 1529 1530
		assert(blocknr>=0);
		while (cb>0) {
			/* we ensured that it is allocated above, so it better is */
			assert(blocknr>=0);
			/* read old block everytime, since we can have
			 * overlapping data at START and END of the write
			 */
1531
			if (!STORAGE_get_big_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1532 1533
				return E_FAIL;

1534
			cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1535 1536
			if (cc>cb)
				cc=cb;
1537
			memcpy(	((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
Marcus Meissner's avatar
Marcus Meissner committed
1538
				pbv+curoffset,
Alexandre Julliard's avatar
Alexandre Julliard committed
1539 1540
				cc
			);
1541
			if (!STORAGE_put_big_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1542 1543 1544
				return E_FAIL;
			cb			-= cc;
			curoffset		+= cc;
Marcus Meissner's avatar
Marcus Meissner committed
1545
			pbv			+= cc;
1546
			This->offset.u.LowPart	+= cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1547
			*byteswritten		+= cc;
1548
			blocknr = STORAGE_get_next_big_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1549 1550
		}
	}
1551
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1552 1553
}

1554 1555 1556
/******************************************************************************
 *		_create_istream16	[Internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1557
static void _create_istream16(LPSTREAM16 *str) {
1558
	IStream16Impl*	lpst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1559

1560
	if (!strvt16.QueryInterface) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1561 1562
		HMODULE16	wp = GetModuleHandle16("STORAGE");
		if (wp>=32) {
1563
		  /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */
1564
#define VTENT(xfn)  strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn)
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
			VTENT(QueryInterface);
			VTENT(AddRef);
			VTENT(Release);
			VTENT(Read);
			VTENT(Write);
			VTENT(Seek);
			VTENT(SetSize);
			VTENT(CopyTo);
			VTENT(Commit);
			VTENT(Revert);
			VTENT(LockRegion);
			VTENT(UnlockRegion);
			VTENT(Stat);
			VTENT(Clone);
Alexandre Julliard's avatar
Alexandre Julliard committed
1579
#undef VTENT
1580
			segstrvt16 = (const IStream16Vtbl*)MapLS( &strvt16 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1581
		} else {
1582
#define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn;
1583 1584 1585 1586 1587 1588
			VTENT(QueryInterface);
			VTENT(AddRef);
			VTENT(Release);
			VTENT(Read);
			VTENT(Write);
			VTENT(Seek);
Alexandre Julliard's avatar
Alexandre Julliard committed
1589
	/*
1590 1591 1592 1593 1594 1595 1596 1597
			VTENT(CopyTo);
			VTENT(Commit);
			VTENT(SetSize);
			VTENT(Revert);
			VTENT(LockRegion);
			VTENT(UnlockRegion);
			VTENT(Stat);
			VTENT(Clone);
Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599 1600 1601 1602
	*/
#undef VTENT
			segstrvt16 = &strvt16;
		}
	}
1603
	lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1604
	lpst->lpVtbl	= segstrvt16;
Alexandre Julliard's avatar
Alexandre Julliard committed
1605
	lpst->ref	= 1;
1606
	lpst->thisptr	= MapLS( lpst );
1607 1608
	lpst->str.hf	= NULL;
	lpst->str.lockbytes	= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1609 1610 1611
	*str = (void*)lpst->thisptr;
}

1612 1613 1614

/* --- IStream32 implementation */

1615 1616
typedef struct
{
1617
        /* IUnknown fields */
1618
        const IStreamVtbl              *lpVtbl;
1619
        LONG                            ref;
1620 1621 1622
        /* IStream32 fields */
        struct storage_pps_entry        stde;
        int                             ppsent;
1623
        HANDLE                          hf;
1624
        ULARGE_INTEGER                  offset;
1625
} IStream32Impl;
1626

Alexandre Julliard's avatar
Alexandre Julliard committed
1627
/*****************************************************************************
Matthew Becker's avatar
Matthew Becker committed
1628
 *		IStream32_QueryInterface	[VTABLE]
Alexandre Julliard's avatar
Alexandre Julliard committed
1629
 */
1630 1631
HRESULT WINAPI IStream_fnQueryInterface(
	IStream* iface,REFIID refiid,LPVOID *obj
Alexandre Julliard's avatar
Alexandre Julliard committed
1632
) {
1633
	IStream32Impl *This = (IStream32Impl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
1634

1635
	TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1636
	if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1637
		*obj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
1638 1639 1640
		return 0;
	}
	return OLE_E_ENUM_NOMORE;
1641

Alexandre Julliard's avatar
Alexandre Julliard committed
1642 1643
}

Matthew Becker's avatar
Matthew Becker committed
1644 1645 1646
/******************************************************************************
 * IStream32_AddRef [VTABLE]
 */
1647
ULONG WINAPI IStream_fnAddRef(IStream* iface) {
1648
	IStream32Impl *This = (IStream32Impl *)iface;
1649
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1650 1651
}

Matthew Becker's avatar
Matthew Becker committed
1652 1653 1654
/******************************************************************************
 * IStream32_Release [VTABLE]
 */
1655
ULONG WINAPI IStream_fnRelease(IStream* iface) {
1656
	IStream32Impl *This = (IStream32Impl *)iface;
1657
        ULONG ref;
1658
	FlushFileBuffers(This->hf);
1659 1660
        ref = InterlockedDecrement(&This->ref);
	if (!ref) {
1661
		CloseHandle(This->hf);
1662
		HeapFree( GetProcessHeap(), 0, This );
Alexandre Julliard's avatar
Alexandre Julliard committed
1663
	}
1664
	return ref;
Alexandre Julliard's avatar
Alexandre Julliard committed
1665 1666 1667
}

/******************************************************************************
1668
 *		IStorage16_QueryInterface	[STORAGE.500]
Alexandre Julliard's avatar
Alexandre Julliard committed
1669
 */
1670
HRESULT IStorage16_fnQueryInterface(
1671
	IStorage16* iface,REFIID refiid,LPVOID *obj
Alexandre Julliard's avatar
Alexandre Julliard committed
1672
) {
1673
	IStorage16Impl *This = (IStorage16Impl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
1674

1675
	TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1676 1677

	if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1678
		*obj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
1679 1680 1681 1682 1683
		return 0;
	}
	return OLE_E_ENUM_NOMORE;
}

Matthew Becker's avatar
Matthew Becker committed
1684 1685 1686
/******************************************************************************
 * IStorage16_AddRef [STORAGE.501]
 */
1687
ULONG IStorage16_fnAddRef(IStorage16* iface) {
1688
	IStorage16Impl *This = (IStorage16Impl *)iface;
1689
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1690 1691
}

Matthew Becker's avatar
Matthew Becker committed
1692 1693 1694
/******************************************************************************
 * IStorage16_Release [STORAGE.502]
 */
1695
ULONG IStorage16_fnRelease(IStorage16* iface) {
1696
	IStorage16Impl *This = (IStorage16Impl *)iface;
1697 1698 1699 1700 1701 1702 1703 1704
        ULONG ref;
        ref = InterlockedDecrement(&This->ref);
        if (!ref)
        {
            UnMapLS( This->thisptr );
            HeapFree( GetProcessHeap(), 0, This );
        }
        return ref;
Alexandre Julliard's avatar
Alexandre Julliard committed
1705 1706
}

Matthew Becker's avatar
Matthew Becker committed
1707 1708 1709
/******************************************************************************
 * IStorage16_Stat [STORAGE.517]
 */
1710
HRESULT IStorage16_fnStat(
1711
        LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag
Alexandre Julliard's avatar
Alexandre Julliard committed
1712
) {
1713
	IStorage16Impl *This = (IStorage16Impl *)iface;
1714 1715 1716
        DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
        LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );

1717
	TRACE("(%p)->(%p,0x%08lx)\n",
1718
		This,pstatstg,grfStatFlag
Alexandre Julliard's avatar
Alexandre Julliard committed
1719
	);
1720 1721
        WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
	pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1722
	pstatstg->type = This->stde.pps_type;
1723
	pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1724 1725 1726
	pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */
	pstatstg->atime = This->stde.pps_ft2; /* FIXME */
	pstatstg->ctime = This->stde.pps_ft2; /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1727 1728
	pstatstg->grfMode	= 0; /* FIXME */
	pstatstg->grfLocksSupported = 0; /* FIXME */
1729
	pstatstg->clsid		= This->stde.pps_guid;
Alexandre Julliard's avatar
Alexandre Julliard committed
1730 1731
	pstatstg->grfStateBits	= 0; /* FIXME */
	pstatstg->reserved	= 0;
1732
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1733 1734
}

1735 1736 1737
/******************************************************************************
 *		IStorage16_Commit	[STORAGE.509]
 */
1738
HRESULT IStorage16_fnCommit(
1739
        LPSTORAGE16 iface,DWORD commitflags
Alexandre Julliard's avatar
Alexandre Julliard committed
1740
) {
1741
	IStorage16Impl *This = (IStorage16Impl *)iface;
1742
	FIXME("(%p)->(0x%08lx),STUB!\n",
1743
		This,commitflags
Alexandre Julliard's avatar
Alexandre Julliard committed
1744
	);
1745
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1746 1747
}

Matthew Becker's avatar
Matthew Becker committed
1748 1749 1750
/******************************************************************************
 * IStorage16_CopyTo [STORAGE.507]
 */
1751
HRESULT IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) {
1752
	IStorage16Impl *This = (IStorage16Impl *)iface;
1753
	FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n",
1754
		This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
Alexandre Julliard's avatar
Alexandre Julliard committed
1755
	);
1756
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1757 1758 1759
}


Matthew Becker's avatar
Matthew Becker committed
1760 1761 1762
/******************************************************************************
 * IStorage16_CreateStorage [STORAGE.505]
 */
1763
HRESULT IStorage16_fnCreateStorage(
1764
	LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1765
) {
1766
	IStorage16Impl *This = (IStorage16Impl *)iface;
1767
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1768 1769 1770
	int		ppsent,x;
	struct storage_pps_entry	stde;
	struct storage_header sth;
1771 1772
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1773

1774
	READ_HEADER(&This->str);
1775
	TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1776
		This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1777 1778
	);
	if (grfMode & STGM_TRANSACTED)
1779
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1780
	_create_istorage16(ppstg);
1781
	lpstg = MapSL((SEGPTR)*ppstg);
1782 1783 1784 1785 1786 1787 1788
	if (This->str.hf) {
	    DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
			     &lpstg->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
	} else {
	    lpstg->str.lockbytes = This->str.lockbytes;
	    _ilockbytes16_addref(This->str.lockbytes);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1789

1790
	ppsent=STORAGE_get_free_pps_entry(&lpstg->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1791 1792
	if (ppsent<0)
		return E_FAIL;
1793
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1794 1795
	if (stde.pps_dir==-1) {
		stde.pps_dir = ppsent;
1796
		x = This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1797
	} else {
1798
		FIXME(" use prev chain too ?\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1799
		x=stde.pps_dir;
1800
		if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1801 1802 1803
			return E_FAIL;
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1804
			if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1805 1806 1807 1808
				return E_FAIL;
		}
		stde.pps_next = ppsent;
	}
1809
	ret = STORAGE_put_pps_entry(&lpstg->str,x,&stde);
1810
	assert(ret);
1811
	nPPSEntries = STORAGE_get_pps_entry(&lpstg->str,ppsent,&(lpstg->stde));
1812
	assert(nPPSEntries == 1);
1813 1814 1815
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname,
                             sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR));
	lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
1816 1817 1818 1819 1820 1821 1822 1823
	lpstg->stde.pps_next	= -1;
	lpstg->stde.pps_prev	= -1;
	lpstg->stde.pps_dir	= -1;
	lpstg->stde.pps_sb	= -1;
	lpstg->stde.pps_size	=  0;
	lpstg->stde.pps_type	=  1;
	lpstg->ppsent		= ppsent;
	/* FIXME: timestamps? */
1824
	if (!STORAGE_put_pps_entry(&lpstg->str,ppsent,&(lpstg->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1825
		return E_FAIL;
1826
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1827 1828
}

1829 1830 1831
/******************************************************************************
 *		IStorage16_CreateStream	[STORAGE.503]
 */
1832
HRESULT IStorage16_fnCreateStream(
1833
	LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1834
) {
1835
	IStorage16Impl *This = (IStorage16Impl *)iface;
1836
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1837 1838
	int		ppsent,x;
	struct storage_pps_entry	stde;
1839 1840
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1841

1842
	TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n",
1843
		This,pwcsName,grfMode,reserved1,reserved2,ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1844 1845
	);
	if (grfMode & STGM_TRANSACTED)
1846
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1847
	_create_istream16(ppstm);
1848
	lpstr = MapSL((SEGPTR)*ppstm);
1849 1850 1851 1852 1853 1854 1855
	if (This->str.hf) {
	    DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
			     &lpstr->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
	} else {
	    lpstr->str.lockbytes = This->str.lockbytes;
	    _ilockbytes16_addref(This->str.lockbytes);
	}
1856
	lpstr->offset.u.LowPart	= 0;
1857
	lpstr->offset.u.HighPart= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1858

1859
	ppsent=STORAGE_get_free_pps_entry(&lpstr->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860 1861
	if (ppsent<0)
		return E_FAIL;
1862
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1863
	if (stde.pps_next==-1)
1864
		x=This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1865 1866 1867
	else
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1868
			if (1!=STORAGE_get_pps_entry(&lpstr->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1869 1870 1871
				return E_FAIL;
		}
	stde.pps_next = ppsent;
1872
	ret = STORAGE_put_pps_entry(&lpstr->str,x,&stde);
1873
	assert(ret);
1874
	nPPSEntries = STORAGE_get_pps_entry(&lpstr->str,ppsent,&(lpstr->stde));
1875
	assert(nPPSEntries == 1);
1876 1877 1878
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname,
                             sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR));
	lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR);
Alexandre Julliard's avatar
Alexandre Julliard committed
1879 1880 1881 1882 1883 1884 1885
	lpstr->stde.pps_next	= -1;
	lpstr->stde.pps_prev	= -1;
	lpstr->stde.pps_dir	= -1;
	lpstr->stde.pps_sb	= -1;
	lpstr->stde.pps_size	=  0;
	lpstr->stde.pps_type	=  2;
	lpstr->ppsent		= ppsent;
1886

Alexandre Julliard's avatar
Alexandre Julliard committed
1887
	/* FIXME: timestamps? */
1888
	if (!STORAGE_put_pps_entry(&lpstr->str,ppsent,&(lpstr->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1889
		return E_FAIL;
1890
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1891 1892
}

1893 1894 1895
/******************************************************************************
 *		IStorage16_OpenStorage	[STORAGE.506]
 */
1896
HRESULT IStorage16_fnOpenStorage(
1897
	LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1898
) {
1899
	IStorage16Impl *This = (IStorage16Impl *)iface;
1900
	IStream16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1901 1902 1903
	WCHAR		name[33];
	int		newpps;

1904
	TRACE("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n",
1905
		This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1906 1907
	);
	if (grfMode & STGM_TRANSACTED)
1908
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1909
	_create_istorage16(ppstg);
1910
	lpstg = MapSL((SEGPTR)*ppstg);
1911 1912 1913 1914 1915 1916 1917
	if (This->str.hf) {
	    DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
			     &lpstg->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
	} else {
	    lpstg->str.lockbytes = This->str.lockbytes;
	    _ilockbytes16_addref(This->str.lockbytes);
	}
1918
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1919
	newpps = STORAGE_look_for_named_pps(&lpstg->str,This->stde.pps_dir,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1920
	if (newpps==-1) {
1921
		IStream16_fnRelease((IStream16*)lpstg);
Alexandre Julliard's avatar
Alexandre Julliard committed
1922 1923 1924
		return E_FAIL;
	}

1925
	if (1!=STORAGE_get_pps_entry(&lpstg->str,newpps,&(lpstg->stde))) {
1926
		IStream16_fnRelease((IStream16*)lpstg);
Alexandre Julliard's avatar
Alexandre Julliard committed
1927 1928 1929
		return E_FAIL;
	}
	lpstg->ppsent		= newpps;
1930
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1931 1932
}

Matthew Becker's avatar
Matthew Becker committed
1933 1934 1935
/******************************************************************************
 * IStorage16_OpenStream [STORAGE.504]
 */
1936
HRESULT IStorage16_fnOpenStream(
1937
	LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1938
) {
1939
	IStorage16Impl *This = (IStorage16Impl *)iface;
1940
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1941 1942 1943
	WCHAR		name[33];
	int		newpps;

1944
	TRACE("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n",
1945
		This,pwcsName,reserved1,grfMode,reserved2,ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1946 1947
	);
	if (grfMode & STGM_TRANSACTED)
1948
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1949
	_create_istream16(ppstm);
1950
	lpstr = MapSL((SEGPTR)*ppstm);
1951 1952 1953 1954 1955 1956 1957
	if (This->str.hf) {
	    DuplicateHandle( GetCurrentProcess(), This->str.hf, GetCurrentProcess(),
			     &lpstr->str.hf, 0, TRUE, DUPLICATE_SAME_ACCESS );
	} else {
	    lpstr->str.lockbytes = This->str.lockbytes;
	    _ilockbytes16_addref(This->str.lockbytes);
	}
1958
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1959
	newpps = STORAGE_look_for_named_pps(&lpstr->str,This->stde.pps_dir,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1960
	if (newpps==-1) {
1961
		IStream16_fnRelease((IStream16*)lpstr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1962 1963 1964
		return E_FAIL;
	}

1965
	if (1!=STORAGE_get_pps_entry(&lpstr->str,newpps,&(lpstr->stde))) {
1966
		IStream16_fnRelease((IStream16*)lpstr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1967 1968
		return E_FAIL;
	}
1969
	lpstr->offset.u.LowPart		= 0;
1970
	lpstr->offset.u.HighPart	= 0;
1971
	lpstr->ppsent			= newpps;
1972
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1973 1974
}

Matthew Becker's avatar
Matthew Becker committed
1975 1976 1977
/******************************************************************************
 * _create_istorage16 [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1978
static void _create_istorage16(LPSTORAGE16 *stg) {
1979
	IStorage16Impl*	lpst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1980

1981
	if (!stvt16.QueryInterface) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1982 1983
		HMODULE16	wp = GetModuleHandle16("STORAGE");
		if (wp>=32) {
1984
#define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
Alexandre Julliard's avatar
Alexandre Julliard committed
1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
			VTENT(QueryInterface)
			VTENT(AddRef)
			VTENT(Release)
			VTENT(CreateStream)
			VTENT(OpenStream)
			VTENT(CreateStorage)
			VTENT(OpenStorage)
			VTENT(CopyTo)
			VTENT(MoveElementTo)
			VTENT(Commit)
			VTENT(Revert)
			VTENT(EnumElements)
			VTENT(DestroyElement)
			VTENT(RenameElement)
			VTENT(SetElementTimes)
			VTENT(SetClass)
			VTENT(SetStateBits)
			VTENT(Stat)
#undef VTENT
2004
			segstvt16 = (const IStorage16Vtbl*)MapLS( &stvt16 );
Alexandre Julliard's avatar
Alexandre Julliard committed
2005
		} else {
2006
#define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
Alexandre Julliard's avatar
Alexandre Julliard committed
2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
			VTENT(QueryInterface)
			VTENT(AddRef)
			VTENT(Release)
			VTENT(CreateStream)
			VTENT(OpenStream)
			VTENT(CreateStorage)
			VTENT(OpenStorage)
			VTENT(CopyTo)
			VTENT(Commit)
	/*  not (yet) implemented ...
			VTENT(MoveElementTo)
			VTENT(Revert)
			VTENT(EnumElements)
			VTENT(DestroyElement)
			VTENT(RenameElement)
			VTENT(SetElementTimes)
			VTENT(SetClass)
			VTENT(SetStateBits)
			VTENT(Stat)
	*/
#undef VTENT
			segstvt16 = &stvt16;
		}
	}
2031
	lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
2032
	lpst->lpVtbl	= segstvt16;
2033 2034
	lpst->str.hf	= NULL;
	lpst->str.lockbytes	= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2035
	lpst->ref	= 1;
2036
	lpst->thisptr	= MapLS(lpst);
Alexandre Julliard's avatar
Alexandre Julliard committed
2037 2038 2039 2040 2041 2042 2043
	*stg = (void*)lpst->thisptr;
}

/******************************************************************************
 *	Storage API functions
 */

2044
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2045
 *		StgCreateDocFileA	[STORAGE.1]
2046
 */
2047
HRESULT WINAPI StgCreateDocFile16(
Alexandre Julliard's avatar
Alexandre Julliard committed
2048 2049
	LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
) {
2050
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2051
	int		i,ret;
2052
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2053 2054
	struct storage_pps_entry	stde;

2055
	TRACE("(%s,0x%08lx,0x%08lx,%p)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2056 2057 2058
		pwcsName,grfMode,reserved,ppstgOpen
	);
	_create_istorage16(ppstgOpen);
2059 2060
	hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
	if (hf==INVALID_HANDLE_VALUE) {
2061
		WARN("couldn't open file for storage:%ld\n",GetLastError());
Alexandre Julliard's avatar
Alexandre Julliard committed
2062 2063
		return E_FAIL;
	}
2064
	lpstg = MapSL((SEGPTR)*ppstgOpen);
2065 2066
	lpstg->str.hf = hf;
	lpstg->str.lockbytes = 0;
Francois Gouget's avatar
Francois Gouget committed
2067
	/* FIXME: check for existence before overwriting? */
2068
	if (!STORAGE_init_storage(&lpstg->str)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2069 2070 2071 2072 2073
		CloseHandle(hf);
		return E_FAIL;
	}
	i=0;ret=0;
	while (!ret) { /* neither 1 nor <0 */
2074
		ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
Alexandre Julliard's avatar
Alexandre Julliard committed
2075 2076 2077 2078 2079 2080 2081 2082
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde	= stde;
			lpstg->ppsent	= i;
			break;
		}
		i++;
	}
	if (ret!=1) {
2083
		IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
Alexandre Julliard's avatar
Alexandre Julliard committed
2084 2085 2086
		return E_FAIL;
	}

2087
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2088 2089
}

Matthew Becker's avatar
Matthew Becker committed
2090
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2091
 * StgIsStorageFile [STORAGE.5]
Matthew Becker's avatar
Matthew Becker committed
2092
 */
2093
HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
2094 2095
	UNICODE_STRING strW;
	HRESULT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2096

2097 2098 2099
	RtlCreateUnicodeStringFromAsciiz(&strW, fn);
	ret = StgIsStorageFile( strW.Buffer );
	RtlFreeUnicodeString( &strW );
Alexandre Julliard's avatar
Alexandre Julliard committed
2100

2101 2102
	return ret;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2103

Matthew Becker's avatar
Matthew Becker committed
2104
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2105
 * StgOpenStorage [STORAGE.3]
Matthew Becker's avatar
Matthew Becker committed
2106
 */
2107
HRESULT WINAPI StgOpenStorage16(
2108
	LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
Alexandre Julliard's avatar
Alexandre Julliard committed
2109 2110
	SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
) {
2111
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2112
	int		ret,i;
2113
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2114 2115
	struct storage_pps_entry	stde;

2116 2117
	TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n",
              pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
Alexandre Julliard's avatar
Alexandre Julliard committed
2118 2119
	);
	_create_istorage16(ppstgOpen);
2120
	hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
2121
	if (hf==INVALID_HANDLE_VALUE) {
2122
		WARN("Couldn't open file for storage\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2123 2124
		return E_FAIL;
	}
2125
	lpstg = MapSL((SEGPTR)*ppstgOpen);
2126
	lpstg->str.hf = hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2127 2128 2129

	i=0;ret=0;
	while (!ret) { /* neither 1 nor <0 */
2130
		ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
Alexandre Julliard's avatar
Alexandre Julliard committed
2131 2132 2133 2134 2135 2136 2137
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde=stde;
			break;
		}
		i++;
	}
	if (ret!=1) {
2138
		IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
Alexandre Julliard's avatar
Alexandre Julliard committed
2139 2140
		return E_FAIL;
	}
2141
	return S_OK;
2142

Alexandre Julliard's avatar
Alexandre Julliard committed
2143
}
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157

/******************************************************************************
 *              StgIsStorageILockBytes        [STORAGE.6]
 *
 * Determines if the ILockBytes contains a storage object.
 */
HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
{
  DWORD args[6];
  HRESULT hres;
  HANDLE16 hsig;
  
  args[0] = (DWORD)plkbyt;	/* iface */
  args[1] = args[2] = 0;	/* ULARGE_INTEGER offset */
2158
  args[3] = WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
2159 2160 2161
  args[4] = 8;
  args[5] = 0;

2162
  if (!WOWCallback16Ex(
2163
      (DWORD)((const ILockBytes16Vtbl*)MapSL(
2164
                  (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
      )->ReadAt,
      WCB16_PASCAL,
      6*sizeof(DWORD),
      (LPVOID)args,
      (LPDWORD)&hres
  )) {
      ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres);
      return hres;
  }
  if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
2175
    WOWGlobalUnlockFree16(args[3]);
2176 2177
    return S_OK;
  }
2178
  WOWGlobalUnlockFree16(args[3]);
2179 2180 2181 2182 2183 2184 2185
  return S_FALSE;
}

/******************************************************************************
 *    StgOpenStorageOnILockBytes    [STORAGE.4]
 */
HRESULT WINAPI StgOpenStorageOnILockBytes16(
2186 2187 2188 2189 2190 2191
	SEGPTR /*ILockBytes16 **/plkbyt,
	IStorage16 *pstgPriority,
	DWORD grfMode,
	SNB16 snbExclude,
	DWORD reserved,
	IStorage16 **ppstgOpen)
2192
{
2193 2194 2195
	IStorage16Impl*	lpstg;
	int i,ret;
	struct storage_pps_entry	stde;
2196

2197 2198 2199
	FIXME("(%lx, %p, 0x%08lx, %d, %lx, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen);
	if ((plkbyt == 0) || (ppstgOpen == 0))
		return STG_E_INVALIDPOINTER;
2200

2201
	*ppstgOpen = 0;
2202

2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
	_create_istorage16(ppstgOpen);
	lpstg = MapSL((SEGPTR)*ppstgOpen);
	lpstg->str.hf = NULL;
	lpstg->str.lockbytes = plkbyt;
	i=0;ret=0;
	while (!ret) { /* neither 1 nor <0 */
		ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde=stde;
			break;
		}
		i++;
	}
	if (ret!=1) {
		IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */
		return E_FAIL;
	}
	return S_OK;
}

/***********************************************************************
2224
 *    ReadClassStg (OLE2.18)
2225
 *
2226 2227 2228 2229
 * This method reads the CLSID previously written to a storage object with
 * the WriteClassStg.
 *
 * PARAMS
2230 2231 2232 2233 2234 2235
 *  pstg    [I] Segmented LPSTORAGE pointer.
 *  pclsid  [O] Pointer to where the CLSID is written
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
2236
 */
2237 2238
HRESULT WINAPI ReadClassStg16(SEGPTR pstg, CLSID *pclsid)
{
2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251
	STATSTG16 statstg;
	HANDLE16 hstatstg;
	HRESULT	hres;
	DWORD args[3];

	TRACE("(%lx, %p)\n", pstg, pclsid);

	if(pclsid==NULL)
		return E_POINTER;
	/*
	 * read a STATSTG structure (contains the clsid) from the storage
	 */
	args[0] = (DWORD)pstg;	/* iface */
2252
	args[1] = WOWGlobalAllocLock16( 0, sizeof(STATSTG16), &hstatstg );
2253 2254
	args[2] = STATFLAG_DEFAULT;

2255
	if (!WOWCallback16Ex(
2256 2257 2258 2259 2260 2261 2262 2263
	    (DWORD)((const IStorage16Vtbl*)MapSL(
			(SEGPTR)((LPSTORAGE16)MapSL(pstg))->lpVtbl)
	    )->Stat,
	    WCB16_PASCAL,
	    3*sizeof(DWORD),
	    (LPVOID)args,
	    (LPDWORD)&hres
	)) {
2264
	    WOWGlobalUnlockFree16(args[1]);
2265 2266 2267 2268
	    ERR("CallTo16 IStorage16::Stat() failed, hres %lx\n",hres);
	    return hres;
	}
	memcpy(&statstg, MapSL(args[1]), sizeof(STATSTG16));
2269
	WOWGlobalUnlockFree16(args[1]);
2270

2271 2272 2273 2274 2275 2276
	if(SUCCEEDED(hres)) {
		*pclsid=statstg.clsid;
		TRACE("clsid is %s\n", debugstr_guid(&statstg.clsid));
	}
	return hres;
}
2277

2278
/***********************************************************************
2279
 *              GetConvertStg (OLE2.82)
2280
 */
2281
HRESULT WINAPI GetConvertStg16(LPSTORAGE stg) {
2282 2283
    FIXME("unimplemented stub!\n");
    return E_FAIL;
2284
}