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