Fix one data case.
[pspp] / dump.c
1 #include <stdbool.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 static uint8_t *data;
10 static size_t n;
11
12 static bool
13 all_ascii(const uint8_t *p, size_t n)
14 {
15   for (size_t i = 0; i < n; i++)
16     if (p[i] < 32 || p[i] > 126)
17       return false;
18   return true;
19 }
20
21 static size_t
22 try_find(const char *target, size_t target_len)
23 {
24   const uint8_t *pos = (const uint8_t *) memmem (data, n, target, target_len);
25   return pos ? pos - data : 0;
26 }
27
28 static size_t
29 try_find_tail(const char *target, size_t target_len)
30 {
31   size_t pos = try_find(target, target_len);
32   return pos ? pos + target_len : 0;
33 }
34
35 static size_t
36 find(const char *target, size_t target_len)
37 {
38   size_t pos = try_find(target, target_len);
39   if (!pos)
40     {
41       fprintf (stderr, "not found\n");
42       exit(1);
43     }
44   return pos;
45 }
46
47 static size_t
48 find_tail(const char *target, size_t target_len)
49 {
50   size_t pos = try_find_tail(target, target_len);
51   if (!pos)
52     {
53       fprintf (stderr, "not found\n");
54       exit(1);
55     }
56   return pos;
57 }
58
59 size_t pos;
60
61 #define XSTR(x) #x
62 #define STR(x) XSTR(x)
63 #define WHERE __FILE__":" STR(__LINE__)
64
65 static unsigned int
66 get_u32(void)
67 {
68   uint32_t x;
69   memcpy(&x, &data[pos], 4);
70   pos += 4;
71   return x;
72 }
73
74 static double
75 get_double(void)
76 {
77   double x;
78   memcpy(&x, &data[pos], 8);
79   pos += 8;
80   return x;
81 }
82
83 static bool
84 match_u32(uint32_t x)
85 {
86   if (get_u32() == x)
87     return true;
88   pos -= 4;
89   return false;
90 }
91
92 static void
93 match_u32_assert(uint32_t x, const char *where)
94 {
95   unsigned int y = get_u32();
96   if (x != y)
97     {
98       fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
99       exit(1);
100     }
101 }
102 #define match_u32_assert(x) match_u32_assert(x, WHERE)
103
104 static bool
105 match_byte(uint8_t b)
106 {
107   if (data[pos] == b)
108     {
109       pos++;
110       return true;
111     }
112   else
113     return false;
114 }
115
116 static void
117 match_byte_assert(uint8_t b, const char *where)
118 {
119   if (!match_byte(b))
120     {
121       fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
122       exit(1);
123     }
124 }
125 #define match_byte_assert(b) match_byte_assert(b, WHERE)
126
127 static char *
128 get_string(const char *where)
129 {
130   if (data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0
131       /*&& all_ascii(&data[pos + 4], data[pos])*/)
132     {
133       int len = data[pos];
134       char *s = malloc(len + 1);
135
136       memcpy(s, &data[pos + 4], len);
137       s[len] = 0;
138       pos += 4 + data[pos];
139       return s;
140     }
141   else
142     {
143       fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
144       exit(1);
145     }
146 }
147 #define get_string() get_string(WHERE)
148
149 static void
150 dump_value(int level)
151 {
152   for (int i = 0; i <= level; i++)
153     printf ("    ");
154
155   match_byte (0);
156   match_byte (0);
157   match_byte (0);
158   match_byte (0);
159   if (match_byte (3))
160     {
161       get_string();
162       if (match_byte (0x31))
163         {
164           if (match_u32 (1))
165             {
166               printf("(footnote %d) ", get_u32());
167               match_byte_assert (0);
168               match_byte_assert (0);
169               int subn = get_u32 ();
170               printf ("nested %d bytes", subn);
171               pos += subn;
172             }
173           else if (match_u32 (2))
174             {
175               printf("(special 2)");
176               match_byte_assert(0);
177               match_byte_assert(0);
178               match_u32_assert(1);
179               match_byte_assert(0);
180               match_byte_assert(0);
181               int subn = get_u32 ();
182               printf ("nested %d bytes", subn);
183               pos += subn;
184             }
185           else
186             {
187               match_u32_assert(3);
188               printf("(special 3)");
189               match_byte_assert(0);
190               match_byte_assert(0);
191               match_byte_assert(1);
192               match_byte_assert(0);
193               int subn = get_u32 ();
194               printf ("nested %d bytes, ", subn);
195               pos += subn;
196               subn = get_u32 ();
197               printf ("nested %d bytes, ", subn);
198               pos += subn;
199             }
200         }
201       else
202         match_byte_assert (0x58);
203       get_string();
204       printf("string \"%s\"", get_string());
205       match_byte (0);
206       match_byte (0);
207       match_byte (0);
208       match_byte (1);
209       match_byte (1);
210       match_byte (0);
211       match_byte (0);
212       match_byte (0);
213       match_byte (1);
214     }
215   else if (match_byte (5))
216     {
217       match_byte_assert (0x58);
218       printf ("variable \"%s\"", get_string());
219       get_string();
220       if (!match_byte(1) && !match_byte(2))
221         match_byte_assert(3);
222       match_byte (0);
223       match_byte (0);
224       match_byte (0);
225       match_byte (0);
226     }
227   else if (match_byte (2))
228     {
229       unsigned int format;
230       char *var, *vallab;
231       double value;
232
233       match_byte_assert (0x58);
234       format = get_u32 ();
235       value = get_double ();
236       var = get_string ();
237       vallab = get_string ();
238       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
239               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
240       if (!match_byte (1) && !match_byte(2))
241         match_byte_assert (3);
242       match_byte (0);
243       match_byte (0);
244       match_byte (0);
245       match_byte (0);
246       match_byte (0);
247       match_byte (0);
248       match_byte (0);
249     }
250   else if (match_byte (4))
251     {
252       unsigned int format;
253       char *var, *vallab, *value;
254
255       match_byte_assert (0x58);
256       format = get_u32 ();
257       vallab = get_string ();
258       var = get_string ();
259       if (!match_byte(1) && !match_byte(2))
260         match_byte_assert (3);
261       value = get_string ();
262       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
263               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
264       match_byte (0);
265       match_byte (0);
266       match_byte (0);
267       match_byte (0);
268     }
269   else if (match_byte (1))
270     {
271       unsigned int format;
272       double value;
273
274       if (match_byte (0x31))
275         {
276           if (match_u32 (1))
277             {
278               printf("(footnote %d) ", get_u32());
279               match_byte_assert (0);
280               match_byte_assert (0);
281               int subn = get_u32 ();
282               printf ("nested %d bytes", subn);
283               pos += subn;
284             }
285         }
286       else
287         match_byte_assert (0x58);
288       format = get_u32 ();
289       value = get_double ();
290       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
291       match_byte (1);
292       match_byte (0);
293       match_byte (0);
294       match_byte (0);
295       match_byte (1);
296     }
297   else if (match_byte (0x31))
298     {
299       int subn;
300
301       if (match_u32 (1))
302         {
303           printf("(footnote %d) ", get_u32());
304           match_byte_assert (0);
305           match_byte_assert (0);
306           int subn = get_u32 ();
307           printf ("nested %d bytes", subn);
308           pos += subn;
309         }
310       else
311         {
312           match_u32_assert (0);
313           match_u32_assert (0);
314           subn = get_u32 ();
315           printf ("nested %d bytes", subn);
316           pos += subn;
317         }
318       char *base = get_string();
319       int x = get_u32();
320       printf ("\"%s\"; %d variables:\n", base, x);
321       if (match_u32(0))
322         {
323           for (int i = 0; i < x; i++)
324             {
325               dump_value (level+1);
326               putchar('\n');
327             }
328         }
329       else
330         {
331           for (int i = 0; i < x; i++)
332             {
333               int y = get_u32();
334               match_u32_assert(0);
335               for (int j = 0; j <= level; j++)
336                 printf ("    ");
337               printf("variable %d has %d values:\n", i, y);
338               for (int j = 0; j < y; j++)
339                 {
340                   if (match_byte(3))
341                     {
342                       char *a = get_string();
343                       match_byte_assert(0x58);
344                       char *b = get_string();
345                       char *c = get_string();
346                       for (int k = 0; k <= level + 1; k++)
347                         printf ("    ");
348                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
349                       match_byte(0);
350                       match_byte(0);
351                       match_byte(0);
352                       match_byte(0);
353                       match_byte(0);
354                     }
355                   else
356                     dump_value (level+1);
357                   putchar('\n');
358                 }
359             }
360         }
361     }
362   else
363     {
364
365       match_byte_assert (0x58);
366       char *base = get_string();
367       int x = get_u32();
368       printf ("\"%s\" with %d variables:\n", base, x);
369       if (match_u32(0))
370         {
371           for (int i = 0; i < x; i++)
372             {
373               dump_value (level+1);
374               putchar('\n');
375             }
376         }
377       else
378         {
379           for (int i = 0; i < x; i++)
380             {
381               int y = get_u32();
382               match_u32_assert(0);
383               for (int j = 0; j <= level; j++)
384                 printf ("    ");
385               printf("variable %d has %d values:\n", i, y);
386               for (int j = 0; j < y; j++)
387                 {
388                   if (match_byte(3))
389                     {
390                       char *a = get_string();
391                       match_byte_assert(0x58);
392                       char *b = get_string();
393                       char *c = get_string();
394                       for (int k = 0; k <= level + 1; k++)
395                         printf ("    ");
396                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
397                       match_byte(0);
398                       match_byte(0);
399                       match_byte(0);
400                       match_byte(0);
401                       match_byte(0);
402                     }
403                   else
404                     dump_value (level+1);
405                   putchar('\n');
406                 }
407             }
408         }
409     }
410 }
411
412 static void
413 dump_dim_value(int level)
414 {
415   for (int i = 0; i <= level; i++)
416     printf ("    ");
417
418   if (match_byte (3))
419     {
420       get_string();
421       if (match_byte (0x31))
422         {
423           match_u32 (1);
424           printf("(footnote %d) ", get_u32());
425           match_byte_assert (0);
426           match_byte_assert (0);
427           int subn = get_u32 ();
428           printf ("nested %d bytes", subn);
429           pos += subn;
430         }
431       else
432         match_byte_assert (0x58);
433       get_string();
434       printf("string \"%s\"", get_string());
435       match_byte (0);
436       match_byte_assert (1);
437       match_byte (0);
438       match_byte (0);
439       match_byte (0);
440       match_byte (1);
441     }
442   else if (match_byte (5))
443     {
444       match_byte_assert (0x58);
445       printf ("variable \"%s\"", get_string());
446       get_string();
447       match_byte_assert (2);
448     }
449   else if (match_byte (2))
450     {
451       unsigned int format;
452       char *var, *vallab;
453       double value;
454
455       match_byte_assert (0x58);
456       format = get_u32 ();
457       value = get_double ();
458       var = get_string ();
459       vallab = get_string ();
460       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
461               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
462       if (!match_u32 (3))
463         match_u32_assert (2);
464       match_byte (0);
465     }
466   else if (match_byte (1))
467     {
468       unsigned int format;
469       double value;
470
471       match_byte_assert (0x58);
472       format = get_u32 ();
473       value = get_double ();
474       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
475       match_byte (1);
476       match_byte (0);
477       match_byte (0);
478       match_byte (0);
479       match_byte (1);
480     }
481   else
482     {
483       int subn;
484
485       match_byte (0);
486       match_byte_assert (0x31);
487       match_u32_assert (0);
488       match_u32_assert (0);
489       subn = get_u32 ();
490       printf ("nested %d bytes", subn);
491       pos += subn;
492       printf ("; \"%s\", substitutions:", get_string());
493       int total_subs = get_u32();
494       int x = get_u32();
495       if (x)
496         {
497           total_subs = (total_subs - 1) + x;
498           match_u32_assert (0);
499         }
500       printf (" (total %d)", total_subs);
501
502       for (int i = 0; i < total_subs; i++)
503         {
504           putc ('\n', stdout);
505           dump_value (level + 1);
506         }
507     }
508 }
509
510 static void
511 dump_category(int level)
512 {
513   match_byte (0);
514   match_byte (0);
515   match_byte (0);
516   match_byte (0);
517   dump_value (level);
518
519   if (match_u32 (2))
520     get_u32 ();
521   else if (match_u32 (1))
522     {
523       match_byte (0);
524       match_byte (0);
525       match_byte (0);
526       get_u32 ();
527     }
528   else if (match_byte (1))
529     {
530       match_byte (0);
531       if (!match_u32 (2))
532         match_u32_assert (1);
533       match_byte (0);
534       get_u32();
535     }
536   else
537     {
538       match_u32_assert (0);
539       get_u32 ();
540     }
541
542   int n_categories = get_u32();
543   if (n_categories > 0)
544     printf (", %d subcategories:", n_categories);
545   printf("\n");
546   for (int i = 0; i < n_categories; i++)
547     dump_category (level + 1);
548 }
549
550 static void
551 dump_dim(void)
552 {
553   int n_categories;
554   printf("next dim\n");
555   match_byte(0);
556   if (match_byte(3))
557     {
558       get_string();
559       match_byte_assert(0x58);
560       get_string();
561       printf("string \"%s\": ", get_string());
562       match_byte(1) || match_byte(0);
563     }
564   else if (match_byte(5)) 
565     {
566       match_byte_assert(0x58);
567       printf("variable \"%s\": ", get_string());
568       get_string();
569       if (!match_byte(2))
570         match_byte_assert(3);
571     }
572   else if (match_byte(0x31))
573     {
574       int subn;
575       int total_subs = 1;
576
577       match_u32_assert (0);
578       match_u32_assert (0);
579       subn = get_u32 ();
580       printf ("nested %d bytes", subn);
581       pos += subn;
582       printf ("; \"%s\", substitutions:", get_string());
583       for (;;)
584         {
585           int n_subst = get_u32();
586           if (!n_subst)
587             break;
588           printf (" %d", n_subst);
589           total_subs *= n_subst;
590         }
591
592       for (int i = 0; i < total_subs; i++)
593         {
594           putc ('\n', stdout);
595           dump_dim_value (0);
596         }
597     }
598   else
599     {
600       int total_subs = 1;
601
602       match_byte_assert (0x58);
603       printf ("\"%s\" with substitutions:", get_string());
604       for (;;)
605         {
606           int n_subst = get_u32();
607           if (!n_subst)
608             break;
609           printf (" %d", n_subst);
610           total_subs *= n_subst;
611         }
612
613       for (int i = 0; i < total_subs; i++)
614         {
615           putc ('\n', stdout);
616           dump_dim_value (0);
617         }
618     }
619
620   /* This byte is usually 0x02 but 0x00 and 0x75 (!) have also been spotted. */
621   pos++;
622
623   if (!match_byte(0) && !match_byte(1))
624     match_byte_assert(2);
625   if (!match_u32(0))
626     match_u32_assert(2);
627   if (!match_byte(0))
628     match_byte_assert(1);
629   match_byte(0);
630   match_byte(0);
631   match_byte(0);
632   match_byte(0);
633   get_u32();
634   match_byte(0);
635   match_byte(0);
636   match_byte(0);
637   match_byte(0);
638   n_categories = get_u32();
639   printf("%d nested categories\n", n_categories);
640   for (int i = 0; i < n_categories; i++)
641     dump_category (0);
642 }
643
644 static void
645 dump_dims(void)
646 {
647   int n_dims = get_u32();
648
649   printf ("%u dimensions\n", n_dims);
650   for (int i = 0; i < n_dims; i++)
651     {
652       printf("\n");
653       dump_dim ();
654     }
655 }
656
657 static void
658 dump_data(void)
659 {
660 #if 1
661   if (!match_u32 (0) || !match_u32 (1) || !match_u32(1) || !match_u32(0) || (!match_u32(1) && !match_u32(13)))
662     {
663       printf ("skipping data\n");
664       return;
665     }
666 #else
667   fprintf (stderr,"data intro:");
668   for (int i = 0; i < 5; i++)
669     fprintf (stderr," %d", get_u32());
670   fprintf(stderr,"\n");
671 #endif
672   int x = get_u32();
673   printf ("%d data values, starting at %08x\n", x, pos);
674   for (int i = 0; i < x; i++)
675     {
676       printf("%08x, index %d:\n", pos, get_u32());
677       match_u32_assert(0);
678       match_byte(0);
679       match_byte(0);
680       match_byte(0);
681       match_byte(0);
682       if (match_byte (1))
683         {
684           unsigned int format;
685           double value;
686
687           if (match_byte (0x31))
688             {
689               if (match_u32 (1))
690                 {
691                   printf("(footnote %d) ", get_u32());
692                   match_byte_assert (0);
693                   match_byte_assert (0);
694                   int subn = get_u32 ();
695                   printf ("nested %d bytes", subn);
696                   pos += subn;
697                 }
698             }
699           else
700             match_byte_assert (0x58);
701           format = get_u32 ();
702           value = get_double ();
703           printf ("    value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
704         }
705       else if (match_byte (3))
706         {
707           get_string();
708           if (match_byte (0x31))
709             {
710               if (match_u32 (0))
711                 {
712                   match_u32_assert (1);
713                   int subn = get_u32 ();
714                   printf ("nested %d bytes", subn);
715                   pos += subn;
716                 }
717               else if (match_u32 (1))
718                 {
719                   printf("(footnote %d) ", get_u32());
720                   match_byte_assert (0);
721                   match_byte_assert (0);
722                   int subn = get_u32 ();
723                   printf ("nested %d bytes", subn);
724                   pos += subn;
725                 }
726               else if (match_u32 (2))
727                 {
728                   printf("(special 2)");
729                   match_byte_assert(0);
730                   match_byte_assert(0);
731                   match_u32_assert(1);
732                   match_byte_assert(0);
733                   match_byte_assert(0);
734                   int subn = get_u32 ();
735                   printf ("nested %d bytes", subn);
736                   pos += subn;
737                 }
738               else
739                 {
740                   match_u32_assert(3);
741                   printf("(special 3)");
742                   match_byte_assert(0);
743                   match_byte_assert(0);
744                   match_byte_assert(1);
745                   match_byte_assert(0);
746                   int subn = get_u32 ();
747                   printf ("nested %d bytes, ", subn);
748                   pos += subn;
749                   subn = get_u32 ();
750                   printf ("nested %d bytes, ", subn);
751                   pos += subn;
752                 }
753             }
754           else
755             match_byte_assert (0x58);
756           get_string();
757           printf("string \"%s\"", get_string());
758           match_byte (0);
759         }
760       else if (match_byte (2))
761         {
762           unsigned int format;
763           char *var, *vallab;
764           double value;
765
766           match_byte_assert (0x58);
767           format = get_u32 ();
768           value = get_double ();
769           var = get_string ();
770           vallab = get_string ();
771           printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
772                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
773           if (!match_byte (1) && !match_byte(2))
774             match_byte_assert (3);
775         }
776       else if (match_byte (4))
777         {
778           unsigned int format;
779           char *var, *vallab, *value;
780
781           match_byte_assert (0x58);
782           format = get_u32 ();
783           vallab = get_string ();
784           var = get_string ();
785           if (!match_byte(1) && !match_byte(2))
786             match_byte_assert (3);
787           value = get_string ();
788           printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
789                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
790         }
791       else
792         dump_value(0);
793       putchar('\n');
794     }
795 }
796
797 int
798 main(int argc, char *argv[])
799 {
800   size_t start;
801   struct stat s;
802
803   if (isatty(STDIN_FILENO))
804     {
805       fprintf(stderr, "redirect stdin from a .bin file\n");
806       exit(1);
807     }
808   if (fstat(STDIN_FILENO, &s))
809     {
810       perror("fstat");
811       exit(1);
812     }
813   n = s.st_size;
814   data = malloc(n);
815   if (!data)
816     {
817       perror("malloc");
818       exit(1);
819     }
820   if (read(STDIN_FILENO, data, n) != n)
821     {
822       perror("read");
823       exit(1);
824     }
825
826   if (argc > 1)
827     {
828       if (!strcmp(argv[1], "title0"))
829         {
830           pos = 0x27;
831           if (match_byte (0x03)
832               || (match_byte (0x05) && match_byte (0x58)))
833             printf ("%s\n", get_string());
834           else
835             printf ("<unknown>\n");
836           return 0;
837         }
838       if (!strcmp(argv[1], "title"))
839         {
840           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
841           start = 0x27;
842           n = find(fonts, sizeof fonts - 1);
843         }
844       else if (!strcmp(argv[1], "fonts"))
845         {
846           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
847           const char styles[] = "\xf0\0\0\0";
848           start = find(fonts, sizeof fonts - 1);
849           n = find(styles, sizeof styles - 1);
850         }
851       else if (!strcmp(argv[1], "styles"))
852         {
853           const char styles[] = "\xf0\0\0\0";
854           const char dimensions[] = "-,,,.\0";
855           start = find(styles, sizeof styles - 1);
856           n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
857         }
858       else if (!strcmp(argv[1], "dimensions"))
859         {
860           {
861             const char dimensions[] = "-,,,.\0";
862             start = try_find_tail(dimensions, sizeof dimensions - 1);
863           }
864
865           if (!start)
866             {
867               const char dimensions[] = "-,,, .\0";
868               start = find_tail(dimensions, sizeof dimensions - 1);
869             }
870
871           pos = start;
872           dump_dims ();
873           dump_data ();
874           start = pos;
875         }
876       else
877         {
878           fprintf (stderr, "unknown section %s\n", argv[1]);
879           exit(1);
880         }
881     }
882   else
883     start = 0x27;
884
885   for (size_t i = start; i < n; )
886     {
887       if (i + 5 <= n
888           && data[i]
889           && !data[i + 1]
890           && !data[i + 2]
891           && !data[i + 3]
892           && i + 4 + data[i] <= n
893           && all_ascii(&data[i + 4], data[i]))
894         {
895           fputs("\n\"", stdout);
896           fwrite(&data[i + 4], 1, data[i], stdout);
897           fputs("\" ", stdout);
898
899           i += 4 + data[i];
900         }
901       else if (i + 12 <= n
902                && data[i + 1] == 40
903                && data[i + 2] == 5
904                && data[i + 3] == 0)
905         {
906           double d;
907
908           memcpy (&d, &data[i + 4], 8);
909           printf ("F40.%d(%.*f)\n", data[i], data[i], d);
910           i += 12;
911         }
912       else if (i + 12 <= n
913                && data[i + 1] == 40
914                && data[i + 2] == 31
915                && data[i + 3] == 0)
916         {
917           double d;
918
919           memcpy (&d, &data[i + 4], 8);
920           printf ("PCT40.%d(%.*f)\n", data[i], data[i], d);
921           i += 12;
922         }
923       else if (i + 4 <= n
924                && (data[i] && data[i] != 88 && data[i] != 0x41)
925                && !data[i + 1]
926                && !data[i + 2]
927                && !data[i + 3])
928         {
929           printf ("i%d ", data[i]);
930           i += 4;
931         }
932       else
933         {
934           printf("%02x ", data[i]);
935           i++;
936         }
937     }
938
939   return 0;
940 }