/[public]/psiconv/trunk/lib/psiconv/parse_simple.c
ViewVC logotype

Contents of /psiconv/trunk/lib/psiconv/parse_simple.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 351 - (show annotations)
Wed Oct 22 19:53:40 2014 UTC (9 years, 5 months ago) by frodo
File MIME type: text/plain
File size: 13194 byte(s)
(Frodo) Update copyright year in all source files

1 /*
2 parse_simple.c - Part of psiconv, a PSION 5 file formats converter
3 Copyright (c) 1999-2014 Frodo Looijaard <frodo@frodo.looijaard.name>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "config.h"
21 #include "compat.h"
22
23 #include <stdlib.h>
24 #include <math.h>
25
26 #include "parse_routines.h"
27 #include "error.h"
28 #include "unicode.h"
29
30 #ifdef DMALLOC
31 #include <dmalloc.h>
32 #endif
33
34 static psiconv_float_t pow2(int n);
35 static psiconv_string_t psiconv_read_string_aux(const psiconv_config config,
36 const psiconv_buffer buf,int lev,
37 psiconv_u32 off,int *length, int *status,
38 int kind);
39
40 /* Very inefficient, but good enough for now. By implementing it ourselves,
41 we do not have to link with -lm */
42 psiconv_float_t pow2(int n)
43 {
44 psiconv_float_t res=1.0;
45 int i;
46
47 for (i = 0; i < (n<0?-n:n); i++)
48 res *= 2.0;
49
50 return n<0?1/res:res;
51 }
52 psiconv_u8 psiconv_read_u8(const psiconv_config config,const psiconv_buffer buf,int lev,psiconv_u32 off,
53 int *status)
54 {
55 psiconv_u8 *ptr;
56 ptr = psiconv_buffer_get(buf,off);
57 if (!ptr) {
58 psiconv_error(config,lev,off,"Trying byte read past the end of the file");
59 if (status)
60 *status = -PSICONV_E_PARSE;
61 return 0;
62 }
63 if (status)
64 *status = 0;
65 return *ptr;
66 }
67
68 psiconv_u16 psiconv_read_u16(const psiconv_config config,const psiconv_buffer buf,int lev,psiconv_u32 off,
69 int *status)
70 {
71 psiconv_u8 *ptr0,*ptr1;
72 ptr0 = psiconv_buffer_get(buf,off);
73 ptr1 = psiconv_buffer_get(buf,off+1);
74 if (!ptr0 || !ptr1) {
75 psiconv_error(config,lev,off,"Trying word read past the end of the file");
76 if (status)
77 *status = -PSICONV_E_PARSE;
78 return 0;
79 }
80 if (status)
81 *status = 0;
82 return *ptr0 + (*ptr1 << 8);
83 }
84
85 psiconv_u32 psiconv_read_u32(const psiconv_config config,const psiconv_buffer buf,int lev,psiconv_u32 off,
86 int *status)
87 {
88 psiconv_u8 *ptr0,*ptr1,*ptr2,*ptr3;
89 ptr0 = psiconv_buffer_get(buf,off);
90 ptr1 = psiconv_buffer_get(buf,off+1);
91 ptr2 = psiconv_buffer_get(buf,off+2);
92 ptr3 = psiconv_buffer_get(buf,off+3);
93 if (!ptr0 || !ptr1 || !ptr2 || !ptr3) {
94 psiconv_error(config,lev,off,"Trying long read past the end of the file");
95 if (status)
96 *status = -PSICONV_E_PARSE;
97 return 0;
98 }
99 if (status)
100 *status = 0;
101 return *ptr0 + (*ptr1 << 8) + (*ptr2 << 16) + (*ptr3 << 24);
102 }
103
104 psiconv_s32 psiconv_read_sint(const psiconv_config config,const psiconv_buffer buf,int lev,psiconv_u32 off,
105 int *length,int *status)
106 {
107 int localstatus;
108 psiconv_u32 temp;
109
110 temp=psiconv_read_u32(config,buf,lev,off,&localstatus);
111 if (status)
112 *status = localstatus;
113 if (length)
114 *length = localstatus?0:4;
115
116 return localstatus?0:(temp & 0x7fffffff)*(temp&0x80000000?-1:1);
117 }
118
119 psiconv_u32 psiconv_read_S(const psiconv_config config,const psiconv_buffer buf, int lev, psiconv_u32 off,
120 int *length,int *status)
121 {
122 psiconv_u8 temp;
123 psiconv_u32 res;
124 int len,localstatus;
125
126 psiconv_progress(config,lev+1,off,"Going to read a S length indicator");
127 temp = psiconv_read_u8(config,buf,lev+2,off,&localstatus);
128 if (localstatus)
129 goto ERROR;
130 if ((temp & 0x03) == 0x02) {
131 res = psiconv_read_u8(config,buf,lev+2,off,&localstatus) >> 2;
132 if (localstatus)
133 goto ERROR;
134 len = 1;
135 psiconv_debug(config,lev+2,off,"Indicator (1 byte): %02x",res);
136 } else if ((temp & 0x07) == 0x05) {
137 res = psiconv_read_u16(config,buf,lev+2,off,&localstatus) >> 3;
138 if (localstatus)
139 goto ERROR;
140 len = 2;
141 psiconv_debug(config,lev+2,off,"Indicator (2 bytes): %04x",res);
142 } else {
143 psiconv_error(config,lev+2,off,"S indicator: unknown encoding!");
144 psiconv_debug(config,lev+2,off,"Raw data first byte: %02x",temp);
145 goto ERROR;
146 }
147
148 if (length)
149 *length = len;
150 if (status)
151 *status = 0;
152
153 psiconv_progress(config,lev+1,off+len-1,
154 "End of S length indicator (total length: %08x)", len);
155
156 return res;
157
158 ERROR:
159 psiconv_error(config,lev+1,off,"Reading of S indicator failed");
160 if (status)
161 *status = localstatus;
162 if (length)
163 *length = 0;
164 return 0;
165 }
166
167 psiconv_u32 psiconv_read_X(const psiconv_config config,const psiconv_buffer buf, int lev, psiconv_u32 off,
168 int *length, int *status)
169 {
170 psiconv_u8 temp;
171 psiconv_u32 res;
172 int len,localstatus;
173
174 psiconv_progress(config,lev+1,off,"Going to read a X length indicator");
175 temp = psiconv_read_u8(config,buf,lev+2,off,&localstatus);
176 if (localstatus)
177 goto ERROR;
178 if ((temp & 0x01) == 0x00) {
179 res = psiconv_read_u8(config,buf,lev+2,off,&localstatus) >> 1;
180 if (localstatus)
181 goto ERROR;
182 len = 1;
183 psiconv_debug(config,lev+2,off,"Indicator (1 byte): %02x",res);
184 } else if ((temp & 0x03) == 0x01) {
185 res = psiconv_read_u16(config,buf,lev+2,off,&localstatus) >> 2;
186 if (localstatus)
187 goto ERROR;
188 len = 2;
189 psiconv_debug(config,lev+2,off,"Indicator (2 bytes): %04x",res);
190 } else if ((temp & 0x07) == 0x03) {
191 res = psiconv_read_u32(config,buf,lev+2,off,&localstatus) >> 3;
192 if (localstatus)
193 goto ERROR;
194 len = 4;
195 psiconv_debug(config,lev+2,off,"Indicator (4 bytes): %08x",res);
196 } else {
197 psiconv_error(config,lev+2,off,"X indicator: unknown encoding!");
198 psiconv_debug(config,lev+2,off,"Raw data first byte: %02x",temp);
199 goto ERROR;
200 }
201
202 if (length)
203 *length = len;
204 if (status)
205 *status = 0;
206
207 psiconv_progress(config,lev+1,off+len-1,
208 "End of X length indicator (total length: %08x)", len);
209
210 return res;
211
212 ERROR:
213 psiconv_error(config,lev+1,off,"Reading of X indicator failed");
214 if (status)
215 *status = localstatus;
216 if (length)
217 *length = 0;
218 return 0;
219 }
220
221 psiconv_length_t psiconv_read_length(const psiconv_config config,const psiconv_buffer buf, int lev,
222 psiconv_u32 off, int *length, int *status)
223 {
224 psiconv_length_t res;
225 int localstatus;
226
227 res = (2.54/1440.0) * ((psiconv_s32) psiconv_read_u32(config,buf,lev,off,
228 &localstatus));
229 if (localstatus) {
230 psiconv_error(config,lev+1,off,"Reading of length failed");
231 if (length)
232 *length = 0;
233 if (status)
234 *status = localstatus;
235 return 0;
236 }
237 psiconv_debug(config,lev+1,off,"Length: %f",res);
238 if (length)
239 *length = 4;
240 if (status)
241 *status = 0;
242 return res;
243 }
244
245 psiconv_size_t psiconv_read_size(const psiconv_config config,const psiconv_buffer buf, int lev,
246 psiconv_u32 off, int *length, int *status)
247 {
248 psiconv_size_t res;
249 int localstatus;
250 res = ((psiconv_s32) psiconv_read_u32(config,buf,lev,off,&localstatus)) / 20.0;
251 if (localstatus) {
252 psiconv_error(config,lev+1,off,"Reading of size failed");
253 if (length)
254 *length = 0;
255 if (status)
256 *status = localstatus;
257 return 0;
258 }
259 psiconv_debug(config,lev+1,off,"Size: %f",res);
260 if (status)
261 *status = 0;
262 if (length)
263 *length = 4;
264 return res;
265 }
266
267 int psiconv_parse_bool(const psiconv_config config,const psiconv_buffer buf, int lev, psiconv_u32 off,
268 int *length, psiconv_bool_t *result)
269 {
270 psiconv_u8 temp;
271 int localstatus;
272 temp = psiconv_read_u8(config,buf,lev,off,&localstatus);
273 if (localstatus) {
274 psiconv_error(config,lev+1,off,"Reading of bool failed");
275 if (length)
276 *length = 0;
277 return localstatus;
278 }
279 if (length)
280 *length = 1;
281 if (temp == 0) {
282 *result = psiconv_bool_false;
283 return 0;
284 } else if (temp == 1) {
285 *result = psiconv_bool_true;
286 return 0;
287 }
288 psiconv_warn(config,lev+1,off,"Unknown value for boolean");
289 psiconv_debug(config,lev+1,off,"Boolean value: %02x",temp);
290 *result = psiconv_bool_true;
291 return 0;
292 }
293
294 psiconv_string_t psiconv_read_string(const psiconv_config config,
295 const psiconv_buffer buf,int lev,
296 psiconv_u32 off,int *length, int *status)
297 {
298 return psiconv_read_string_aux(config,buf,lev,off,length,status,-1);
299 }
300
301 psiconv_string_t psiconv_read_short_string(const psiconv_config config,
302 const psiconv_buffer buf,int lev,
303 psiconv_u32 off,int *length, int *status)
304 {
305 return psiconv_read_string_aux(config,buf,lev,off,length,status,-2);
306 }
307
308 psiconv_string_t psiconv_read_charlist(const psiconv_config config,
309 const psiconv_buffer buf, int lev,
310 psiconv_u32 off, int nrofchars,
311 int *status)
312 {
313 int length;
314 if (nrofchars <= 0) {
315 psiconv_error(config,lev,off,
316 "psiconv_read_charlist called with non-positive nrofchars");
317 if (status)
318 *status = -PSICONV_E_OTHER;
319 return NULL;
320 }
321 return psiconv_read_string_aux(config,buf,lev,off,&length,status,nrofchars);
322 }
323
324
325 psiconv_string_t psiconv_read_string_aux(const psiconv_config config,
326 const psiconv_buffer buf,int lev,
327 psiconv_u32 off,int *length, int *status,
328 int kind)
329 {
330 int bytecount,i,leng,len,localstatus;
331 psiconv_string_t result;
332 char *res_copy;
333 psiconv_list string;
334 psiconv_ucs2 nextchar;
335 psiconv_ucs2 *nextcharptr;
336
337 psiconv_progress(config,lev+1,off,"Going to read a string");
338
339 if (kind == -1)
340 bytecount = psiconv_read_S(config,buf,lev+2,off,&leng,&localstatus);
341 else if (kind == -2) {
342 bytecount = psiconv_read_u8(config,buf,lev+2,off,&localstatus);
343 leng = 1;
344 } else {
345 bytecount = kind;
346 leng = 0;
347 localstatus = 0;
348 }
349 if (localstatus)
350 goto ERROR1;
351 psiconv_debug(config,lev+2,off,"Length: %i",bytecount);
352 len = leng;
353
354 if (!(string = psiconv_list_new(sizeof(*result))))
355 goto ERROR1;
356
357 /* Read the string into a temporary list */
358 i = 0;
359 while (i < bytecount) {
360 nextchar = psiconv_unicode_read_char(config,buf,lev,off+i+len,
361 &leng,&localstatus);
362 if (localstatus)
363 goto ERROR2;
364 if ((localstatus = psiconv_list_add(string,&nextchar)))
365 goto ERROR2;
366 i += leng;
367 }
368 if (i > bytecount) {
369 psiconv_error(config,lev,off+i+len,"Malformed string");
370 localstatus = PSICONV_E_PARSE;
371 goto ERROR2;
372 }
373 len += bytecount;
374
375 /* Copy the list to the actual string */
376 if (!(result = malloc(sizeof(*result) * (psiconv_list_length(string) + 1))))
377 goto ERROR2;
378 for (i = 0; i < psiconv_list_length(string); i++) {
379 if (!(nextcharptr = psiconv_list_get(string,i))) {
380 psiconv_error(config,lev,off+i+len,"Data structure corruption");
381 goto ERROR3;
382 }
383 result[i] = *nextcharptr;
384 }
385 result[i] = 0;
386
387 res_copy = psiconv_make_printable(config,result);
388 if (!res_copy)
389 goto ERROR3;
390 psiconv_debug(config,lev+2,off,"Contents: `%s'",res_copy);
391 free(res_copy);
392
393 psiconv_list_free(string);
394
395 if (length)
396 *length = len;
397
398 if (status)
399 *status = 0;
400
401 psiconv_progress(config,lev+1,off+len-1,"End of string (total length: %08x)",len);
402
403 return result;
404
405 ERROR3:
406 free(result);
407 ERROR2:
408 psiconv_list_free(string);
409 ERROR1:
410 psiconv_error(config,lev+1,off,"Reading of string failed");
411 if (status)
412 *status = localstatus;
413 if (length)
414 *length = 0;
415 return NULL;
416 }
417
418 psiconv_float_t psiconv_read_float(const psiconv_config config,const psiconv_buffer buf, int lev,
419 psiconv_u32 off, int *length, int *status)
420 {
421 psiconv_float_t result,bitvalue;
422 int res,bit;
423 psiconv_u32 temp=0;
424
425 psiconv_progress(config,lev+1,off,"Going to read a float");
426
427 bitvalue = 0.5;
428 result = 1.0;
429 for (bit = 0x33; bit > 0; bit--) {
430 if ((bit == 0x33) || ((bit & 0x07) == 0x07))
431 temp = psiconv_read_u8(config,buf,lev+2,off+ (bit >> 3),&res);
432 if (res)
433 goto ERROR;
434 if (temp & (0x01 << (bit & 0x07)))
435 result += bitvalue;
436 bitvalue /= 2.0;
437 }
438 temp = psiconv_read_u16(config,buf,lev+2,off+6,&res);
439 if (res)
440 goto ERROR;
441 if (temp & 0x8000)
442 result = -result;
443 temp = (temp & 0x7ff0) >> 4;
444 result *= pow2(((int) temp)-0x3ff);
445 psiconv_debug(config,lev+1,off,"Float value: %f",result);
446 if (length)
447 *length = 8;
448 if (*status)
449 *status = res;
450 return result;
451 ERROR:
452 psiconv_error(config,lev+1,off,"Reading of float failed");
453 if (length)
454 *length = 0;
455 if (*status)
456 *status = res;
457 return 0.0;
458 }
459

frodo@frodo.looijaard.name
ViewVC Help
Powered by ViewVC 1.1.26