aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp b/libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp
new file mode 100644
index 0000000..bbc9a8c
--- /dev/null
+++ b/libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp
@@ -0,0 +1,258 @@
1// Copyright (C) 2009-2012 Gaz Davidson
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CTarReader.h"
6
7#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
8
9#include "CFileList.h"
10#include "CLimitReadFile.h"
11#include "os.h"
12#include "coreutil.h"
13#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
14#include "errno.h"
15#endif
16
17namespace irr
18{
19namespace io
20{
21
22//! Constructor
23CArchiveLoaderTAR::CArchiveLoaderTAR(io::IFileSystem* fs)
24: FileSystem(fs)
25{
26 #ifdef _DEBUG
27 setDebugName("CArchiveLoaderTAR");
28 #endif
29}
30
31
32//! returns true if the file maybe is able to be loaded by this class
33bool CArchiveLoaderTAR::isALoadableFileFormat(const io::path& filename) const
34{
35 return core::hasFileExtension(filename, "tar");
36}
37
38//! Check to see if the loader can create archives of this type.
39bool CArchiveLoaderTAR::isALoadableFileFormat(E_FILE_ARCHIVE_TYPE fileType) const
40{
41 return fileType == EFAT_TAR;
42}
43
44//! Creates an archive from the filename
45/** \param file File handle to check.
46\return Pointer to newly created archive, or 0 upon error. */
47IFileArchive* CArchiveLoaderTAR::createArchive(const io::path& filename, bool ignoreCase, bool ignorePaths) const
48{
49 IFileArchive *archive = 0;
50 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
51
52 if (file)
53 {
54 archive = createArchive(file, ignoreCase, ignorePaths);
55 file->drop();
56 }
57
58 return archive;
59}
60
61
62//! creates/loads an archive from the file.
63//! \return Pointer to the created archive. Returns 0 if loading failed.
64IFileArchive* CArchiveLoaderTAR::createArchive(io::IReadFile* file, bool ignoreCase, bool ignorePaths) const
65{
66 IFileArchive *archive = 0;
67 if (file)
68 {
69 file->seek(0);
70 archive = new CTarReader(file, ignoreCase, ignorePaths);
71 }
72 return archive;
73}
74
75//! Check if the file might be loaded by this class
76/** Check might look into the file.
77\param file File handle to check.
78\return True if file seems to be loadable. */
79bool CArchiveLoaderTAR::isALoadableFileFormat(io::IReadFile* file) const
80{
81 // TAR files consist of blocks of 512 bytes
82 // if it isn't a multiple of 512 then it's not a TAR file.
83 if (file->getSize() % 512)
84 return false;
85
86 file->seek(0);
87
88 // read header of first file
89 STarHeader fHead;
90 file->read(&fHead, sizeof(STarHeader));
91
92 u32 checksum = 0;
93 sscanf(fHead.Checksum, "%o", &checksum);
94
95 // verify checksum
96
97 // some old TAR writers assume that chars are signed, others assume unsigned
98 // USTAR archives have a longer header, old TAR archives end after linkname
99
100 u32 checksum1=0;
101 s32 checksum2=0;
102
103 // remember to blank the checksum field!
104 memset(fHead.Checksum, ' ', 8);
105
106 // old header
107 for (u8* p = (u8*)(&fHead); p < (u8*)(&fHead.Magic[0]); ++p)
108 {
109 checksum1 += *p;
110 checksum2 += c8(*p);
111 }
112
113 if (!strncmp(fHead.Magic, "ustar", 5))
114 {
115 for (u8* p = (u8*)(&fHead.Magic[0]); p < (u8*)(&fHead) + sizeof(fHead); ++p)
116 {
117 checksum1 += *p;
118 checksum2 += c8(*p);
119 }
120 }
121 return checksum1 == checksum || checksum2 == (s32)checksum;
122}
123
124/*
125 TAR Archive
126*/
127CTarReader::CTarReader(IReadFile* file, bool ignoreCase, bool ignorePaths)
128 : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), File(file)
129{
130 #ifdef _DEBUG
131 setDebugName("CTarReader");
132 #endif
133
134 if (File)
135 {
136 File->grab();
137
138 // fill the file list
139 populateFileList();
140
141 sort();
142 }
143}
144
145
146CTarReader::~CTarReader()
147{
148 if (File)
149 File->drop();
150}
151
152const IFileList* CTarReader::getFileList() const
153{
154 return this;
155}
156
157
158u32 CTarReader::populateFileList()
159{
160 STarHeader fHead;
161 Files.clear();
162
163 u32 pos = 0;
164 while ( s32(pos + sizeof(STarHeader)) < File->getSize())
165 {
166 // seek to next file header
167 File->seek(pos);
168
169 // read the header
170 File->read(&fHead, sizeof(fHead));
171
172 // only add standard files for now
173 if (fHead.Link == ETLI_REGULAR_FILE || ETLI_REGULAR_FILE_OLD)
174 {
175 io::path fullPath = "";
176 fullPath.reserve(255);
177
178 // USTAR archives have a filename prefix
179 // may not be null terminated, copy carefully!
180 if (!strncmp(fHead.Magic, "ustar", 5))
181 {
182 c8* np = fHead.FileNamePrefix;
183 while(*np && (np - fHead.FileNamePrefix) < 155)
184 fullPath.append(*np);
185 np++;
186 }
187
188 // append the file name
189 c8* np = fHead.FileName;
190 while(*np && (np - fHead.FileName) < 100)
191 {
192 fullPath.append(*np);
193 np++;
194 }
195
196 // get size
197 core::stringc sSize = "";
198 sSize.reserve(12);
199 np = fHead.Size;
200 while(*np && (np - fHead.Size) < 12)
201 {
202 sSize.append(*np);
203 np++;
204 }
205
206 u32 size = strtoul(sSize.c_str(), NULL, 8);
207#if !defined(_IRR_WINDOWS_CE_PLATFORM_)
208 if (errno == ERANGE)
209 os::Printer::log("File too large", fullPath, ELL_WARNING);
210#endif
211
212 // save start position
213 u32 offset = pos + 512;
214
215 // move to next file header block
216 pos = offset + (size / 512) * 512 + ((size % 512) ? 512 : 0);
217
218 // add file to list
219 addItem(fullPath, offset, size, false );
220 }
221 else
222 {
223 // todo: ETLI_DIRECTORY, ETLI_LINK_TO_ARCHIVED_FILE
224
225 // move to next block
226 pos += 512;
227 }
228
229 }
230
231 return Files.size();
232}
233
234//! opens a file by file name
235IReadFile* CTarReader::createAndOpenFile(const io::path& filename)
236{
237 const s32 index = findFile(filename, false);
238
239 if (index != -1)
240 return createAndOpenFile(index);
241
242 return 0;
243}
244
245//! opens a file by index
246IReadFile* CTarReader::createAndOpenFile(u32 index)
247{
248 if (index >= Files.size() )
249 return 0;
250
251 const SFileListEntry &entry = Files[index];
252 return createLimitReadFile( entry.FullName, File, entry.Offset, entry.Size );
253}
254
255} // end namespace io
256} // end namespace irr
257
258#endif // __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_