-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathZipArchiveEntry.h
391 lines (323 loc) · 11.7 KB
/
ZipArchiveEntry.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
#pragma once
#include "detail/ZipLocalFileHeader.h"
#include "detail/ZipCentralDirectoryFileHeader.h"
#include "methods/ICompressionMethod.h"
#include "methods/StoreMethod.h"
#include "methods/DeflateMethod.h"
#include "methods/LzmaMethod.h"
#include "streams/substream.h"
#include "utils/enum_utils.h"
#include <cstdint>
#include <ctime>
#include <string>
#include <vector>
#include <memory>
class ZipArchive;
/**
* \brief Represents a compressed file within a zip archive.
*/
class ZipArchiveEntry
: public std::enable_shared_from_this<ZipArchiveEntry>
{
friend class ZipFile;
friend class ZipArchive;
public:
typedef std::shared_ptr<ZipArchiveEntry> Ptr;
/**
* \brief Values that represent the way the zip entry will be compressed.
*/
enum class CompressionMode
{
Immediate,
Deferred
};
/**
* \brief Values that represent the MS-DOS file attributes.
*/
enum class Attributes : uint32_t
{
None = 0,
ReadOnly = 1,
Hidden = 2,
System = 4,
Directory = 16,
Archive = 32,
Device = 64,
Normal = 128,
Temporary = 256,
SparseFile = 512,
ReparsePoint = 1024,
Compressed = 2048,
};
MARK_AS_TYPED_ENUMFLAGS_FRIEND(Attributes);
MARK_AS_TYPED_ENUMFLAGS_FRIEND(CompressionMode);
/**
* \brief Destructor.
*/
~ZipArchiveEntry();
/**
* \brief Gets full path of the entry.
*
* \return The full name with the path.
*/
const std::string& GetFullName() const;
/**
* \brief Sets full name with the path of the entry.
*
* \param fullName The full name with the path.
*/
void SetFullName(const std::string& fullName);
/**
* \brief Gets only the file name of the entry (without path).
*
* \return The file name.
*/
const std::string& GetName() const;
/**
* \brief Sets only a file name of the entry.
* If the file is located within some folder, the path is kept.
*
* \param name The file name.
*/
void SetName(const std::string& name);
/**
* \brief Gets the comment of this zip entry.
*
* \return The comment.
*/
const std::string& GetComment() const;
/**
* \brief Sets a comment of this zip entry.
*
* \param comment The comment.
*/
void SetComment(const std::string& comment);
/**
* \brief Gets the time the file was last modified.
*
* \return The last write time.
*/
time_t GetLastWriteTime() const;
/**
* \brief Sets the time the file was last modified.
*
* \param modTime Time of the modifier.
*/
void SetLastWriteTime(time_t modTime);
/**
* \brief Gets the file attributes of this zip entry.
*
* \return The file attributes.
*/
Attributes GetAttributes() const;
/**
* \brief Gets the compression method.
*
* \return The compression method.
*/
uint16_t GetCompressionMethod() const;
/**
* \brief Sets the file attributes of this zip entry.
*
* \param value The file attributes.
*/
void SetAttributes(Attributes value);
/**
* \brief Query if this entry is password protected.
*
* \return true if password protected, false if not.
*/
bool IsPasswordProtected() const;
/**
* \brief Gets the password of the zip entry. If the password is empty string, the password is not set.
*
* \return The password.
*/
const std::string& GetPassword() const;
/**
* \brief Sets a password of the zip entry. If the password is empty string, the password is not set.
* Use before GetDecompressionStream or SetCompressionStream.
*
* \param password The password.
*/
void SetPassword(const std::string& password);
/**
* \brief Gets CRC 32 of the file.
*
* \return The CRC 32.
*/
uint32_t GetCrc32() const;
/**
* \brief Gets the size of the uncompressed data.
*
* \return The size.
*/
size_t GetSize() const;
/**
* \brief Gets the size of compressed data.
*
* \return The compressed size.
*/
size_t GetCompressedSize() const;
/**
* \brief Determine if we can extract the entry.
* It depends on which version was the zip archive created with.
*
* \return true if we can extract, false if not.
*/
bool CanExtract() const;
/**
* \brief Query if this entry is a directory.
*
* \return true if directory, false if not.
*/
bool IsDirectory() const;
/**
* \brief Query if this object is using data descriptor.
* Data descriptor is small chunk of information written after the compressed data.
* It's most useful when encrypting a zip entry.
* When it is not using, the CRC32 value is required before
* encryption of the file data begins. In this case there is no way
* around it: must read the stream in its entirety to compute the
* actual CRC32 before proceeding.
*
* \return true if using data descriptor, false if not.
*/
bool IsUsingDataDescriptor() const;
/**
* \brief Use data descriptor.
* Data descriptor is small chunk of information written after the compressed data.
* It's most useful when encrypting a zip entry.
* When it is not using, the CRC32 value is required before
* encryption of the file data begins. In this case there is no way
* around it: must read the stream in its entirety to compute the
* actual CRC32 before proceeding.
* \param use (Optional) If true, use the data descriptor, false to not use.
*/
void UseDataDescriptor(bool use = true);
/**
* \brief Sets the input stream to fetch the data to compress from.
*
* \param stream The input stream to compress.
* \param method (Optional) The method of compression.
* \param mode (Optional) The mode of compression.
* If deferred mode is chosen, the data are compressed when the zip archive is about to be written.
* The stream instance must exist when the ZipArchive::WriteToStream method is called.
* The advantage of deferred compression mode is the compressed data needs not to be loaded
* into the memory, because they are streamed into the final output stream.
*
* If immediate mode is chosen, the data are compressed immediately into the memory buffer.
* It is not recommended to use this method for large files.
* The advantage of immediate mode is the input stream can be destroyed (i.e. by scope)
* even before the ZipArchive::WriteToStream method is called.
*
* \return true if it succeeds, false if it fails.
*/
bool SetCompressionStream(std::istream& stream, ICompressionMethod::Ptr method = DeflateMethod::Create(), CompressionMode mode = CompressionMode::Deferred);
/**
* \brief Sets compression stream to be null and unsets the password. The entry would contain no data with zero size.
*/
void UnsetCompressionStream();
/**
* \brief Gets raw stream of the compressed data.
*
* \return null if it fails, else the stream of raw data.
*/
std::istream* GetRawStream();
/**
* \brief Gets decompression stream.
* If the file is encrypted and correct password is not provided, it returns nullptr.
*
* \return null if it fails, else the decompression stream.
*/
std::istream* GetDecompressionStream();
/**
* \brief Query if the GetRawStream method has been already called.
*
* \return true if the raw stream is opened, false if not.
*/
bool IsRawStreamOpened() const;
/**
* \brief Query if the GetDecompressionStream method has been already called.
*
* \return true if the decompression stream is opened, false if not.
*/
bool IsDecompressionStreamOpened() const;
/**
* \brief Closes the raw stream, opened by GetRawStream.
*/
void CloseRawStream();
/**
* \brief Closes the decompression stream, opened by GetDecompressionStream.
*/
void CloseDecompressionStream();
/**
* \brief Removes this entry from the ZipArchive.
*/
void Remove();
private:
static const uint16_t VERSION_MADEBY_DEFAULT = 63;
static const uint16_t VERSION_NEEDED_DEFAULT = 10;
static const uint16_t VERSION_NEEDED_EXPLICIT_DIRECTORY = 20;
static const uint16_t VERSION_NEEDED_ZIP64 = 45;
enum class BitFlag : uint16_t
{
None = 0,
Encrypted = 1,
DataDescriptor = 8,
UnicodeFileName = 0x800
};
MARK_AS_TYPED_ENUMFLAGS_FRIEND(BitFlag);
ZipArchiveEntry();
ZipArchiveEntry(const ZipArchiveEntry&);
ZipArchiveEntry& operator = (ZipArchiveEntry&);
// static methods
static ZipArchiveEntry::Ptr CreateNew(ZipArchive* zipArchive, const std::string& fullPath);
static ZipArchiveEntry::Ptr CreateExisting(ZipArchive* zipArchive, detail::ZipCentralDirectoryFileHeader& cd);
// methods
void SetCompressionMethod(uint16_t value);
BitFlag GetGeneralPurposeBitFlag() const;
void SetGeneralPurposeBitFlag(BitFlag value, bool set = true);
uint16_t GetVersionToExtract() const;
void SetVersionToExtract(uint16_t value);
uint16_t GetVersionMadeBy() const;
void SetVersionMadeBy(uint16_t value);
int32_t GetOffsetOfLocalHeader() const;
void SetOffsetOfLocalHeader(int32_t value);
bool HasCompressionStream() const;
void FetchLocalFileHeader();
void CheckFilenameCorrection();
void FixVersionToExtractAtLeast(uint16_t value);
void SyncLFH_with_CDFH();
void SyncCDFH_with_LFH();
std::ios::pos_type GetOffsetOfCompressedData();
std::ios::pos_type SeekToCompressedData();
void SerializeLocalFileHeader(std::ostream& stream);
void SerializeCentralDirectoryFileHeader(std::ostream& stream);
void UnloadCompressionData();
void InternalCompressStream(std::istream& inputStream, std::ostream& outputStream);
// for encryption
void FigureCrc32();
uint8_t GetLastByteOfEncryptionHeader();
//////////////////////////////////////////////////////////////////////////
ZipArchive* _archive; //< pointer to the owning zip archive
std::shared_ptr<std::istream> _rawStream; //< stream of raw compressed data
std::shared_ptr<std::istream> _compressionStream; //< stream of uncompressed data
std::shared_ptr<std::istream> _encryptionStream; //< underlying encryption stream
std::shared_ptr<std::istream> _archiveStream; //< substream of owning zip archive file
// internal compression data
std::shared_ptr<std::iostream> _immediateBuffer; //< stream used in the immediate mode, stores compressed data in memory
std::istream* _inputStream; //< input stream
ICompressionMethod::Ptr _compressionMethod; //< compression method
CompressionMode _compressionMode; //< compression mode, either deferred or immediate
std::string _name;
// TODO: make as flags
bool _originallyInArchive;
bool _isNewOrChanged;
bool _hasLocalFileHeader;
detail::ZipLocalFileHeader _localFileHeader;
detail::ZipCentralDirectoryFileHeader _centralDirectoryFileHeader;
std::ios::pos_type _offsetOfCompressedData;
std::ios::pos_type _offsetOfSerializedLocalFileHeader;
std::string _password;
};