/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2014 Torus Knot Software Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * -----------------------------------------------------------------------------
 */
#include "OgrePackageArchive.h"

#include "OgreException.h"
#include "OgreLogManager.h"
#include "OgreString.h"
#include "OgreStringVector.h"

#include <algorithm>
#include <cstring>
#include <sys/stat.h>

namespace Ogre
{

const uint32_t PackageArchive::MAGIC = 0x4B434150; // "PACK" in little-endian
const uint32_t PackageArchive::FORMAT_VERSION = 1;

//-----------------------------------------------------------------------
PackageArchive::PackageArchive(const String &name, const String &archType)
	: Archive(name, archType)
	, mLoaded(false)
{
	mFilePath = name;
}

//-----------------------------------------------------------------------
PackageArchive::~PackageArchive()
{
	unload();
}

//-----------------------------------------------------------------------
void PackageArchive::load()
{
	OGRE_LOCK_AUTO_MUTEX;

	if (mLoaded)
		return;

	// Open the file for reading
	mFileStream.open(mFilePath.c_str(),
			 std::ios::in | std::ios::out | std::ios::binary);

	if (!mFileStream.is_open()) {
		// Try opening as read-only if read-write failed
		mFileStream.clear();
		mFileStream.open(mFilePath.c_str(),
				 std::ios::in | std::ios::binary);
	}

	if (mFileStream.is_open()) {
		// Read the index from the existing file
		readIndex();
		mLoaded = true;
		// Check if we have write access
		mFileStream.clear();
		mFileStream.seekp(0, std::ios::end);
		mReadOnly = !mFileStream.good();
	} else {
		// File doesn't exist yet - create it for writing
		mFileStream.clear();
		mFileStream.open(mFilePath.c_str(),
				 std::ios::in | std::ios::out |
					 std::ios::binary | std::ios::trunc);

		if (mFileStream.is_open()) {
			mLoaded = true;
			mReadOnly = false;
		} else {
			OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
				    "Cannot open package file: " + mFilePath,
				    "PackageArchive::load");
		}
	}
}

//-----------------------------------------------------------------------
void PackageArchive::unload()
{
	OGRE_LOCK_AUTO_MUTEX;

	if (mFileStream.is_open()) {
		mFileStream.close();
	}
	mFileIndex.clear();
	mLoaded = false;
}

//-----------------------------------------------------------------------
void PackageArchive::readIndex()
{
	// Seek to end to read footer
	mFileStream.seekg(0, std::ios::end);
	std::streampos fileSize = mFileStream.tellg();

	if (fileSize < static_cast<std::streamoff>(12)) {
		// File too small to contain a valid footer
		return;
	}

	// Read magic number and index offset from the end
	// Footer layout (last 12 bytes):
	//   [index offset (uint64_t)] [magic (uint32_t)]
	// The index offset is at offset -12 from end, magic is at offset -4
	uint64_t indexOffset;
	uint32_t magic;

	mFileStream.seekg(-static_cast<std::streamoff>(12), std::ios::end);
	mFileStream.read(reinterpret_cast<char *>(&indexOffset),
			 sizeof(indexOffset));
	mFileStream.read(reinterpret_cast<char *>(&magic), sizeof(magic));

	if (magic != MAGIC) {
		// Not a valid package file
		if (LogManager::getSingletonPtr())
			LogManager::getSingleton().logMessage(
				"PackageArchive: Invalid magic number in " +
				mFilePath);
		return;
	}

	// Seek to the index
	mFileStream.seekg(static_cast<std::streamoff>(indexOffset),
			  std::ios::beg);

	// Read number of files
	uint32_t numFiles;
	mFileStream.read(reinterpret_cast<char *>(&numFiles), sizeof(numFiles));

	mFileIndex.clear();

	for (uint32_t i = 0; i < numFiles; i++) {
		// Read filename length and data
		uint32_t nameLen;
		mFileStream.read(reinterpret_cast<char *>(&nameLen),
				 sizeof(nameLen));

		std::string filename(nameLen, '\0');
		mFileStream.read(&filename[0], nameLen);

		// Read entry data
		FileEntry entry;
		mFileStream.read(reinterpret_cast<char *>(&entry.offset),
				 sizeof(entry.offset));
		mFileStream.read(reinterpret_cast<char *>(&entry.size),
				 sizeof(entry.size));
		mFileStream.read(reinterpret_cast<char *>(&entry.timestamp),
				 sizeof(entry.timestamp));

		mFileIndex[filename] = entry;
	}
}

