📄 datafile_inputprovider.cpp
字号:
/* $Id: datafile_inputprovider.cpp,v 1.20 2003/09/19 10:33:02 mbn Exp $
**
** ClanLib Game SDK
** Copyright (C) 2003 The ClanLib Team
** For a total list of contributers see the file CREDITS.
**
** 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
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
**
*/
#include "Core/precomp.h"
#include "datafile_inputprovider.h"
#include "API/Core/System/cl_assert.h"
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>
#ifdef WIN32
#define OPENFLAGS O_RDONLY|O_BINARY
#else
#define OPENFLAGS O_RDONLY
#endif
char datafile_id[]="ClanSoft datafile version 4.0";
CL_InputSourceProvider *CL_InputSourceProvider::create_datafile_provider(const std::string &filename)
{
return new CL_InputSourceProvider_Datafile(filename);
}
CL_InputSourceProvider_Datafile::CL_InputSourceProvider_Datafile(const std::string &_datafile) : resource_cache(NULL), datafile_handle(-1)
{
datafile = _datafile;
open();
load_resource_ids();
}
CL_InputSourceProvider_Datafile::CL_InputSourceProvider_Datafile(CL_InputSourceProvider_Datafile *other)
{
datafile = other->datafile;
resource_cache = other->resource_cache;
resource_cache->addref();
datafile_handle = dup(other->datafile_handle);
}
CL_InputSourceProvider_Datafile::~CL_InputSourceProvider_Datafile()
{
if (resource_cache != NULL)
resource_cache->release();
if (datafile_handle != -1)
::close(datafile_handle);
}
CL_InputSource *CL_InputSourceProvider_Datafile::open_source(const std::string &filename)
{
if (datafile_handle == -1)
open();
return new CL_InputSource_Datafile(filename, this);
}
CL_InputSourceProvider *CL_InputSourceProvider_Datafile::clone()
{
return new CL_InputSourceProvider_Datafile(this);
}
void CL_InputSourceProvider_Datafile::open()
{
datafile_handle = ::open(datafile.c_str(), OPENFLAGS);
if (datafile_handle == -1)
{
std::string err = std::string("Could not open datafile ") + datafile;
throw CL_Error(err);
}
int id_len = strlen(datafile_id);
char *temp = new char[id_len+1];
::read(datafile_handle, temp, id_len);
temp[id_len] = 0;
if (strcmp(temp, datafile_id) != 0)
{
::close(datafile_handle);
datafile_handle = -1;
delete[] temp;
throw CL_Error("Invalid datafile format");
}
delete[] temp;
}
void CL_InputSourceProvider_Datafile::load_resource_ids()
{
resource_cache = new IndexLocationCache;
lseek(datafile_handle, strlen(datafile_id), SEEK_SET); // Skip file ID
int index_pos;
::read(datafile_handle, &index_pos, sizeof(int));
lseek(datafile_handle, index_pos, SEEK_SET);
int num_indexes = 0;
::read(datafile_handle, &num_indexes, sizeof(int));
for (int i=0; i<num_indexes; i++)
{
short length;
::read(datafile_handle, &length,sizeof(short));
char *objname = new char[length];
int objpos;
int objsize;
::read(datafile_handle, objname, length);
::read(datafile_handle, &objpos, sizeof(int));
::read(datafile_handle, &objsize, sizeof(int));
resource_cache->insert(objname, objpos, objsize);
delete[] objname;
}
}
std::string CL_InputSourceProvider_Datafile::get_pathname(const std::string &filename)
{
return filename;
}
CL_InputSourceProvider *CL_InputSourceProvider_Datafile::create_relative(const std::string &path)
{
return clone();
}
/**************************
CL_InputSource_Datafile
**************************/
CL_InputSource_Datafile::CL_InputSource_Datafile(
const std::string &filename,
CL_InputSourceProvider_Datafile *provider) : filename(filename), provider(provider), index_open(0)
{
open();
}
CL_InputSource_Datafile::CL_InputSource_Datafile(const CL_InputSource_Datafile *source)
{
filename = source->filename;
provider = source->provider;
index_open = 0;
open();
}
CL_InputSource_Datafile::~CL_InputSource_Datafile()
{
close();
}
int CL_InputSource_Datafile::read(void *addr, int size)
{
if (compressed)
{
int svar = gzread(gzfile, addr, size);
seek_pos += svar;
return svar;
}
else
{
if (seek_pos + size > objsize) size = objsize - seek_pos;
int svar = ::read(datafile_handle, addr, size);
seek_pos += svar;
return svar;
}
}
void CL_InputSource_Datafile::open()
{
if (index_open)
close();
int pos, size;
if (provider->lookup_resource(filename, pos, size))
{
datafile_handle = dup(provider->get_handle());
lseek(datafile_handle, pos, SEEK_SET);
size--;
::read(datafile_handle, &compressed, sizeof(char));
if (compressed) gzfile = gzdopen(datafile_handle, "rb");
index_open = 1;
seek_pos = 0;
objsize = size;
index_pos = pos+1;
}
else
{
std::string err("ClanLib: Couldn't find datafile index: ");
err += std::string(filename);
throw CL_Error(err);
}
}
void CL_InputSource_Datafile::close()
{
if (index_open == 0) return;
index_open=0;
if (compressed) gzclose(gzfile);
else ::close(datafile_handle);
}
CL_InputSource *CL_InputSource_Datafile::clone() const
{
return new CL_InputSource_Datafile(this);
}
int CL_InputSource_Datafile::tell() const
{
return seek_pos;
}
void CL_InputSource_Datafile::seek(int pos, SeekEnum seek_type)
{
if (compressed)
{
if (seek_type == seek_cur)
{
if (pos > 0)
{
char *temp = new char[pos];
read(temp, pos);
delete temp;
}
else if (pos < 0)
{
seek(tell()+pos, seek_set);
}
return;
}
else if (seek_type == seek_set)
{
int cur_pos = tell();
if (pos >= cur_pos)
{
seek(pos - cur_pos, seek_cur);
return;
}
else if (pos>=0)
{
/*
* OK, now we have to go backwards. Since there's no
* easy way to do it (think about compressed datafiles)
* we close and then open the datafile. This way we are
* back to position 0, and can proceed to a standard
* forward seek. OK this is a performance killer
* method, but it's better than nothing...
*/
close();
open();
seek(pos, seek_cur);
return;
}
}
throw CL_Error("ClanLib: seek() in datafiles called with an invalid position");
}
else
{
if (seek_type == seek_set)
{
lseek(datafile_handle, index_pos+pos, SEEK_SET);
}
else if (seek_type == seek_cur)
{
lseek(datafile_handle, pos, SEEK_CUR);
}
else if (seek_type == seek_end)
{
lseek(datafile_handle, index_pos+objsize+pos, SEEK_SET);
}
}
}
int CL_InputSource_Datafile::size() const
{
return objsize;
}
void CL_InputSource_Datafile::push_position()
{
CL_Zipped_Position indexpos;
indexpos.gzfile = gzfile;
// indexpos.datafile_pos = lseek(datafile_handle, 0, SEEK_CUR);
indexpos.seek_pos = seek_pos;
index_stack.push(indexpos);
index_open=0;
}
void CL_InputSource_Datafile::pop_position()
{
// if (index_open != 0) close_index();
// index_open = 1;
CL_Zipped_Position pushed_index = index_stack.top();
index_stack.pop();
gzfile = pushed_index.gzfile;
// lseek(datafile_handle, pushed_index.datafile_pos, SEEK_SET);
seek_pos = pushed_index.seek_pos;
if (!compressed) seek(seek_pos, seek_set);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -