10 #include "u8-mbtouc.h"
16 #define STR(x) XSTR(x)
17 #define WHERE __FILE__":" STR(__LINE__)
25 memcpy(&x, &data[pos], 4);
34 memcpy(&x, &data[pos], 8);
49 match_u32_assert(uint32_t x, const char *where)
51 unsigned int y = get_u32();
54 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
58 #define match_u32_assert(x) match_u32_assert(x, WHERE)
63 if (pos < n && data[pos] == b)
73 match_byte_assert(uint8_t b, const char *where)
77 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
81 #define match_byte_assert(b) match_byte_assert(b, WHERE)
84 all_ascii(const uint8_t *p)
87 if (*p < 32 || *p > 126)
93 all_utf8(const uint8_t *p)
95 size_t len = strlen ((char *) p);
96 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
100 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
101 if (uc < 32 || uc == 127 || uc == 0xfffd)
108 get_fixed_string(int len, const char *where)
117 fprintf(stderr, "%s: 0x%x: unterminated fixed-width string\n", where, pos);
121 if (!all_utf8(&data[pos]))
123 fprintf(stderr, "%s: 0x%x: bad fixed-width string\n", where, pos);
130 fprintf(stderr, "%s: 0x%x: text in middle of fixed-width string\n", where, pos);
135 char *s = (char *) &data[pos];
139 #define get_fixed_string(len) get_fixed_string(len, WHERE)
142 all_ascii2(const uint8_t *p, size_t n)
144 for (size_t i = 0; i < n; i++)
145 if (p[i] < 32 || p[i] > 126)
151 get_string(const char *where)
154 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
155 /*&& all_ascii(&data[pos + 4], data[pos])*/)
157 int len = data[pos] + data[pos + 1] * 256;
158 char *s = malloc(len + 1);
160 memcpy(s, &data[pos + 4], len);
167 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
171 #define get_string() get_string(WHERE)
174 dump_raw(FILE *stream, int start, int end, const char *separator)
176 for (size_t i = start; i < end; )
183 && i + 4 + data[i] + data[i + 1] * 256 <= end
184 && all_ascii2(&data[i + 4], data[i] + data[i + 1] * 256))
186 fprintf(stream, "%s\"", separator);
187 fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stream);
188 fputs("\" ", stream);
190 i += 4 + data[i] + data[i + 1] * 256;
192 else if (i + 12 <= end
199 memcpy (&d, &data[i + 4], 8);
200 fprintf (stream, "F40.%d(%.*f)%s", data[i], data[i], d, separator);
203 else if (i + 12 <= end
210 memcpy (&d, &data[i + 4], 8);
211 fprintf (stream, "PCT40.%d(%.*f)%s", data[i], data[i], d, separator);
214 else if (i + 4 <= end
219 fprintf (stream, "i%d ", data[i]);
224 fprintf(stream, "%02x ", data[i]);
231 dump_source(int end, int count, int n_series, const char *name)
238 sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
240 for (int i = 0; i < n_series; i++)
242 printf (" %08x: series %d: \"%s\", %d values:\n ",
243 pos, i, get_fixed_string(288), count);
244 for (int i = 0; i < count; i++)
246 double d = get_double();
253 printf (" %.*g", DBL_DIG, d);
268 int n_maps = get_u32();
270 for (int k = 0; k < n_maps; k++)
272 char *source_name = get_string();
273 printf ("%08x: %s\n", offset, source_name);
275 int n_series = get_u32();
276 for (int i = 0; i < n_series; i++)
278 printf ("%08x:", pos);
279 printf (" \"%s\"", get_string());
280 int n_pairs = get_u32();
281 for (int j = 0; j < n_pairs; j++)
285 printf (" (%d, %d)", x, y);
292 printf ("\n%08x:", pos);
293 int n_strings = get_u32();
294 if (n_strings != max1 + 1)
296 fprintf (stderr, "n_strings=%d max1+1=%d (-s %#x -n %u)\n", n_strings, max1 + 1, start, n - start);
297 dump_raw (stderr, start, n, "\n");
298 assert(n_strings == max1 + 1);
300 printf (" %d strings\n", n_strings);
302 char **strings = malloc((max1 + 1) * sizeof *strings);
303 for (int i = 0; i <= max1; i++)
305 int frequency = get_u32();
306 char *s = get_string();
307 printf ("%d: \"%s\" (%d)\n", i, s, frequency);
315 printf("Strings:\n");
316 for (int i = 0; i < n_more_series; i++)
318 printf (" \"%s\"\n", get_string());
319 int n_pairs = get_u32();
320 for (int j = 0; j < n_pairs; j++)
325 printf (" %d: \"%s\"\n", x, strings[y]);
333 main(int argc, char **argv)
338 if (isatty(STDIN_FILENO))
340 fprintf(stderr, "redirect stdin from a .bin file\n");
343 if (fstat(STDIN_FILENO, &s))
355 if (read(STDIN_FILENO, data, n) != n)
362 match_byte_assert(0);
363 int version = data[pos];
364 if (!match_byte(0xaf))
365 match_byte_assert(0xb0);
366 int n_sources = data[pos++];
367 match_byte_assert(0);
369 match_u32_assert(s.st_size);
370 printf ("%d sources\n", n_sources);
374 int offset, count, n_series;
378 for (int i = 0; i < n_sources; i++)
380 int count = get_u32();
381 int n_series = get_u32();
382 int offset = get_u32();
383 char *name = get_fixed_string(version == 0xb0 ? 64 : 28);
384 int dunno = version == 0xb0 ? get_u32() : 0;
385 printf ("source %d: %d series, %d observations per series, offset %08x, \"%s\", %x\n",
386 i, n_series, count, offset, name, dunno);
387 sources[i].offset = offset;
388 sources[i].count = count;
389 sources[i].n_series = n_series;
390 sources[i].name = name;
393 for (int i = 0; i < n_sources; i++)
395 if (pos != sources[i].offset)
397 fprintf (stderr, "pos=0x%x expected=0x%x reading source %d\n", pos, sources[i].offset, i);
400 printf ("source %d:\n", i);
401 pos = sources[i].offset;
402 dump_source(i + 1 >= n_sources ? n : sources[i + 1].offset, sources[i].count, sources[i].n_series, sources[i].name);
408 fprintf (stderr, "consumed %zu bytes, file has %zu bytes\n", pos, n);
414 return ok ? EXIT_SUCCESS : EXIT_FAILURE;