Fix Serpent-AVX2 and Camellia-AVX2 counter modes
[libgcrypt.git] / src / dumpsexp.c
1 /* dumpsexp.c - Dump S-expressions.
2  * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 3 of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <config.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 /* For a native WindowsCE binary we need to include gpg-error.h to
26    provide a replacement for strerror.  */
27 #ifdef __MINGW32CE__
28 # include <gpg-error.h>
29 #endif
30
31 #define PGM "dumpsexp"
32 #define MYVERSION_LINE PGM " (Libgcrypt) " VERSION
33 #define BUGREPORT_LINE "\nReport bugs to <bug-libgcrypt@gnupg.org>.\n"
34
35
36 static int verbose;  /* Verbose mode.  */
37 static int decimal;  /* Print addresses in decimal.  */
38 static int assume_hex;  /* Assume input is hexencoded.  */
39 static int advanced; /* Advanced format output.  */
40
41 static void
42 print_version (int with_help)
43 {
44   fputs (MYVERSION_LINE "\n"
45          "Copyright (C) 2010 Free Software Foundation, Inc.\n"
46          "License GPLv3+: GNU GPL version 3 or later "
47          "<http://gnu.org/licenses/gpl.html>\n"
48          "This is free software: you are free to change and redistribute it.\n"
49          "There is NO WARRANTY, to the extent permitted by law.\n",
50          stdout);
51
52   if (with_help)
53     fputs ("\n"
54            "Usage: " PGM " [OPTIONS] [file]\n"
55            "Debug tool for S-expressions\n"
56            "\n"
57            "  --decimal     Print offsets using decimal notation\n"
58            "  --assume-hex  Assume input is a hex dump\n"
59            "  --advanced    Print file in advanced format\n"
60            "  --verbose     Show what we are doing\n"
61            "  --version     Print version of the program and exit\n"
62            "  --help        Display this help and exit\n"
63            BUGREPORT_LINE, stdout );
64
65   exit (0);
66 }
67
68 static int
69 print_usage (void)
70 {
71   fputs ("usage: " PGM " [OPTIONS] NBYTES\n", stderr);
72   fputs ("       (use --help to display options)\n", stderr);
73   exit (1);
74 }
75
76
77 #define space_p(a)    ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
78 #define digit_p(a)    ((a) >= '0' && (a) <= '9')
79 #define octdigit_p(a) ((a) >= '0' && (a) <= '7')
80 #define alpha_p(a)    (   ((a) >= 'A' && (a) <= 'Z')  \
81                        || ((a) >= 'a' && (a) <= 'z'))
82 #define hexdigit_p(a) (digit_p (a)                     \
83                        || ((a) >= 'A' && (a) <= 'F')  \
84                        || ((a) >= 'a' && (a) <= 'f'))
85 #define xtoi_1(a)     ((a) <= '9'? ((a)- '0'): \
86                        (a) <= 'F'? ((a)-'A'+10):((a)-'a'+10))
87
88
89 /* Return true if P points to a byte containing a whitespace according
90    to the S-expressions definition. */
91 static inline int
92 whitespace_p (int c)
93 {
94   switch (c)
95     {
96     case ' ': case '\t': case '\v': case '\f': case '\r': case '\n': return 1;
97     default: return 0;
98     }
99 }
100
101 static void
102 logit (const char *format, ...)
103 {
104   va_list arg_ptr;
105
106   va_start (arg_ptr, format) ;
107   fputs (PGM ": ", stderr);
108   vfprintf (stderr, format, arg_ptr);
109   putc ('\n', stderr);
110   va_end (arg_ptr);
111 }
112
113 /* The raw data buffer and its current length */
114 static unsigned char databuffer[16];
115 static int databufferlen;
116 /* The number of bytes in databuffer which should be skipped at a flush.  */
117 static int skipdatabufferlen;
118 /* The number of raw bytes printed on the last line.  */
119 static int nbytesprinted;
120 /* The file offset of the current data buffer .  */
121 static unsigned long databufferoffset;
122
123
124
125 static int
126 my_getc (FILE *fp)
127 {
128   int c1, c2;
129
130   if (!assume_hex)
131     return getc (fp);
132
133   while ( (c1=getc (fp)) != EOF && space_p (c1) )
134     ;
135   if (c1 == EOF)
136     return EOF;
137
138   if (!hexdigit_p (c1))
139     {
140       logit ("non hex-digit encountered\n");
141       return EOF;
142     }
143
144   while ( (c2=getc (fp)) != EOF && space_p (c2) )
145     ;
146   if (c2 == EOF)
147     {
148       logit ("error reading second hex nibble\n");
149       return EOF;
150     }
151   if (!hexdigit_p (c2))
152     {
153       logit ("second hex nibble is not a hex-digit\n");
154       return EOF;
155     }
156   return xtoi_1 (c1) * 16 + xtoi_1 (c2);
157 }
158
159
160
161
162
163 /* Flush the raw data buffer.  */
164 static void
165 flushdatabuffer (void)
166 {
167   int i;
168
169   if (!databufferlen)
170     return;
171   nbytesprinted = 0;
172   if (decimal)
173     printf ("%08lu ", databufferoffset);
174   else
175     printf ("%08lx ", databufferoffset);
176   for (i=0; i < databufferlen; i++)
177     {
178       if (i == 8)
179         putchar (' ');
180       if (i < skipdatabufferlen)
181         fputs ("   ", stdout);
182       else
183         {
184           printf (" %02x", databuffer[i]);
185           databufferoffset++;
186         }
187       nbytesprinted++;
188     }
189   for (; i < sizeof (databuffer); i++)
190     {
191       if (i == 8)
192         putchar (' ');
193       fputs ("   ", stdout);
194     }
195   fputs ("  |", stdout);
196   for (i=0; i < databufferlen; i++)
197     {
198       if (i < skipdatabufferlen)
199         putchar (' ');
200       else if (databuffer[i] >= ' ' && databuffer[i] <= '~'
201                && databuffer[i] != '|')
202         putchar (databuffer[i]);
203       else
204         putchar ('.');
205     }
206   putchar ('|');
207   putchar ('\n');
208   databufferlen = 0;
209   skipdatabufferlen = 0;
210 }
211
212
213 /* Add C to the raw data buffer and flush as needed.  */
214 static void
215 addrawdata (int c)
216 {
217   if ( databufferlen >= sizeof databuffer )
218     flushdatabuffer ();
219   databuffer[databufferlen++] = c;
220 }
221
222
223 static void
224 printcursor (int both)
225 {
226   int i;
227
228   flushdatabuffer ();
229   printf ("%8s ", "");
230   for (i=0; i < sizeof (databuffer); i++)
231     {
232       if (i == 8)
233         putchar (' ');
234       if (i+1 == nbytesprinted)
235         {
236           fputs (" ^ ", stdout);
237           if (!both)
238             break;
239         }
240       else
241         fputs ("   ", stdout);
242     }
243   if (both)
244     {
245       fputs ("   ", stdout);
246       for (i=0; i < nbytesprinted-1; i++)
247         putchar (' ');
248       putchar ('^');
249     }
250   databufferlen = skipdatabufferlen = nbytesprinted;
251 }
252
253 static void
254 printerr (const char *text)
255 {
256   printcursor (1);
257   printf ("\n          Error: %s\n", text);
258 }
259
260 static void
261 printctl (const char *text)
262 {
263   if (verbose && !advanced)
264     {
265       printcursor (0);
266       printf ("%s\n", text);
267     }
268 }
269
270 static void
271 printchr (int c)
272 {
273   putchar (c);
274 }
275
276 /* static void */
277 /* printhex (int c) */
278 /* { */
279 /*   printf ("\\x%02x", c); */
280 /* } */
281
282
283 #if 0
284 /****************
285  * Print SEXP to buffer using the MODE.  Returns the length of the
286  * SEXP in buffer or 0 if the buffer is too short (We have at least an
287  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
288  * the required length is returned.
289  */
290 size_t
291 gcry_sexp_sprint (const gcry_sexp_t list,
292                   void *buffer, size_t maxlength )
293 {
294   static unsigned char empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
295   const unsigned char *s;
296   char *d;
297   DATALEN n;
298   char numbuf[20];
299   int i, indent = 0;
300
301   s = list? list->d : empty;
302   d = buffer;
303   while ( *s != ST_STOP )
304     {
305       switch ( *s )
306         {
307         case ST_OPEN:
308           s++;
309           if (indent)
310             putchar ('\n');
311           for (i=0; i < indent; i++)
312             putchar (' ');
313           putchar ('(');
314           indent++;
315           break;
316         case ST_CLOSE:
317           s++;
318           putchar (')');
319           indent--;
320           if (*s != ST_OPEN && *s != ST_STOP)
321             {
322               putchar ('\n');
323               for (i=0; i < indent; i++)
324                 putchar (' ');
325             }
326           break;
327         case ST_DATA:
328           s++;
329           memcpy (&n, s, sizeof n);
330           s += sizeof n;
331           {
332             int type;
333             size_t nn;
334
335             switch ( (type=suitable_encoding (s, n)))
336               {
337               case 1: nn = convert_to_string (s, n, NULL); break;
338               case 2: nn = convert_to_token (s, n, NULL); break;
339               default: nn = convert_to_hex (s, n, NULL); break;
340               }
341             switch (type)
342               {
343               case 1: convert_to_string (s, n, d); break;
344               case 2: convert_to_token (s, n, d); break;
345               default: convert_to_hex (s, n, d); break;
346               }
347             d += nn;
348             if (s[n] != ST_CLOSE)
349               putchar (' ');
350           }
351           else
352             {
353               snprintf (numbuf, sizeof numbuf,  "%u:", (unsigned int)n );
354               d = stpcpy (d, numbuf);
355               memcpy (d, s, n);
356               d += n;
357             }
358           s += n;
359           break;
360         default:
361           BUG ();
362         }
363     }
364   putchar ('\n');
365   return len;
366 }
367 #endif
368
369
370 /* Prepare for saving a chunk of data.  */
371 static void
372 init_data (void)
373 {
374
375 }
376
377 /* Push C on the current data chunk.  */
378 static void
379 push_data (int c)
380 {
381   (void)c;
382 }
383
384 /* Flush and thus print the current data chunk.  */
385 static void
386 flush_data (void)
387 {
388
389 }
390
391
392 /* Returns 0 on success.  */
393 static int
394 parse_and_print (FILE *fp)
395 {
396   static const char tokenchars[] =
397     "abcdefghijklmnopqrstuvwxyz"
398     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
399     "0123456789-./_:*+=";
400   int c;
401   int level = 0;
402   int tokenc = 0;
403   int hexcount = 0;
404   int disphint = 0;
405   unsigned long datalen = 0;
406   char quote_buf[10];
407   int quote_idx = 0;
408   enum
409     {
410       INIT_STATE = 0, IN_NUMBER, PRE_DATA, IN_DATA, IN_STRING,
411       IN_ESCAPE, IN_OCT_ESC, IN_HEX_ESC,
412       CR_ESC, LF_ESC, IN_HEXFMT, IN_BASE64
413     }
414   state = INIT_STATE;
415
416
417   while ((c = my_getc (fp)) != EOF )
418     {
419       addrawdata (c);
420       switch (state)
421         {
422         case INIT_STATE:
423           if (tokenc)
424             {
425               if (strchr (tokenchars, c))
426                 {
427                   printchr (c);
428                   continue;
429                 }
430               tokenc = 0;
431             }
432         parse_init_state:
433           if (c == '(')
434             {
435               if (disphint)
436                 {
437                   printerr ("unmatched display hint");
438                   disphint = 0;
439                 }
440               printctl ("open");
441               level++;
442             }
443           else if (c == ')')
444             {
445               if (disphint)
446                 {
447                   printerr ("unmatched display hint");
448                   disphint = 0;
449                 }
450               printctl ("close");
451               level--;
452             }
453           else if (c == '\"')
454             {
455               state = IN_STRING;
456               printctl ("beginstring");
457               init_data ();
458             }
459           else if (c == '#')
460             {
461               state = IN_HEXFMT;
462               hexcount = 0;
463               printctl ("beginhex");
464               init_data ();
465             }
466           else if (c == '|')
467             {
468               state = IN_BASE64;
469               printctl ("beginbase64");
470               init_data ();
471             }
472           else if (c == '[')
473             {
474               if (disphint)
475                 printerr ("nested display hint");
476               disphint = c;
477             }
478           else if (c == ']')
479             {
480               if (!disphint)
481                 printerr ("no open display hint");
482               disphint = 0;
483             }
484           else if (c >= '0' && c <= '9')
485             {
486               if (c == '0')
487                 printerr ("zero prefixed length");
488               state = IN_NUMBER;
489               datalen = (c - '0');
490             }
491           else if (strchr (tokenchars, c))
492             {
493               printchr (c);
494               tokenc = c;
495             }
496           else if (whitespace_p (c))
497             ;
498           else if (c == '{')
499             {
500               printerr ("rescanning is not supported");
501             }
502           else if (c == '&' || c == '\\')
503             {
504               printerr ("reserved punctuation detected");
505             }
506           else
507             {
508               printerr ("bad character detected");
509             }
510           break;
511
512         case IN_NUMBER:
513           if (digit_p (c))
514             {
515               unsigned long tmp = datalen * 10 + (c - '0');
516               if (tmp < datalen)
517                 {
518                   printerr ("overflow in data length");
519                   state = INIT_STATE;
520                   datalen = 0;
521                 }
522               else
523                 datalen = tmp;
524             }
525           else if (c == ':')
526             {
527               if (!datalen)
528                 {
529                   printerr ("no data length");
530                   state = INIT_STATE;
531                 }
532               else
533                 state = PRE_DATA;
534             }
535           else if (c == '\"' || c == '#' || c == '|' )
536             {
537               /* We ignore the optional length and divert to the init
538                  state parser code. */
539               goto parse_init_state;
540             }
541           else
542             printerr ("invalid length specification");
543           break;
544
545         case PRE_DATA:
546           state = IN_DATA;
547           printctl ("begindata");
548           init_data ();
549         case IN_DATA:
550           if (datalen)
551             {
552               push_data (c);
553               datalen--;
554             }
555           if (!datalen)
556             {
557               state = INIT_STATE;
558               printctl ("enddata");
559               flush_data ();
560             }
561           break;
562
563         case IN_STRING:
564           if (c == '\"')
565             {
566               printctl ("endstring");
567               flush_data ();
568               state = INIT_STATE;
569             }
570           else if (c == '\\')
571             state = IN_ESCAPE;
572           else
573             push_data (c);
574           break;
575
576         case IN_ESCAPE:
577           switch (c)
578             {
579             case 'b':  push_data ('\b'); state = IN_STRING; break;
580             case 't':  push_data ('\t'); state = IN_STRING; break;
581             case 'v':  push_data ('\v'); state = IN_STRING; break;
582             case 'n':  push_data ('\n'); state = IN_STRING; break;
583             case 'f':  push_data ('\f'); state = IN_STRING; break;
584             case 'r':  push_data ('\r'); state = IN_STRING; break;
585             case '"':  push_data ('"');  state = IN_STRING; break;
586             case '\'': push_data ('\''); state = IN_STRING; break;
587             case '\\': push_data ('\\'); state = IN_STRING; break;
588
589             case '0': case '1': case '2': case '3': case '4':
590             case '5': case '6': case '7':
591               state = IN_OCT_ESC;
592               quote_idx = 0;
593               quote_buf[quote_idx++] = c;
594               break;
595
596             case 'x':
597               state = IN_HEX_ESC;
598               quote_idx = 0;
599               break;
600
601             case '\r':
602               state = CR_ESC;
603               break;
604
605             case '\n':
606               state = LF_ESC;
607               break;
608
609             default:
610               printerr ("invalid escape sequence");
611               state = IN_STRING;
612               break;
613             }
614           break;
615
616         case IN_OCT_ESC:
617           if (quote_idx < 3 && strchr ("01234567", c))
618             {
619               quote_buf[quote_idx++] = c;
620               if (quote_idx == 3)
621                 {
622                   push_data ((unsigned int)quote_buf[0] * 8 * 8
623                              + (unsigned int)quote_buf[1] * 8
624                              + (unsigned int)quote_buf[2]);
625                   state = IN_STRING;
626                 }
627             }
628           else
629             state = IN_STRING;
630           break;
631         case IN_HEX_ESC:
632           if (quote_idx < 2 && strchr ("0123456789abcdefABCDEF", c))
633             {
634               quote_buf[quote_idx++] = c;
635               if (quote_idx == 2)
636                 {
637                   push_data (xtoi_1 (quote_buf[0]) * 16
638                              + xtoi_1 (quote_buf[1]));
639                   state = IN_STRING;
640                 }
641             }
642           else
643             state = IN_STRING;
644           break;
645         case CR_ESC:
646           state = IN_STRING;
647           break;
648         case LF_ESC:
649           state = IN_STRING;
650           break;
651
652         case IN_HEXFMT:
653           if (hexdigit_p (c))
654             {
655               push_data (c);
656               hexcount++;
657             }
658           else if (c == '#')
659             {
660               if ((hexcount & 1))
661                 printerr ("odd number of hex digits");
662               printctl ("endhex");
663               flush_data ();
664               state = INIT_STATE;
665             }
666           else if (!whitespace_p (c))
667             printerr ("bad hex character");
668           break;
669
670         case IN_BASE64:
671           if (c == '|')
672             {
673               printctl ("endbase64");
674               flush_data ();
675               state = INIT_STATE;
676             }
677           else
678             push_data (c);
679           break;
680
681         default:
682           logit ("invalid state %d detected", state);
683           exit (1);
684         }
685     }
686   flushdatabuffer ();
687   if (ferror (fp))
688     {
689       logit ("error reading input: %s\n", strerror (errno));
690       return -1;
691     }
692   return 0;
693 }
694
695
696
697 int
698 main (int argc, char **argv)
699 {
700   int rc;
701
702   if (argc)
703     {
704       argc--; argv++;
705     }
706   while (argc && **argv == '-' && (*argv)[1] == '-')
707     {
708       if (!(*argv)[2])
709         {
710           argc--; argv++;
711           break;
712         }
713       else if (!strcmp (*argv, "--version"))
714         print_version (0);
715       else if (!strcmp (*argv, "--help"))
716         print_version (1);
717       else if (!strcmp (*argv, "--verbose"))
718         {
719           argc--; argv++;
720           verbose = 1;
721         }
722       else if (!strcmp (*argv, "--decimal"))
723         {
724           argc--; argv++;
725           decimal = 1;
726         }
727       else if (!strcmp (*argv, "--assume-hex"))
728         {
729           argc--; argv++;
730           assume_hex = 1;
731         }
732       else if (!strcmp (*argv, "--advanced"))
733         {
734           argc--; argv++;
735           advanced = 1;
736         }
737       else
738         print_usage ();
739     }
740
741   if (!argc)
742     {
743       rc = parse_and_print (stdin);
744     }
745   else
746     {
747       rc = 0;
748       for (; argc; argv++, argc--)
749         {
750           FILE *fp = fopen (*argv, "rb");
751           if (!fp)
752             {
753               logit ("can't open `%s': %s\n", *argv, strerror (errno));
754               rc = 1;
755             }
756           else
757             {
758               if (parse_and_print (fp))
759                 rc = 1;
760               fclose (fp);
761             }
762         }
763     }
764
765   return !!rc;
766 }