storage.c 64.7 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 36

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

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


Alexandre Julliard's avatar
Alexandre Julliard committed
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=-1;
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 1182 1183 1184
HRESULT CDECL IStream16_fnSeek(IStream16 *iface, LARGE_INTEGER offset, DWORD whence,
	ULARGE_INTEGER *newpos)
{
	IStream16Impl *This = impl_from_IStream16(iface);
1185
	TRACE_(relay)("(%p)->([%d.%d],%d,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos);
Alexandre Julliard's avatar
Alexandre Julliard committed
1186 1187 1188 1189 1190 1191 1192

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

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

1222 1223 1224
/******************************************************************************
 *		IStream16_Read	[STORAGE.521]
 */
1225 1226 1227
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
1228 1229 1230
	BYTE	block[BIGSIZE];
	ULONG	*bytesread=pcbRead,xxread;
	int	blocknr;
Marcus Meissner's avatar
Marcus Meissner committed
1231
	LPBYTE	pbv = pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1232

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

1237 1238
	if (cb>This->stde.pps_size-This->offset.u.LowPart)
		cb=This->stde.pps_size-This->offset.u.LowPart;
1239
	if (This->stde.pps_size < 0x1000) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1240
		/* use small block reader */
1241
		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
1242
		while (cb) {
1243
			unsigned int cc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1244

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

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

1283 1284 1285
/******************************************************************************
 *		IStream16_Write	[STORAGE.522]
 */
1286 1287 1288
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
1289 1290 1291
	BYTE	block[BIGSIZE];
	ULONG	*byteswritten=pcbWrite,xxwritten;
	int	oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc;
1292
	const BYTE* pbv = pv;
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294 1295 1296

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

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

			assert(blocknr>=0);

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

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

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

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

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

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

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

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

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

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

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

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

1612 1613 1614 1615
static inline IStorage16Impl *impl_from_IStorage16(IStorage16 *iface)
{
        return CONTAINING_RECORD(iface, IStorage16Impl, IStorage16_iface);
}
1616

Alexandre Julliard's avatar
Alexandre Julliard committed
1617
/******************************************************************************
1618
 *		IStorage16_QueryInterface	[STORAGE.500]
Alexandre Julliard's avatar
Alexandre Julliard committed
1619
 */
1620 1621 1622
HRESULT CDECL IStorage16_fnQueryInterface(IStorage16 *iface, REFIID refiid, void **obj)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1623

1624
	TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1625 1626

	if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) {
1627
		*obj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
1628 1629 1630 1631 1632
		return 0;
	}
	return OLE_E_ENUM_NOMORE;
}

Matthew Becker's avatar
Matthew Becker committed
1633 1634 1635
/******************************************************************************
 * IStorage16_AddRef [STORAGE.501]
 */
1636 1637 1638
ULONG CDECL IStorage16_fnAddRef(IStorage16 *iface)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1639
	return InterlockedIncrement(&This->ref);
Alexandre Julliard's avatar
Alexandre Julliard committed
1640 1641
}

Matthew Becker's avatar
Matthew Becker committed
1642 1643 1644
/******************************************************************************
 * IStorage16_Release [STORAGE.502]
 */
1645 1646 1647
ULONG CDECL IStorage16_fnRelease(IStorage16 *iface)
{
        IStorage16Impl *This = impl_from_IStorage16(iface);
1648 1649 1650 1651 1652 1653 1654 1655
        ULONG ref;
        ref = InterlockedDecrement(&This->ref);
        if (!ref)
        {
            UnMapLS( This->thisptr );
            HeapFree( GetProcessHeap(), 0, This );
        }
        return ref;
Alexandre Julliard's avatar
Alexandre Julliard committed
1656 1657
}

Matthew Becker's avatar
Matthew Becker committed
1658 1659 1660
/******************************************************************************
 * IStorage16_Stat [STORAGE.517]
 */
1661 1662 1663
HRESULT CDECL IStorage16_fnStat(IStorage16 *iface, STATSTG16 *pstatstg, DWORD grfStatFlag)
{
        IStorage16Impl *This = impl_from_IStorage16(iface);
1664 1665 1666
        DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL );
        LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len );

1667
	TRACE("(%p)->(%p,0x%08x)\n",
1668
		This,pstatstg,grfStatFlag
Alexandre Julliard's avatar
Alexandre Julliard committed
1669
	);
1670 1671
        WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL );
	pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA );
