2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
24 #include "idatastream.h"
26 #include "bytestreamutils.h"
28 #include "stream/filestream.h"
32 #include "archivelib.h"
36 #include "string/string.h"
37 #include "fs_filesystem.h"
39 inline void buffer_findreplace(char *buffer, char find, char replace)
41 while (*buffer != '\0') {
42 if (*buffer == find) {
51 class PakArchive : public Archive {
54 PakRecord(unsigned int position, unsigned int stream_size)
55 : m_position(position), m_stream_size(stream_size)
59 unsigned int m_position;
60 unsigned int m_stream_size;
63 typedef GenericFileSystem<PakRecord> PakFileSystem;
64 PakFileSystem m_filesystem;
65 FileInputStream m_pakfile;
70 PakArchive(const char *name)
71 : m_pakfile(name), m_name(name)
73 if (!m_pakfile.failed()) {
76 m_pakfile.read(reinterpret_cast<FileInputStream::byte_type *>( header.magic ), 4);
77 header.diroffset = istream_read_uint32_le(m_pakfile);
78 header.dirsize = istream_read_uint32_le(m_pakfile);
80 if (strncmp(header.magic, "PACK", 4) == 0) {
81 m_pakfile.seek(header.diroffset);
83 for (unsigned int i = 0; i < header.dirsize; i += sizeof(pakentry_t)) {
86 m_pakfile.read(reinterpret_cast<FileInputStream::byte_type *>( entry.filename ), 0x38);
87 entry.offset = istream_read_uint32_le(m_pakfile);
88 entry.size = istream_read_uint32_le(m_pakfile);
90 buffer_findreplace(entry.filename, '\\', '/');
92 PakFileSystem::entry_type &file = m_filesystem[entry.filename];
93 if (!file.is_directory()) {
94 globalOutputStream() << "Warning: pak archive " << makeQuoted(m_name.c_str())
95 << " contains duplicated file: " << makeQuoted(entry.filename) << "\n";
97 file = new PakRecord(entry.offset, entry.size);
106 for (PakFileSystem::iterator i = m_filesystem.begin(); i != m_filesystem.end(); ++i) {
107 delete i->second.file();
116 ArchiveFile *openFile(const char *name)
118 PakFileSystem::iterator i = m_filesystem.find(name);
119 if (i != m_filesystem.end() && !i->second.is_directory()) {
120 PakRecord *file = i->second.file();
121 return StoredArchiveFile::create(name, m_name.c_str(), file->m_position, file->m_stream_size,
122 file->m_stream_size);
127 virtual ArchiveTextFile *openTextFile(const char *name)
129 PakFileSystem::iterator i = m_filesystem.find(name);
130 if (i != m_filesystem.end() && !i->second.is_directory()) {
131 PakRecord *file = i->second.file();
132 return StoredArchiveTextFile::create(name, m_name.c_str(), file->m_position, file->m_stream_size);
137 bool containsFile(const char *name)
139 PakFileSystem::iterator i = m_filesystem.find(name);
140 return i != m_filesystem.end() && !i->second.is_directory();
143 void forEachFile(VisitorFunc visitor, const char *root)
145 m_filesystem.traverse(visitor, root);
150 Archive *OpenArchive(const char *name)
152 return new PakArchive(name);
161 Archive* archive = OpenArchive( "c:/quake3/baseq3/pak0.pak" );
162 ArchiveFile* file = archive->openFile( "gfx/palette.lmp" );
165 file->getInputStream().read( (InputStream::byte_type*)buffer, 1024 );
180 class TestVisitor : public Archive::IVisitor
183 void visit( const char* name ){
190 Archive* archive = OpenArchive( "" );
194 Archive* archive = OpenArchive( "NONEXISTANTFILE" );
198 Archive* archive = OpenArchive( "c:/quake/id1/pak0.pak" );
199 ArchiveFile* file = archive->openFile( "gfx/palette.lmp" );
202 file->getInputStream().read( (InputStream::byte_type*)buffer, 1024 );
206 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
207 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFiles, 0 ), "progs/" );
208 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFiles, 0 ), "maps/" );
209 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFiles, 1 ), "sound/ambience/" );
210 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "sound/" );
211 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eDirectories, 1 ), "sound/" );
212 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 2 ), "sound/" );
213 archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 2 ), "" );