storage.c 64.5 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
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

#define NONAMELESSUNION
36

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

47 48
#include "ifs.h"

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

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
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 */
73
	FILETIME pps_ft2;	/* 6C: filetime2 */
74 75 76 77 78 79 80 81 82 83
	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
84 85 86 87 88 89 90
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)

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

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

#define IMPLEMENTED 1

103 104 105 106 107 108 109 110 111 112 113 114 115 116
/* 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
117
 *
118 119 120 121 122
 * #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
123
 *
124 125 126 127
 * #define DF_BLOCK_SIZE	0x200
 * #define DF_VTOC_SIZE		0x80
 * #define DF_DE_PER_BLOCK	4
 * #define DF_STREAM_BLOCK_SIZE	0x40
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
 * 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
202
 *
203 204
 * struct	DocFile_Header
 * {
205 206 207 208 209 210 211 212
 * 	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
213
 * 	df_int4 aiUnknown1[4];
214
 * 	df_int4 iVersion;	// DocFile Version - 0x03003E
215
 * 	df_int4 aiUnknown2[4];
216 217
 * 	df_int4 nVTOCs;		// Number of VTOCs
 * 	df_int4 iFirstDirBlock; // First Directory Block
218
 * 	df_int4 aiUnknown3[2];
219
 * 	df_int4 iFirstDataVTOC; // First data VTOC block
220
 * 	df_int4 iHasData;	// 1 if there is data in the file - yes, this is important
221 222
 * 	df_int4 iExtendedVTOC;	// Extended VTOC location
 * 	df_int4 iExtendedVTOCSize; // Size of extended VTOC (+1?)
223 224
 * 	df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS];
 * };
225
 *
226 227 228 229
 * struct	DocFile_VTOC
 * {
 * 	df_int4 aiBlocks[DF_VTOC_SIZE];
 * };
230 231
 *
 *
232 233 234 235 236 237 238 239 240 241 242 243 244 245
 * 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.
 *
246
 *
247 248
 * struct	DocFile_DirEnt
 * {
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
 * 	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
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
 * 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
Austin English's avatar
Austin English committed
307
 * an alternative to docfiles that we use internally that
308 309 310 311 312 313 314 315 316 317 318 319 320
 * 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.
 */

321 322 323 324 325 326 327 328
typedef struct {
	HANDLE		hf;
	SEGPTR		lockbytes;
} stream_access16;
/* --- IStorage16 implementation struct */

typedef struct
{
329
        IStorage16                      IStorage16_iface;
330 331 332 333 334 335 336 337
        LONG                            ref;
        /* IStorage16 fields */
        SEGPTR                          thisptr; /* pointer to this struct as segmented */
        struct storage_pps_entry        stde;
        int                             ppsent;
	stream_access16			str;
} IStorage16Impl;

338

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

    assert(n>=-1);
350 351 352 353
    if (str->hf) {
	if ((SetFilePointer( str->hf, (n+1)*BIGSIZE, NULL,
			     SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError())
	{
354
            WARN("(%p,%d,%p), seek failed (%d)\n",str->hf, n, block, GetLastError());
355 356 357 358
	    return FALSE;
	}
	if (!ReadFile( str->hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE)
	{
359
            WARN("(hf=%p, block size %d): read didn't read (%d)\n",str->hf,n,GetLastError());
360 361 362 363 364 365
	    return FALSE;
	}
    } else {
	DWORD args[6];
	HRESULT hres;
	HANDLE16 hsig;
366

367 368 369
	args[0] = (DWORD)str->lockbytes;	/* iface */
	args[1] = (n+1)*BIGSIZE;
	args[2] = 0;	/* ULARGE_INTEGER offset */
370
	args[3] = WOWGlobalAllocLock16( 0, BIGSIZE, &hsig ); /* sig */
371 372 373
	args[4] = BIGSIZE;
	args[5] = 0;

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

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

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

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

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

458
	READ_HEADER(str);
459

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

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
481 482 483 484 485 486 487
	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]) {
488
			BOOL ret = STORAGE_get_big_block(str,sth.bbd_list[blocknr>>7],(LPBYTE)bbs);
489
			assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
490 491 492 493 494 495 496
			lastblock = sth.bbd_list[blocknr>>7];
		}
		blocknr = bbs[blocknr&0x7f];
	}
	return blocknr;
}

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

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

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

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

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

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

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

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

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

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

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

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

