worldspawn/plugins/archivewad/archive.cpp

212 lines
5.2 KiB
C++

/*
Copyright (C) 2001-2006, William Joseph.
All Rights Reserved.
This file is part of GtkRadiant.
GtkRadiant is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GtkRadiant 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 GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "archive.h"
#include "idatastream.h"
#include "bytestreamutils.h"
#include <algorithm>
#include "stream/filestream.h"
#include "iarchive.h"
#include "archivelib.h"
#include <map>
#include "string/string.h"
#include "wad.h"
class WadArchive final : public Archive
{
class wad_record_t
{
public:
wad_record_t( unsigned int position, unsigned int stream_size, unsigned int file_size )
: m_position( position ), m_stream_size( stream_size ), m_file_size( file_size )
{}
unsigned int m_position;
unsigned int m_stream_size;
unsigned int m_file_size;
};
enum EWadVersion
{
eNotValid,
eWAD2,
eWAD3,
};
typedef std::map<CopiedString, wad_record_t, StringLessNoCase> files_t;
files_t m_files;
CopiedString m_name;
FileInputStream m_wadfile;
EWadVersion wad_version( const char* identification ){
if ( strncmp( identification, "WAD2", 4 ) == 0 ) {
return eWAD2;
}
if ( strncmp( identification, "WAD3", 4 ) == 0 ) {
return eWAD3;
}
return eNotValid;
}
const char* type_for_version( EWadVersion version ){
switch ( version )
{
case eWAD2:
return ".mip";
case eWAD3:
return ".hlw";
default:
break;
}
return "";
}
int miptex_type_for_version( EWadVersion version ){
switch ( version )
{
case eWAD2:
return TYP_MIPTEX;
case eWAD3:
return 67;
default:
break;
}
return -1;
}
public:
WadArchive( const char* name )
: m_name( name ), m_wadfile( name ){
if ( !m_wadfile.failed() ) {
wadinfo_t wadinfo;
istream_read_wadinfo( m_wadfile, wadinfo );
EWadVersion version = wad_version( wadinfo.identification );
int miptexType = miptex_type_for_version( version );
if ( version != eNotValid ) {
m_wadfile.seek( wadinfo.infotableofs );
for ( int i = 0; i < wadinfo.numlumps; ++i )
{
char buffer[32];
lumpinfo_t lumpinfo;
istream_read_lumpinfo( m_wadfile, lumpinfo );
if ( lumpinfo.type == miptexType ) {
strcpy( buffer, "textures/" );
strcat( buffer, lumpinfo.name );
strcat( buffer, type_for_version( version ) );
m_files.insert( files_t::value_type( buffer, wad_record_t( lumpinfo.filepos, lumpinfo.disksize, lumpinfo.size ) ) );
}
}
}
}
}
void release(){
delete this;
}
ArchiveFile* openFile( const char* name ){
files_t::iterator i = m_files.find( name );
if ( i != m_files.end() ) {
return StoredArchiveFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size, i->second.m_file_size );
}
return 0;
}
virtual ArchiveTextFile* openTextFile( const char* name ){
files_t::iterator i = m_files.find( name );
if ( i != m_files.end() ) {
return StoredArchiveTextFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size );
}
return 0;
}
bool containsFile( const char* name ){
return m_files.find( name ) != m_files.end();
}
void forEachFile( VisitorFunc visitor, const char* root ){
if ( root[0] == '\0' ) {
if ( visitor.directory( "textures/", 1 ) ) {
return;
}
}
else if ( strcmp( root, "textures/" ) != 0 ) {
return;
}
for ( files_t::iterator i = m_files.begin(); i != m_files.end(); ++i )
visitor.file( i->first.c_str() );
}
};
Archive* OpenArchive( const char* name ){
return new WadArchive( name );
}
#if 0
class TestArchive
{
class TestVisitor : public Archive::IVisitor
{
public:
void visit( const char* name ){
int bleh = 0;
}
};
public:
TestArchive(){
{
Archive* archive = OpenArchive( "" );
archive->release();
}
{
Archive* archive = OpenArchive( "NONEXISTANTFILE" );
archive->release();
}
{
Archive* archive = OpenArchive( "c:/quake/id1/quake101.wad" );
ArchiveFile* file = archive->openFile( "textures/sky1.mip" );
if ( file != 0 ) {
unsigned char* buffer = new unsigned char[file->size()];
file->getInputStream().read( (InputStream::byte_type*)buffer, file->size() );
delete[] buffer;
file->release();
}
TestVisitor visitor;
archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "" );
archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "textures/" );
archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures/" );
archive->release();
}
}
};
TestArchive g_test;
#endif