Mercurial > audlegacy-plugins
annotate src/xsf/corlett.c @ 3085:ac0af6b39272
Introduce new GIO plugin to buildsystem. stdio is now deprecated.
Thoughts:
- getc()/ungetc() should be moved to VFS core now
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Wed, 29 Apr 2009 20:58:36 -0500 |
parents | 4c112fb7f9f5 |
children |
rev | line source |
---|---|
2961 | 1 /* |
2 | |
3 Audio Overload SDK | |
4 | |
5 Copyright (c) 2007-2008, R. Belmont and Richard Bannister. | |
6 | |
7 All rights reserved. | |
8 | |
9 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | |
10 | |
11 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | |
12 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | |
13 * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | |
14 | |
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
16 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
17 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
18 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
19 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
20 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
22 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
24 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 // corlett.c | |
29 | |
30 // Decodes file format designed by Neill Corlett (PSF, QSF, ...) | |
31 | |
32 /* | |
33 - First 3 bytes: ASCII signature: "PSF" (case sensitive) | |
34 | |
35 - Next 1 byte: Version byte | |
36 The version byte is used to determine the type of PSF file. It does NOT | |
37 affect the basic structure of the file in any way. | |
38 | |
39 Currently accepted version bytes are: | |
40 0x01: Playstation (PSF1) | |
41 0x02: Playstation 2 (PSF2) | |
42 0x11: Saturn (SSF) [TENTATIVE] | |
43 0x12: Dreamcast (DSF) [TENTATIVE] | |
44 0x21: Nintendo 64 (USF) [RESERVED] | |
45 0x41: Capcom QSound (QSF) | |
46 | |
47 - Next 4 bytes: Size of reserved area (R), little-endian unsigned long | |
48 | |
49 - Next 4 bytes: Compressed program length (N), little-endian unsigned long | |
50 This is the length of the program data _after_ compression. | |
51 | |
52 - Next 4 bytes: Compressed program CRC-32, little-endian unsigned long | |
53 This is the CRC-32 of the program data _after_ compression. Filling in | |
54 this value is mandatory, as a PSF file may be regarded as corrupt if it | |
55 does not match. | |
56 | |
57 - Next R bytes: Reserved area. | |
58 May be empty if R is 0 bytes. | |
59 | |
60 - Next N bytes: Compressed program, in zlib compress() format. | |
61 May be empty if N is 0 bytes. | |
62 | |
63 The following data is optional and may be omitted: | |
64 | |
65 - Next 5 bytes: ASCII signature: "[TAG]" (case sensitive) | |
66 If these 5 bytes do not match, then the remainder of the file may be | |
67 regarded as invalid and discarded. | |
68 | |
69 - Remainder of file: Uncompressed ASCII tag data. | |
70 */ | |
71 | |
72 #include <assert.h> | |
73 #include <string.h> | |
74 #include <stdlib.h> | |
75 | |
76 #include "ao.h" | |
77 #include "corlett.h" | |
78 | |
79 #include <zlib.h> | |
80 #include <stdlib.h> | |
81 | |
82 #define DECOMP_MAX_SIZE ((32 * 1024 * 1024) + 12) | |
83 | |
84 int corlett_decode(uint8 *input, uint32 input_len, uint8 **output, uint64 *size, corlett_t **c) | |
85 { | |
86 uint32 *buf; | |
87 uint32 res_area, comp_crc, actual_crc; | |
88 uint8 *decomp_dat, *tag_dec; | |
89 uLongf decomp_length, comp_length; | |
90 | |
91 // 32-bit pointer to data | |
92 buf = (uint32 *)input; | |
93 | |
94 // Check we have a PSF format file. | |
95 if ((input[0] != 'P') || (input[1] != 'S') || (input[2] != 'F')) | |
96 { | |
97 return AO_FAIL; | |
98 } | |
99 | |
100 // Get our values | |
101 res_area = LE32(buf[1]); | |
102 comp_length = LE32(buf[2]); | |
103 comp_crc = LE32(buf[3]); | |
104 | |
105 if (comp_length > 0) | |
106 { | |
107 // Check length | |
108 if (input_len < comp_length + 16) | |
109 return AO_FAIL; | |
110 | |
111 // Check CRC is correct | |
112 actual_crc = crc32(0, (unsigned char *)&buf[4+(res_area/4)], comp_length); | |
113 if (actual_crc != comp_crc) | |
114 return AO_FAIL; | |
115 | |
116 // Decompress data if any | |
117 decomp_dat = malloc(DECOMP_MAX_SIZE); | |
118 decomp_length = DECOMP_MAX_SIZE; | |
119 if (uncompress(decomp_dat, &decomp_length, (unsigned char *)&buf[4+(res_area/4)], comp_length) != Z_OK) | |
120 { | |
121 free(decomp_dat); | |
122 return AO_FAIL; | |
123 } | |
124 | |
125 // Resize memory buffer to what we actually need | |
126 decomp_dat = realloc(decomp_dat, (size_t)decomp_length + 1); | |
127 } | |
128 else | |
129 { | |
130 decomp_dat = NULL; | |
131 decomp_length = 0; | |
132 } | |
133 | |
134 // Make structure | |
135 *c = malloc(sizeof(corlett_t)); | |
136 if (!(*c)) | |
137 { | |
138 free(decomp_dat); | |
139 return AO_FAIL; | |
140 } | |
141 memset(*c, 0, sizeof(corlett_t)); | |
142 strcpy((*c)->inf_title, "n/a"); | |
143 strcpy((*c)->inf_copy, "n/a"); | |
144 strcpy((*c)->inf_artist, "n/a"); | |
145 strcpy((*c)->inf_game, "n/a"); | |
146 strcpy((*c)->inf_year, "n/a"); | |
147 strcpy((*c)->inf_length, "n/a"); | |
148 strcpy((*c)->inf_fade, "n/a"); | |
149 | |
150 // set reserved section pointer | |
151 (*c)->res_section = &buf[4]; | |
152 (*c)->res_size = res_area; | |
153 | |
154 // Return it | |
155 if (output != NULL && size != NULL) | |
156 { | |
157 *output = decomp_dat; | |
158 *size = decomp_length; | |
159 } | |
160 else | |
161 free(decomp_dat); | |
162 | |
163 // Next check for tags | |
164 input_len -= (comp_length + 16 + res_area); | |
165 if (input_len < 5) | |
166 return AO_SUCCESS; | |
167 | |
2963
4c112fb7f9f5
Comment out debug messages.
William Pitcock <nenolod@atheme.org>
parents:
2961
diff
changeset
|
168 // printf("\n\nNew corlett: input len %d comp length %d res area %d\n", input_len, comp_length, res_area); |
2961 | 169 |
170 tag_dec = input + (comp_length + res_area + 16); | |
171 if ((tag_dec[0] == '[') && (tag_dec[1] == 'T') && (tag_dec[2] == 'A') && (tag_dec[3] == 'G') && (tag_dec[4] == ']')) | |
172 { | |
173 int tag, l, num_tags, data; | |
174 | |
175 // Tags found! | |
176 tag_dec += 5; | |
177 input_len -= 5; | |
178 | |
179 tag = 0; | |
180 data = false; | |
181 num_tags = 0; | |
182 l = 0; | |
183 while (input_len && (num_tags < MAX_UNKNOWN_TAGS)) | |
184 { | |
185 if (data) | |
186 { | |
187 if ((*tag_dec == 0xA) || (*tag_dec == 0x00)) | |
188 { | |
189 (*c)->tag_data[num_tags][l] = 0; | |
190 data = false; | |
191 num_tags++; | |
192 l = 0; | |
193 } | |
194 else | |
195 { | |
196 (*c)->tag_data[num_tags][l++] = *tag_dec; | |
197 } | |
198 } | |
199 else | |
200 { | |
201 if (*tag_dec == '=') | |
202 { | |
203 (*c)->tag_name[num_tags][l] = 0; | |
204 l = 0; | |
205 data = true; | |
206 } | |
207 else | |
208 { | |
209 (*c)->tag_name[num_tags][l++] = *tag_dec; | |
210 } | |
211 } | |
212 | |
213 tag_dec++; | |
214 input_len--; | |
215 } | |
216 | |
217 | |
218 // Now, process that tag array into what we expect | |
219 for (num_tags = 0; num_tags < MAX_UNKNOWN_TAGS; num_tags++) | |
220 { | |
221 // See if tag belongs in one of the special fields we have | |
222 if (!strcasecmp((*c)->tag_name[num_tags], "_lib")) | |
223 { | |
224 strcpy((*c)->lib, (*c)->tag_data[num_tags]); | |
225 (*c)->tag_data[num_tags][0] = 0; | |
226 (*c)->tag_name[num_tags][0] = 0; | |
227 } | |
228 else if (!strncmp((*c)->tag_name[num_tags], "_lib2", 5)) | |
229 { | |
230 strcpy((*c)->libaux[0], (*c)->tag_data[num_tags]); | |
231 (*c)->tag_data[num_tags][0] = 0; | |
232 (*c)->tag_name[num_tags][0] = 0; | |
233 } | |
234 else if (!strncmp((*c)->tag_name[num_tags], "_lib3", 5)) | |
235 { | |
236 strcpy((*c)->libaux[1], (*c)->tag_data[num_tags]); | |
237 (*c)->tag_data[num_tags][0] = 0; | |
238 (*c)->tag_name[num_tags][0] = 0; | |
239 } | |
240 else if (!strncmp((*c)->tag_name[num_tags], "_lib4", 5)) | |
241 { | |
242 strcpy((*c)->libaux[2], (*c)->tag_data[num_tags]); | |
243 (*c)->tag_data[num_tags][0] = 0; | |
244 (*c)->tag_name[num_tags][0] = 0; | |
245 } | |
246 else if (!strncmp((*c)->tag_name[num_tags], "_lib5", 5)) | |
247 { | |
248 strcpy((*c)->libaux[3], (*c)->tag_data[num_tags]); | |
249 (*c)->tag_data[num_tags][0] = 0; | |
250 (*c)->tag_name[num_tags][0] = 0; | |
251 } | |
252 else if (!strncmp((*c)->tag_name[num_tags], "_lib6", 5)) | |
253 { | |
254 strcpy((*c)->libaux[4], (*c)->tag_data[num_tags]); | |
255 (*c)->tag_data[num_tags][0] = 0; | |
256 (*c)->tag_name[num_tags][0] = 0; | |
257 } | |
258 else if (!strncmp((*c)->tag_name[num_tags], "_lib7", 5)) | |
259 { | |
260 strcpy((*c)->libaux[5], (*c)->tag_data[num_tags]); | |
261 (*c)->tag_data[num_tags][0] = 0; | |
262 (*c)->tag_name[num_tags][0] = 0; | |
263 } | |
264 else if (!strncmp((*c)->tag_name[num_tags], "_lib8", 5)) | |
265 { | |
266 strcpy((*c)->libaux[6], (*c)->tag_data[num_tags]); | |
267 (*c)->tag_data[num_tags][0] = 0; | |
268 (*c)->tag_name[num_tags][0] = 0; | |
269 } | |
270 else if (!strncmp((*c)->tag_name[num_tags], "_lib9", 5)) | |
271 { | |
272 strcpy((*c)->libaux[7], (*c)->tag_data[num_tags]); | |
273 (*c)->tag_data[num_tags][0] = 0; | |
274 (*c)->tag_name[num_tags][0] = 0; | |
275 } | |
276 else if (!strncmp((*c)->tag_name[num_tags], "_refresh", 8)) | |
277 { | |
278 strcpy((*c)->inf_refresh, (*c)->tag_data[num_tags]); | |
279 (*c)->tag_data[num_tags][0] = 0; | |
280 (*c)->tag_name[num_tags][0] = 0; | |
281 } | |
282 else if (!strncmp((*c)->tag_name[num_tags], "title", 5)) | |
283 { | |
284 strcpy((*c)->inf_title, (*c)->tag_data[num_tags]); | |
285 (*c)->tag_data[num_tags][0] = 0; | |
286 (*c)->tag_name[num_tags][0] = 0; | |
287 } | |
288 else if (!strncmp((*c)->tag_name[num_tags], "copyright", 9)) | |
289 { | |
290 strcpy((*c)->inf_copy, (*c)->tag_data[num_tags]); | |
291 (*c)->tag_data[num_tags][0] = 0; | |
292 (*c)->tag_name[num_tags][0] = 0; | |
293 } | |
294 else if (!strncmp((*c)->tag_name[num_tags], "artist", 6)) | |
295 { | |
296 strcpy((*c)->inf_artist, (*c)->tag_data[num_tags]); | |
297 (*c)->tag_data[num_tags][0] = 0; | |
298 (*c)->tag_name[num_tags][0] = 0; | |
299 } | |
300 else if (!strncmp((*c)->tag_name[num_tags], "game", 4)) | |
301 { | |
302 strcpy((*c)->inf_game, (*c)->tag_data[num_tags]); | |
303 (*c)->tag_data[num_tags][0] = 0; | |
304 (*c)->tag_name[num_tags][0] = 0; | |
305 } | |
306 else if (!strncmp((*c)->tag_name[num_tags], "year", 4)) | |
307 { | |
308 strcpy((*c)->inf_year, (*c)->tag_data[num_tags]); | |
309 (*c)->tag_data[num_tags][0] = 0; | |
310 (*c)->tag_name[num_tags][0] = 0; | |
311 } | |
312 else if (!strncmp((*c)->tag_name[num_tags], "length", 6)) | |
313 { | |
314 strcpy((*c)->inf_length, (*c)->tag_data[num_tags]); | |
315 (*c)->tag_data[num_tags][0] = 0; | |
316 (*c)->tag_name[num_tags][0] = 0; | |
317 } | |
318 else if (!strncmp((*c)->tag_name[num_tags], "fade", 4)) | |
319 { | |
320 strcpy((*c)->inf_fade, (*c)->tag_data[num_tags]); | |
321 (*c)->tag_data[num_tags][0] = 0; | |
322 (*c)->tag_name[num_tags][0] = 0; | |
323 } | |
324 } | |
325 } | |
326 | |
327 // Bingo | |
328 return AO_SUCCESS; | |
329 } | |
330 | |
331 uint32 psfTimeToMS(char *str) | |
332 { | |
333 int x, c=0; | |
334 uint32 acc=0; | |
335 char s[100]; | |
336 | |
337 strncpy(s,str,100); | |
338 s[99]=0; | |
339 | |
340 for (x=strlen(s); x>=0; x--) | |
341 { | |
342 if (s[x]=='.' || s[x]==',') | |
343 { | |
344 acc=atoi(s+x+1); | |
345 s[x]=0; | |
346 } | |
347 else if (s[x]==':') | |
348 { | |
349 if(c==0) | |
350 { | |
351 acc+=atoi(s+x+1)*10; | |
352 } | |
353 else if(c==1) | |
354 { | |
355 acc+=atoi(s+x+(x?1:0))*10*60; | |
356 } | |
357 | |
358 c++; | |
359 s[x]=0; | |
360 } | |
361 else if (x==0) | |
362 { | |
363 if(c==0) | |
364 { | |
365 acc+=atoi(s+x)*10; | |
366 } | |
367 else if(c==1) | |
368 { | |
369 acc+=atoi(s+x)*10*60; | |
370 } | |
371 else if(c==2) | |
372 { | |
373 acc+=atoi(s+x)*10*60*60; | |
374 } | |
375 } | |
376 } | |
377 | |
378 acc*=100; | |
379 return(acc); | |
380 } | |
381 |