609 610
	TRACE("(blocknr=%d, nr=%d)\n", blocknr, nr);
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
611 612 613 614
	assert(blocknr>=0);
	while ((nr--) && (blocknr>=0)) {
		if (lastblocknr/128!=blocknr/128) {
			int	bigblocknr;
615
			bigblocknr = STORAGE_get_nth_next_big_blocknr(str,sth.sbd_startblock,blocknr/128);
Alexandre Julliard's avatar
Alexandre Julliard committed
616
			assert(bigblocknr>=0);
617
			ret = STORAGE_get_big_block(str,bigblocknr,block);
618
			assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620 621 622 623 624 625 626 627 628
			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
629 630 631
/******************************************************************************
 * STORAGE_get_pps_entry [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
632
static int
633
STORAGE_get_pps_entry(stream_access16*str,int n,struct storage_pps_entry *pstde) {
Alexandre Julliard's avatar
Alexandre Julliard committed
634 635 636 637
	int	blocknr;
	BYTE	block[BIGSIZE];
	struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3));
	struct storage_header sth;
638
	BOOL ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
639

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

	*pstde=*stde;
	return 1;
}

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

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

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

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

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

705 706 707
/******************************************************************************
 *		STORAGE_dump_pps_entry	[Internal]
 *
708
 * This function is there to simplify debugging. It is otherwise unused.
709
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
710
void
Alexandre Julliard's avatar
Alexandre Julliard committed
711
STORAGE_dump_pps_entry(struct storage_pps_entry *stde) {
712
    char	name[33];
Alexandre Julliard's avatar
Alexandre Julliard committed
713

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

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

748 749
	if (str->hf)
	    SetFilePointer( str->hf, 0, NULL, SEEK_SET );
Alexandre Julliard's avatar
Alexandre Julliard committed
750 751 752 753 754 755 756 757 758 759 760
	/* 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;
761 762 763 764 765
	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
766 767 768 769 770
	/* 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 */
771 772 773 774 775
	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
776 777 778
	/* block 1 is the root directory entry */
	memset(block,0x00,sizeof(block));
	stde = (struct storage_pps_entry*)block;
779 780 781
        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
782 783 784 785 786 787
	stde->pps_type		= 5;
	stde->pps_dir		= -1;
	stde->pps_next		= -1;
	stde->pps_prev		= -1;
	stde->pps_sb		= 0xffffffff;
	stde->pps_size		= 0;
788 789 790 791 792
	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
793 794
}

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

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

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

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

837
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
838 839 840 841 842 843

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

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

874
	READ_HEADER(str);
Alexandre Julliard's avatar
Alexandre Julliard committed
875 876 877 878 879
	curblock	= 0;
	lastbigblocknr	= -1;
	bigblocknr	= sth.bbd_list[curblock];
	while (curblock<sth.num_of_bbd_blocks) {
		assert(bigblocknr>=0);
880
		ret = STORAGE_get_big_block(str,bigblocknr,block);
881
		assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
882 883 884
		for (i=0;i<128;i++)
			if (sbd[i]==STORAGE_CHAINENTRY_FREE) {
				sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN;
885
				ret = STORAGE_put_big_block(str,bigblocknr,block);
886
				assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
887
				memset(block,0x42,sizeof(block));
888
				ret = STORAGE_put_big_block(str,i+curblock*128,block);
889
				assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891 892 893 894 895
				return i+curblock*128;
			}
		lastbigblocknr = bigblocknr;
		bigblocknr = sth.bbd_list[++curblock];
	}
	bigblocknr = curblock*128;
896 897
	/* 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
898 899 900 901 902
	 * next large block depot.
	 */
	memset(block,0xff,sizeof(block));
	/* mark the block allocated and returned by this function */
	sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN;
903
	ret = STORAGE_put_big_block(str,bigblocknr,block);
904
	assert(ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
905

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

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


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

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

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

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

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

1053 1054
/* --- IStream16 implementation */

1055 1056
typedef struct
{
1057
        IStream16                       IStream16_iface;
1058
        LONG                            ref;
1059 1060 1061 1062 1063
        /* IStream16 fields */
        SEGPTR                          thisptr; /* pointer to this struct as segmented */
        struct storage_pps_entry        stde;
        int                             ppsent;
        ULARGE_INTEGER                  offset;
1064
	stream_access16			str;
1065
} IStream16Impl;
1066

1067 1068 1069 1070 1071
static inline IStream16Impl *impl_from_IStream16(IStream16 *iface)
{
        return CONTAINING_RECORD(iface, IStream16Impl, IStream16_iface);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1072
/******************************************************************************
1073
 *		IStream16_QueryInterface	[STORAGE.518]
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
 */
1075 1076 1077
HRESULT CDECL IStream16_fnQueryInterface(IStream16 *iface, REFIID refiid, void **obj)
{
	IStream16Impl *This = impl_from_IStream16(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 1091 1092
ULONG CDECL IStream16_fnAddRef(IStream16 *iface)
{
	IStream16Impl *This = impl_from_IStream16(iface);
1093
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1094 1095
}

1096 1097 1098 1099
static void
_ilockbytes16_addref(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
1100

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

static void
_ilockbytes16_release(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
1118

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

static void
_ilockbytes16_flush(SEGPTR lockbytes) {
    DWORD args[1];
    HRESULT hres;
1136

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

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

	if (This->str.hf)
	    FlushFileBuffers(This->str.hf);
	else
	    _ilockbytes16_flush(This->str.lockbytes);
1162
        ref = InterlockedDecrement(&This->ref);
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
	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
1173 1174
}

1175 1176 1177 1178 1179 1180
/******************************************************************************
 *		IStream16_Seek	[STORAGE.523]
 *
 * FIXME
 *    Does not handle 64 bits
 */
1181
HRESULT CDECL IStream16_fnSeek(IStream16 *iface, LARGE_INTEGER offset, DWORD whence,
1182
                               ULARGE_INTEGER *newpos)
1183
{
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
    IStream16Impl *This = impl_from_IStream16(iface);
    TRACE_(relay)("(%p)->([%d.%d],%d,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);

    switch (whence) {
    case STREAM_SEEK_SET:
        This->offset.QuadPart = offset.QuadPart;
        break;
    case STREAM_SEEK_CUR:
        if ((offset.QuadPart < 0 && -offset.QuadPart > This->offset.QuadPart) ||
            (offset.QuadPart > 0 && -offset.QuadPart <= This->offset.QuadPart))
            return STG_E_INVALIDFUNCTION;
        This->offset.QuadPart += offset.QuadPart;
        break;
    case STREAM_SEEK_END:
        if (-offset.QuadPart > This->stde.pps_size)
            return STG_E_INVALIDFUNCTION;

        This->offset.QuadPart = This->stde.pps_size + offset.QuadPart;
        break;
    }

    if (This->offset.QuadPart>This->stde.pps_size)
        This->offset.QuadPart=This->stde.pps_size;
    if (newpos) *newpos = This->offset;
    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1209 1210
}

1211 1212 1213
/******************************************************************************
 *		IStream16_Read	[STORAGE.521]
 */
1214 1215 1216
HRESULT CDECL IStream16_fnRead(IStream16 *iface, void *pv, ULONG cb, ULONG *pcbRead)
{
	IStream16Impl *This = impl_from_IStream16(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1217 1218 1219
	BYTE	block[BIGSIZE];
	ULONG	*bytesread=pcbRead,xxread;
	int	blocknr;
Marcus Meissner's avatar
Marcus Meissner committed
1220
	LPBYTE	pbv = pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1221

1222
	TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbRead);
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225
	if (!pcbRead) bytesread=&xxread;
	*bytesread = 0;

1226 1227
	if (cb>This->stde.pps_size-This->offset.u.LowPart)
		cb=This->stde.pps_size-This->offset.u.LowPart;
1228
	if (This->stde.pps_size < 0x1000) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1229
		/* use small block reader */
1230
		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
1231
		while (cb) {
1232
			unsigned int cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1233

1234
			if (!STORAGE_get_small_block(&This->str,blocknr,block)) {
1235
			   WARN("small block read failed!!!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1236 1237
				return E_FAIL;
			}
1238
			cc = cb;
1239 1240
			if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)))
				cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
Marcus Meissner's avatar
Marcus Meissner committed
1241
			memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc);
1242
			This->offset.u.LowPart+=cc;
Marcus Meissner's avatar
Marcus Meissner committed
1243
			pbv+=cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1244 1245
			*bytesread+=cc;
			cb-=cc;
1246
			blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1247 1248 1249
		}
	} else {
		/* use big block reader */
1250
		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
1251
		while (cb) {
1252
			unsigned int cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1253

1254
			if (!STORAGE_get_big_block(&This->str,blocknr,block)) {
1255
				WARN("big block read failed!!!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1256 1257
				return E_FAIL;
			}
1258
			cc = cb;
1259 1260
			if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)))
				cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
Marcus Meissner's avatar
Marcus Meissner committed
1261
			memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc);
1262
			This->offset.u.LowPart+=cc;
Marcus Meissner's avatar
Marcus Meissner committed
1263
			pbv+=cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265
			*bytesread+=cc;
			cb-=cc;
1266
			blocknr=STORAGE_get_next_big_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1267 1268
		}
	}
1269
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1270 1271
}

1272 1273 1274
/******************************************************************************
 *		IStream16_Write	[STORAGE.522]
 */
1275 1276 1277
HRESULT CDECL IStream16_fnWrite(IStream16 *iface, const void *pv, ULONG cb, ULONG *pcbWrite)
{
	IStream16Impl *This = impl_from_IStream16(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1278 1279 1280
	BYTE	block[BIGSIZE];
	ULONG	*byteswritten=pcbWrite,xxwritten;
	int	oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1281
	const BYTE* pbv = pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1282 1283 1284 1285

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

1286
	TRACE_(relay)("(%p)->(%p,%d,%p)\n",This,pv,cb,pcbWrite);
Alexandre Julliard's avatar
Alexandre Julliard committed
1287
	/* do we need to junk some blocks? */
1288
	newsize	= This->offset.u.LowPart+cb;
1289
	oldsize	= This->stde.pps_size;
Alexandre Julliard's avatar
Alexandre Julliard committed
1290 1291 1292
	if (newsize < oldsize) {
		if (oldsize < 0x1000) {
			/* only small blocks */
1293
			blocknr=STORAGE_get_nth_next_small_blocknr(&This->str,This->stde.pps_sb,newsize/SMALLSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1294 1295 1296 1297

			assert(blocknr>=0);

			/* will set the rest of the chain to 'free' */
1298
			if (!STORAGE_set_small_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1299 1300 1301
				return E_FAIL;
		} else {
			if (newsize >= 0x1000) {
1302
				blocknr=STORAGE_get_nth_next_big_blocknr(&This->str,This->stde.pps_sb,newsize/BIGSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1303 1304 1305
				assert(blocknr>=0);

				/* will set the rest of the chain to 'free' */
1306
				if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1307 1308
					return E_FAIL;
			} else {
1309
				/* Migrate large blocks to small blocks
Alexandre Julliard's avatar
Alexandre Julliard committed
1310 1311 1312
				 * (we just migrate newsize bytes)
				 */
				LPBYTE	curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE);
1313 1314
				HRESULT r = E_FAIL;

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

	if (newsize > oldsize) {
		if (oldsize >= 0x1000) {
			/* should return the block right before the 'endofchain' */
1366
			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
1367 1368 1369
			assert(blocknr>=0);
			lastblocknr	= blocknr;
			for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) {
1370
				blocknr = STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372
				if (blocknr<0)
					return E_FAIL;
1373
				if (!STORAGE_set_big_chain(&This->str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1374 1375 1376
					return E_FAIL;
				lastblocknr = blocknr;
			}
1377
			if (!STORAGE_set_big_chain(&This->str,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1378 1379 1380 1381 1382
				return E_FAIL;
		} else {
			if (newsize < 0x1000) {
				/* find startblock */
				if (!oldsize)
1383
					This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1384
				else
1385
					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
1386 1387 1388 1389 1390 1391
				if (blocknr<0)
					return E_FAIL;

				/* allocate required new small blocks */
				lastblocknr = blocknr;
				for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) {
1392
					blocknr = STORAGE_get_free_small_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1393 1394
					if (blocknr<0)
						return E_FAIL;
1395
					if (!STORAGE_set_small_chain(&This->str,lastblocknr,blocknr))
Alexandre Julliard's avatar
Alexandre Julliard committed
1396 1397 1398 1399
						return E_FAIL;
					lastblocknr = blocknr;
				}
				/* and terminate the chain */
1400
				if (!STORAGE_set_small_chain(&This->str,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1401 1402 1403 1404
					return E_FAIL;
			} else {
				if (!oldsize) {
					/* no single block allocated yet */
1405
					blocknr=STORAGE_get_free_big_blocknr(&This->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1406 1407
					if (blocknr<0)
						return E_FAIL;
1408
					This->stde.pps_sb = blocknr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1409 1410 1411
				} else {
					/* Migrate small blocks to big blocks */
					LPBYTE	curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE);
1412 1413
					HRESULT r = E_FAIL;

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

	/* There are just some cases where we didn't modify it, we write it out
1477
	 * every time
Alexandre Julliard's avatar
Alexandre Julliard committed
1478
	 */
1479
	if (!STORAGE_put_pps_entry(&This->str,This->ppsent,&(This->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1480 1481 1482
		return E_FAIL;

	/* finally the write pass */
1483
	if (This->stde.pps_size < 0x1000) {
1484
		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
1485 1486 1487 1488
		assert(blocknr>=0);
		while (cb>0) {
			/* we ensured that it is allocated above */
			assert(blocknr>=0);
1489
			/* Read old block every time, since we can have
Alexandre Julliard's avatar
Alexandre Julliard committed
1490 1491
			 * overlapping data at START and END of the write
			 */
1492
			if (!STORAGE_get_small_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1493 1494
				return E_FAIL;

1495
			cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1496 1497
			if (cc>cb)
				cc=cb;
1498
			memcpy(	((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)),
Marcus Meissner's avatar
Marcus Meissner committed
1499
				pbv+curoffset,
Alexandre Julliard's avatar
Alexandre Julliard committed
1500 1501
				cc
			);
1502
			if (!STORAGE_put_small_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1503 1504 1505
				return E_FAIL;
			cb			-= cc;
			curoffset		+= cc;
Marcus Meissner's avatar
Marcus Meissner committed
1506
			pbv			+= cc;
1507
			This->offset.u.LowPart	+= cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1508
			*byteswritten		+= cc;
1509
			blocknr = STORAGE_get_next_small_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511
		}
	} else {
1512
		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
1513 1514 1515 1516
		assert(blocknr>=0);
		while (cb>0) {
			/* we ensured that it is allocated above, so it better is */
			assert(blocknr>=0);
1517
			/* read old block every time, since we can have
Alexandre Julliard's avatar
Alexandre Julliard committed
1518 1519
			 * overlapping data at START and END of the write
			 */
1520
			if (!STORAGE_get_big_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1521 1522
				return E_FAIL;

1523
			cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1524 1525
			if (cc>cb)
				cc=cb;
1526
			memcpy(	((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)),
Marcus Meissner's avatar
Marcus Meissner committed
1527
				pbv+curoffset,
Alexandre Julliard's avatar
Alexandre Julliard committed
1528 1529
				cc
			);
1530
			if (!STORAGE_put_big_block(&This->str,blocknr,block))
Alexandre Julliard's avatar
Alexandre Julliard committed
1531 1532 1533
				return E_FAIL;
			cb			-= cc;
			curoffset		+= cc;
Marcus Meissner's avatar
Marcus Meissner committed
1534
			pbv			+= cc;
1535
			This->offset.u.LowPart	+= cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1536
			*byteswritten		+= cc;
1537
			blocknr = STORAGE_get_next_big_blocknr(&This->str,blocknr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1538 1539
		}
	}
1540
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1541 1542
}

1543 1544 1545
/******************************************************************************
 *		_create_istream16	[Internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1546
static void _create_istream16(LPSTREAM16 *str) {
1547
	IStream16Impl*	lpst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1548

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

1601 1602 1603 1604
static inline IStorage16Impl *impl_from_IStorage16(IStorage16 *iface)
{
        return CONTAINING_RECORD(iface, IStorage16Impl, IStorage16_iface);
}
1605

Alexandre Julliard's avatar
Alexandre Julliard committed
1606
/******************************************************************************
1607
 *		IStorage16_QueryInterface	[STORAGE.500]
Alexandre Julliard's avatar
Alexandre Julliard committed
1608
 */
1609 1610 1611
HRESULT CDECL IStorage16_fnQueryInterface(IStorage16 *iface, REFIID refiid, void **obj)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1612

1613
	TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1614 1615

	if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1616
		*obj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
1617 1618 1619 1620 1621
		return 0;
	}
	return OLE_E_ENUM_NOMORE;
}

Matthew Becker's avatar
Matthew Becker committed
1622 1623 1624
/******************************************************************************
 * IStorage16_AddRef [STORAGE.501]
 */
1625 1626 1627
ULONG CDECL IStorage16_fnAddRef(IStorage16 *iface)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1628
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1629 1630
}

Matthew Becker's avatar
Matthew Becker committed
1631 1632 1633
/******************************************************************************
 * IStorage16_Release [STORAGE.502]
 */
1634 1635 1636
ULONG CDECL IStorage16_fnRelease(IStorage16 *iface)
{
        IStorage16Impl *This = impl_from_IStorage16(iface);
1637 1638 1639 1640 1641 1642 1643 1644
        ULONG ref;
        ref = InterlockedDecrement(&This->ref);
        if (!ref)
        {
            UnMapLS( This->thisptr );
            HeapFree( GetProcessHeap(), 0, This );
        }
        return ref;
Alexandre Julliard's avatar
Alexandre Julliard committed
1645 1646
}

Matthew Becker's avatar
Matthew Becker committed
1647 1648 1649
/******************************************************************************
 * IStorage16_Stat [STORAGE.517]
 */
1650 1651 1652
HRESULT CDECL IStorage16_fnStat(IStorage16 *iface, STATSTG16 *pstatstg, DWORD grfStatFlag)
{
        IStorage16Impl *This = impl_from_IStorage16(iface);
1653 1654 1655
        DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
        LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );

1656
	TRACE("(%p)->(%p,0x%08x)\n",
1657
		This,pstatstg,grfStatFlag
Alexandre Julliard's avatar
Alexandre Julliard committed
1658
	);
1659 1660
        WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
	pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1661
	pstatstg->type = This->stde.pps_type;
1662
	pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1663 1664 1665
	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
1666 1667
	pstatstg->grfMode	= 0; /* FIXME */
	pstatstg->grfLocksSupported = 0; /* FIXME */
1668
	pstatstg->clsid		= This->stde.pps_guid;
Alexandre Julliard's avatar
Alexandre Julliard committed
1669 1670
	pstatstg->grfStateBits	= 0; /* FIXME */
	pstatstg->reserved	= 0;
1671
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1672 1673
}

1674 1675 1676
/******************************************************************************
 *		IStorage16_Commit	[STORAGE.509]
 */
1677 1678 1679
HRESULT CDECL IStorage16_fnCommit(IStorage16 *iface, DWORD commitflags)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1680
	FIXME("(%p)->(0x%08x),STUB!\n",
1681
		This,commitflags
Alexandre Julliard's avatar
Alexandre Julliard committed
1682
	);
1683
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1684 1685
}

Matthew Becker's avatar
Matthew Becker committed
1686 1687 1688
/******************************************************************************
 * IStorage16_CopyTo [STORAGE.507]
 */
1689 1690 1691 1692
HRESULT CDECL IStorage16_fnCopyTo(IStorage16 *iface, DWORD ciidExclude, const IID *rgiidExclude,
	SNB16 SNB16Exclude, IStorage16 *pstgDest)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1693
	FIXME("IStorage16(%p)->(0x%08x,%s,%p,%p),stub!\n",
1694
		This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
Alexandre Julliard's avatar
Alexandre Julliard committed
1695
	);
1696
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1697 1698 1699
}


Matthew Becker's avatar
Matthew Becker committed
1700 1701 1702
/******************************************************************************
 * IStorage16_CreateStorage [STORAGE.505]
 */
1703 1704 1705 1706
HRESULT CDECL IStorage16_fnCreateStorage(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
	DWORD dwStgFormat, DWORD reserved2, IStorage16 **ppstg)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1707
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1708 1709 1710
	int		ppsent,x;
	struct storage_pps_entry	stde;
	struct storage_header sth;
1711 1712
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1713

1714
	READ_HEADER(&This->str);
1715
	TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1716
		This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1717 1718
	);
	if (grfMode & STGM_TRANSACTED)
1719
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1720
	_create_istorage16(ppstg);
1721
	lpstg = MapSL((SEGPTR)*ppstg);
1722 1723 1724 1725 1726 1727 1728
	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
1729

1730
	ppsent=STORAGE_get_free_pps_entry(&lpstg->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1731 1732
	if (ppsent<0)
		return E_FAIL;
1733
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1734 1735
	if (stde.pps_dir==-1) {
		stde.pps_dir = ppsent;
1736
		x = This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1737
	} else {
1738
		FIXME(" use prev chain too ?\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1739
		x=stde.pps_dir;
1740
		if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1741 1742 1743
			return E_FAIL;
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1744
			if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1745 1746 1747 1748
				return E_FAIL;
		}
		stde.pps_next = ppsent;
	}
1749
	ret = STORAGE_put_pps_entry(&lpstg->str,x,&stde);
1750
	assert(ret);
1751
	nPPSEntries = STORAGE_get_pps_entry(&lpstg->str,ppsent,&(lpstg->stde));
1752
	assert(nPPSEntries == 1);
1753 1754 1755
        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
1756 1757 1758 1759 1760 1761 1762 1763
	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? */
1764
	if (!STORAGE_put_pps_entry(&lpstg->str,ppsent,&(lpstg->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1765
		return E_FAIL;
1766
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1767 1768
}

1769 1770 1771
/******************************************************************************
 *		IStorage16_CreateStream	[STORAGE.503]
 */
1772 1773 1774 1775
HRESULT CDECL IStorage16_fnCreateStream(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
	DWORD reserved1, DWORD reserved2, IStream16 **ppstm)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1776
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1777 1778
	int		ppsent,x;
	struct storage_pps_entry	stde;
1779 1780
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1781

1782
	TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1783
		This,pwcsName,grfMode,reserved1,reserved2,ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1784 1785
	);
	if (grfMode & STGM_TRANSACTED)
1786
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1787
	_create_istream16(ppstm);
1788
	lpstr = MapSL((SEGPTR)*ppstm);
1789 1790 1791 1792 1793 1794 1795
	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);
	}
1796
	lpstr->offset.u.LowPart	= 0;
1797
	lpstr->offset.u.HighPart= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1798

1799
	ppsent=STORAGE_get_free_pps_entry(&lpstr->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1800 1801
	if (ppsent<0)
		return E_FAIL;
1802
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1803
	if (stde.pps_next==-1)
1804
		x=This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1805 1806 1807
	else
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1808
			if (1!=STORAGE_get_pps_entry(&lpstr->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1809 1810 1811
				return E_FAIL;
		}
	stde.pps_next = ppsent;
1812
	ret = STORAGE_put_pps_entry(&lpstr->str,x,&stde);
1813
	assert(ret);
1814
	nPPSEntries = STORAGE_get_pps_entry(&lpstr->str,ppsent,&(lpstr->stde));
1815
	assert(nPPSEntries == 1);
1816 1817 1818
        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
1819 1820 1821 1822 1823 1824 1825
	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;
1826

Alexandre Julliard's avatar
Alexandre Julliard committed
1827
	/* FIXME: timestamps? */
1828
	if (!STORAGE_put_pps_entry(&lpstr->str,ppsent,&(lpstr->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1829
		return E_FAIL;
1830
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1831 1832
}

1833 1834 1835
/******************************************************************************
 *		IStorage16_OpenStorage	[STORAGE.506]
 */
1836 1837 1838 1839
HRESULT CDECL IStorage16_fnOpenStorage(IStorage16 *iface, LPCOLESTR16 pwcsName,
	IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1840
	IStorage16Impl *lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1841 1842 1843
	WCHAR		name[33];
	int		newpps;

1844
	TRACE("(%p)->(%s,%p,0x%08x,%p,0x%08x,%p)\n",
1845
		This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1846 1847
	);
	if (grfMode & STGM_TRANSACTED)
1848
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1849
	_create_istorage16(ppstg);
1850
	lpstg = MapSL((SEGPTR)*ppstg);
1851 1852 1853 1854 1855 1856 1857
	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);
	}
1858
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1859
	newpps = STORAGE_look_for_named_pps(&lpstg->str,This->stde.pps_dir,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860
	if (newpps==-1) {
1861
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
1862
		*ppstg = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1863 1864 1865
		return E_FAIL;
	}

1866
	if (1!=STORAGE_get_pps_entry(&lpstg->str,newpps,&(lpstg->stde))) {
1867
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
1868
		*ppstg = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1869 1870 1871
		return E_FAIL;
	}
	lpstg->ppsent		= newpps;
1872
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1873 1874
}

Matthew Becker's avatar
Matthew Becker committed
1875 1876 1877
/******************************************************************************
 * IStorage16_OpenStream [STORAGE.504]
 */
1878 1879 1880 1881
HRESULT CDECL IStorage16_fnOpenStream(IStorage16 *iface, LPCOLESTR16 pwcsName, void *reserved1,
	DWORD grfMode, DWORD reserved2, IStream16 **ppstm)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1882
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1883 1884 1885
	WCHAR		name[33];
	int		newpps;

1886
	TRACE("(%p)->(%s,%p,0x%08x,0x%08x,%p)\n",
1887
		This,pwcsName,reserved1,grfMode,reserved2,ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1888 1889
	);
	if (grfMode & STGM_TRANSACTED)
1890
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1891
	_create_istream16(ppstm);
1892
	lpstr = MapSL((SEGPTR)*ppstm);
1893 1894 1895 1896 1897 1898 1899
	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);
	}
1900
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1901
	newpps = STORAGE_look_for_named_pps(&lpstr->str,This->stde.pps_dir,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1902
	if (newpps==-1) {
1903
		IStream16_fnRelease(&lpstr->IStream16_iface);
1904
		*ppstm = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1905 1906 1907
		return E_FAIL;
	}

1908
	if (1!=STORAGE_get_pps_entry(&lpstr->str,newpps,&(lpstr->stde))) {
1909
		IStream16_fnRelease(&lpstr->IStream16_iface);
1910
		*ppstm = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1911 1912
		return E_FAIL;
	}
1913
	lpstr->offset.u.LowPart		= 0;
1914
	lpstr->offset.u.HighPart	= 0;
1915
	lpstr->ppsent			= newpps;
1916
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1917 1918
}

Matthew Becker's avatar
Matthew Becker committed
1919 1920 1921
/******************************************************************************
 * _create_istorage16 [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1922
static void _create_istorage16(LPSTORAGE16 *stg) {
1923
	IStorage16Impl*	lpst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1924

1925
	if (!stvt16.QueryInterface) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1926 1927
		HMODULE16	wp = GetModuleHandle16("STORAGE");
		if (wp>=32) {
1928
#define VTENT(xfn)  stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn);
Alexandre Julliard's avatar
Alexandre Julliard committed
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947
			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
1948
			segstvt16 = (const IStorage16Vtbl*)MapLS( &stvt16 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1949
		} else {
1950
#define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn;
Alexandre Julliard's avatar
Alexandre Julliard committed
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974
			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;
		}
	}
1975
	lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) );
1976
	lpst->IStorage16_iface.lpVtbl = segstvt16;
1977 1978
	lpst->str.hf	= NULL;
	lpst->str.lockbytes	= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1979
	lpst->ref	= 1;
1980
	lpst->thisptr	= MapLS(lpst);
Alexandre Julliard's avatar
Alexandre Julliard committed
1981 1982 1983 1984 1985 1986 1987
	*stg = (void*)lpst->thisptr;
}

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

1988
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1989
 *		StgCreateDocFileA	[STORAGE.1]
1990
 */
1991
HRESULT WINAPI StgCreateDocFile16(
Alexandre Julliard's avatar
Alexandre Julliard committed
1992 1993
	LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
) {
1994
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
1995
	int		i,ret;
1996
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1997 1998
	struct storage_pps_entry	stde;

1999
	TRACE("(%s,0x%08x,0x%08x,%p)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2000 2001 2002
		pwcsName,grfMode,reserved,ppstgOpen
	);
	_create_istorage16(ppstgOpen);
2003 2004
	hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
	if (hf==INVALID_HANDLE_VALUE) {
2005
		WARN("couldn't open file for storage:%d\n",GetLastError());
Alexandre Julliard's avatar
Alexandre Julliard committed
2006 2007
		return E_FAIL;
	}
2008
	lpstg = MapSL((SEGPTR)*ppstgOpen);
2009 2010
	lpstg->str.hf = hf;
	lpstg->str.lockbytes = 0;
Francois Gouget's avatar
Francois Gouget committed
2011
	/* FIXME: check for existence before overwriting? */
2012
	if (!STORAGE_init_storage(&lpstg->str)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2013 2014 2015 2016 2017
		CloseHandle(hf);
		return E_FAIL;
	}
	i=0;ret=0;
	while (!ret) { /* neither 1 nor <0 */
2018
		ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
Alexandre Julliard's avatar
Alexandre Julliard committed
2019 2020 2021 2022 2023 2024 2025 2026
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde	= stde;
			lpstg->ppsent	= i;
			break;
		}
		i++;
	}
	if (ret!=1) {
2027
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
2028 2029 2030
		return E_FAIL;
	}

2031
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2032 2033
}

Matthew Becker's avatar
Matthew Becker committed
2034
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2035
 * StgIsStorageFile [STORAGE.5]
Matthew Becker's avatar
Matthew Becker committed
2036
 */
2037
HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
2038 2039
	UNICODE_STRING strW;
	HRESULT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2040

2041 2042 2043
	RtlCreateUnicodeStringFromAsciiz(&strW, fn);
	ret = StgIsStorageFile( strW.Buffer );
	RtlFreeUnicodeString( &strW );
Alexandre Julliard's avatar
Alexandre Julliard committed
2044

2045 2046
	return ret;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2047

Matthew Becker's avatar
Matthew Becker committed
2048
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2049
 * StgOpenStorage [STORAGE.3]
Matthew Becker's avatar
Matthew Becker committed
2050
 */
2051
HRESULT WINAPI StgOpenStorage16(
2052
	LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
Alexandre Julliard's avatar
Alexandre Julliard committed
2053 2054
	SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
) {
2055
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2056
	int		ret,i;
2057
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2058 2059
	struct storage_pps_entry	stde;

2060
	TRACE("(%s,%p,0x%08x,%p,%d,%p)\n",
2061
              pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen
Alexandre Julliard's avatar
Alexandre Julliard committed
2062 2063
	);
	_create_istorage16(ppstgOpen);
2064
	hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
2065
	if (hf==INVALID_HANDLE_VALUE) {
2066
		WARN("Couldn't open file for storage\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2067 2068
		return E_FAIL;
	}
2069
	lpstg = MapSL((SEGPTR)*ppstgOpen);
2070
	lpstg->str.hf = hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2071 2072 2073

	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
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde=stde;
			break;
		}
		i++;
	}
	if (ret!=1) {
2082
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
2083 2084
		return E_FAIL;
	}
2085
	return S_OK;
2086

Alexandre Julliard's avatar
Alexandre Julliard committed
2087
}
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098

/******************************************************************************
 *              StgIsStorageILockBytes        [STORAGE.6]
 *
 * Determines if the ILockBytes contains a storage object.
 */
HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt)
{
  DWORD args[6];
  HRESULT hres;
  HANDLE16 hsig;
2099

2100 2101
  args[0] = (DWORD)plkbyt;	/* iface */
  args[1] = args[2] = 0;	/* ULARGE_INTEGER offset */
2102
  args[3] = WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
2103 2104 2105
  args[4] = 8;
  args[5] = 0;

2106
  if (!WOWCallback16Ex(
2107
      (DWORD)((const ILockBytes16Vtbl*)MapSL(
2108
                  (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl)
2109 2110 2111 2112 2113 2114
      )->ReadAt,
      WCB16_PASCAL,
      6*sizeof(DWORD),
      (LPVOID)args,
      (LPDWORD)&hres
  )) {
2115
      ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %x\n",hres);
2116 2117 2118
      return hres;
  }
  if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) {
2119
    WOWGlobalUnlockFree16(args[3]);
2120 2121
    return S_OK;
  }
2122
  WOWGlobalUnlockFree16(args[3]);
2123 2124 2125 2126 2127
  return S_FALSE;
}

/******************************************************************************
 *    StgOpenStorageOnILockBytes    [STORAGE.4]
2128 2129 2130
 *
 * PARAMS
 *  plkbyt  FIXME: Should probably be an ILockBytes16 *.
2131 2132
 */
HRESULT WINAPI StgOpenStorageOnILockBytes16(
2133
	SEGPTR plkbyt,
2134 2135 2136 2137 2138
	IStorage16 *pstgPriority,
	DWORD grfMode,
	SNB16 snbExclude,
	DWORD reserved,
	IStorage16 **ppstgOpen)
2139
{
2140 2141 2142
	IStorage16Impl*	lpstg;
	int i,ret;
	struct storage_pps_entry	stde;
2143

2144
	FIXME("(%x, %p, 0x%08x, %d, %x, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen);
2145 2146
	if ((plkbyt == 0) || (ppstgOpen == 0))
		return STG_E_INVALIDPOINTER;
2147

2148
	*ppstgOpen = 0;
2149

2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
	_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) {
2164
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
2165 2166 2167 2168
		return E_FAIL;
	}
	return S_OK;
}