comparison dmpackutil.c @ 0:32250b436bca

Initial re-import.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 28 Sep 2012 01:54:23 +0300
parents
children 09528946f92b bb14d7907eb2
comparison
equal deleted inserted replaced
-1:000000000000 0:32250b436bca
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 }