1 #include <string.h>
2 #include "zip/ZipArchiveWriter.h"
3 #include "zip/ZipDeflateStream.h"
4 #include "zip/ZipDefs.h"
5 #include <zlib.h>
6
7 using namespace Framework;
8 using namespace std;
9 using namespace Zip;
10
CZipArchiveWriter()11 CZipArchiveWriter::CZipArchiveWriter()
12 {
13
14 }
15
~CZipArchiveWriter()16 CZipArchiveWriter::~CZipArchiveWriter()
17 {
18 for(FileList::iterator fileIterator(m_files.begin());
19 m_files.end() != fileIterator; fileIterator++)
20 {
21 delete (*fileIterator);
22 }
23 }
24
Write(CStream & stream)25 void CZipArchiveWriter::Write(CStream& stream)
26 {
27 typedef pair<std::string, ZIPDIRFILEHEADER> DirectoryEntry;
28 typedef list<DirectoryEntry> DirectoryEntryList;
29
30 DirectoryEntryList directoryEntries;
31
32 for(FileList::iterator fileIterator(m_files.begin());
33 m_files.end() != fileIterator; fileIterator++)
34 {
35 CZipFile* file(*fileIterator);
36
37 string fileName(file->GetName());
38 uint32 relativePosition = static_cast<uint32>(stream.Tell());
39
40 //Build an incomplete file header
41 ZIPFILEHEADER fileHeader;
42 memset(&fileHeader, 0, sizeof(ZIPFILEHEADER));
43 fileHeader.signature = FILEHEADER_SIG;
44 fileHeader.versionNeeded = 0x14;
45 fileHeader.compressedSize = 0;
46 fileHeader.uncompressedSize = 0;
47 fileHeader.compressionMethod = 8;
48 fileHeader.fileNameLength = static_cast<uint16>(fileName.length());
49 fileHeader.crc = 0;
50
51 //Write file header
52 stream.Write(&fileHeader, sizeof(ZIPFILEHEADER));
53
54 //Write file name
55 stream.Write(fileName.c_str(), fileName.length());
56
57 //Write body
58 CZipDeflateStream proxyStream(stream);
59 file->Write(proxyStream);
60 proxyStream.Flush();
61
62 //Update header with info
63 fileHeader.crc = proxyStream.GetCrc();
64 fileHeader.compressedSize = static_cast<uint32>(proxyStream.GetCompressedLength());
65 fileHeader.uncompressedSize = static_cast<uint32>(proxyStream.GetUncompressedLength());
66
67 //Write back old header
68 stream.Seek(relativePosition, STREAM_SEEK_SET);
69 stream.Write(&fileHeader, sizeof(ZIPFILEHEADER));
70 stream.Seek(0, STREAM_SEEK_END);
71
72 //Create directory entry for this file
73 ZIPDIRFILEHEADER dirFileHeader;
74 memset(&dirFileHeader, 0, sizeof(ZIPDIRFILEHEADER));
75 dirFileHeader.signature = DIRFILEHEADER_SIG;
76 dirFileHeader.versionMadeBy = 0x14;
77 dirFileHeader.versionNeeded = 0x14;
78 dirFileHeader.crc = fileHeader.crc;
79 dirFileHeader.fileStartOffset = relativePosition;
80 dirFileHeader.compressedSize = fileHeader.compressedSize;
81 dirFileHeader.uncompressedSize = fileHeader.uncompressedSize;
82 dirFileHeader.fileNameLength = fileHeader.fileNameLength;
83 dirFileHeader.compressionMethod = fileHeader.compressionMethod;
84
85 directoryEntries.push_back(DirectoryEntry(fileName, dirFileHeader));
86 }
87
88 //Write directory
89 uint64 dirStart = stream.Tell();
90
91 for(DirectoryEntryList::const_iterator entryIterator(directoryEntries.begin());
92 directoryEntries.end() != entryIterator; entryIterator++)
93 {
94 const DirectoryEntry& entry(*entryIterator);
95
96 //Write file header
97 stream.Write(&entry.second, sizeof(ZIPDIRFILEHEADER));
98
99 //Write file name
100 stream.Write(entry.first.c_str(), entry.first.length());
101 }
102
103 uint64 dirEnd = stream.Tell();
104
105 //Write directory header
106 {
107 ZIPDIRENDHEADER dirHeader;
108 memset(&dirHeader, 0, sizeof(ZIPDIRENDHEADER));
109 dirHeader.signature = DIRENDHEADER_SIG;
110 dirHeader.dirEntryCount = static_cast<uint16>(directoryEntries.size());
111 dirHeader.totalDirEntryCount = static_cast<uint16>(directoryEntries.size());
112 dirHeader.dirSize = static_cast<uint32>(dirEnd - dirStart);
113 dirHeader.dirStartOffset = static_cast<uint32>(dirStart);
114
115 //Write file header
116 stream.Write(&dirHeader, sizeof(ZIPDIRENDHEADER));
117 }
118 }
119
InsertFile(CZipFile * file)120 void CZipArchiveWriter::InsertFile(CZipFile* file)
121 {
122 m_files.push_back(file);
123 }
124