//-----------------------------------------------------------------------
void PackageArchive::writeIndex()
{
	// Write the index and footer at the current stream position.
	// The caller is responsible for positioning the write cursor
	// at the correct offset (after all file data).

	uint32_t numFiles = static_cast<uint32_t>(mFileIndex.size());

	mFileStream.write(reinterpret_cast<const char *>(&numFiles),
			  sizeof(numFiles));

	for (auto &[filename, entry] : mFileIndex) {
		uint32_t nameLen = static_cast<uint32_t>(filename.length());
		mFileStream.write(reinterpret_cast<const char *>(&nameLen),
				  sizeof(nameLen));
		mFileStream.write(filename.c_str(), nameLen);
		mFileStream.write(reinterpret_cast<const char *>(&entry.offset),
				  sizeof(entry.offset));
		mFileStream.write(reinterpret_cast<const char *>(&entry.size),
				  sizeof(entry.size));
		mFileStream.write(
			reinterpret_cast<const char *>(&entry.timestamp),
			sizeof(entry.timestamp));
	}

	// Write footer: index offset + magic
	uint64_t indexOffset = static_cast<uint64_t>(mFileStream.tellp());
	mFileStream.write(reinterpret_cast<const char *>(&indexOffset),
			  sizeof(indexOffset));
	mFileStream.write(reinterpret_cast<const char *>(&MAGIC),
			  sizeof(MAGIC));

	mFileStream.flush();
}

//-----------------------------------------------------------------------
void PackageArchive::rebuildPackage()
{
	// Rebuild the entire package file from the in-memory index.
	// Strategy: write to a temporary file, then swap.

	String tmpPath = mFilePath + ".tmp";

	std::ofstream tmpFile(tmpPath.c_str(),
			      std::ios::binary | std::ios::trunc);
	if (!tmpFile.is_open()) {
		OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
			    "Cannot create temporary file: " + tmpPath,
			    "PackageArchive::rebuildPackage");
	}

	// Write file data sequentially and build new offsets
	std::map<String, FileEntry> newIndex;
	uint64_t currentOffset = 0;

	for (auto &[filename, entry] : mFileIndex) {
		// Read the old data from the original file
		std::vector<char> buffer(static_cast<size_t>(entry.size));
		mFileStream.seekg(static_cast<std::streamoff>(entry.offset),
				  std::ios::beg);
		mFileStream.read(buffer.data(), buffer.size());

		// Write to temp file at new position
		tmpFile.write(buffer.data(), buffer.size());

		// Update entry
		FileEntry newEntry;
		newEntry.offset = currentOffset;
		newEntry.size = entry.size;
		newEntry.timestamp = entry.timestamp;
		newIndex[filename] = newEntry;

		currentOffset += entry.size;
	}

	// Write index and footer to temp file
	uint32_t numFiles = static_cast<uint32_t>(newIndex.size());
	tmpFile.write(reinterpret_cast<const char *>(&numFiles),
		      sizeof(numFiles));

	for (auto &[filename, entry] : newIndex) {
		uint32_t nameLen = static_cast<uint32_t>(filename.length());
		tmpFile.write(reinterpret_cast<const char *>(&nameLen),
			      sizeof(nameLen));
		tmpFile.write(filename.c_str(), nameLen);
		tmpFile.write(reinterpret_cast<const char *>(&entry.offset),
			      sizeof(entry.offset));
		tmpFile.write(reinterpret_cast<const char *>(&entry.size),
			      sizeof(entry.size));
		tmpFile.write(reinterpret_cast<const char *>(&entry.timestamp),
			      sizeof(entry.timestamp));
	}

	uint64_t indexOffset = currentOffset;
	tmpFile.write(reinterpret_cast<const char *>(&indexOffset),
		      sizeof(indexOffset));
	tmpFile.write(reinterpret_cast<const char *>(&MAGIC), sizeof(MAGIC));

	tmpFile.flush();
	tmpFile.close();

	// Close the original file
	mFileStream.close();

	// Replace the original with the temp file
	if (std::rename(tmpPath.c_str(), mFilePath.c_str()) != 0) {
		OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
			    "Cannot replace package file: " + mFilePath,
			    "PackageArchive::rebuildPackage");
	}

	// Re-open the file
	mFileStream.open(mFilePath.c_str(),
			 std::ios::in | std::ios::out | std::ios::binary);
	if (!mFileStream.is_open()) {
		OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
			    "Cannot re-open package file after rebuild: " +
				    mFilePath,
			    "PackageArchive::rebuildPackage");
	}

	// Update the in-memory index with new offsets
	mFileIndex = newIndex;
}

