~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CTarReader.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2009-2011 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_