summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/src/dumpsexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgcrypt-1.8.7/src/dumpsexp.c')
-rw-r--r--libotr/libgcrypt-1.8.7/src/dumpsexp.c767
1 files changed, 767 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/src/dumpsexp.c b/libotr/libgcrypt-1.8.7/src/dumpsexp.c
new file mode 100644
index 0000000..5aeb77d
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/src/dumpsexp.c
@@ -0,0 +1,767 @@
+/* dumpsexp.c - Dump S-expressions.
+ * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <errno.h>
+/* For a native WindowsCE binary we need to include gpg-error.h to
+   provide a replacement for strerror.  */
+#ifdef __MINGW32CE__
+# include <gpg-error.h>
+#endif
+
+#define PGM "dumpsexp"
+#define MYVERSION_LINE PGM " (Libgcrypt) " VERSION
+#define BUGREPORT_LINE "\nReport bugs to <bug-libgcrypt@gnupg.org>.\n"
+
+
+static int verbose;  /* Verbose mode.  */
+static int decimal;  /* Print addresses in decimal.  */
+static int assume_hex;  /* Assume input is hexencoded.  */
+static int advanced; /* Advanced format output.  */
+
+static void
+print_version (int with_help)
+{
+  fputs (MYVERSION_LINE "\n"
+         "Copyright (C) 2010 Free Software Foundation, Inc.\n"
+         "License GPLv3+: GNU GPL version 3 or later "
+         "<http://gnu.org/licenses/gpl.html>\n"
+         "This is free software: you are free to change and redistribute it.\n"
+         "There is NO WARRANTY, to the extent permitted by law.\n",
+         stdout);
+
+  if (with_help)
+    fputs ("\n"
+           "Usage: " PGM " [OPTIONS] [file]\n"
+           "Debug tool for S-expressions\n"
+           "\n"
+           "  --decimal     Print offsets using decimal notation\n"
+           "  --assume-hex  Assume input is a hex dump\n"
+           "  --advanced    Print file in advanced format\n"
+           "  --verbose     Show what we are doing\n"
+           "  --version     Print version of the program and exit\n"
+           "  --help        Display this help and exit\n"
+           BUGREPORT_LINE, stdout );
+
+  exit (0);
+}
+
+static int
+print_usage (void)
+{
+  fputs ("usage: " PGM " [OPTIONS] NBYTES\n", stderr);
+  fputs ("       (use --help to display options)\n", stderr);
+  exit (1);
+}
+
+
+#define space_p(a)    ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
+#define digit_p(a)    ((a) >= '0' && (a) <= '9')
+#define octdigit_p(a) ((a) >= '0' && (a) <= '7')
+#define alpha_p(a)    (   ((a) >= 'A' && (a) <= 'Z')  \
+                       || ((a) >= 'a' && (a) <= 'z'))
+#define hexdigit_p(a) (digit_p (a)                     \
+                       || ((a) >= 'A' && (a) <= 'F')  \
+                       || ((a) >= 'a' && (a) <= 'f'))
+#define xtoi_1(a)     ((a) <= '9'? ((a)- '0'): \
+                       (a) <= 'F'? ((a)-'A'+10):((a)-'a'+10))
+
+
+/* Return true if P points to a byte containing a whitespace according
+   to the S-expressions definition. */
+static inline int
+whitespace_p (int c)
+{
+  switch (c)
+    {
+    case ' ': case '\t': case '\v': case '\f': case '\r': case '\n': return 1;
+    default: return 0;
+    }
+}
+
+static void
+logit (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format) ;
+  fputs (PGM ": ", stderr);
+  vfprintf (stderr, format, arg_ptr);
+  putc ('\n', stderr);
+  va_end (arg_ptr);
+}
+
+/* The raw data buffer and its current length */
+static unsigned char databuffer[16];
+static int databufferlen;
+/* The number of bytes in databuffer which should be skipped at a flush.  */
+static int skipdatabufferlen;
+/* The number of raw bytes printed on the last line.  */
+static int nbytesprinted;
+/* The file offset of the current data buffer .  */
+static unsigned long databufferoffset;
+
+
+
+static int
+my_getc (FILE *fp)
+{
+  int c1, c2;
+
+  if (!assume_hex)
+    return getc (fp);
+
+  while ( (c1=getc (fp)) != EOF && space_p (c1) )
+    ;
+  if (c1 == EOF)
+    return EOF;
+
+  if (!hexdigit_p (c1))
+    {
+      logit ("non hex-digit encountered\n");
+      return EOF;
+    }
+
+  while ( (c2=getc (fp)) != EOF && space_p (c2) )
+    ;
+  if (c2 == EOF)
+    {
+      logit ("error reading second hex nibble\n");
+      return EOF;
+    }
+  if (!hexdigit_p (c2))
+    {
+      logit ("second hex nibble is not a hex-digit\n");
+      return EOF;
+    }
+  return xtoi_1 (c1) * 16 + xtoi_1 (c2);
+}
+
+
+
+
+
+/* Flush the raw data buffer.  */
+static void
+flushdatabuffer (void)
+{
+  int i;
+
+  if (!databufferlen)
+    return;
+  nbytesprinted = 0;
+  if (decimal)
+    printf ("%08lu ", databufferoffset);
+  else
+    printf ("%08lx ", databufferoffset);
+  for (i=0; i < databufferlen; i++)
+    {
+      if (i == 8)
+        putchar (' ');
+      if (i < skipdatabufferlen)
+        fputs ("   ", stdout);
+      else
+        {
+          printf (" %02x", databuffer[i]);
+          databufferoffset++;
+        }
+      nbytesprinted++;
+    }
+  for (; i < sizeof (databuffer); i++)
+    {
+      if (i == 8)
+        putchar (' ');
+      fputs ("   ", stdout);
+    }
+  fputs ("  |", stdout);
+  for (i=0; i < databufferlen; i++)
+    {
+      if (i < skipdatabufferlen)
+        putchar (' ');
+      else if (databuffer[i] >= ' ' && databuffer[i] <= '~'
+               && databuffer[i] != '|')
+        putchar (databuffer[i]);
+      else
+        putchar ('.');
+    }
+  putchar ('|');
+  putchar ('\n');
+  databufferlen = 0;
+  skipdatabufferlen = 0;
+}
+
+
+/* Add C to the raw data buffer and flush as needed.  */
+static void
+addrawdata (int c)
+{
+  if ( databufferlen >= sizeof databuffer )
+    flushdatabuffer ();
+  databuffer[databufferlen++] = c;
+}
+
+
+static void
+printcursor (int both)
+{
+  int i;
+
+  flushdatabuffer ();
+  printf ("%8s ", "");
+  for (i=0; i < sizeof (databuffer); i++)
+    {
+      if (i == 8)
+        putchar (' ');
+      if (i+1 == nbytesprinted)
+        {
+          fputs (" ^ ", stdout);
+          if (!both)
+            break;
+        }
+      else
+        fputs ("   ", stdout);
+    }
+  if (both)
+    {
+      fputs ("   ", stdout);
+      for (i=0; i < nbytesprinted-1; i++)
+        putchar (' ');
+      putchar ('^');
+    }
+  databufferlen = skipdatabufferlen = nbytesprinted;
+}
+
+static void
+printerr (const char *text)
+{
+  printcursor (1);
+  printf ("\n          Error: %s\n", text);
+}
+
+static void
+printctl (const char *text)
+{
+  if (verbose && !advanced)
+    {
+      printcursor (0);
+      printf ("%s\n", text);
+    }
+}
+
+static void
+printchr (int c)
+{
+  putchar (c);
+}
+
+/* static void */
+/* printhex (int c) */
+/* { */
+/*   printf ("\\x%02x", c); */
+/* } */
+
+
+#if 0
+/****************
+ * Print SEXP to buffer using the MODE.  Returns the length of the
+ * SEXP in buffer or 0 if the buffer is too short (We have at least an
+ * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
+ * the required length is returned.
+ */
+size_t
+gcry_sexp_sprint (const gcry_sexp_t list,
+                  void *buffer, size_t maxlength )
+{
+  static unsigned char empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
+  const unsigned char *s;
+  char *d;
+  DATALEN n;
+  char numbuf[20];
+  int i, indent = 0;
+
+  s = list? list->d : empty;
+  d = buffer;
+  while ( *s != ST_STOP )
+    {
+      switch ( *s )
+        {
+        case ST_OPEN:
+          s++;
+          if (indent)
+            putchar ('\n');
+          for (i=0; i < indent; i++)
+            putchar (' ');
+          putchar ('(');
+          indent++;
+          break;
+        case ST_CLOSE:
+          s++;
+          putchar (')');
+          indent--;
+          if (*s != ST_OPEN && *s != ST_STOP)
+            {
+              putchar ('\n');
+              for (i=0; i < indent; i++)
+                putchar (' ');
+            }
+          break;
+        case ST_DATA:
+          s++;
+          memcpy (&n, s, sizeof n);
+          s += sizeof n;
+          {
+            int type;
+            size_t nn;
+
+            switch ( (type=suitable_encoding (s, n)))
+              {
+              case 1: nn = convert_to_string (s, n, NULL); break;
+              case 2: nn = convert_to_token (s, n, NULL); break;
+              default: nn = convert_to_hex (s, n, NULL); break;
+              }
+            switch (type)
+              {
+              case 1: convert_to_string (s, n, d); break;
+              case 2: convert_to_token (s, n, d); break;
+              default: convert_to_hex (s, n, d); break;
+              }
+            d += nn;
+            if (s[n] != ST_CLOSE)
+              putchar (' ');
+          }
+          else
+            {
+              snprintf (numbuf, sizeof numbuf,  "%u:", (unsigned int)n );
+              d = stpcpy (d, numbuf);
+              memcpy (d, s, n);
+              d += n;
+            }
+          s += n;
+          break;
+        default:
+          BUG ();
+	}
+    }
+  putchar ('\n');
+  return len;
+}
+#endif
+
+
+/* Prepare for saving a chunk of data.  */
+static void
+init_data (void)
+{
+
+}
+
+/* Push C on the current data chunk.  */
+static void
+push_data (int c)
+{
+  (void)c;
+}
+
+/* Flush and thus print the current data chunk.  */
+static void
+flush_data (void)
+{
+
+}
+
+
+/* Returns 0 on success.  */
+static int
+parse_and_print (FILE *fp)
+{
+  static const char tokenchars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789-./_:*+=";
+  int c;
+  int level = 0;
+  int tokenc = 0;
+  int hexcount = 0;
+  int disphint = 0;
+  unsigned long datalen = 0;
+  char quote_buf[10];
+  int quote_idx = 0;
+  enum
+    {
+      INIT_STATE = 0, IN_NUMBER, PRE_DATA, IN_DATA, IN_STRING,
+      IN_ESCAPE, IN_OCT_ESC, IN_HEX_ESC,
+      CR_ESC, LF_ESC, IN_HEXFMT, IN_BASE64
+    }
+  state = INIT_STATE;
+
+
+  while ((c = my_getc (fp)) != EOF )
+    {
+      addrawdata (c);
+      switch (state)
+        {
+        case INIT_STATE:
+          if (tokenc)
+            {
+              if (strchr (tokenchars, c))
+                {
+                  printchr (c);
+                  continue;
+                }
+              tokenc = 0;
+            }
+        parse_init_state:
+          if (c == '(')
+            {
+              if (disphint)
+                {
+                  printerr ("unmatched display hint");
+                  disphint = 0;
+                }
+              printctl ("open");
+              level++;
+            }
+          else if (c == ')')
+            {
+              if (disphint)
+                {
+                  printerr ("unmatched display hint");
+                  disphint = 0;
+                }
+              printctl ("close");
+              level--;
+            }
+          else if (c == '\"')
+            {
+              state = IN_STRING;
+              printctl ("beginstring");
+              init_data ();
+            }
+          else if (c == '#')
+            {
+              state = IN_HEXFMT;
+              hexcount = 0;
+              printctl ("beginhex");
+              init_data ();
+            }
+          else if (c == '|')
+            {
+              state = IN_BASE64;
+              printctl ("beginbase64");
+              init_data ();
+            }
+          else if (c == '[')
+            {
+              if (disphint)
+                printerr ("nested display hint");
+              disphint = c;
+            }
+          else if (c == ']')
+            {
+              if (!disphint)
+                printerr ("no open display hint");
+              disphint = 0;
+            }
+          else if (c >= '0' && c <= '9')
+            {
+              if (c == '0')
+                printerr ("zero prefixed length");
+              state = IN_NUMBER;
+              datalen = (c - '0');
+            }
+          else if (strchr (tokenchars, c))
+            {
+              printchr (c);
+              tokenc = c;
+            }
+          else if (whitespace_p (c))
+            ;
+          else if (c == '{')
+            {
+              printerr ("rescanning is not supported");
+            }
+          else if (c == '&' || c == '\\')
+            {
+              printerr ("reserved punctuation detected");
+            }
+          else
+            {
+              printerr ("bad character detected");
+            }
+          break;
+
+        case IN_NUMBER:
+          if (digit_p (c))
+            {
+              unsigned long tmp = datalen * 10 + (c - '0');
+              if (tmp < datalen)
+                {
+                  printerr ("overflow in data length");
+                  state = INIT_STATE;
+                  datalen = 0;
+                }
+              else
+                datalen = tmp;
+            }
+          else if (c == ':')
+            {
+              if (!datalen)
+                {
+                  printerr ("no data length");
+                  state = INIT_STATE;
+                }
+              else
+                state = PRE_DATA;
+            }
+          else if (c == '\"' || c == '#' || c == '|' )
+            {
+              /* We ignore the optional length and divert to the init
+                 state parser code. */
+              goto parse_init_state;
+            }
+          else
+            printerr ("invalid length specification");
+          break;
+
+        case PRE_DATA:
+          state = IN_DATA;
+          printctl ("begindata");
+          init_data ();
+	  /* fall through */
+        case IN_DATA:
+          if (datalen)
+            {
+              push_data (c);
+              datalen--;
+            }
+          if (!datalen)
+            {
+              state = INIT_STATE;
+              printctl ("enddata");
+              flush_data ();
+            }
+          break;
+
+        case IN_STRING:
+          if (c == '\"')
+            {
+              printctl ("endstring");
+              flush_data ();
+              state = INIT_STATE;
+            }
+          else if (c == '\\')
+            state = IN_ESCAPE;
+          else
+            push_data (c);
+          break;
+
+        case IN_ESCAPE:
+          switch (c)
+            {
+            case 'b':  push_data ('\b'); state = IN_STRING; break;
+            case 't':  push_data ('\t'); state = IN_STRING; break;
+            case 'v':  push_data ('\v'); state = IN_STRING; break;
+            case 'n':  push_data ('\n'); state = IN_STRING; break;
+            case 'f':  push_data ('\f'); state = IN_STRING; break;
+            case 'r':  push_data ('\r'); state = IN_STRING; break;
+            case '"':  push_data ('"');  state = IN_STRING; break;
+            case '\'': push_data ('\''); state = IN_STRING; break;
+            case '\\': push_data ('\\'); state = IN_STRING; break;
+
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7':
+              state = IN_OCT_ESC;
+              quote_idx = 0;
+              quote_buf[quote_idx++] = c;
+              break;
+
+            case 'x':
+              state = IN_HEX_ESC;
+              quote_idx = 0;
+              break;
+
+            case '\r':
+              state = CR_ESC;
+              break;
+
+            case '\n':
+              state = LF_ESC;
+              break;
+
+            default:
+              printerr ("invalid escape sequence");
+              state = IN_STRING;
+              break;
+            }
+          break;
+
+        case IN_OCT_ESC:
+          if (quote_idx < 3 && strchr ("01234567", c))
+            {
+              quote_buf[quote_idx++] = c;
+              if (quote_idx == 3)
+                {
+                  push_data ((unsigned int)quote_buf[0] * 8 * 8
+                             + (unsigned int)quote_buf[1] * 8
+                             + (unsigned int)quote_buf[2]);
+                  state = IN_STRING;
+                }
+            }
+          else
+            state = IN_STRING;
+          break;
+        case IN_HEX_ESC:
+          if (quote_idx < 2 && strchr ("0123456789abcdefABCDEF", c))
+            {
+              quote_buf[quote_idx++] = c;
+              if (quote_idx == 2)
+                {
+                  push_data (xtoi_1 (quote_buf[0]) * 16
+                             + xtoi_1 (quote_buf[1]));
+                  state = IN_STRING;
+                }
+            }
+          else
+            state = IN_STRING;
+          break;
+        case CR_ESC:
+          state = IN_STRING;
+          break;
+        case LF_ESC:
+          state = IN_STRING;
+          break;
+
+        case IN_HEXFMT:
+          if (hexdigit_p (c))
+            {
+              push_data (c);
+              hexcount++;
+            }
+          else if (c == '#')
+            {
+              if ((hexcount & 1))
+                printerr ("odd number of hex digits");
+              printctl ("endhex");
+              flush_data ();
+              state = INIT_STATE;
+            }
+          else if (!whitespace_p (c))
+            printerr ("bad hex character");
+          break;
+
+        case IN_BASE64:
+          if (c == '|')
+            {
+              printctl ("endbase64");
+              flush_data ();
+              state = INIT_STATE;
+            }
+          else
+            push_data (c);
+          break;
+
+        default:
+          logit ("invalid state %d detected", state);
+          exit (1);
+        }
+    }
+  flushdatabuffer ();
+  if (ferror (fp))
+    {
+      logit ("error reading input: %s\n", strerror (errno));
+      return -1;
+    }
+  return 0;
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int rc;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+  while (argc && **argv == '-' && (*argv)[1] == '-')
+    {
+      if (!(*argv)[2])
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--version"))
+        print_version (0);
+      else if (!strcmp (*argv, "--help"))
+        print_version (1);
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          argc--; argv++;
+          verbose = 1;
+        }
+      else if (!strcmp (*argv, "--decimal"))
+        {
+          argc--; argv++;
+          decimal = 1;
+        }
+      else if (!strcmp (*argv, "--assume-hex"))
+        {
+          argc--; argv++;
+          assume_hex = 1;
+        }
+      else if (!strcmp (*argv, "--advanced"))
+        {
+          argc--; argv++;
+          advanced = 1;
+        }
+      else
+        print_usage ();
+    }
+
+  if (!argc)
+    {
+      rc = parse_and_print (stdin);
+    }
+  else
+    {
+      rc = 0;
+      for (; argc; argv++, argc--)
+        {
+          FILE *fp = fopen (*argv, "rb");
+          if (!fp)
+            {
+              logit ("can't open `%s': %s\n", *argv, strerror (errno));
+              rc = 1;
+            }
+          else
+            {
+              if (parse_and_print (fp))
+                rc = 1;
+              fclose (fp);
+            }
+        }
+    }
+
+  return !!rc;
+}