//---------------------------------------------------------------------------
/*
	TVP2 ( T Visual Presenter 2 )  A script authoring tool
	Copyright (C) 2000 W.Dee <dee@kikyou.info> and contributors

	See details of license at "license.txt"
*/
//---------------------------------------------------------------------------
// XP3 virtual file system support
//---------------------------------------------------------------------------

#ifndef XP3ArchiveH
#define XP3ArchiveH


#include "StorageIntf.h"



/*[*/
//---------------------------------------------------------------------------
// Extraction filter related
//---------------------------------------------------------------------------
#pragma pack(push, 4)
struct tTVPXP3ExtractionFilterInfo
{
	const tjs_uint SizeOfSelf; // structure size of tTVPXP3ExtractionFilterInfo itself
	const tjs_uint64 Offset; // offset of the buffer data in uncompressed stream position
	void * Buffer; // target data buffer
	const tjs_uint BufferSize; // buffer size in bytes pointed by "Buffer"
	const tjs_uint32 FileHash; // hash value of the file (since inteface v2)

	tTVPXP3ExtractionFilterInfo(tjs_uint64 offset, void *buffer,
		tjs_uint buffersize, tjs_uint32 filehash) :
			Offset(offset), Buffer(buffer), BufferSize(buffersize),
			FileHash(filehash),
			SizeOfSelf(sizeof(tTVPXP3ExtractionFilterInfo)) {;}
};
#pragma pack(pop)

#ifndef TVP_tTVPXP3ArchiveExtractionFilter_CONVENTION
	#ifdef _WIN32
		#define	TVP_tTVPXP3ArchiveExtractionFilter_CONVENTION _stdcall
	#else
		#define TVP_tTVPXP3ArchiveExtractionFilter_CONVENTION
	#endif
#endif
	// TVP_tTVPXP3ArchiveExtractionFilter_CONV is _stdcall on win32 platforms,
	// for backward application compatibility.

typedef void (TVP_tTVPXP3ArchiveExtractionFilter_CONVENTION *
	tTVPXP3ArchiveExtractionFilter)(tTVPXP3ExtractionFilterInfo *info);


/*]*/
//---------------------------------------------------------------------------
TJS_EXP_FUNC_DEF(void, TVPSetXP3ArchiveExtractionFilter, (tTVPXP3ArchiveExtractionFilter filter));
//---------------------------------------------------------------------------





//---------------------------------------------------------------------------
// tTVPXP3Archive  : XP3 ( TVP's native archive format ) Implmentation
//---------------------------------------------------------------------------
#define TVP_XP3_INDEX_ENCODE_METHOD_MASK 0x07
#define TVP_XP3_INDEX_ENCODE_RAW      0
#define TVP_XP3_INDEX_ENCODE_ZLIB     1

#define TVP_XP3_INDEX_CONTINUE   0x80

#define TVP_XP3_FILE_PROTECTED (1<<31)

#define TVP_XP3_SEGM_ENCODE_METHOD_MASK  0x07
#define TVP_XP3_SEGM_ENCODE_RAW       0
#define TVP_XP3_SEGM_ENCODE_ZLIB      1

//---------------------------------------------------------------------------
extern bool TVPIsXP3Archive(const ttstr &name); // check XP3 archive
extern void TVPClearXP3SegmentCache(); // clear XP3 segment cache
//---------------------------------------------------------------------------
struct tTVPXP3ArchiveSegment
{
	tjs_uint64 Start;  // start position in archive storage
	tjs_uint64 Offset; // offset in in-archive storage (in uncompressed offset)
	tjs_uint64 OrgSize; // original segment (uncompressed) size
	tjs_uint64 ArcSize; // in-archive segment (compressed) size
	bool IsCompressed; // is compressed ?
};
//---------------------------------------------------------------------------
class tTVPXP3Archive : public tTVPArchive
{
	ttstr Name;

	struct tArchiveItem
	{
		ttstr Name;
		tjs_uint32 FileHash;
		tjs_uint64 OrgSize; // original ( uncompressed ) size
		tjs_uint64 ArcSize; // in-archive size
		std::vector<tTVPXP3ArchiveSegment> Segments;
		bool operator < (const tArchiveItem &rhs) const
		{
			return this->Name < rhs.Name;
		}
	};

	tjs_int Count;

	std::vector<tArchiveItem> ItemVector;
public:
	tTVPXP3Archive(const ttstr & name);
	~tTVPXP3Archive();

	tjs_uint GetCount() { return Count; }
	const ttstr & GetName(tjs_uint idx) const { return ItemVector[idx].Name; }
	tjs_uint32 GetFileHash(tjs_uint idx) const { return ItemVector[idx].FileHash; }
	ttstr GetName(tjs_uint idx) { return ItemVector[idx].Name; }

	const ttstr & GetName() const { return Name; }

	tTJSBinaryStream * CreateStreamByIndex(tjs_uint idx);

private:
	static bool FindChunk(const tjs_uint8 *data, const tjs_uint8 * name,
		tjs_uint &start, tjs_uint &size);
	static tjs_int16 ReadI16FromMem(const tjs_uint8 *mem);
	static tjs_int32 ReadI32FromMem(const tjs_uint8 *mem);
	static tjs_int64 ReadI64FromMem(const tjs_uint8 *mem);
};
//---------------------------------------------------------------------------





//---------------------------------------------------------------------------
// tTVPXP3ArchiveStream  : XP3 In-Archive Stream Implmentation
//---------------------------------------------------------------------------
class tTVPSegmentData;
class tTVPXP3ArchiveStream : public tTJSBinaryStream
{
	tTVPXP3Archive * Owner;

	tjs_int StorageIndex; // index in archive

	std::vector<tTVPXP3ArchiveSegment> * Segments;
	tTJSBinaryStream * Stream;
	tjs_uint64 OrgSize; // original storage size

	tjs_int CurSegmentNum;
	tTVPXP3ArchiveSegment *CurSegment;
		// currently opened segment ( NULL for not opened )

	tjs_int LastOpenedSegmentNum;

	tjs_uint64 CurPos; // current position in absolute file position

	tjs_uint64 SegmentRemain; // remain bytes in current segment
	tjs_uint64 SegmentPos; // offset from current segment's start

	tTVPSegmentData *SegmentData; // uncompressed segment data

	bool SegmentOpened;

public:
	tTVPXP3ArchiveStream(tTVPXP3Archive *owner, tjs_int storageindex,
		std::vector<tTVPXP3ArchiveSegment> *segments, tTJSBinaryStream *stream,
			tjs_uint64 orgsize);
	~tTVPXP3ArchiveStream();

private:
	void EnsureSegment(); // ensure accessing to current segment
	void SeekToPosition(tjs_uint64 pos); // open segment at 'pos' and seek
	bool OpenNextSegment();


public:
	tjs_uint64 TJS_INTF_METHOD Seek(tjs_int64 offset, tjs_int whence);
	tjs_uint TJS_INTF_METHOD Read(void *buffer, tjs_uint read_size);
	tjs_uint TJS_INTF_METHOD Write(const void *buffer, tjs_uint write_size);
	tjs_uint64 TJS_INTF_METHOD GetSize();

};
//---------------------------------------------------------------------------





#endif
