… | |
… | |
19 | |
19 | |
20 | #include "config.h" |
20 | #include "config.h" |
21 | #include "compat.h" |
21 | #include "compat.h" |
22 | |
22 | |
23 | #include <stdlib.h> |
23 | #include <stdlib.h> |
|
|
24 | #include <math.h> |
24 | |
25 | |
25 | #include "parse_routines.h" |
26 | #include "parse_routines.h" |
26 | #include "error.h" |
27 | #include "error.h" |
27 | |
28 | |
|
|
29 | /* Very inefficient, but good enough for now. By implementing it ourselves, |
|
|
30 | we do not have to link with -lm */ |
|
|
31 | psiconv_float_t pow2(int n) |
|
|
32 | { |
|
|
33 | psiconv_float_t res=1.0; |
|
|
34 | int i; |
|
|
35 | |
|
|
36 | for (i = 0; i < (n<0?-n:n); i++) |
|
|
37 | res *= 2.0; |
|
|
38 | |
|
|
39 | return n<0?1/res:res; |
|
|
40 | } |
28 | psiconv_u8 psiconv_read_u8(const psiconv_buffer buf,int lev,psiconv_u32 off, |
41 | psiconv_u8 psiconv_read_u8(const psiconv_buffer buf,int lev,psiconv_u32 off, |
29 | int *status) |
42 | int *status) |
30 | { |
43 | { |
31 | psiconv_u8 *ptr; |
44 | psiconv_u8 *ptr; |
32 | ptr = psiconv_list_get(buf,off); |
45 | ptr = psiconv_buffer_get(buf,off); |
33 | if (!ptr) { |
46 | if (!ptr) { |
34 | psiconv_warn(lev,off,"Trying byte read past the end of the file"); |
47 | psiconv_warn(lev,off,"Trying byte read past the end of the file"); |
35 | if (status) |
48 | if (status) |
36 | *status = -PSICONV_E_PARSE; |
49 | *status = -PSICONV_E_PARSE; |
37 | return 0; |
50 | return 0; |
… | |
… | |
43 | |
56 | |
44 | psiconv_u16 psiconv_read_u16(const psiconv_buffer buf,int lev,psiconv_u32 off, |
57 | psiconv_u16 psiconv_read_u16(const psiconv_buffer buf,int lev,psiconv_u32 off, |
45 | int *status) |
58 | int *status) |
46 | { |
59 | { |
47 | psiconv_u8 *ptr0,*ptr1; |
60 | psiconv_u8 *ptr0,*ptr1; |
48 | ptr0 = psiconv_list_get(buf,off); |
61 | ptr0 = psiconv_buffer_get(buf,off); |
49 | ptr1 = psiconv_list_get(buf,off+1); |
62 | ptr1 = psiconv_buffer_get(buf,off+1); |
50 | if (!ptr0 || !ptr1) { |
63 | if (!ptr0 || !ptr1) { |
51 | psiconv_warn(lev,off,"Trying word read past the end of the file"); |
64 | psiconv_warn(lev,off,"Trying word read past the end of the file"); |
52 | if (status) |
65 | if (status) |
53 | *status = -PSICONV_E_PARSE; |
66 | *status = -PSICONV_E_PARSE; |
54 | return 0; |
67 | return 0; |
… | |
… | |
60 | |
73 | |
61 | psiconv_u32 psiconv_read_u32(const psiconv_buffer buf,int lev,psiconv_u32 off, |
74 | psiconv_u32 psiconv_read_u32(const psiconv_buffer buf,int lev,psiconv_u32 off, |
62 | int *status) |
75 | int *status) |
63 | { |
76 | { |
64 | psiconv_u8 *ptr0,*ptr1,*ptr2,*ptr3; |
77 | psiconv_u8 *ptr0,*ptr1,*ptr2,*ptr3; |
65 | ptr0 = psiconv_list_get(buf,off); |
78 | ptr0 = psiconv_buffer_get(buf,off); |
66 | ptr1 = psiconv_list_get(buf,off+1); |
79 | ptr1 = psiconv_buffer_get(buf,off+1); |
67 | ptr2 = psiconv_list_get(buf,off+2); |
80 | ptr2 = psiconv_buffer_get(buf,off+2); |
68 | ptr3 = psiconv_list_get(buf,off+3); |
81 | ptr3 = psiconv_buffer_get(buf,off+3); |
69 | if (!ptr0 || !ptr1 || !ptr2 || !ptr3) { |
82 | if (!ptr0 || !ptr1 || !ptr2 || !ptr3) { |
70 | psiconv_warn(lev,off,"Trying long read past the end of the file"); |
83 | psiconv_warn(lev,off,"Trying long read past the end of the file"); |
71 | if (status) |
84 | if (status) |
72 | *status = -PSICONV_E_PARSE; |
85 | *status = -PSICONV_E_PARSE; |
73 | return 0; |
86 | return 0; |
74 | } |
87 | } |
75 | if (status) |
88 | if (status) |
76 | *status = 0; |
89 | *status = 0; |
77 | return *ptr0 + (*ptr1 << 8) + (*ptr2 << 16) + (*ptr3 << 24); |
90 | return *ptr0 + (*ptr1 << 8) + (*ptr2 << 16) + (*ptr3 << 24); |
|
|
91 | } |
|
|
92 | |
|
|
93 | psiconv_s32 psiconv_read_sint(const psiconv_buffer buf,int lev,psiconv_u32 off, |
|
|
94 | int *length,int *status) |
|
|
95 | { |
|
|
96 | int localstatus; |
|
|
97 | psiconv_u32 temp; |
|
|
98 | |
|
|
99 | temp=psiconv_read_u32(buf,lev,off,&localstatus); |
|
|
100 | if (status) |
|
|
101 | *status = localstatus; |
|
|
102 | if (length) |
|
|
103 | *length = localstatus?0:4; |
|
|
104 | |
|
|
105 | return localstatus?0:(temp & 0x7fffffff)*(temp&0x80000000?-1:1); |
78 | } |
106 | } |
79 | |
107 | |
80 | psiconv_S_t psiconv_read_S(const psiconv_buffer buf, int lev, psiconv_u32 off, |
108 | psiconv_S_t psiconv_read_S(const psiconv_buffer buf, int lev, psiconv_u32 off, |
81 | int *length,int *status) |
109 | int *length,int *status) |
82 | { |
110 | { |
… | |
… | |
301 | *status = localstatus; |
329 | *status = localstatus; |
302 | if (length) |
330 | if (length) |
303 | *length = 0; |
331 | *length = 0; |
304 | return NULL; |
332 | return NULL; |
305 | } |
333 | } |
|
|
334 | |
|
|
335 | psiconv_string_t psiconv_read_short_string(const psiconv_buffer buf, |
|
|
336 | int lev, |
|
|
337 | psiconv_u32 off,int *length, int *status) |
|
|
338 | { |
|
|
339 | int stringlen,i,len,localstatus; |
|
|
340 | psiconv_string_t result; |
|
|
341 | char *res_copy; |
|
|
342 | |
|
|
343 | psiconv_progress(lev+1,off,"Going to read a short string"); |
|
|
344 | |
|
|
345 | stringlen = psiconv_read_u8(buf,lev+2,off,&localstatus); |
|
|
346 | if (localstatus) |
|
|
347 | goto ERROR1; |
|
|
348 | psiconv_debug(lev+2,off,"Length: %i",stringlen); |
|
|
349 | len = 1; |
|
|
350 | |
|
|
351 | result = malloc(stringlen + 1); |
|
|
352 | if (!result) |
|
|
353 | goto ERROR1; |
|
|
354 | for (i = 0; (i < stringlen) && !localstatus; i++) |
|
|
355 | result[i] = psiconv_read_u8(buf,lev,off+i+len,&localstatus); |
|
|
356 | if (localstatus) |
|
|
357 | goto ERROR2; |
|
|
358 | result[stringlen] = 0; |
|
|
359 | len += stringlen; |
|
|
360 | |
|
|
361 | res_copy = psiconv_make_printable(result); |
|
|
362 | if (!res_copy) |
|
|
363 | goto ERROR2; |
|
|
364 | psiconv_debug(lev+2,off,"Contents: `%s'",res_copy); |
|
|
365 | free(res_copy); |
|
|
366 | |
|
|
367 | if (length) |
|
|
368 | *length = len; |
|
|
369 | |
|
|
370 | if (status) |
|
|
371 | *status = 0; |
|
|
372 | |
|
|
373 | psiconv_progress(lev+1,off+len-1,"End of short string (total length: %08x)", |
|
|
374 | len); |
|
|
375 | |
|
|
376 | return result; |
|
|
377 | |
|
|
378 | |
|
|
379 | ERROR2: |
|
|
380 | free(result); |
|
|
381 | ERROR1: |
|
|
382 | psiconv_warn(lev+1,off,"Reading of short string failed"); |
|
|
383 | if (status) |
|
|
384 | *status = localstatus; |
|
|
385 | if (length) |
|
|
386 | *length = 0; |
|
|
387 | return NULL; |
|
|
388 | } |
|
|
389 | |
|
|
390 | psiconv_float_t psiconv_read_float(const psiconv_buffer buf, int lev, |
|
|
391 | psiconv_u32 off, int *length, int *status) |
|
|
392 | { |
|
|
393 | psiconv_float_t result,bitvalue; |
|
|
394 | int res,bit; |
|
|
395 | psiconv_u32 temp=0; |
|
|
396 | |
|
|
397 | psiconv_progress(lev+1,off,"Going to read a float"); |
|
|
398 | |
|
|
399 | bitvalue = 0.5; |
|
|
400 | result = 1.0; |
|
|
401 | for (bit = 0x33; bit > 0; bit--) { |
|
|
402 | if ((bit == 0x33) || ((bit & 0x07) == 0x07)) |
|
|
403 | temp = psiconv_read_u8(buf,lev+2,off+ (bit >> 3),&res); |
|
|
404 | if (res) |
|
|
405 | goto ERROR; |
|
|
406 | if (temp & (0x01 << (bit & 0x07))) |
|
|
407 | result += bitvalue; |
|
|
408 | bitvalue /= 2.0; |
|
|
409 | } |
|
|
410 | temp = psiconv_read_u16(buf,lev+2,off+6,&res); |
|
|
411 | if (res) |
|
|
412 | goto ERROR; |
|
|
413 | if (temp & 0x8000) |
|
|
414 | result = -result; |
|
|
415 | temp = (temp & 0x7ff0) >> 4; |
|
|
416 | result *= pow2(((int) temp)-0x3ff); |
|
|
417 | psiconv_debug(lev+1,off,"Float value: %f",result); |
|
|
418 | if (length) |
|
|
419 | *length = 8; |
|
|
420 | if (*status) |
|
|
421 | *status = res; |
|
|
422 | return result; |
|
|
423 | ERROR: |
|
|
424 | psiconv_warn(lev+1,off,"Reading of float failed"); |
|
|
425 | if (length) |
|
|
426 | *length = 0; |
|
|
427 | if (*status) |
|
|
428 | *status = res; |
|
|
429 | return 0.0; |
|
|
430 | } |
|
|
431 | |