]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/archivelib.h
ok
[xonotic/netradiant.git] / libs / archivelib.h
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 #if !defined (INCLUDED_ARCHIVELIB_H)
23 #define INCLUDED_ARCHIVELIB_H
24
25 #include "debugging/debugging.h"
26 #include "iarchive.h"
27 #include "stream/filestream.h"
28 #include "stream/textfilestream.h"
29 #include "memory/allocator.h"
30 #include "string/string.h"
31
32 /// \brief A single-byte-reader wrapper around an InputStream.
33 /// Optimised for reading one byte at a time.
34 /// Uses a buffer to reduce the number of times the wrapped stream must be read.
35 template<typename InputStreamType, int SIZE = 1024>
36 class SingleByteInputStream
37 {
38   typedef typename InputStreamType::byte_type byte_type;
39   static const int BUFFERSIZE = SIZE;
40
41   InputStreamType& m_inputStream;
42   byte_type m_buffer[BUFFERSIZE];
43   byte_type* m_cur;
44   byte_type* m_end;
45
46 public:
47
48   SingleByteInputStream(InputStreamType& inputStream) : m_inputStream(inputStream), m_cur(m_buffer + BUFFERSIZE), m_end(m_cur)
49   {
50   }
51   bool readByte(byte_type& b)
52   {
53     if(m_cur == m_end)
54     {
55       if(m_end != m_buffer + BUFFERSIZE)
56       {
57         return false;
58       }
59
60       m_end = m_buffer + m_inputStream.read(m_buffer, BUFFERSIZE);
61       m_cur = m_buffer;
62
63       if(m_end == m_buffer)
64       {
65         return false;
66       }
67     }
68
69     b = *m_cur++;
70
71     return true;
72   }
73 };
74
75 /// \brief A binary-to-text wrapper around an InputStream.
76 /// Converts CRLF or LFCR line-endings to LF line-endings.
77 template<typename BinaryInputStreamType>
78 class BinaryToTextInputStream : public TextInputStream
79 {
80   SingleByteInputStream<BinaryInputStreamType> m_inputStream;
81 public:
82   BinaryToTextInputStream(BinaryInputStreamType& inputStream) : m_inputStream(inputStream)
83   {
84   }
85   std::size_t read(char* buffer, std::size_t length)
86   {
87     char* p = buffer;
88     for(;;)
89     {
90       if(length != 0 && m_inputStream.readByte(*reinterpret_cast<typename BinaryInputStreamType::byte_type*>(p)))
91       {
92         if(*p != '\r')
93         {
94           ++p;
95           --length;
96         }
97       }
98       else
99       {
100         return p - buffer;
101       }
102     }
103   }
104 };
105
106 /// \brief An ArchiveFile which is stored uncompressed as part of a larger archive file.
107 class StoredArchiveFile : public ArchiveFile
108 {
109   CopiedString m_name;
110   FileInputStream m_filestream;
111   SubFileInputStream m_substream;
112   FileInputStream::size_type m_size;
113 public:
114   typedef FileInputStream::size_type size_type;
115   typedef FileInputStream::position_type position_type;
116
117   StoredArchiveFile(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
118     : m_name(name), m_filestream(archiveName), m_substream(m_filestream, position, stream_size), m_size(file_size)
119   {
120   }
121
122   static StoredArchiveFile* create(const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size)
123   {
124     return New<StoredArchiveFile>().scalar(name, archiveName, position, stream_size, file_size);
125   }
126
127   void release()
128   {
129     Delete<StoredArchiveFile>().scalar(this);
130   }
131   size_type size() const
132   {
133     return m_size;
134   }
135   const char* getName() const
136   {
137     return m_name.c_str();
138   }
139   InputStream& getInputStream()
140   {
141     return m_substream;
142   }
143 };
144
145 /// \brief An ArchiveTextFile which is stored uncompressed as part of a larger archive file.
146 class StoredArchiveTextFile : public ArchiveTextFile
147 {
148   CopiedString m_name;
149   FileInputStream m_filestream;
150   SubFileInputStream m_substream;
151   BinaryToTextInputStream<SubFileInputStream> m_textStream;
152 public:
153   typedef FileInputStream::size_type size_type;
154   typedef FileInputStream::position_type position_type;
155
156   StoredArchiveTextFile(const char* name, const char* archiveName, position_type position, size_type stream_size)
157     : m_name(name), m_filestream(archiveName), m_substream(m_filestream, position, stream_size), m_textStream(m_substream)
158   {
159   }
160
161   static StoredArchiveTextFile* create(const char* name, const char* archiveName, position_type position, size_type stream_size)
162   {
163     return New<StoredArchiveTextFile>().scalar(name, archiveName, position, stream_size);
164   }
165
166   void release()
167   {
168     Delete<StoredArchiveTextFile>().scalar(this);
169   }
170   const char* getName() const
171   {
172     return m_name.c_str();
173   }
174   TextInputStream& getInputStream()
175   {
176     return m_textStream;
177   }
178 };
179
180 /// \brief An ArchiveFile which is stored as a single file on disk.
181 class DirectoryArchiveFile : public ArchiveFile
182 {
183   CopiedString m_name;
184   FileInputStream m_istream;
185   FileInputStream::size_type m_size;
186 public:
187   typedef FileInputStream::size_type size_type;
188
189   DirectoryArchiveFile(const char* name, const char* filename)
190     : m_name(name), m_istream(filename)
191   {
192     if(!failed())
193     {
194       m_istream.seek(0, FileInputStream::end);
195       m_size = m_istream.tell();
196       m_istream.seek(0);
197     }
198     else
199     {
200       m_size = 0;
201     }
202   }
203   bool failed() const
204   {
205     return m_istream.failed();
206   }
207
208   void release()
209   {
210     delete this;
211   }
212   size_type size() const
213   {
214     return m_size;
215   }
216   const char* getName() const
217   {
218     return m_name.c_str();
219   }
220   InputStream& getInputStream()
221   {
222     return m_istream;
223   }
224 };
225
226 /// \brief An ArchiveTextFile which is stored as a single file on disk.
227 class DirectoryArchiveTextFile : public ArchiveTextFile
228 {
229   CopiedString m_name;
230   TextFileInputStream m_inputStream;
231 public:
232
233   DirectoryArchiveTextFile(const char* name, const char* filename)
234     : m_name(name), m_inputStream(filename)
235   {
236   }
237   bool failed() const
238   {
239     return m_inputStream.failed();
240   }
241
242   void release()
243   {
244     delete this;
245   }
246   const char* getName() const
247   {
248     return m_name.c_str();
249   }
250   TextInputStream& getInputStream()
251   {
252     return m_inputStream;
253   }
254 };
255
256
257 #endif