//-----------------------------------------------------------------------
DataStreamPtr PackageArchive::open(const String &filename, bool readOnly) const
{
	OGRE_LOCK_AUTO_MUTEX;

	if (!mLoaded) {
		OGRE_EXCEPT(Exception::ERR_INVALID_STATE, "Archive not loaded",
			    "PackageArchive::open");
	}

	String lookUp = filename;

	// Try direct match first
	auto it = mFileIndex.find(lookUp);
	if (it == mFileIndex.end()) {
		// Try with just the basename (non-strict mode)
		String basename, path;
		StringUtil::splitFilename(lookUp, basename, path);

		// Search for matching basename
		for (auto &[fname, entry] : mFileIndex) {
			String fbasename, fpath;
			StringUtil::splitFilename(fname, fbasename, fpath);
			if (fbasename == basename) {
				lookUp = fname;
				it = mFileIndex.find(lookUp);
				break;
			}
		}
	}

	if (it == mFileIndex.end()) {
		OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
			    "File not found in package: " + filename,
			    "PackageArchive::open");
	}

	const FileEntry &entry = it->second;

	// Read the data from the file
	auto buf = OGRE_ALLOC_T(char, entry.size, MEMCATEGORY_GENERAL);

	mFileStream.seekg(static_cast<std::streamoff>(entry.offset),
			  std::ios::beg);
	mFileStream.read(buf, entry.size);

	auto ret = std::make_shared<MemoryDataStream>(
		lookUp, buf, static_cast<size_t>(entry.size), true, true);

	return ret;
}

//-----------------------------------------------------------------------
DataStreamPtr PackageArchive::create(const String &filename)
{
	OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
		    "Use addFile() to add files to a package archive",
		    "PackageArchive::create");
}

//-----------------------------------------------------------------------
void PackageArchive::remove(const String &filename)
{
	OGRE_LOCK_AUTO_MUTEX;

	if (mReadOnly) {
		OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
			    "Cannot remove file from read-only package",
			    "PackageArchive::remove");
	}

	auto it = mFileIndex.find(filename);
	if (it == mFileIndex.end()) {
		OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
			    "File not found in package: " + filename,
			    "PackageArchive::remove");
	}

	mFileIndex.erase(it);

	// Rebuild the entire package without the removed file
	rebuildPackage();
}

//-----------------------------------------------------------------------
StringVectorPtr PackageArchive::list(bool recursive, bool dirs) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto ret = std::make_shared<StringVector>();

	for (auto &[filename, entry] : mFileIndex) {
		// In our flat archive, there are no directories
		if (dirs)
			continue;

		if (recursive) {
			ret->push_back(filename);
		} else {
			// Only top-level files (no '/' in path)
			if (filename.find('/') == String::npos)
				ret->push_back(filename);
		}
	}

	return ret;
}

