33671632755321814dcae1ac86a1d78983fbf1cb
[pspp] / dump-spo2.c
1 #include <assert.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <float.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <time.h>
12 #include <unistd.h>
13 #include "u8-mbtouc.h"
14
15 static const char *filename;
16 static uint8_t *data;
17 static size_t n;
18
19 int version;
20
21 unsigned int pos;
22
23 #define XSTR(x) #x
24 #define STR(x) XSTR(x)
25 #define WHERE __FILE__":" STR(__LINE__)
26
27 static uint8_t
28 get_byte(void)
29 {
30   return data[pos++];
31 }
32
33 static unsigned int
34 get_u32(void)
35 {
36   uint32_t x;
37   memcpy(&x, &data[pos], 4);
38   pos += 4;
39   return x;
40 }
41
42 static unsigned long long int
43 get_u64(void)
44 {
45   uint64_t x;
46   memcpy(&x, &data[pos], 8);
47   pos += 8;
48   return x;
49 }
50
51 static unsigned int
52 get_be32(void)
53 {
54   uint32_t x;
55   x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
56   pos += 4;
57   return x;
58 }
59
60 static unsigned int
61 get_u16(void)
62 {
63   uint16_t x;
64   memcpy(&x, &data[pos], 2);
65   pos += 2;
66   return x;
67 }
68
69 static double
70 get_double(void)
71 {
72   double x;
73   memcpy(&x, &data[pos], 8);
74   pos += 8;
75   return x;
76 }
77
78 static double __attribute__((unused))
79 get_float(void)
80 {
81   float x;
82   memcpy(&x, &data[pos], 4);
83   pos += 4;
84   return x;
85 }
86
87 static bool
88 match_u32(uint32_t x)
89 {
90   if (get_u32() == x)
91     return true;
92   pos -= 4;
93   return false;
94 }
95
96 bool
97 match_u16(uint16_t x)
98 {
99   if (get_u16() == x)
100     return true;
101   pos -= 2;
102   return false;
103 }
104
105 static void
106 match_u32_assert(uint32_t x, const char *where)
107 {
108   unsigned int y = get_u32();
109   if (x != y)
110     {
111       fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
112       exit(1);
113     }
114 }
115 #define match_u32_assert(x) match_u32_assert(x, WHERE)
116
117 static void
118 match_u16_assert(uint16_t x, const char *where)
119 {
120   unsigned int y = get_u16();
121   if (x != y)
122     {
123       fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u\n", where, pos - 2, x, y);
124       exit(1);
125     }
126 }
127 #define match_u16_assert(x) match_u16_assert(x, WHERE)
128
129 static bool __attribute__((unused))
130 match_u64(uint64_t x)
131 {
132   if (get_u64() == x)
133     return true;
134   pos -= 8;
135   return false;
136 }
137
138 static void __attribute__((unused))
139 match_u64_assert(uint64_t x, const char *where)
140 {
141   unsigned long long int y = get_u64();
142   if (x != y)
143     {
144       fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
145       exit(1);
146     }
147 }
148 #define match_u64_assert(x) match_u64_assert(x, WHERE)
149
150 static bool __attribute__((unused))
151 match_be32(uint32_t x)
152 {
153   if (get_be32() == x)
154     return true;
155   pos -= 4;
156   return false;
157 }
158
159 static void
160 match_be32_assert(uint32_t x, const char *where)
161 {
162   unsigned int y = get_be32();
163   if (x != y)
164     {
165       fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
166       exit(1);
167     }
168 }
169 #define match_be32_assert(x) match_be32_assert(x, WHERE)
170
171 static bool
172 match_byte(uint8_t b)
173 {
174   if (pos < n && data[pos] == b)
175     {
176       pos++;
177       return true;
178     }
179   else
180     return false;
181 }
182
183 static void
184 match_byte_assert(uint8_t b, const char *where)
185 {
186   if (!match_byte(b))
187     {
188       fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
189       exit(1);
190     }
191 }
192 #define match_byte_assert(b) match_byte_assert(b, WHERE)
193
194 static bool
195 match_bytes(int start, const int *bytes, size_t n_bytes)
196 {
197   for (size_t i = 0; i < n_bytes; i++)
198     if (bytes[i] >= 0 && data[start + i] != bytes[i])
199       return false;
200   return true;
201 }
202
203 static char *
204 xmemdup0(const void *p, size_t n)
205 {
206   char *s = malloc(n + 1);
207   memcpy(s, p, n);
208   s[n] = 0;
209   return s;
210 }
211
212 static bool
213 get_bool(void)
214 {
215   if (match_byte(0))
216     return false;
217   match_byte_assert(1);
218   return true;
219 }
220
221 static bool __attribute__((unused))
222 is_ascii(uint8_t p)
223 {
224   return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
225 }
226
227 static int
228 count_zeros(const uint8_t *p)
229 {
230   size_t n = 0;
231   while (p[n] == 0)
232     n++;
233   return n;
234 }
235
236 static bool __attribute__((unused))
237 all_utf8(const char *p_, size_t len)
238 {
239   const uint8_t *p = (const uint8_t *) p_;
240   for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
241     {
242       ucs4_t uc;
243
244       mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
245       if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
246         return false;
247     }
248   return true;
249 }
250
251 static char *
252 get_string1(void)
253 {
254   int len = data[pos++];
255   char *s = xmemdup0(&data[pos], len);
256   pos += len;
257   return s;
258 }
259
260 static char *
261 get_string2(void)
262 {
263   int len = data[pos] + data[pos + 1] * 256;
264   char *s = xmemdup0(&data[pos + 2], len);
265   pos += 2 + len;
266   return s;
267 }
268
269 static char *
270 get_string(const char *where)
271 {
272   if (1
273       /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
274       /*&& all_ascii(&data[pos + 4], data[pos])*/)
275     {
276       int len = data[pos] + data[pos + 1] * 256;
277       char *s = malloc(len + 1);
278
279       memcpy(s, &data[pos + 4], len);
280       s[len] = 0;
281       pos += 4 + len;
282       return s;
283     }
284   else
285     {
286       fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
287       exit(1);
288     }
289 }
290 #define get_string() get_string(WHERE)
291
292 static char *
293 get_string_be(const char *where)
294 {
295   if (1
296       /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
297       /*&& all_ascii(&data[pos + 4], data[pos])*/)
298     {
299       int len = data[pos + 2] * 256 + data[pos + 3];
300       char *s = malloc(len + 1);
301
302       memcpy(s, &data[pos + 4], len);
303       s[len] = 0;
304       pos += 4 + len;
305       return s;
306     }
307   else
308     {
309       fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
310       exit(1);
311     }
312 }
313 #define get_string_be() get_string_be(WHERE)
314
315 static int
316 get_end(void)
317 {
318   int len = get_u32();
319   return pos + len;
320 }
321
322 static void __attribute__((unused))
323 hex_dump(FILE *stream, int ofs, int n)
324 {
325   int n_ascii = 0;
326   for (int i = 0; i < n; i++)
327     {
328       int c = data[ofs + i];
329       n_ascii += is_ascii(c);
330       fprintf(stream, " %02x", c);
331     }
332   if (n_ascii >= 3)
333     {
334       putc(' ', stream);
335       for (int i = 0; i < n; i++)
336         {
337           int c = data[ofs + i];
338           putc(c >= 32 && c < 127 ? c : '.', stream);
339         }
340     }
341   putc('\n', stream);
342 }
343
344 static void __attribute__((unused))
345 char_dump(FILE *stream, int ofs, int n)
346 {
347   for (int i = 0; i < n; i++)
348     {
349       int c = data[ofs + i];
350       putc(c >= 32 && c < 127 ? c : '.', stream);
351     }
352   putc('\n', stream);
353 }
354
355
356 static int
357 compare_int(const void *a_, const void *b_)
358 {
359   const int *a = a_;
360   const int *b = b_;
361   return *a < *b ? -1 : *a > *b;
362 }
363
364
365 static const char *
366 format_name (int format, char *buf)
367 {
368   switch (format)
369     {
370     case 1: return "A";
371     case 2: return "AHEX";
372     case 3: return "COMMA";
373     case 4: return "DOLLAR";
374     case 5: case 40: return "F";
375     case 6: return "IB";
376     case 7: return "PIBHEX";
377     case 8: return "P";
378     case 9: return "PIB";
379     case 10: return "PK";
380     case 11: return "RB";
381     case 12: return "RBHEX";
382     case 15: return "Z";
383     case 16: return "N";
384     case 17: return "E";
385     case 20: return "DATE";
386     case 21: return "TIME";
387     case 22: return "DATETIME";
388     case 23: return "ADATE";
389     case 24: return "JDATE";
390     case 25: return "DTIME";
391     case 26: return "WKDAY";
392     case 27: return "MONTH";
393     case 28: return "MOYR";
394     case 29: return "QYR";
395     case 30: return "WKYR";
396     case 31: return "PCT";
397     case 32: return "DOT";
398     case 33: return "CCA";
399     case 34: return "CCB";
400     case 35: return "CCC";
401     case 36: return "CCD";
402     case 37: return "CCE";
403     case 38: return "EDATE";
404     case 39: return "SDATE";
405     default: sprintf(buf, "(%d)", format); return buf;
406     }
407 }
408
409
410 int
411 main(int argc, char *argv[])
412 {
413   bool print_offsets = false;
414   for (;;)
415     {
416       int c = getopt (argc, argv, "o");
417       if (c == -1)
418         break;
419
420       switch (c)
421         {
422         case 'o':
423           print_offsets = true;
424           break;
425
426         case '?':
427           exit (-1);
428         }
429     }
430   if (argc - optind != 1)
431     {
432       fprintf (stderr, "usage: %s FILE.bin", argv[0]);
433       exit (1);
434     }
435
436   const char *filename = argv[optind];
437   int fd = open(filename, O_RDONLY);
438   if (fd < 0)
439     {
440       fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
441       exit (1);
442     }
443
444   struct stat s;
445   if (fstat(fd, &s))
446     {
447       perror("fstat");
448       exit(1);
449     }
450   n = s.st_size;
451   data = malloc(n);
452   if (!data)
453     {
454       perror("malloc");
455       exit(1);
456     }
457   if (read(fd, data, n) != n)
458     {
459       perror("read");
460       exit(1);
461     }
462   close(fd);
463
464   setvbuf (stdout, NULL, _IOLBF, 0);
465
466   return 0;
467 }