diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8.1/source/Irrlicht/CTarReader.cpp | 258 |
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 | |||
17 | namespace irr | ||
18 | { | ||
19 | namespace io | ||
20 | { | ||
21 | |||
22 | //! Constructor | ||
23 | CArchiveLoaderTAR::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 | ||
33 | bool 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. | ||
39 | bool 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. */ | ||
47 | IFileArchive* 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. | ||
64 | IFileArchive* 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. */ | ||
79 | bool 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 | */ | ||
127 | CTarReader::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 | |||
146 | CTarReader::~CTarReader() | ||
147 | { | ||
148 | if (File) | ||
149 | File->drop(); | ||
150 | } | ||
151 | |||
152 | const IFileList* CTarReader::getFileList() const | ||
153 | { | ||
154 | return this; | ||
155 | } | ||
156 | |||
157 | |||
158 | u32 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 | ||
235 | IReadFile* 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 | ||
246 | IReadFile* 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_ | ||