/*
===========================================================================
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors
This file is part of the OpenJK source code.
OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
===========================================================================
*/
////////////////////////////////////////////////////////////////////////////////////////
// RAVEN STANDARD USEFUL FUNCTION LIBRARY
// (c) 2002 Activision
//
//
// Handle File
// -----------
//
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////
#include "../qcommon/q_shared.h"
#ifndef _WIN32
#define Pool FilePool
#endif
#include "hfile.h"
#if !defined(RATL_HANDLE_POOL_VS_INC)
#include "../Ratl/handle_pool_vs.h"
#endif
#if !defined(RATL_VECTOR_VS_INC)
#include "../Ratl/vector_vs.h"
#endif
#if !defined(RUFL_HSTRING_INC)
#include "hstring.h"
#endif
extern bool HFILEopen_read(int& handle, const char* filepath);
extern bool HFILEopen_write(int& handle, const char* filepath);
extern bool HFILEread(int& handle, void* data, int size);
extern bool HFILEwrite(int& handle, const void* data, int size);
extern bool HFILEclose(int& handle);
////////////////////////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////////////////////////
#define MAX_OPEN_FILES 20
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
struct SOpenFile
{
hstring mPath;
bool mForRead;
int mHandle;
float mVersion;
int mChecksum;
};
typedef ratl::handle_pool_vs TFilePool;
static TFilePool& Pool()
{
static TFilePool TFP;
return TFP;
}
////////////////////////////////////////////////////////////////////////////////////////
// Constructor
//
// Allocates a new OpenFile structure and initializes it. DOES NOT OPEN!
//
////////////////////////////////////////////////////////////////////////////////////////
hfile::hfile(const char* file)
{
if (Pool().full())
{
mHandle = 0;
assert("HFILE: Too Many Files Open, Unable To Grab An Unused Handle"==0);
return;
}
mHandle = Pool().alloc();
SOpenFile& sfile = Pool()[mHandle];
sfile.mPath = file;
sfile.mHandle = 0;
sfile.mForRead = true;
}
////////////////////////////////////////////////////////////////////////////////////////
// Destructor
//
// Releases the open file structure for resue. Also closes the file if open.
//
////////////////////////////////////////////////////////////////////////////////////////
hfile::~hfile()
{
if (is_open())
{
close();
}
if (mHandle && Pool().is_used(mHandle))
{
Pool().free(mHandle);
}
mHandle = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
bool hfile::is_open(void) const
{
if (mHandle && Pool().is_used(mHandle))
{
return (Pool()[mHandle].mHandle!=0);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
bool hfile::is_open_for_read(void) const
{
if (mHandle && Pool().is_used(mHandle))
{
SOpenFile& sfile = Pool()[mHandle];
return (sfile.mHandle!=0 && sfile.mForRead);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
bool hfile::is_open_for_write(void) const
{
if (mHandle && Pool().is_used(mHandle))
{
SOpenFile& sfile = Pool()[mHandle];
return (sfile.mHandle!=0 && !sfile.mForRead);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
bool hfile::open(float version, int checksum, bool read)
{
// Make Sure This Is A Valid Handle
//----------------------------------
if (!mHandle || !Pool().is_used(mHandle))
{
assert("HFILE: Invalid Handle"==0);
return false;
}
// Make Sure The File Is Not ALREADY Open
//----------------------------------------
SOpenFile& sfile = Pool()[mHandle];
if (sfile.mHandle!=0)
{
assert("HFILE: Attempt To Open An Already Open File"==0);
return false;
}
sfile.mForRead = read;
if (read)
{
HFILEopen_read(sfile.mHandle, *sfile.mPath);
}
else
{
HFILEopen_write(sfile.mHandle, *sfile.mPath);
}
// If The Open Failed, Report It And Free The SOpenFile
//------------------------------------------------------
if (sfile.mHandle==0)
{
if (!read)
{
assert("HFILE: Unable To Open File"==0);
}
return false;
}
// Read The File's Header
//------------------------
if (read)
{
if (!HFILEread(sfile.mHandle, &sfile.mVersion, sizeof(sfile.mVersion)))
{
assert("HFILE: Unable To Read File Header"==0);
close();
return false;
}
if (!HFILEread(sfile.mHandle, &sfile.mChecksum, sizeof(sfile.mChecksum)))
{
assert("HFILE: Unable To Read File Header"==0);
close();
return false;
}
// Make Sure The Checksum & Version Match
//----------------------------------------
if (sfile.mVersion!=version || sfile.mChecksum!=checksum)
{
close();
return false; // Failed To Match Checksum Or Version Number -> Old Data
}
}
else
{
sfile.mVersion = version;
sfile.mChecksum = checksum;
if (!HFILEwrite(sfile.mHandle, &sfile.mVersion, sizeof(sfile.mVersion)))
{
assert("HFILE: Unable To Write File Header"==0);
close();
return false;
}
if (!HFILEwrite(sfile.mHandle, &sfile.mChecksum, sizeof(sfile.mChecksum)))
{
assert("HFILE: Unable To Write File Header"==0);
close();
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
bool hfile::close()
{
if (!mHandle || !Pool().is_used(mHandle))
{
assert("HFILE: Invalid Handle"==0);
return false;
}
SOpenFile& sfile = Pool()[mHandle];
if (sfile.mHandle==0)
{
assert("HFILE: Unable TO Close Unopened File"==0);
return false;
}
if (!HFILEclose(sfile.mHandle))
{
sfile.mHandle = 0;
assert("HFILE: Unable To Close File"==0);
return false;
}
sfile.mHandle = 0;
return true;
}
////////////////////////////////////////////////////////////////////////////////////
// Searches for the first block with the matching data size, and reads it in.
////////////////////////////////////////////////////////////////////////////////////
bool hfile::load(void* data, int datasize)
{
// Go Ahead And Open The File For Reading
//----------------------------------------
bool auto_opened = false;
if (!is_open())
{
if (!open_read())
{
return false;
}
auto_opened = true;
}
// Make Sure That The File Is Readable
//-------------------------------------
SOpenFile& sfile = Pool()[mHandle];
if (!sfile.mForRead)
{
assert("HFILE: Unable to load from a file that is opened for save"==0);
if (auto_opened)
{
close();
}
return false;
}
// Now Read It
//-------------
if (!HFILEread(sfile.mHandle, data, datasize))
{
assert("HFILE: Unable To Read Object"==0);
if (auto_opened)
{
close();
}
return false;
}
// Success!
//----------
if (auto_opened)
{
close();
}
return true;
}
////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////
bool hfile::save(void* data, int datasize)
{
// Go Ahead And Open The File For Reading
//----------------------------------------
bool auto_opened = false;
if (!is_open())
{
if (!open_write())
{
return false;
}
auto_opened = true;
}
// Make Sure That The File Is Readable
//-------------------------------------
SOpenFile& sfile = Pool()[mHandle];
if (sfile.mForRead)
{
assert("HFILE: Unable to save to a file that is opened for read"==0);
if (auto_opened)
{
close();
}
return false;
}
// Write The Actual Object
//-------------------------
if (!HFILEwrite(sfile.mHandle, data, datasize))
{
assert("HFILE: Unable To Write File Data"==0);
if (auto_opened)
{
close();
}
return false;
}
if (auto_opened)
{
close();
}
return true;
}