Skip to content
Snippets Groups Projects
Select Git revision
  • cfd07ba9c54cc099a3e5da30376cf297f4151e31
  • master default protected
  • streebog
  • gost28147
  • master-updates
  • ed448
  • shake256
  • curve448
  • ecc-sqrt
  • gosthash94cp
  • cmac64
  • block16-refactor
  • siv-mode
  • cmac-layout
  • delete-des-compat
  • delete-rsa_blind
  • aes-struct-layout
  • release-3.4-fixes
  • struct-layout
  • attribute-deprecated
  • rename-data-symbols
  • nettle_3.5.1_release_20190627
  • nettle_3.5_release_20190626
  • nettle_3.5rc1
  • nettle_3.4.1_release_20181204
  • nettle_3.4.1rc1
  • nettle_3.4_release_20171119
  • nettle_3.4rc2
  • nettle_3.4rc1
  • nettle_3.3_release_20161001
  • nettle_3.2_release_20160128
  • nettle_3.1.1_release_20150424
  • nettle_3.1_release_20150407
  • nettle_3.1rc3
  • nettle_3.1rc2
  • nettle_3.1rc1
  • nettle_3.0_release_20140607
  • nettle_2.7.1_release_20130528
  • nettle_2.7_release_20130424
  • nettle_2.6_release_20130116
  • nettle_2.5_release_20120707
41 results

input.c

