Merge branch 'master' into divVerent/farplanedist-sky-fix
[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 "plugin.h"
35
36 #include <map>
37 #include "string/string.h"
38
39 #include "wad.h"
40
41 class WadArchive : public Archive
42 {
43 class wad_record_t
44 {
45 public:
46 wad_record_t( unsigned int position, unsigned int stream_size, unsigned int file_size )
47         : m_position( position ), m_stream_size( stream_size ), m_file_size( file_size )
48 {}
49 unsigned int m_position;
50 unsigned int m_stream_size;
51 unsigned int m_file_size;
52 };
53
54 enum EWadVersion
55 {
56         eNotValid,
57         eWAD2,
58         eWAD3,
59 };
60
61 typedef std::map<CopiedString, wad_record_t, StringLessNoCase> files_t;
62 files_t m_files;
63 CopiedString m_name;
64 FileInputStream m_wadfile;
65
66 EWadVersion wad_version( const char* identification ){
67         if ( strncmp( identification, "WAD2", 4 ) == 0 ) {
68                 return eWAD2;
69         }
70         if ( strncmp( identification, "WAD3", 4 ) == 0 ) {
71                 return eWAD3;
72         }
73         return eNotValid;
74 }
75
76 const char* type_for_version( EWadVersion version ){
77         switch ( version )
78         {
79         case eWAD2:
80                 return ".mip";
81         case eWAD3:
82                 return ".hlw";
83         default:
84                 break;
85         }
86         return "";
87 }
88
89 int miptex_type_for_version( EWadVersion version ){
90         switch ( version )
91         {
92         case eWAD2:
93                 return TYP_MIPTEX;
94         case eWAD3:
95                 return 67;
96         default:
97                 break;
98         }
99         return -1;
100 }
101
102 public:
103 WadArchive( const char* name )
104         : m_name( name ), m_wadfile( name ){
105         if ( !m_wadfile.failed() ) {
106                 wadinfo_t wadinfo;
107                 istream_read_wadinfo( m_wadfile, wadinfo );
108
109                 EWadVersion version = wad_version( wadinfo.identification );
110                 int miptexType = miptex_type_for_version( version );
111
112                 if ( version != eNotValid ) {
113                         m_wadfile.seek( wadinfo.infotableofs );
114
115                         for ( int i = 0; i < wadinfo.numlumps; ++i )
116                         {
117                                 char buffer[32];
118                                 lumpinfo_t lumpinfo;
119                                 istream_read_lumpinfo( m_wadfile, lumpinfo );
120                                 if ( lumpinfo.type == miptexType ) {
121                                         strcpy( buffer, "textures/" );
122                                         strcat( buffer, lumpinfo.name );
123                                         strcat( buffer, type_for_version( version ) );
124                                         m_files.insert( files_t::value_type( buffer, wad_record_t( lumpinfo.filepos, lumpinfo.disksize, lumpinfo.size ) ) );
125                                 }
126                         }
127                 }
128         }
129 }
130
131 void release(){
132         delete this;
133 }
134 ArchiveFile* openFile( const char* name ){
135         files_t::iterator i = m_files.find( name );
136         if ( i != m_files.end() ) {
137                 return StoredArchiveFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size, i->second.m_file_size );
138         }
139         return 0;
140 }
141 virtual ArchiveTextFile* openTextFile( const char* name ){
142         files_t::iterator i = m_files.find( name );
143         if ( i != m_files.end() ) {
144                 return StoredArchiveTextFile::create( name, m_name.c_str(), i->second.m_position, i->second.m_stream_size );
145         }
146         return 0;
147 }
148 bool containsFile( const char* name ){
149         return m_files.find( name ) != m_files.end();
150 }
151 void forEachFile( VisitorFunc visitor, const char* root ){
152         if ( root[0] == '\0' ) {
153                 if ( visitor.directory( "textures/", 1 ) ) {
154                         return;
155                 }
156         }
157         else if ( strcmp( root, "textures/" ) != 0 ) {
158                 return;
159         }
160
161         for ( files_t::iterator i = m_files.begin(); i != m_files.end(); ++i )
162                 visitor.file( i->first.c_str() );
163 }
164 };
165
166
167 Archive* OpenArchive( const char* name ){
168         return new WadArchive( name );
169 }
170
171 #if 0
172
173 class TestArchive
174 {
175 class TestVisitor : public Archive::IVisitor
176 {
177 public:
178 void visit( const char* name ){
179         int bleh = 0;
180 }
181 };
182 public:
183 TestArchive(){
184         {
185                 Archive* archive = OpenArchive( "" );
186                 archive->release();
187         }
188         {
189                 Archive* archive = OpenArchive( "NONEXISTANTFILE" );
190                 archive->release();
191         }
192         {
193                 Archive* archive = OpenArchive( "c:/quake/id1/quake101.wad" );
194                 ArchiveFile* file = archive->openFile( "textures/sky1.mip" );
195                 if ( file != 0 ) {
196                         unsigned char* buffer = new unsigned char[file->size()];
197                         file->getInputStream().read( (InputStream::byte_type*)buffer, file->size() );
198                         delete[] buffer;
199                         file->release();
200                 }
201                 TestVisitor visitor;
202                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "" );
203                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
204                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "textures/" );
205                 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures/" );
206                 archive->release();
207         }
208 }
209 };
210
211 TestArchive g_test;
212
213 #endif