1 /*
2  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
3  *
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *
9  *    Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *    Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the
15  *    distribution.
16  *
17  *    Neither the name of Texas Instruments Incorporated nor the names of
18  *    its contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <pch.h>
35 #include <tinfl.c>
36 #include "ziparchive.h"
37 #include "devicedb.h"
38 
39 using namespace std;
40 using namespace TI::DLL430;
41 using namespace DeviceDb;
42 
43 
44 #pragma pack(push, 1)
45 	struct LocalFileHeader
46 	{
47 		uint32_t signature;
48 		uint16_t version;
49 		uint16_t bitFlag;
50 		uint16_t compression;
51 		uint16_t modificationTime;
52 		uint16_t modificationDate;
53 		uint32_t crc;
54 		uint32_t compressedSize;
55 		uint32_t uncompressedSize;
56 		uint16_t fileNameLength;
57 		uint16_t extraFieldLength;
58 	};
59 
60 	struct DirectoryFileHeader
61 	{
62 		uint32_t signature;
63 		uint16_t versionMadeBy;
64 		uint16_t versionNeeded;
65 		uint16_t bitFlag;
66 		uint16_t compression;
67 		uint16_t modificationTime;
68 		uint16_t modificationDate;
69 		uint32_t crc;
70 		uint32_t compressedSize;
71 		uint32_t uncompressedSize;
72 		uint16_t fileNameLength;
73 		uint16_t extraFieldLength;
74 		uint16_t fileCommentLength;
75 		uint16_t diskNumberStart;
76 		uint16_t internalFileAttributes;
77 		uint32_t externalFileAttributes;
78 		uint32_t offset;
79 	};
80 
81 	struct EndOfDirectory
82 	{
83 		uint32_t signature;
84 		uint16_t diskNumber;
85 		uint16_t directoryStartDisk;
86 		uint16_t entriesOnDisk;
87 		uint16_t totalEntries;
88 		uint32_t directorySize;
89 		uint32_t directoryOffset;
90 		uint16_t commentLength;
91 	};
92 #pragma pack(pop)
93 
94 
open(const string & filename,bool usefile)95 void Archive::open(const string& filename, bool usefile)
96 {
97 	useFile = usefile;
98 
99 	EndOfDirectory endOfDir;
100 	uint8_t * pzip = &g_database[0];
101 
102 	if (useFile)
103 	{
104 		file.open(filename, ios::binary | ios::in);
105 		if (!file)
106 		{
107 			throw runtime_error("failed to open archive");
108 		}
109 		file.seekg(-(int)sizeof(endOfDir), ios::end);
110 		file.read((char*)&endOfDir, sizeof(endOfDir));
111 	}
112 	else
113 	{
114 		memcpy(&endOfDir, &TI::DLL430::DeviceDb::g_database[sizeof(TI::DLL430::DeviceDb::g_database) - sizeof(endOfDir)], sizeof(endOfDir));
115 	}
116 
117 	if (endOfDir.signature != 0x06054b50)
118 	{
119 		throw runtime_error("no file comment allowed");
120 	}
121 
122 	if (useFile)
123 	{
124 		file.seekg(endOfDir.directoryOffset, ios::beg);
125 	}
126 	else
127 	{
128 		pzip = pzip + endOfDir.directoryOffset;
129 	}
130 
131 	DirectoryFileHeader header;
132 
133 	const uint16_t supportedCompressions[] = {0, 8, 9};
134 
135 	for (int i = 0; i < endOfDir.totalEntries; ++i)
136 	{
137 		if (useFile)
138 		{
139 			file.read((char*)&header, sizeof(header));
140 		}
141 		else
142 		{
143 			memcpy(&header, pzip, sizeof(header));
144 			pzip = pzip + sizeof(header);
145 		}
146 
147 		const uint16_t* endComp = end(supportedCompressions);
148 		if (find(begin(supportedCompressions), endComp, header.compression) == endComp)
149 			throw runtime_error("compression type not supported (only deflate/deflate64)");
150 
151 		if (header.bitFlag & 0xfff9)
152 			throw runtime_error("unsupported option (encrypted?)");
153 
154 		vector<char> name(header.fileNameLength);
155 		if (useFile)
156 		{
157 			file.read(name.data(), name.size());
158 		}
159 		else
160 		{
161 			memcpy(name.data(), pzip, name.size());
162 			pzip = pzip + name.size();
163 		}
164 		if (header.compressedSize > 0)
165 		{
166 			string n(name.data(), name.size());
167 			size_t pos = n.find_last_of("/") + 1;
168 			directory[n.substr(pos)] = header.offset;
169 		}
170 		if (useFile)
171 		{
172 			file.seekg(header.extraFieldLength + header.fileCommentLength, ios::cur);
173 		}
174 		else
175 		{
176 			pzip = pzip + header.extraFieldLength + header.fileCommentLength;
177 		}
178 	}
179 }
180 
readFile(const string & filename,vector<char> * dst) const181 void Archive::readFile(const string& filename, vector<char>* dst) const
182 {
183 	const auto it = directory.find(filename);
184 	if (it == directory.end())
185 		throw runtime_error("file does not exist");
186 
187 	const uint32_t offset = it->second;
188 	uint8_t * pzip = &g_database[0];
189 	if (useFile)
190 	{
191 		file.seekg(offset, ios::beg);
192 	}
193 	else
194 	{
195 		pzip = pzip + offset;
196 	}
197 
198 	LocalFileHeader header;
199 	if (useFile)
200 	{
201 		file.read((char*)&header, sizeof(header));
202 	}
203 	else
204 	{
205 		memcpy(&header, pzip, sizeof(header));
206 		pzip = pzip + sizeof(header);
207 	}
208 
209 	if (useFile)
210 	{
211 		file.seekg(header.fileNameLength + header.extraFieldLength, ios::cur);
212 	}
213 	else
214 	{
215 		dst->resize(header.uncompressedSize);
216 		pzip = pzip + header.fileNameLength + header.extraFieldLength;
217 	}
218 
219 	if (header.compression != 0)
220 	{
221 		vector<unsigned char> compressedData(header.compressedSize);
222 		if (useFile)
223 		{
224 			file.read((char*)compressedData.data(), compressedData.size());
225 		}
226 		else
227 		{
228 			memcpy(compressedData.data(), pzip, compressedData.size());
229 		}
230 		size_t uncompressed = tinfl_decompress_mem_to_mem(dst->data(), dst->size(), compressedData.data(), compressedData.size(), 0);
231 		if (uncompressed != header.uncompressedSize)
232 		{
233 			throw runtime_error("error decompressing data");
234 		}
235 	}
236 	else
237 	{
238 		if (useFile)
239 		{
240 			file.read(dst->data(), dst->size());
241 		}
242 		else
243 		{
244 			memcpy(dst->data(), pzip, dst->size());
245 			pzip = pzip + dst->size();
246 		}
247 	}
248 }
249 
250 
getFileList(vector<string> * list) const251 void Archive::getFileList(vector<string>* list) const
252 {
253 	for (const auto& it : directory)
254 	{
255 		if (it.first.rfind(".xml") != string::npos)
256 			list->push_back(it.first);
257 	}
258 }
259