0
|
1 /*
|
|
2 * DMLib
|
|
3 * -- PACK-file additional utility routines
|
|
4 * Programmed and designed by Matti 'ccr' Hamalainen
|
|
5 * (C) Copyright 2011 Tecnic Software productions (TNSP)
|
|
6 */
|
|
7 #include "dmpackutil.h"
|
|
8 #include <zlib.h>
|
|
9 #include "dmfile.h"
|
|
10
|
|
11
|
|
12 DMPackEntry *dm_pack_entry_copy(const DMPackEntry *src)
|
|
13 {
|
|
14 DMPackEntry *node = dm_pack_entry_new();
|
|
15 if (node == NULL)
|
|
16 return NULL;
|
|
17
|
|
18 strncpy(node->filename, src->filename, sizeof(node->filename));
|
|
19 node->filename[sizeof(node->filename) - 1] = 0;
|
|
20
|
|
21 node->size = src->size;
|
|
22 node->offset = src->offset;
|
|
23 node->length = src->length;
|
|
24 node->resFlags = src->resFlags;
|
|
25
|
|
26 return node;
|
|
27 }
|
|
28
|
|
29
|
|
30 /*
|
|
31 * CLOSE/WRITE the packfile
|
|
32 */
|
|
33 int dm_pack_write(DMPackFile * pack)
|
|
34 {
|
|
35 DMPackEntry *node;
|
|
36 DMPackFileHeader hdr;
|
|
37
|
|
38 if (pack == NULL)
|
|
39 return DMERR_OK;
|
|
40
|
|
41 if (pack->file == NULL)
|
|
42 return DMERR_FOPEN;
|
|
43
|
|
44 // Compute directory offset and number of entries
|
|
45 memcpy(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident));
|
|
46 hdr.version = DPACK_VERSION;
|
|
47 hdr.dirEntries = 0;
|
|
48 hdr.dirOffset =
|
|
49 sizeof(hdr.ident) + sizeof(hdr.version) +
|
|
50 sizeof(hdr.dirEntries) + sizeof(hdr.dirOffset);
|
|
51
|
|
52 node = pack->entries;
|
|
53 while (node != NULL)
|
|
54 {
|
|
55 hdr.dirEntries++;
|
|
56 hdr.dirOffset += node->length;
|
|
57 node = node->next;
|
|
58 }
|
|
59
|
|
60 // Write PACK header
|
|
61 if (fseek(pack->file, 0L, SEEK_SET) != 0)
|
|
62 return -4;
|
|
63
|
|
64 dm_fwrite_str(pack->file, (Uint8 *) & hdr.ident, sizeof(hdr.ident));
|
|
65 dm_fwrite_le16(pack->file, hdr.version);
|
|
66 dm_fwrite_le32(pack->file, hdr.dirEntries);
|
|
67 dm_fwrite_le32(pack->file, hdr.dirOffset);
|
|
68
|
|
69 // Write the directory
|
|
70 if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
|
|
71 return -5;
|
|
72
|
|
73 node = pack->entries;
|
|
74 while (node != NULL)
|
|
75 {
|
|
76 // Write one entry
|
|
77 dm_fwrite_str(pack->file, node->filename, sizeof(node->filename));
|
|
78 dm_fwrite_le32(pack->file, node->size);
|
|
79 dm_fwrite_le32(pack->file, node->offset);
|
|
80 dm_fwrite_le32(pack->file, node->length);
|
|
81 dm_fwrite_le32(pack->file, node->resFlags);
|
|
82
|
|
83 node = node->next;
|
|
84 }
|
|
85
|
|
86 return DMERR_OK;
|
|
87 }
|
|
88
|
|
89
|
|
90 /*
|
|
91 * CREATE a packfile, for writing
|
|
92 */
|
|
93 int dm_pack_create(const char *filename, DMPackFile ** pack)
|
|
94 {
|
|
95 // Allocate packfile-structure
|
|
96 *pack = (DMPackFile *) dmCalloc(1, sizeof(DMPackFile));
|
|
97 if (*pack == NULL)
|
|
98 return DMERR_MALLOC;
|
|
99
|
|
100 // Open the file
|
|
101 (*pack)->file = fopen(filename, "wb");
|
|
102 if ((*pack)->file == NULL)
|
|
103 {
|
|
104 dmFree(*pack);
|
|
105 return DMERR_FOPEN;
|
|
106 }
|
|
107
|
|
108 (*pack)->filename = dm_strdup(filename);
|
|
109
|
|
110 // Set the result
|
|
111 return DMERR_OK;
|
|
112 }
|
|
113
|
|
114
|
|
115 /*
|
|
116 * ADD a file into the PACK
|
|
117 */
|
|
118 int dm_pack_add_file(DMPackFile * pack, const char *filename, BOOL doCompress, int resFlags,
|
|
119 DMPackEntry ** ppEntry)
|
|
120 {
|
|
121 z_stream compStream;
|
|
122 off_t startOffs;
|
|
123 unsigned int compSize;
|
|
124 FILE *inFile;
|
|
125 Uint8 *inBuffer, *outBuffer;
|
|
126 DMPackEntry entry, *node;
|
|
127 int result;
|
|
128
|
|
129 *ppEntry = NULL;
|
|
130
|
|
131 if (pack == NULL)
|
|
132 return DMERR_OK;
|
|
133
|
|
134 if (pack->file == NULL)
|
|
135 return DMERR_FOPEN;
|
|
136
|
|
137 // Compute starting offset
|
|
138 startOffs = sizeof(DMPackFileHeader);
|
|
139 node = pack->entries;
|
|
140 while (node != NULL)
|
|
141 {
|
|
142 startOffs += node->length;
|
|
143 node = node->next;
|
|
144 }
|
|
145
|
|
146 // Seek to the position
|
|
147 if (fseek(pack->file, startOffs, SEEK_SET) != 0)
|
|
148 return DMERR_INVALID;
|
|
149
|
|
150 // Read file data
|
|
151 if ((inFile = fopen(filename, "rb")) == NULL)
|
|
152 return -1;
|
|
153
|
|
154 // Allocate temporary buffer
|
|
155 inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
|
|
156 if (!inBuffer)
|
|
157 {
|
|
158 fclose(inFile);
|
|
159 return DMERR_MALLOC;
|
|
160 }
|
|
161
|
|
162 outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
|
|
163 if (!outBuffer)
|
|
164 {
|
|
165 dmFree(inBuffer);
|
|
166 fclose(inFile);
|
|
167 return DMERR_MALLOC;
|
|
168 }
|
|
169
|
|
170 // Read (and possibly compress) the data
|
|
171 compSize = 0;
|
|
172 compStream.zalloc = (alloc_func) Z_NULL;
|
|
173 compStream.zfree = (free_func) Z_NULL;
|
|
174 compStream.opaque = (voidpf) Z_NULL;
|
|
175 result = deflateInit(&compStream, (doCompress) ? Z_DEFAULT_COMPRESSION : 0);
|
|
176 if (result != Z_OK)
|
|
177 {
|
|
178 dmFree(inBuffer);
|
|
179 dmFree(outBuffer);
|
|
180 fclose(inFile);
|
|
181 return DMERR_COMPRESSION;
|
|
182 }
|
|
183
|
|
184 // Initialize compression streams
|
|
185 result = Z_OK;
|
|
186 while (!feof(inFile) && result == Z_OK)
|
|
187 {
|
|
188 compStream.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, inFile);
|
|
189 compStream.next_in = inBuffer;
|
|
190 compStream.next_out = outBuffer;
|
|
191 compStream.avail_out = DPACK_TMPSIZE;
|
|
192 compStream.total_out = 0;
|
|
193 result = deflate(&compStream, Z_FULL_FLUSH);
|
|
194
|
|
195 if (result == Z_OK && compStream.total_out > 0)
|
|
196 {
|
|
197 compSize += compStream.total_out;
|
|
198 fwrite(outBuffer, sizeof(Uint8), compStream.total_out, pack->file);
|
|
199 }
|
|
200 }
|
|
201
|
|
202 // Create directory entry
|
|
203 strncpy(entry.filename, filename, sizeof(entry.filename));
|
|
204 entry.filename[sizeof(entry.filename) - 1] = 0;
|
|
205 entry.size = compStream.total_in;
|
|
206 entry.offset = startOffs;
|
|
207 entry.length = compSize;
|
|
208 entry.resFlags = resFlags;
|
|
209
|
|
210 // Cleanup
|
|
211 deflateEnd(&compStream);
|
|
212 dmFree(inBuffer);
|
|
213 dmFree(outBuffer);
|
|
214 fclose(inFile);
|
|
215
|
|
216 // Add directory entry
|
|
217 *ppEntry = dm_pack_entry_copy(&entry);
|
|
218 if (*ppEntry == NULL)
|
|
219 return DMERR_MALLOC;
|
|
220
|
|
221 dm_pack_entry_insert(&pack->entries, *ppEntry);
|
|
222
|
|
223 return DMERR_OK;
|
|
224 }
|
|
225
|
|
226
|
|
227 /*
|
|
228 * EXTRACT a file from the PACK
|
|
229 */
|
|
230 int dm_pack_extract_file(DMPackFile *pack, DMPackEntry * entry)
|
|
231 {
|
|
232 z_stream compStream;
|
|
233 FILE *outFile;
|
|
234 Uint8 *inBuffer, *outBuffer;
|
|
235 size_t inDataLeft;
|
|
236 int ret;
|
|
237
|
|
238 if (pack == NULL)
|
|
239 return DMERR_OK;
|
|
240
|
|
241 if (pack->file == NULL)
|
|
242 return DMERR_FOPEN;
|
|
243
|
|
244 // Seek to the position
|
|
245 if (fseek(pack->file, entry->offset, SEEK_SET) != 0)
|
|
246 return DMERR_INVALID;
|
|
247
|
|
248 // Open destination file
|
|
249 if ((outFile = fopen(entry->filename, "wb")) == NULL)
|
|
250 return -1;
|
|
251
|
|
252 // Allocate temporary buffer
|
|
253 if ((inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
|
|
254 {
|
|
255 fclose(outFile);
|
|
256 return DMERR_MALLOC;
|
|
257 }
|
|
258
|
|
259 if ((outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
|
|
260 {
|
|
261 dmFree(inBuffer);
|
|
262 fclose(outFile);
|
|
263 return DMERR_MALLOC;
|
|
264 }
|
|
265
|
|
266 // Read and uncompress the data
|
|
267 compStream.zalloc = (alloc_func) Z_NULL;
|
|
268 compStream.zfree = (free_func) Z_NULL;
|
|
269 compStream.opaque = (voidpf) Z_NULL;
|
|
270 ret = inflateInit(&compStream);
|
|
271 if (ret != Z_OK)
|
|
272 {
|
|
273 dmFree(inBuffer);
|
|
274 dmFree(outBuffer);
|
|
275 fclose(outFile);
|
|
276 return DMERR_COMPRESSION;
|
|
277 }
|
|
278
|
|
279 // Initialize compression streams
|
|
280 inDataLeft = entry->length;
|
|
281 ret = Z_OK;
|
|
282 while (inDataLeft > 0 && ret == Z_OK)
|
|
283 {
|
|
284 if (inDataLeft >= DPACK_TMPSIZE)
|
|
285 compStream.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, pack->file);
|
|
286 else
|
|
287 compStream.avail_in = fread(inBuffer, sizeof(Uint8), inDataLeft, pack->file);
|
|
288
|
|
289 inDataLeft -= compStream.avail_in;
|
|
290 compStream.next_in = inBuffer;
|
|
291
|
|
292 while (compStream.avail_in > 0 && ret == Z_OK)
|
|
293 {
|
|
294 compStream.next_out = outBuffer;
|
|
295 compStream.avail_out = DPACK_TMPSIZE;
|
|
296 compStream.total_out = 0;
|
|
297 ret = inflate(&compStream, Z_FULL_FLUSH);
|
|
298 if (compStream.total_out > 0)
|
|
299 {
|
|
300 fwrite(outBuffer, sizeof(Uint8), compStream.total_out, outFile);
|
|
301 }
|
|
302 }
|
|
303 }
|
|
304
|
|
305 // Cleanup
|
|
306 inflateEnd(&compStream);
|
|
307 dmFree(inBuffer);
|
|
308 dmFree(outBuffer);
|
|
309 fclose(outFile);
|
|
310
|
|
311 return DMERR_OK;
|
|
312 }
|