common: Change license of mbox-util to LGPLv2.1+.
[gnupg.git] / common / b64dec.c
index 3e02e4a..c84c35a 100644 (file)
@@ -1,29 +1,20 @@
 /* b64dec.c - Simple Base64 decoder.
  * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * This file is free software; you can redistribute it and/or modify
- * it under the terms of either
- *
- *   - the GNU Lesser General Public License as published by the Free
- *     Software Foundation; either version 3 of the License, or (at
- *     your option) any later version.
- *
- * or
- *
- *   - the GNU General Public License as published by the Free
- *     Software Foundation; either version 2 of the License, or (at
- *     your option) any later version.
- *
- * or both in parallel, as here.
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
  * This file 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
+ * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
@@ -61,7 +52,7 @@ static unsigned char const asctobin[128] =
 
 enum decoder_states
   {
-    s_init, s_idle, s_lfseen, s_begin,
+    s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
     s_b64_0, s_b64_1, s_b64_2, s_b64_3,
     s_waitendtitle, s_waitend
   };
@@ -71,26 +62,18 @@ enum decoder_states
 /* Initialize the context for the base64 decoder.  If TITLE is NULL a
    plain base64 decoding is done.  If it is the empty string the
    decoder will skip everything until a "-----BEGIN " line has been
-   seen, decoding ends at a "----END " line.
-
-   Not yet implemented: If TITLE is either "PGP" or begins with "PGP "
-   the PGP armor lines are skipped as well.  */
+   seen, decoding ends at a "----END " line.  */
 gpg_error_t
 b64dec_start (struct b64state *state, const char *title)
 {
   memset (state, 0, sizeof *state);
   if (title)
     {
-      if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
-        state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+      state->title = xtrystrdup (title);
+      if (!state->title)
+        state->lasterr = gpg_error_from_syserror ();
       else
-        {
-          state->title = xtrystrdup (title);
-          if (!state->title)
-            state->lasterr = gpg_error_from_syserror ();
-          else
-            state->idx = s_init;
-        }
+        state->idx = s_init;
     }
   else
     state->idx = s_b64_0;
@@ -123,6 +106,7 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
 
   for (s=d=buffer; length && !state->stop_seen; length--, s++)
     {
+    again:
       switch (ds)
         {
         case s_idle:
@@ -136,12 +120,42 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
           ds = s_lfseen;
         case s_lfseen:
           if (*s != "-----BEGIN "[pos])
-            ds = s_idle;
+            {
+              ds = s_idle;
+              goto again;
+            }
           else if (pos == 10)
-            ds = s_begin;
+            {
+              pos = 0;
+              ds = s_beginseen;
+            }
+          else
+            pos++;
+          break;
+        case s_beginseen:
+          if (*s != "PGP "[pos])
+            ds = s_begin; /* Not a PGP armor.  */
+          else if (pos == 3)
+            ds = s_waitheader;
           else
             pos++;
           break;
+        case s_waitheader:
+          if (*s == '\n')
+            ds = s_waitblank;
+          break;
+        case s_waitblank:
+          if (*s == '\n')
+            ds = s_b64_0; /* blank line found.  */
+          else if (*s == ' ' || *s == '\r' || *s == '\t')
+            ; /* Ignore spaces. */
+          else
+            {
+              /* Armor header line.  Note that we don't care that our
+               * FSM accepts a header prefixed with spaces.  */
+              ds = s_waitheader; /* Wait for next header.  */
+            }
+          break;
         case s_begin:
           if (*s == '\n')
             ds = s_b64_0;
@@ -229,10 +243,11 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
 gpg_error_t
 b64dec_finish (struct b64state *state)
 {
+  xfree (state->title);
+  state->title = NULL;
+
   if (state->lasterr)
     return state->lasterr;
 
-  xfree (state->title);
-  state->title = NULL;
   return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
 }