//-----------------------------------------------------------------------
FileInfoListPtr PackageArchive::listFileInfo(bool recursive, bool dirs) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto ret = std::make_shared<FileInfoList>();

	for (auto &[filename, entry] : mFileIndex) {
		if (dirs)
			continue;

		if (!recursive && filename.find('/') != String::npos)
			continue;

		FileInfo info;
		info.archive = this;
		info.filename = filename;
		info.compressedSize = static_cast<size_t>(entry.size);
		info.uncompressedSize = static_cast<size_t>(entry.size);

		StringUtil::splitFilename(filename, info.basename, info.path);

		ret->push_back(info);
	}

	return ret;
}

//-----------------------------------------------------------------------
StringVectorPtr PackageArchive::find(const String &pattern, bool recursive,
				     bool dirs) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto ret = std::make_shared<StringVector>();

	bool full_match = (pattern.find('/') != String::npos) ||
			  (pattern.find('\\') != String::npos);
	bool wildCard = pattern.find('*') != String::npos;

	for (auto &[filename, entry] : mFileIndex) {
		if (dirs)
			continue;

		if (!recursive && !full_match && !wildCard) {
			// For non-recursive, non-wildcard searches,
			// check exact match
			String basename, path;
			StringUtil::splitFilename(filename, basename, path);
			if (filename == pattern || basename == pattern)
				ret->push_back(filename);
			continue;
		}

		String basename, path;
		StringUtil::splitFilename(filename, basename, path);

		// For non-recursive searches with wildcards, skip files in subdirectories
		if (!recursive && !full_match && wildCard && !path.empty())
			continue;

		if (StringUtil::match(full_match ? filename : basename, pattern,
				      false)) {
			ret->push_back(filename);
		}
	}

	return ret;
}

//-----------------------------------------------------------------------
FileInfoListPtr PackageArchive::findFileInfo(const String &pattern,
					     bool recursive, bool dirs) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto ret = std::make_shared<FileInfoList>();

	bool full_match = (pattern.find('/') != String::npos) ||
			  (pattern.find('\\') != String::npos);
	bool wildCard = pattern.find('*') != String::npos;

	for (auto &[filename, entry] : mFileIndex) {
		if (dirs)
			continue;

		if (!recursive && !full_match && !wildCard) {
			// For non-recursive, non-wildcard searches,
			// check exact match
			String basename, path;
			StringUtil::splitFilename(filename, basename, path);
			if (filename == pattern || basename == pattern) {
				FileInfo info;
				info.archive = this;
				info.filename = filename;
				info.compressedSize =
					static_cast<size_t>(entry.size);
				info.uncompressedSize =
					static_cast<size_t>(entry.size);
				info.basename = basename;
				info.path = path;
				ret->push_back(info);
			}
			continue;
		}

		String basename, path;
		StringUtil::splitFilename(filename, basename, path);

		// For non-recursive searches with wildcards, skip files in subdirectories
		if (!recursive && !full_match && wildCard && !path.empty())
			continue;

		if (StringUtil::match(full_match ? filename : basename, pattern,
				      false)) {
			FileInfo info;
			info.archive = this;
			info.filename = filename;
			info.compressedSize = static_cast<size_t>(entry.size);
			info.uncompressedSize = static_cast<size_t>(entry.size);
			info.basename = basename;
			info.path = path;
			ret->push_back(info);
		}
	}

	return ret;
}

