Mercurial > hg > dmlib
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 } |