1672
	pstatstg->type = This->stde.pps_type;
1673
	pstatstg->cbSize.u.LowPart = This->stde.pps_size;
1674 1675 1676
	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
1677 1678
	pstatstg->grfMode	= 0; /* FIXME */
	pstatstg->grfLocksSupported = 0; /* FIXME */
1679
	pstatstg->clsid		= This->stde.pps_guid;
Alexandre Julliard's avatar
Alexandre Julliard committed
1680 1681
	pstatstg->grfStateBits	= 0; /* FIXME */
	pstatstg->reserved	= 0;
1682
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1683 1684
}

1685 1686 1687
/******************************************************************************
 *		IStorage16_Commit	[STORAGE.509]
 */
1688 1689 1690
HRESULT CDECL IStorage16_fnCommit(IStorage16 *iface, DWORD commitflags)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1691
	FIXME("(%p)->(0x%08x),STUB!\n",
1692
		This,commitflags
Alexandre Julliard's avatar
Alexandre Julliard committed
1693
	);
1694
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1695 1696
}

Matthew Becker's avatar
Matthew Becker committed
1697 1698 1699
/******************************************************************************
 * IStorage16_CopyTo [STORAGE.507]
 */
1700 1701 1702 1703
HRESULT CDECL IStorage16_fnCopyTo(IStorage16 *iface, DWORD ciidExclude, const IID *rgiidExclude,
	SNB16 SNB16Exclude, IStorage16 *pstgDest)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1704
	FIXME("IStorage16(%p)->(0x%08x,%s,%p,%p),stub!\n",
1705
		This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest
Alexandre Julliard's avatar
Alexandre Julliard committed
1706
	);
1707
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1708 1709 1710
}


Matthew Becker's avatar
Matthew Becker committed
1711 1712 1713
/******************************************************************************
 * IStorage16_CreateStorage [STORAGE.505]
 */
1714 1715 1716 1717
HRESULT CDECL IStorage16_fnCreateStorage(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
	DWORD dwStgFormat, DWORD reserved2, IStorage16 **ppstg)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1718
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1719 1720 1721
	int		ppsent,x;
	struct storage_pps_entry	stde;
	struct storage_header sth;
1722 1723
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1724

1725
	READ_HEADER(&This->str);
1726
	TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1727
		This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1728 1729
	);
	if (grfMode & STGM_TRANSACTED)
1730
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1731
	_create_istorage16(ppstg);
1732
	lpstg = MapSL((SEGPTR)*ppstg);
1733 1734 1735 1736 1737 1738 1739
	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
1740