//-----------------------------------------------------------------------
bool PackageArchive::exists(const String &filename) const
{
	OGRE_LOCK_AUTO_MUTEX;

	if (!mLoaded)
		return false;

	String lookUp = filename;

	// Try direct match
	if (mFileIndex.find(lookUp) != mFileIndex.end())
		return true;

	// Try basename match
	String basename, path;
	StringUtil::splitFilename(lookUp, basename, path);

	for (auto &[fname, entry] : mFileIndex) {
		String fbasename, fpath;
		StringUtil::splitFilename(fname, fbasename, fpath);
		if (fbasename == basename)
			return true;
	}

	return false;
}

//-----------------------------------------------------------------------
time_t PackageArchive::getModifiedTime(const String &filename) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto it = mFileIndex.find(filename);
	if (it == mFileIndex.end()) {
		// Fall back to the package file's modification time
		struct stat tagStat;
		if (stat(mFilePath.c_str(), &tagStat) == 0)
			return tagStat.st_mtime;
		return 0;
	}

	return static_cast<time_t>(it->second.timestamp);
}

//-----------------------------------------------------------------------
void PackageArchive::addFile(const String &filename, const void *data,
			     size_t size, int64_t timestamp)
{
	OGRE_LOCK_AUTO_MUTEX;

	if (mReadOnly) {
		OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
			    "Cannot add file to read-only package",
			    "PackageArchive::addFile");
	}

	if (!mLoaded) {
		load();
		// After loading a non-existent file, it's writable
		mReadOnly = false;
	}

	// Create new entry
	FileEntry entry;
	entry.offset = 0; // Will be set during rebuild
	entry.size = size;
	entry.timestamp = (timestamp != 0) ? timestamp : time(nullptr);

	// If the file already exists, we need to replace it
	auto it = mFileIndex.find(filename);
	if (it != mFileIndex.end()) {
		// Replace existing entry
		it->second = entry;
	} else {
		mFileIndex[filename] = entry;
	}

	// Rebuild the entire package with the new file data
	// We need to write the new data into the rebuilt file.
	// rebuildPackage reads from the old file, so we need to handle
	// the new data separately. We'll do a custom rebuild.

	String tmpPath = mFilePath + ".tmp";

	std::ofstream tmpFile(tmpPath.c_str(),
			      std::ios::binary | std::ios::trunc);
	if (!tmpFile.is_open()) {
		OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
			    "Cannot create temporary file: " + tmpPath,
			    "PackageArchive::addFile");
	}

	// Write file data sequentially and build new offsets
	std::map<String, FileEntry> newIndex;
	uint64_t currentOffset = 0;

	for (auto &[fname, fentry] : mFileIndex) {
		if (fname == filename) {
			// This is the new/updated file - write the provided
			// data
			tmpFile.write(static_cast<const char *>(data),
				      static_cast<std::streamsize>(size));

			FileEntry newEntry;
			newEntry.offset = currentOffset;
			newEntry.size = size;
			newEntry.timestamp = entry.timestamp;
			newIndex[fname] = newEntry;

			currentOffset += size;
		} else {
			// Read existing data from the original file
			std::vector<char> buffer(
				static_cast<size_t>(fentry.size));
			mFileStream.seekg(
				static_cast<std::streamoff>(fentry.offset),
				std::ios::beg);
			mFileStream.read(buffer.data(), buffer.size());

			// Write to temp file
			tmpFile.write(buffer.data(), buffer.size());

			FileEntry newEntry;
			newEntry.offset = currentOffset;
			newEntry.size = fentry.size;
			newEntry.timestamp = fentry.timestamp;
			newIndex[fname] = newEntry;

			currentOffset += fentry.size;
		}
	}

	// Write index and footer to temp file
	uint32_t numFiles = static_cast<uint32_t>(newIndex.size());
	tmpFile.write(reinterpret_cast<const char *>(&numFiles),
		      sizeof(numFiles));

	for (auto &[fname, fentry] : newIndex) {
		uint32_t nameLen = static_cast<uint32_t>(fname.length());
		tmpFile.write(reinterpret_cast<const char *>(&nameLen),
			      sizeof(nameLen));
		tmpFile.write(fname.c_str(), nameLen);
		tmpFile.write(reinterpret_cast<const char *>(&fentry.offset),
			      sizeof(fentry.offset));
		tmpFile.write(reinterpret_cast<const char *>(&fentry.size),
			      sizeof(fentry.size));
		tmpFile.write(reinterpret_cast<const char *>(&fentry.timestamp),
			      sizeof(fentry.timestamp));
	}

	uint64_t indexOffset = currentOffset;
	tmpFile.write(reinterpret_cast<const char *>(&indexOffset),
		      sizeof(indexOffset));
	tmpFile.write(reinterpret_cast<const char *>(&MAGIC), sizeof(MAGIC));

	tmpFile.flush();
	tmpFile.close();

	// Close the original file
	mFileStream.close();

	// Replace the original with the temp file
	if (std::rename(tmpPath.c_str(), mFilePath.c_str()) != 0) {
		OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
			    "Cannot replace package file: " + mFilePath,
			    "PackageArchive::addFile");
	}

	// Re-open the file
	mFileStream.open(mFilePath.c_str(),
			 std::ios::in | std::ios::out | std::ios::binary);
	if (!mFileStream.is_open()) {
		OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
			    "Cannot re-open package file after add: " +
				    mFilePath,
			    "PackageArchive::addFile");
	}

	// Update the in-memory index with new offsets
	mFileIndex = newIndex;
}