Blame
  • Forked from Nettle / nettle
    1200 commits behind the upstream repository.
    input.c 9.00 KiB
    /* input.c
    
       Copyright (C) 2002, 2003, 2008 Niels Möller
    
       This file is part of GNU Nettle.
    
       GNU Nettle 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.
    
       GNU Nettle 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 copies of the GNU General Public License and
       the GNU Lesser General Public License along with this program.  If
       not, see http://www.gnu.org/licenses/.
    */
    
    #if HAVE_CONFIG_H
    # include "config.h"
    #endif
    
    #include <assert.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include "input.h"
    
    void
    sexp_input_init(struct sexp_input *input, FILE *f)
    {
      input->f = f;
      input->coding = NULL;
    }
    
    static void
    sexp_get_raw_char(struct sexp_input *input)
    {
      int c = getc(input->f);
      
      if (c < 0)
        {
          if (ferror(input->f))
    	die("Read error: %s\n", strerror(errno));
          
          input->ctype = SEXP_EOF_CHAR;
        }
      else
        {
          input->ctype = SEXP_NORMAL_CHAR;
          input->c = c;
        }
    }
    
    void
    sexp_get_char(struct sexp_input *input)
    {
      if (input->coding)
        for (;;)
          {
    	size_t done;
    
    	sexp_get_raw_char(input);
    	if (input->ctype == SEXP_EOF_CHAR)
    	  die("Unexpected end of file in coded data.\n");
    
    	if (input->c == input->terminator)
    	  {
    	    input->ctype = SEXP_END_CHAR;
    	    return;
    	  }
    
    	done = 1;
    
    	/* Decodes in place. Should always work, when we decode one
    	 * character at a time. */
    	if (!input->coding->decode_update(&input->state,
    					  &done, &input->c,
    					  1, (const char*) &input->c))
    	  die("Invalid coded data.\n");
    	
    	if (done)
    	  return;
          }
      else
        sexp_get_raw_char(input);
    }
    
    static uint8_t
    sexp_next_char(struct sexp_input *input)
    {
      sexp_get_char(input);
      if (input->ctype != SEXP_NORMAL_CHAR)
        die("Unexpected end of file.\n");
    
      return input->c;
    }
    
    static void
    sexp_push_char(struct sexp_input *input,
    	       struct nettle_buffer *string)
    {
      assert(input->ctype == SEXP_NORMAL_CHAR);
        
      if (!NETTLE_BUFFER_PUTC(string, input->c))
        die("Virtual memory exhasuted.\n");
    }
    
    static void
    sexp_input_start_coding(struct sexp_input *input,
    			const struct nettle_armor *coding,
    			uint8_t terminator)
    {
      assert(!input->coding);
      
      input->coding = coding;
      input->coding->decode_init(&input->state);
      input->terminator = terminator;
    }
    
    static void
    sexp_input_end_coding(struct sexp_input *input)
    {
      assert(input->coding);
    
      if (!input->coding->decode_final(&input->state))
        die("Invalid coded data.\n");
      
      input->coding = NULL;
    }
    
    
    /* Return 0 at end-of-string */
    static int
    sexp_get_quoted_char(struct sexp_input *input)
    {
      sexp_next_char(input);
    
      switch (input->c)
        {
        default:
          return 1;
        case '\"':
          return 0;
        case '\\':
          sexp_next_char(input);
    	
          switch (input->c)
    	{
    	case 'b': input->c = '\b'; return 1;
    	case 't': input->c = '\t'; return 1;
    	case 'n': input->c = '\n'; return 1;
    	case 'f': input->c = '\f'; return 1;
    	case 'r': input->c = '\r'; return 1;
    	case '\\': input->c = '\\'; return 1;
    	case 'o':
    	case 'x':
    	  /* FIXME: Not implemnted */
    	  abort();
    	case '\n':
    	  if (sexp_next_char(input) == '\r')
    	    sexp_next_char(input);
    
    	  break;
    	case '\r':
    	  if (sexp_next_char(input) == '\n')
    	    sexp_next_char(input);
    
    	  break;
    	}
          return 1;
        }
    }
    
    static void
    sexp_get_token_string(struct sexp_input *input,
    		      struct nettle_buffer *string)
    {
      assert(!input->coding);
      assert(input->ctype == SEXP_NORMAL_CHAR);
      
      if (!TOKEN_CHAR(input->c))
        die("Invalid token.\n");
    
      do
        {
          sexp_push_char(input, string);
          sexp_get_char(input);
        }
      while (input->ctype == SEXP_NORMAL_CHAR && TOKEN_CHAR(input->c));
      
      assert (string->size);
    }
    
    static void
    sexp_get_string(struct sexp_input *input,
    		struct nettle_buffer *string)
    {
      nettle_buffer_reset(string);
      input->token = SEXP_STRING;
      
      switch (input->c)
        {
        case '\"':
          while (sexp_get_quoted_char(input))
    	sexp_push_char(input, string);
          
          sexp_get_char(input);
          break;
          
        case '#':
          sexp_input_start_coding(input, &nettle_base16, '#');
          goto decode;
    
        case '|':
          sexp_input_start_coding(input, &nettle_base64, '|');
    
        decode:
          for (;;)
    	{
    	  sexp_get_char(input);
    	  switch (input->ctype)
    	    {
    	    case SEXP_NORMAL_CHAR:
    	      sexp_push_char(input, string);
    	      break;
    	    case SEXP_EOF_CHAR:
    	      die("Unexpected end of file in coded string.\n");
    	    case SEXP_END_CHAR:
    	      sexp_input_end_coding(input);
    	      sexp_get_char(input);
    	      return;
    	    }
    	}
    
          break;
    
        default:
          sexp_get_token_string(input, string);
          break;
        }
    }
    
    static void
    sexp_get_string_length(struct sexp_input *input, enum sexp_mode mode,
    		       struct nettle_buffer *string)
    {
      unsigned length;
    
      nettle_buffer_reset(string);
      input->token = SEXP_STRING;
      
      length = input->c - '0';
      
      if (!length)
        /* There must be no more digits */
        sexp_next_char(input);
    
      else
        {
          assert(length < 10);
          /* Get rest of digits */
          for (;;)
    	{
    	  sexp_next_char(input);
    	  
    	  if (input->c < '0' || input->c > '9')
    	    break;
    	  
    	  /* FIXME: Check for overflow? */
    	  length = length * 10 + input->c - '0';
    	}
        }
    
      if (input->c == ':')
        /* Verbatim */
        for (; length; length--)
          {
    	sexp_next_char(input);
    	sexp_push_char(input, string);
          }
    
      else if (mode != SEXP_ADVANCED)
        die("Encountered advanced string in canonical mode.\n");
    
      else
        switch(input->c)
          {
          case '"':
    	for (; length; length--)
    	  if (sexp_get_quoted_char(input))
    	    sexp_push_char(input, string);
    	  else
    	    die("Unexpected end of string.\n");
          
    	if (sexp_get_quoted_char(input))
    	  die("Quoted string longer than expected.\n");
    
    	break;
          
          case '#':
    	sexp_input_start_coding(input, &nettle_base16, '#');
    	goto decode;
    
          case '|':
    	sexp_input_start_coding(input, &nettle_base64, '|');
    
          decode:
    	for (; length; length--)
    	  {
    	    sexp_next_char(input);
    	    sexp_push_char(input, string);
    	  }
    	sexp_get_char(input);
    	if (input->ctype != SEXP_END_CHAR)
    	  die("Coded string too long.\n");
    
    	sexp_input_end_coding(input);
          
    	break;
          
          default:
    	die("Invalid string.\n");
          }
    
      /* Skip the ending character. */
      sexp_get_char(input);  
    }
    
    static void
    sexp_get_comment(struct sexp_input *input, struct nettle_buffer *string)
    {
      nettle_buffer_reset(string);
    
      assert(input->ctype == SEXP_NORMAL_CHAR);
      assert(input->c == ';');
    
      do
        {
          sexp_push_char(input, string);
          sexp_get_raw_char(input);
        }
      while (input->ctype == SEXP_NORMAL_CHAR && input->c != '\n');
    
      input->token = SEXP_COMMENT;
    }
    
    /* When called, input->c should be the first character of the current
     * token.
     *
     * When returning, input->c should be the first character of the next
     * token. */
    void
    sexp_get_token(struct sexp_input *input, enum sexp_mode mode,
    	       struct nettle_buffer *string)
    {
      for(;;)
        switch(input->ctype)
          {
          case SEXP_EOF_CHAR:
    	input->token = SEXP_EOF;
    	return;
    
          case SEXP_END_CHAR:
    	input->token = SEXP_CODING_END;
    	sexp_input_end_coding(input);
    	sexp_get_char(input);
    	return;
    
          case SEXP_NORMAL_CHAR:
    	switch(input->c)
    	  {
    	  case '0': case '1': case '2': case '3': case '4':
    	  case '5': case '6': case '7': case '8': case '9':
    	    sexp_get_string_length(input, mode, string);
    	    return;
    	  
    	  case '(':
    	    input->token = SEXP_LIST_START;
    	    sexp_get_char(input);
    	    return;
    	  
    	  case ')':
    	    input->token = SEXP_LIST_END;
    	    sexp_get_char(input);
    	    return;
    
    	  case '[':
    	    input->token = SEXP_DISPLAY_START;
    	    sexp_get_char(input);
    	    return;
    
    	  case ']':
    	    input->token = SEXP_DISPLAY_END;
    	    sexp_get_char(input);
    	    return;
    
    	  case '{':
    	    if (mode == SEXP_CANONICAL)
    	      die("Unexpected transport data in canonical mode.\n");
    	    
    	    sexp_input_start_coding(input, &nettle_base64, '}');
    	    sexp_get_char(input);
    
    	    input->token = SEXP_TRANSPORT_START;
    	    
    	    return;
    	  
    	  case ' ':  /* SPC, TAB, LF, CR */
    	  case '\t':
    	  case '\n':
    	  case '\r':
    	    if (mode == SEXP_CANONICAL)
    	      die("Whitespace encountered in canonical mode.\n");
    
    	    sexp_get_char(input);
    	    break;
    
    	  case ';': /* Comments */
    	    if (mode == SEXP_CANONICAL)
    	      die("Comment encountered in canonical mode.\n");
    
    	    sexp_get_comment(input, string);
    	    return;
    	  
    	  default:
    	    /* Ought to be a string */
    	    if (mode != SEXP_ADVANCED)
    	      die("Encountered advanced string in canonical mode.\n");
    
    	    sexp_get_string(input, string);
    	    return;
    	  }
          }
    }