Merge branch 'illwieckz/externalnames' into 'master'
[xonotic/netradiant.git] / plugins / archivewad / archive.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "archive.h"
23
24 #include "idatastream.h"
25 #include "cmdlib.h"
26 #include "bytestreamutils.h"
27 #include <algorithm>
28 #include "stream/filestream.h"
29
30 #include "iarchive.h"
31
32 #include "archivelib.h"
33
34 #include <map>
35 #include "string/string.h"
36
37 #include "wad.h"
38
39 class WadArchive : public Archive
40 {
41 class wad_record_t
42 {
43 public:
44 wad_record_t( unsigned int position, unsigned int stream_size, unsigned int file_size )
45         : m_position( position ), m_stream_size( stream_size ), m_file_size( file_size )
46 {}
47 unsigned int m_position;
48 unsigned int m_stream_size;
49 unsigned int m_file_size;
50 };
51
52 enum EWadVersion
53 {
54         eNotValid,
55         eWAD2,
56         eWAD3,
57 };
58
59 typedef std::map<CopiedString, wad_record_t, StringLessNoCase> files_t;
60 files_t m_files;
61 CopiedString m_name;
62 FileInputStream m_wadfile;
63
64 EWadVersion wad_version( const char* identification ){
65         if ( strncmp( identification, "WAD2", 4 ) == 0 ) {
66                 return eWAD2;
67         }
68         if ( strncmp( identification, "WAD3", 4 ) == 0 ) {
69                 return eWAD3;
70         }
71         return eNotValid;
72 }
73
74 const char* type_for_version( EWadVersion version ){
75         switch ( version )
76         {
77         case eWAD2:
78                 return ".mip";
79         case eWAD3:
80                 return ".hlw";
81         default:
82                 break;
83         }
84         return "";
85 }
86
87 int miptex_type_for_version( EWadVersion version ){
88         switch ( version )
89         {
90         case eWAD2:
91                 return TYP_MIPTEX;
92         case eWAD3:
93                 return 67;
94         default:
95                 break;
96         }
97         return -1;
98 }
99
100 public:
101 WadArchive( const char* name )
102         : m_name( name ), m_wadfile( name ){
103         if ( !m_wadfile.failed() ) {
104                 wadinfo_t wadinfo;
105                 istream_read_wadinfo( m_wadfile, wadinfo );
106
107                 EWadVersion version = wad_version( wadinfo.identification );
108                 int miptexType = miptex_type_for_version( version );
109
110                 if ( version != eNotValid ) {
111                         m_wadfile.seek( wadinfo.infotableofs );
112
113                         for ( int i = 0; i < wadinfo.numlumps; ++i )
114                         {
115                                 char buffer[32];
116                                 lumpinfo_t lumpinfo;
117                                 istream_read_lumpinfo( m_wadfile, lumpinfo );
118                                 if ( lumpinfo.type == miptexType ) {
119                                         strcpy( buffer, "textures/" );
120                                         strcat( buffer, lumpinfo.name );
121                                         strcat( buffer, type_for_version( version ) );
122                                         m_files.insert( files_t::value_type( buffer, wad_record_t( lumpinfo.filepos, lumpinfo.disksize, lumpinfo.size ) ) );
123                                 }
124                         }
125                 }
126         }
127 }
128
129 void release(){
130         delete this;
131 }
132 ArchiveFile* openFile( const char* name ){
133         files_t::iterator i = m_files.find( name );
134         if ( i != m_files.end() ) {
135                 return StoredArchiveFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size, i->second.m_file_size );
136         }
137         return 0;
138 }
139 virtual ArchiveTextFile* openTextFile( const char* name ){
140         files_t::iterator i = m_files.find( name );
141         if ( i != m_files.end() ) {
142                 return StoredArchiveTextFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size );
143         }
144         return 0;
145 }
146 bool containsFile( const char* name ){
147         return m_files.find( name ) != m_files.end();
148 }
149 void forEachFile( VisitorFunc visitor, const char* root ){
150         if ( root[0] == '\0' ) {
151                 if ( visitor.directory( "textures/", 1 ) ) {
152                         return;
153                 }
154         }
155         else if ( strcmp( root, "textures/" ) != 0 ) {
156                 return;
157         }
158
159         for ( files_t::iterator i = m_files.begin(); i != m_files.end(); ++i )
160                 visitor.file( i->first.c_str() );
161 }
162 };
163
164
165 Archive* OpenArchive( const char* name ){
166         return new WadArchive( name );
167 }
168
169 #if 0
170
171 class TestArchive
172 {
173 class TestVisitor : public Archive::IVisitor
174 {
175 public:
176 void visit( const char* name ){
177         int bleh = 0;
178 }
179 };
180 public:
181 TestArchive(){
182         {
183                 Archive* archive = OpenArchive( "" );
184                 archive->release();
185         }
186         {
187                 Archive* archive = OpenArchive( "NONEXISTANTFILE" );
188                 archive->release();
189         }
190         {
191                 Archive* archive = OpenArchive( "c:/quake/id1/quake101.wad" );
192                 ArchiveFile* file = archive->openFile( "textures/sky1.mip" );
193                 if ( file != 0 ) {
194                         unsigned char* buffer = new unsigned char[file->size()];
195                         file->getInputStream().read( (InputStream::byte_type*)buffer, file->size() );
196                         delete[] buffer;
197                         file->release();
198                 }
199                 TestVisitor visitor;
200                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "" );
201                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
202                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "textures/" );
203                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures/" );
204                 archive->release();
205         }
206 }
207 };
208
209 TestArchive g_test;
210
211 #endif