1741
	ppsent=STORAGE_get_free_pps_entry(&lpstg->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1742 1743
	if (ppsent<0)
		return E_FAIL;
1744
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1745 1746
	if (stde.pps_dir==-1) {
		stde.pps_dir = ppsent;
1747
		x = This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1748
	} else {
1749
		FIXME(" use prev chain too ?\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1750
		x=stde.pps_dir;
1751
		if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1752 1753 1754
			return E_FAIL;
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1755
			if (1!=STORAGE_get_pps_entry(&lpstg->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1756 1757 1758 1759
				return E_FAIL;
		}
		stde.pps_next = ppsent;
	}
1760
	ret = STORAGE_put_pps_entry(&lpstg->str,x,&stde);
1761
	assert(ret);
1762
	nPPSEntries = STORAGE_get_pps_entry(&lpstg->str,ppsent,&(lpstg->stde));
1763
	assert(nPPSEntries == 1);
1764 1765 1766
        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
1767 1768 1769 1770 1771 1772 1773 1774
	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? */
1775
	if (!STORAGE_put_pps_entry(&lpstg->str,ppsent,&(lpstg->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1776
		return E_FAIL;
1777
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1778 1779
}

1780 1781 1782
/******************************************************************************
 *		IStorage16_CreateStream	[STORAGE.503]
 */
1783 1784 1785 1786
HRESULT CDECL IStorage16_fnCreateStream(IStorage16 *iface, LPCOLESTR16 pwcsName, DWORD grfMode,
	DWORD reserved1, DWORD reserved2, IStream16 **ppstm)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1787
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1788 1789
	int		ppsent,x;
	struct storage_pps_entry	stde;
1790 1791
	BOOL ret;
	int	 nPPSEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
1792

1793
	TRACE("(%p)->(%s,0x%08x,0x%08x,0x%08x,%p)\n",
1794
		This,pwcsName,grfMode,reserved1,reserved2,ppstm
Alexandre Julliard's avatar
Alexandre Julliard committed
1795 1796
	);
	if (grfMode & STGM_TRANSACTED)
1797
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1798
	_create_istream16(ppstm);
1799
	lpstr = MapSL((SEGPTR)*ppstm);
1800 1801 1802 1803 1804 1805 1806
	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);
	}
1807
	lpstr->offset.u.LowPart	= 0;
1808
	lpstr->offset.u.HighPart= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1809

1810
	ppsent=STORAGE_get_free_pps_entry(&lpstr->str);
Alexandre Julliard's avatar
Alexandre Julliard committed
1811 1812
	if (ppsent<0)
		return E_FAIL;
1813
	stde=This->stde;
Alexandre Julliard's avatar
Alexandre Julliard committed
1814
	if (stde.pps_next==-1)
1815
		x=This->ppsent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1816 1817 1818
	else
		while (stde.pps_next!=-1) {
			x=stde.pps_next;
1819
			if (1!=STORAGE_get_pps_entry(&lpstr->str,x,&stde))
Alexandre Julliard's avatar
Alexandre Julliard committed
1820 1821 1822
				return E_FAIL;
		}
	stde.pps_next = ppsent;
1823
	ret = STORAGE_put_pps_entry(&lpstr->str,x,&stde);
1824
	assert(ret);
1825
	nPPSEntries = STORAGE_get_pps_entry(&lpstr->str,ppsent,&(lpstr->stde));
1826
	assert(nPPSEntries == 1);
1827 1828 1829
        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
1830 1831 1832 1833 1834 1835 1836
	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;
1837

Alexandre Julliard's avatar
Alexandre Julliard committed
1838
	/* FIXME: timestamps? */
1839
	if (!STORAGE_put_pps_entry(&lpstr->str,ppsent,&(lpstr->stde)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1840
		return E_FAIL;
1841
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1842 1843
}

1844 1845 1846
/******************************************************************************
 *		IStorage16_OpenStorage	[STORAGE.506]
 */
1847 1848 1849 1850
HRESULT CDECL IStorage16_fnOpenStorage(IStorage16 *iface, LPCOLESTR16 pwcsName,
	IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1851
	IStream16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
1852 1853 1854
	WCHAR		name[33];
	int		newpps;

1855
	TRACE("(%p)->(%s,%p,0x%08x,%p,0x%08x,%p)\n",
1856
		This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg
Alexandre Julliard's avatar
Alexandre Julliard committed
1857 1858
	);
	if (grfMode & STGM_TRANSACTED)
1859
		FIXME("We do not support transacted Compound Storage. Using direct mode.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1860
	_create_istorage16(ppstg);
1861
	lpstg = MapSL((SEGPTR)*ppstg);
1862 1863 1864 1865 1866 1867 1868
	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);
	}
1869
        MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR));
1870
	newpps = STORAGE_look_for_named_pps(&lpstg->str,This->stde.pps_dir,name);
Alexandre Julliard's avatar
Alexandre Julliard committed
1871
	if (newpps==-1) {
1872
		IStream16_fnRelease(&lpstg->IStream16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1873 1874 1875
		return E_FAIL;
	}

1876
	if (1!=STORAGE_get_pps_entry(&lpstg->str,newpps,&(lpstg->stde))) {
1877
		IStream16_fnRelease(&lpstg->IStream16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1878 1879 1880
		return E_FAIL;
	}
	lpstg->ppsent		= newpps;
1881
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1882 1883
}

Matthew Becker's avatar
Matthew Becker committed
1884 1885 1886
/******************************************************************************
 * IStorage16_OpenStream [STORAGE.504]
 */
1887 1888 1889 1890
HRESULT CDECL IStorage16_fnOpenStream(IStorage16 *iface, LPCOLESTR16 pwcsName, void *reserved1,
	DWORD grfMode, DWORD reserved2, IStream16 **ppstm)
{
	IStorage16Impl *This = impl_from_IStorage16(iface);
1891
	IStream16Impl*	lpstr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1892 1893 1894
	WCHAR		name[33];
	int		newpps;

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

1916
	if (1!=STORAGE_get_pps_entry(&lpstr->str,newpps,&(lpstr->stde))) {
1917
		IStream16_fnRelease(&lpstr->IStream16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
1918 1919
		return E_FAIL;
	}
1920
	lpstr->offset.u.LowPart		= 0;
1921
	lpstr->offset.u.HighPart	= 0;
1922
	lpstr->ppsent			= newpps;
1923
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1924 1925
}

Matthew Becker's avatar
Matthew Becker committed
1926 1927 1928
/******************************************************************************
 * _create_istorage16 [INTERNAL]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1929
static void _create_istorage16(LPSTORAGE16 *stg) {
1930
	IStorage16Impl*	lpst;
Alexandre Julliard's avatar
Alexandre Julliard committed
1931

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

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

1995
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1996
 *		StgCreateDocFileA	[STORAGE.1]
1997
 */
1998
HRESULT WINAPI StgCreateDocFile16(
Alexandre Julliard's avatar
Alexandre Julliard committed
1999 2000
	LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen
) {
2001
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2002
	int		i,ret;
2003
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2004 2005
	struct storage_pps_entry	stde;

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

2038
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2039 2040
}

Matthew Becker's avatar
Matthew Becker committed
2041
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2042
 * StgIsStorageFile [STORAGE.5]
Matthew Becker's avatar
Matthew Becker committed
2043
 */
2044
HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
2045 2046
	UNICODE_STRING strW;
	HRESULT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2047

2048 2049 2050
	RtlCreateUnicodeStringFromAsciiz(&strW, fn);
	ret = StgIsStorageFile( strW.Buffer );
	RtlFreeUnicodeString( &strW );
Alexandre Julliard's avatar
Alexandre Julliard committed
2051

2052 2053
	return ret;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2054

Matthew Becker's avatar
Matthew Becker committed
2055
/******************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
2056
 * StgOpenStorage [STORAGE.3]
Matthew Becker's avatar
Matthew Becker committed
2057
 */
2058
HRESULT WINAPI StgOpenStorage16(
2059
	LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode,
Alexandre Julliard's avatar
Alexandre Julliard committed
2060 2061
	SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen
) {
2062
	HANDLE		hf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2063
	int		ret,i;
2064
	IStorage16Impl*	lpstg;
Alexandre Julliard's avatar
Alexandre Julliard committed
2065 2066
	struct storage_pps_entry	stde;

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

	i=0;ret=0;
	while (!ret) { /* neither 1 nor <0 */
2081
		ret=STORAGE_get_pps_entry(&lpstg->str,i,&stde);
Alexandre Julliard's avatar
Alexandre Julliard committed
2082 2083 2084 2085 2086 2087 2088
		if ((ret==1) && (stde.pps_type==5)) {
			lpstg->stde=stde;
			break;
		}
		i++;
	}
	if (ret!=1) {
2089
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
2090 2091
		return E_FAIL;
	}
2092
	return S_OK;
2093

Alexandre Julliard's avatar
Alexandre Julliard committed
2094
}
2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105

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

2107 2108
  args[0] = (DWORD)plkbyt;	/* iface */
  args[1] = args[2] = 0;	/* ULARGE_INTEGER offset */
2109
  args[3] = WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */
2110 2111 2112
  args[4] = 8;
  args[5] = 0;

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

/******************************************************************************
 *    StgOpenStorageOnILockBytes    [STORAGE.4]
2135 2136 2137
 *
 * PARAMS
 *  plkbyt  FIXME: Should probably be an ILockBytes16 *.
2138 2139
 */
HRESULT WINAPI StgOpenStorageOnILockBytes16(
2140
	SEGPTR plkbyt,
2141 2142 2143 2144 2145
	IStorage16 *pstgPriority,
	DWORD grfMode,
	SNB16 snbExclude,
	DWORD reserved,
	IStorage16 **ppstgOpen)
2146
{
2147 2148 2149
	IStorage16Impl*	lpstg;
	int i,ret;
	struct storage_pps_entry	stde;
2150

2151
	FIXME("(%x, %p, 0x%08x, %d, %x, %p)\n", plkbyt, pstgPriority, grfMode, (int)snbExclude, reserved, ppstgOpen);
2152 2153
	if ((plkbyt == 0) || (ppstgOpen == 0))
		return STG_E_INVALIDPOINTER;
2154

2155
	*ppstgOpen = 0;
2156

2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
	_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) {
2171
		IStorage16_fnRelease(&lpstg->IStorage16_iface);
2172 2173 2174 2175
		return E_FAIL;
	}
	return S_OK;
}