//-----------------------------------------------------------------------
void PackageArchive::addFileFromDisk(const String &destFilename,
				     const String &sourcePath)
{
	std::ifstream source(sourcePath.c_str(),
			     std::ios::binary | std::ios::ate);
	if (!source.is_open()) {
		OGRE_EXCEPT(Exception::ERR_FILE_NOT_FOUND,
			    "Cannot open source file: " + sourcePath,
			    "PackageArchive::addFileFromDisk");
	}

	std::streamsize size = source.tellg();
	source.seekg(0, std::ios::beg);

	std::vector<char> buffer(static_cast<size_t>(size));
	source.read(buffer.data(), size);
	source.close();

	// Get file modification time
	struct stat tagStat;
	int64_t timestamp = 0;
	if (stat(sourcePath.c_str(), &tagStat) == 0) {
		timestamp = static_cast<int64_t>(tagStat.st_mtime);
	}

	addFile(destFilename, buffer.data(), static_cast<size_t>(size),
		timestamp);
}

//-----------------------------------------------------------------------
bool PackageArchive::extractFile(const String &filename,
				 const String &destPath) const
{
	OGRE_LOCK_AUTO_MUTEX;

	auto it = mFileIndex.find(filename);
	if (it == mFileIndex.end())
		return false;

	const FileEntry &entry = it->second;

	std::vector<char> buffer(static_cast<size_t>(entry.size));

	mFileStream.seekg(static_cast<std::streamoff>(entry.offset),
			  std::ios::beg);
	mFileStream.read(buffer.data(), buffer.size());

	std::ofstream dest(destPath.c_str(), std::ios::binary);
	if (!dest.is_open())
		return false;

	dest.write(buffer.data(), buffer.size());
	dest.close();

	return true;
}

//-----------------------------------------------------------------------
StringVector PackageArchive::listFiles() const
{
	OGRE_LOCK_AUTO_MUTEX;

	StringVector result;
	for (auto &[filename, entry] : mFileIndex) {
		result.push_back(filename);
	}
	return result;
}

//-----------------------------------------------------------------------
//  PackageArchiveFactory
//-----------------------------------------------------------------------
Archive *PackageArchiveFactory::createInstance(const String &name,
					       bool readOnly)
{
	// Package archives support both read-only and read-write access
	return OGRE_NEW PackageArchive(name, getType());
}

//-----------------------------------------------------------------------
const String &PackageArchiveFactory::getType(void) const
{
	static String name = "Package";
	return name;
}

} // namespace Ogre
