Merge branch 'transfilterfix' into 'master'
[xonotic/netradiant.git] / plugins / vfspk3 / 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 "iarchive.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <vector>
30
31 #include "stream/filestream.h"
32 #include "stream/textfilestream.h"
33 #include "string/string.h"
34 #include "os/path.h"
35 #include "os/file.h"
36 #include "os/dir.h"
37 #include "archivelib.h"
38 #include "fs_path.h"
39
40
41 class DirectoryArchive : public Archive {
42     CopiedString m_root;
43 public:
44     DirectoryArchive(const char *root) : m_root(root)
45     {
46     }
47
48     void release()
49     {
50         delete this;
51     }
52
53     virtual ArchiveFile *openFile(const char *name)
54     {
55         UnixPath path(m_root.c_str());
56         path.push_filename(name);
57         DirectoryArchiveFile *file = new DirectoryArchiveFile(name, path.c_str());
58         if (!file->failed()) {
59             return file;
60         }
61         file->release();
62         return 0;
63     }
64
65     virtual ArchiveTextFile *openTextFile(const char *name)
66     {
67         UnixPath path(m_root.c_str());
68         path.push_filename(name);
69         DirectoryArchiveTextFile *file = new DirectoryArchiveTextFile(name, path.c_str());
70         if (!file->failed()) {
71             return file;
72         }
73         file->release();
74         return 0;
75     }
76
77     virtual bool containsFile(const char *name)
78     {
79         UnixPath path(m_root.c_str());
80         path.push_filename(name);
81         return file_readable(path.c_str());
82     }
83
84     virtual void forEachFile(VisitorFunc visitor, const char *root)
85     {
86         std::vector<Directory *> dirs;
87         UnixPath path(m_root.c_str());
88         path.push(root);
89         dirs.push_back(directory_open(path.c_str()));
90
91         while (!dirs.empty() && directory_good(dirs.back())) {
92             const char *name = directory_read_and_increment(dirs.back());
93
94             if (name == 0) {
95                 directory_close(dirs.back());
96                 dirs.pop_back();
97                 path.pop();
98             } else if (!string_equal(name, ".") && !string_equal(name, "..")) {
99                 path.push_filename(name);
100
101                 bool is_directory = file_is_directory(path.c_str());
102
103                 if (!is_directory) {
104                     visitor.file(path_make_relative(path.c_str(), m_root.c_str()));
105                 }
106
107                 path.pop();
108
109                 if (is_directory) {
110                     path.push(name);
111
112                     if (!visitor.directory(path_make_relative(path.c_str(), m_root.c_str()), dirs.size())) {
113                         dirs.push_back(directory_open(path.c_str()));
114                     } else {
115                         path.pop();
116                     }
117                 }
118             }
119         }
120     }
121 };
122
123 Archive *OpenArchive(const char *name)
124 {
125     return new DirectoryArchive(name);
126 }
127
128 #if 0
129
130 class TestArchive
131 {
132 class TestVisitor : public Archive::IVisitor
133 {
134 public:
135 virtual void visit( const char* name ){
136     int bleh = 0;
137 }
138 };
139 public:
140 void test1(){
141     Archive* archive = OpenArchive( "d:/quake/id1/" );
142     ArchiveFile* file = archive->openFile( "quake101.wad" );
143     if ( file != 0 ) {
144         char buffer[1024];
145         file->getInputStream().read( buffer, 1024 );
146         file->release();
147     }
148     TestVisitor visitor;
149     archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 0 ), "" );
150     archive->release();
151 }
152 void test2(){
153     Archive* archive = OpenArchive( "d:/gtkradiant_root/baseq3/" );
154     TestVisitor visitor;
155     archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 2 ), "" );
156     archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFiles, 1 ), "textures" );
157     archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eDirectories, 1 ), "textures" );
158     archive->forEachFile( Archive::VisitorFunc( &visitor, Archive::eFilesAndDirectories, 1 ), "textures" );
159     archive->release();
160 }
161 TestArchive(){
162     test1();
163     test2();
164 }
165 };
166
167 TestArchive g_test;
168
169 #endif