Skip to content
Snippets Groups Projects
Select Git revision
  • 93ea0d33532c60d95b6a94e28a946bcc19b1420c
  • master default protected
  • siv-mode
  • delete-des-compat
  • delete-rsa_blind
  • aes-struct-layout
  • master-updates
  • release-3.4-fixes
  • struct-layout
  • attribute-deprecated
  • rename-data-symbols
  • x86_64-sha_ni-sha256
  • ecc-params-tweak
  • delete-old-aes
  • cmac-support
  • x86_64-sha_ni-sha1
  • gcm-ctr-opt
  • ctr-opt
  • skein
  • api-opaque-fix
  • curve448
  • 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
  • converted-master-branch-to-git
  • nettle_2.4_release_20110903
  • nettle_2.3_release_20110902
41 results

cbc.c

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    encode.c 31.04 KiB
    /*\
    ||| This file a part of Pike, and is copyright by Fredrik Hubinette
    ||| Pike is distributed as GPL (General Public License)
    ||| See the files COPYING and DISCLAIMER for more information.
    \*/
    /**/
    #include "global.h"
    #include "stralloc.h"
    #include "pike_macros.h"
    #include "object.h"
    #include "constants.h"
    #include "interpret.h"
    #include "svalue.h"
    #include "mapping.h"
    #include "array.h"
    #include "multiset.h"
    #include "dynamic_buffer.h"
    #include "error.h"
    #include "operators.h"
    #include "builtin_functions.h"
    #include "module_support.h"
    #include "fsort.h"
    #include "threads.h"
    #include "stuff.h"
    #include "version.h"
    
    RCSID("$Id: encode.c,v 1.39 1999/09/22 19:01:27 grubba Exp $");
    
    #ifdef _AIX
    #include <net/nh.h>
    #endif
    
    #ifdef HAVE_NETINET_IN_H
    #include <netinet/in.h>
    #endif
    
    #include <math.h>
    
    #ifdef HAVE_FREXP
    #define FREXP frexp
    #else
    double FREXP(double x, int *exp)
    {
      double ret;
      *exp=(int)ceil(log(fabs(x))/log(2.0));
      ret=(x*pow(2.0,(float)-*exp));
      return ret;
    }
    #endif
    
    #if HAVE_LDEXP
    #define LDEXP ldexp
    #else
    double LDEXP(double x, int exp)
    {
      return x * pow(2.0,(double)exp);
    }
    #endif
    
    #ifdef PIKE_DEBUG
    #define encode_value2 encode_value2_
    #define decode_value2 decode_value2_
    #endif
    
    
    
    struct encode_data
    {
      struct object *codec;
      struct svalue counter;
      struct mapping *encoded;
      dynamic_buffer buf;
    };
    
    static void encode_value2(struct svalue *val, struct encode_data *data);
    
    #define addstr(s, l) low_my_binary_strcat((s), (l), &(data->buf))
    #define addchar(t)   low_my_putchar((t),&(data->buf))
    
    /* Code a pike string */
    
    #if BYTEORDER == 4321
    #define ENCODE_DATA(S) \
       addstr( (S)->str, (S)->len << (S)->size_shift );
    #else
    #define ENCODE_DATA(S) 				\
        switch((S)->size_shift)			\
        {						\
          case 1:					\
            for(q=0;q<(S)->len;q++) {		\
               INT16 s=htons( STR1(S)[q] );		\
               addstr( (char *)&s, sizeof(s));	\
            }					\
            break;					\
          case 2:					\
            for(q=0;q<(S)->len;q++) {		\
               INT32 s=htonl( STR2(S)[q] );		\
               addstr( (char *)&s, sizeof(s));	\
            }					\
            break;					\
        }
    #endif
    
    #define adddata(S) do {					\
      if((S)->size_shift)					\
      {							\
        int q;                                              \
        code_entry(T_STRING,-1, data);			\
        code_entry((S)->size_shift, (S)->len, data);	\
        ENCODE_DATA(S);                                     \
      }else{						\
        code_entry(T_STRING, (S)->len, data);		\
        addstr((char *)((S)->str),(S)->len);		\
      }							\
    }while(0)
    
    /* Like adddata, but allows null pointers */
    
    #define adddata3(S) do {			\
      if(S) {					\
        adddata(S);                                 \
      } else {					\
        code_entry(T_INT, 0, data);			\
      }						\
    }while(0)
    
    #define adddata2(s,l) addstr((char *)(s),(l) * sizeof(s[0]));
    
    /* Current encoding: ik0 */
    #define T_AGAIN 15
    #define T_MASK 15
    #define T_NEG 16
    #define T_SMALL 32
    #define SIZE_SHIFT 6
    #define MAX_SMALL (1<<(8-SIZE_SHIFT))
    #define COUNTER_START -MAX_SMALL
    
    /* Let's cram those bits... */
    static void code_entry(int type, INT32 num, struct encode_data *data)
    {
      int t;
      if(num<0)
      {
        type|=T_NEG;
        num=~num;
      }
    
      if(num < MAX_SMALL)
      {
        type|=T_SMALL | (num << SIZE_SHIFT);
        addchar(type);
        return;
      }else{
        num-=MAX_SMALL;
      }
    
      for(t=0;t<3;t++)
      {
        if(num >= (256 << (t<<3)))
          num-=(256 << (t<<3));
        else
          break;
      }
    
      type|=t << SIZE_SHIFT;
      addchar(type);
    
      switch(t)
      {
      case 3: addchar((num >> 24)&0xff);
      case 2: addchar((num >> 16)&0xff);
      case 1: addchar((num >> 8)&0xff);
      case 0: addchar(num&0xff);
      }
    }
    
    
    static void code_number(INT32 num, struct encode_data *data)
    {
      code_entry(num & 15, num >> 4, data);
    }
    
    #ifdef _REENTRANT
    static void do_enable_threads(void)
    {
      exit_threads_disable(NULL);
    }
    #endif
    
    static int encode_type(char *t, struct encode_data *data)
    {
      char *q=t;
    one_more_type:
      addchar(EXTRACT_UCHAR(t));
      switch(EXTRACT_UCHAR(t++))
      {
        default:
          fatal("error in type string.\n");
          /*NOTREACHED*/
          
          break;
          
        case T_ASSIGN:
          addchar(EXTRACT_UCHAR(t++));
          goto one_more_type;
          
        case T_FUNCTION:
          while(EXTRACT_UCHAR(t)!=T_MANY)
    	t+=encode_type(t, data);
          addchar(EXTRACT_UCHAR(t++));
          
        case T_MAPPING:
        case T_OR:
        case T_AND:
          t+=encode_type(t, data);
          
        case T_ARRAY:
        case T_MULTISET:
        case T_NOT:
          goto one_more_type;
          
        case T_INT:
          {
    	int i;
    	/* FIXME: I assume the type is saved in network byte order. Is it?
    	 *	/grubba 1999-03-07
    	 */
    	for(i = 0; i < (int)(2*sizeof(INT32)); i++) {
    	  addchar(EXTRACT_UCHAR(t++));
    	}
          }
          break;
    
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case T_FLOAT:
        case T_STRING:
        case T_PROGRAM:
        case T_MIXED:
        case T_VOID:
        case T_UNKNOWN:
          break;
          
        case T_OBJECT:
        {
          INT32 x;
          addchar(EXTRACT_UCHAR(t++));
          x=EXTRACT_INT(t);
          t+=sizeof(INT32);
          if(x)
          {
    	struct program *p=id_to_program(x);
    	if(p)
    	{
    	  ref_push_program(p);
    	}else{
    	  push_int(0);
    	}
          }else{
    	push_int(0);
          }
          encode_value2(sp-1, data);
          pop_stack();
          break;
        }
      }
      return t-q;
    }
    
    
    static void encode_value2(struct svalue *val, struct encode_data *data)
    
    #ifdef PIKE_DEBUG
    #undef encode_value2
    #define encode_value2(X,Y) do { struct svalue *_=sp; encode_value2_(X,Y); if(sp!=_) fatal("encode_value2 failed!\n"); } while(0)
    #endif
    
    {
      static struct svalue dested = { T_INT, NUMBER_DESTRUCTED };
      INT32 i;
      struct svalue *tmp;
      
      if((val->type == T_OBJECT || (val->type==T_FUNCTION && \
    				val->subtype!=FUNCTION_BUILTIN)) && !val->u.object->prog)
        val=&dested;
      
      if((tmp=low_mapping_lookup(data->encoded, val)))
      {
        code_entry(T_AGAIN, tmp->u.integer, data);
        return;
      }else{
        mapping_insert(data->encoded, val, &data->counter);
        data->counter.u.integer++;
      }
      
      
      switch(val->type)
      {
        case T_INT:
          code_entry(T_INT, val->u.integer,data);
          break;
          
        case T_STRING:
          adddata(val->u.string);
          break;
          
        case T_FLOAT:
        {
          if(val->u.float_number==0.0)
          {
    	code_entry(T_FLOAT,0,data);
    	code_entry(T_FLOAT,0,data);
          }else{
    	INT32 x;
    	int y;
    	double tmp;
    	
    	tmp=FREXP((double)val->u.float_number, &y);
    	x=(INT32)((1<<30)*tmp);
    	y-=30;
    #if 0
    	while(x && y && !(x&1))
    	{
    	  x>>=1;
    	  y++;
    	}
    #endif
    	code_entry(T_FLOAT,x,data);
    	code_entry(T_FLOAT,y,data);
          }
          break;
        }
        
        case T_ARRAY:
          code_entry(T_ARRAY, val->u.array->size, data);
          for(i=0; i<val->u.array->size; i++)
    	encode_value2(ITEM(val->u.array)+i, data);
          break;
          
        case T_MAPPING:
          check_stack(2);
          ref_push_mapping(val->u.mapping);
          f_indices(1);
          
          ref_push_mapping(val->u.mapping);
          f_values(1);
          
          code_entry(T_MAPPING, sp[-2].u.array->size,data);
          for(i=0; i<sp[-2].u.array->size; i++)
          {
    	encode_value2(ITEM(sp[-2].u.array)+i, data); /* indices */
    	encode_value2(ITEM(sp[-1].u.array)+i, data); /* values */
          }
          pop_n_elems(2);
          break;
          
        case T_MULTISET:
          code_entry(T_MULTISET, val->u.multiset->ind->size,data);
          for(i=0; i<val->u.multiset->ind->size; i++)
    	encode_value2(ITEM(val->u.multiset->ind)+i, data);
          break;
          
        case T_OBJECT:
          check_stack(1);
          push_svalue(val);
          apply(data->codec, "nameof", 1);
          switch(sp[-1].type)
          {
    	case T_INT:
    	  if(sp[-1].subtype == NUMBER_UNDEFINED) 
    	  {
    	    pop_stack();
    	    push_svalue(val);
    	    f_object_program(1);
    	    
    	    code_entry(val->type, 1,data);
    	    encode_value2(sp-1, data);
    	    pop_stack();
    	    
    	    push_svalue(val);
    	    apply(data->codec,"encode_object",1);
    	    break;
    	  }
    	  /* FALL THROUGH */
    	
    	default:
    	  code_entry(val->type, 0,data);
    	  break;
    	  
          }
          encode_value2(sp-1, data);
          pop_stack();
          break;
          
        case T_FUNCTION:
          check_stack(1);
          push_svalue(val);
          apply(data->codec,"nameof", 1);
          if(sp[-1].type == T_INT && sp[-1].subtype==NUMBER_UNDEFINED)
          {
    	if(val->subtype != FUNCTION_BUILTIN)
    	{
    	  int eq;
    	  code_entry(val->type, 1, data);
    	  push_svalue(val);
    	  sp[-1].type=T_OBJECT;
    	  ref_push_string(ID_FROM_INT(val->u.object->prog, val->subtype)->name);
    	  f_arrow(2);
    	  eq=is_eq(sp-1, val);
    	  pop_stack();
    	  if(eq)
    	  {
    	    /* We have to remove ourself from the cache for now */
    	    struct svalue tmp=data->counter;
    	    tmp.u.integer--;
    	    map_delete(data->encoded, val);
    	    
    	    push_svalue(val);
    	    sp[-1].type=T_OBJECT;
    	    encode_value2(sp-1, data);
    	    ref_push_string(ID_FROM_INT(val->u.object->prog, val->subtype)->name);
    	    encode_value2(sp-1, data);
    	    pop_n_elems(3);
    	    
    	    /* Put value back in cache */
    	    mapping_insert(data->encoded, val, &tmp);
    	    return;
    	  }
    	}
          }
    
          code_entry(val->type, 0,data);
          encode_value2(sp-1, data);
          pop_stack();
          break;
          
          
        case T_PROGRAM:
        {
          int d;
          check_stack(1);
          push_svalue(val);
          apply(data->codec,"nameof", 1);
          if(sp[-1].type == val->type)
    	error("Error in master()->nameof(), same type returned.\n");
          if(sp[-1].type == T_INT && sp[-1].subtype == NUMBER_UNDEFINED)
          {
    	INT32 e;
    	struct program *p=val->u.program;
    	if(p->init || p->exit || p->gc_marked || p->gc_check ||
    	   (p->flags & PROGRAM_HAS_C_METHODS))
    	  error("Cannot encode C programs.\n");
    	code_entry(val->type, 1,data);
    	f_version(0);
    	encode_value2(sp-1,data);
    	pop_stack();
    	code_number(p->flags,data);
    	code_number(p->storage_needed,data);
    	code_number(p->alignment_needed,data);
    	code_number(p->timestamp.tv_sec,data);
    	code_number(p->timestamp.tv_usec,data);
    
    #define FOO(X,Y,Z) \
    	code_number( p->num_##Z, data);
    #include "program_areas.h"
    
    	adddata2(p->program, p->num_program);
    	adddata2(p->linenumbers, p->num_linenumbers);
    
    	for(d=0;d<p->num_identifier_index;d++)
    	  code_number(p->identifier_index[d],data);
    
    	for(d=0;d<p->num_variable_index;d++)
    	  code_number(p->variable_index[d],data);
    
    	for(d=0;d<p->num_identifier_references;d++)
    	{
    	  code_number(p->identifier_references[d].inherit_offset,data);
    	  code_number(p->identifier_references[d].identifier_offset,data);
    	  code_number(p->identifier_references[d].id_flags,data);
    	}
    	  
    	for(d=0;d<p->num_strings;d++) adddata(p->strings[d]);
    
    	for(d=0;d<p->num_inherits;d++)
    	{
    	  code_number(p->inherits[d].inherit_level,data);
    	  code_number(p->inherits[d].identifier_level,data);
    	  code_number(p->inherits[d].parent_offset,data);
    	  code_number(p->inherits[d].storage_offset,data);
    
    	  if(p->inherits[d].parent)
    	  {
    	    ref_push_object(p->inherits[d].parent);
    	    sp[-1].subtype=p->inherits[d].parent_identifier;
    	    sp[-1].type=T_FUNCTION;
    	  }else if(p->inherits[d].prog){
    	    ref_push_program(p->inherits[d].prog);
    	  }else{
    	    push_int(0);
    	  }
    	  encode_value2(sp-1,data);
    	  pop_stack();
    
              adddata3(p->inherits[d].name);
    	}
    
    	for(d=0;d<p->num_identifiers;d++)
    	{
    	  adddata(p->identifiers[d].name);
    	  encode_type(p->identifiers[d].type->str, data);
    	  code_number(p->identifiers[d].identifier_flags,data);
    	  code_number(p->identifiers[d].run_time_type,data);
    	  code_number(p->identifiers[d].func.offset,data);
    	}
    
    	for(d=0;d<p->num_constants;d++)
    	{
    	  encode_value2(& p->constants[d].sval, data);
    	  adddata3(p->constants[d].name);
    	}
    
    	for(d=0;d<NUM_LFUNS;d++)
    	  code_number(p->lfuns[d], data);
          }else{
    	code_entry(val->type, 0,data);
    	encode_value2(sp-1, data);
          }
          pop_stack();
          break;
          }
      }
    }
    
    static void free_encode_data(struct encode_data *data)
    {
      toss_buffer(& data->buf);
      free_mapping(data->encoded);
    }
    
    void f_encode_value(INT32 args)
    {
      ONERROR tmp;
      struct encode_data d, *data;
      data=&d;
      
      check_all_args("encode_value", args, BIT_MIXED, BIT_VOID | BIT_OBJECT, 0);
    
      initialize_buf(&data->buf);
      data->encoded=allocate_mapping(128);
      data->counter.type=T_INT;
      data->counter.u.integer=COUNTER_START;
      if(args > 1)
      {
        data->codec=sp[1-args].u.object;
      }else{
        data->codec=get_master();
      }
    
      SET_ONERROR(tmp, free_encode_data, data);
      addstr("\266ke0", 4);
      encode_value2(sp-args, data);
      UNSET_ONERROR(tmp);
    
      free_mapping(data->encoded);
    
      pop_n_elems(args);
      push_string(low_free_buf(&data->buf));
    }
    
    struct decode_data
    {
      unsigned char *data;
      INT32 len;
      INT32 ptr;
      struct mapping *decoded;
      struct svalue counter;
      struct object *codec;
      int pickyness;
    };
    
    static void decode_value2(struct decode_data *data);
    
    static int my_extract_char(struct decode_data *data)
    {
      if(data->ptr >= data->len)
        error("Format error, not enough data in string.\n");
      return data->data [ data->ptr++ ];
    }
    
    #define GETC() my_extract_char(data)
    
    #define DECODE() \
      what=GETC(); \
      e=what>>SIZE_SHIFT; \
      if(what & T_SMALL)  { \
         num=e; \
      } else { \
         num=0; \
         while(e-->=0) num=(num<<8) + (GETC()+1); \
         num+=MAX_SMALL - 1; \
      } \
      if(what & T_NEG) num=~num
    
    
    #define decode_entry(X,Y,Z)					\
      do {								\
        INT32 what, e, num;                                         \
        DECODE();							\
        if((what & T_MASK) != (X)) error("Failed to decode, wrong bits (%d).\n", what & T_MASK);\
        (Y)=num;							\
      } while(0);
    
    #define getdata2(S,L) do {						\
          if(data->ptr + (long)(sizeof(S[0])*(L)) > data->len)		\
    	error("Failed to decode string. (string range error)\n");	\
          MEMCPY((S),(data->data + data->ptr), sizeof(S[0])*(L));		\
          data->ptr+=sizeof(S[0])*(L);					\
      }while(0)
    
    #if BYTEORDER == 4123
    #define BITFLIP(S)
    #else
    #define BITFLIP(S)						\
       switch(what)							\
       {								\
         case 1: for(e=0;e<num;e++) STR1(S)[e]=ntohs(STR1(S)[e]); break;	\
         case 2: for(e=0;e<num;e++) STR2(S)[e]=ntohl(STR2(S)[e]); break;    \
       }
    #endif
    
    #define get_string_data(STR,LEN, data) do {				    \
      if((LEN) == -1)							    \
      {									    \
        INT32 what, e, num;							    \
        DECODE();								    \
        what&=T_MASK;							    \
        if(data->ptr + num > data->len || num <0)				    \
           error("Failed to decode string. (string range error)\n");	    \
        if(what<0 || what>2) error("Failed to decode string. (Illegal size shift)\n"); \
        STR=begin_wide_shared_string(num, what);				    \
        MEMCPY(STR->str, data->data + data->ptr, num << what);		    \
        data->ptr+=(num << what);						    \
        BITFLIP(STR);							    \
        STR=end_shared_string(STR);                                             \
      }else{								    \
        if(data->ptr + (LEN) > data->len || (LEN) <0)			    \
          error("Failed to decode string. (string range error)\n");		    \
        STR=make_shared_binary_string((char *)(data->data + data->ptr), (LEN)); \
        data->ptr+=(LEN);							    \
      }									    \
    }while(0)
    
    #define getdata(X) do {				\
       long length;					\
       decode_entry(T_STRING, length,data);		\
       get_string_data(X, length, data);		\
      }while(0)
    
    #define getdata3(X) do {						     \
      INT32 what, e, num;							     \
      DECODE();								     \
      switch(what & T_MASK)							     \
      {									     \
        case T_INT:								     \
          X=0;								     \
          break;								     \
    									     \
        case T_STRING:							     \
          get_string_data(X,num,data);                                           \
          break;								     \
    									     \
        default:								     \
          error("Failed to decode string, type is wrong: %d\n",what & T_MASK);   \
        }									     \
    }while(0)
    
    #define decode_number(X,data) do {	\
       int what, e, num;				\
       DECODE();					\
       X=(what & T_MASK) | (num<<4);		\
      }while(0)					\
    
    
    static void low_decode_type(struct decode_data *data)
    {
      int tmp;
    one_more_type:
      push_type(tmp=GETC());
      switch(tmp)
      {
        default:
          fatal("error in type string.\n");
          /*NOTREACHED*/
          break;
          
        case T_ASSIGN:
          push_type(GETC());
          goto one_more_type;
          
        case T_FUNCTION:
          while(GETC()!=T_MANY)
          {
    	data->ptr--;
    	low_decode_type(data);
          }
          push_type(T_MANY);
          
        case T_MAPPING:
        case T_OR:
        case T_AND:
          low_decode_type(data);
    
        case T_ARRAY:
        case T_MULTISET:
        case T_NOT:
          goto one_more_type;
    
        case T_INT:
          {
    	int i;
    	/* FIXME: I assume the type is saved in network byte order. Is it?
    	 *	/grubba 1999-03-07
    	 */
    	for(i = 0; i < (int)(2*sizeof(INT32)); i++) {
    	  push_type(GETC());
    	}
          }
          break;
    
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case T_FLOAT:
        case T_STRING:
        case T_PROGRAM:
        case T_MIXED:
        case T_VOID:
        case T_UNKNOWN:
          break;
          
        case T_OBJECT:
        {
          INT32 x;
          push_type(GETC());
          decode_value2(data);
          type_stack_mark();
          switch(sp[-1].type)
          {
    	case T_INT:
    	  push_type_int(0);
    	  break;
    
    	case T_PROGRAM:
    	  push_type_int(sp[-1].u.program->id);
    	  break;
    	  
    	default:
    	  error("Failed to decode type.\n");
          }
          pop_stack();
          type_stack_reverse();
        }
      }
    }
    
    /* This really needs to disable threads.... */
    #define decode_type(X,data)  do {		\
      type_stack_mark();				\
      type_stack_mark();				\
      low_decode_type(data);			\
      type_stack_reverse();				\
      (X)=pop_unfinished_type();			\
    } while(0)
    
    static void decode_value2(struct decode_data *data)
    
    #ifdef PIKE_DEBUG
    #undef decode_value2
    #define decode_value2(X) do { struct svalue *_=sp; decode_value2_(X); if(sp!=_+1) fatal("decode_value2 failed!\n"); } while(0)
    #endif
    
    
    {
      INT32 what, e, num;
      struct svalue tmp, *tmp2;
      
      DECODE();
      
      check_stack(1);
      
      switch(what & T_MASK)
      {
        case T_AGAIN:
          tmp.type=T_INT;
          tmp.subtype=0;
          tmp.u.integer=num;
          if((tmp2=low_mapping_lookup(data->decoded, &tmp)))
          {
    	push_svalue(tmp2);
          }else{
    	error("Failed to decode string. (invalid T_AGAIN)\n");
          }
          return;
          
        case T_INT:
          tmp=data->counter;
          data->counter.u.integer++;
          push_int(num);
          break;
          
        case T_STRING:
        {
          struct pike_string *str;
          tmp=data->counter;
          data->counter.u.integer++;
          get_string_data(str, num, data);
          push_string(str);
          break;
        }
          
        case T_FLOAT:
        {
          INT32 num2=num;
          
          tmp=data->counter;
          data->counter.u.integer++;
          
          DECODE();
          push_float(LDEXP((double)num2, num));
          break;
        }
        
        case T_ARRAY:
        {
          struct array *a;
          if(num < 0)
    	error("Failed to decode string. (array size is negative)\n");
    
          /* Heruetical */
          if(data->ptr + num > data->len)
    	error("Failed to decode array. (not enough data)\n");
    
          tmp.type=T_ARRAY;
          tmp.u.array=a=allocate_array(num);
          mapping_insert(data->decoded, & data->counter, &tmp);
          data->counter.u.integer++;
          
          /* Since a reference to the array is stored in the mapping, we can
           * safely decrease this reference here. Thus it will be automatically
           * freed if something goes wrong.
           */
          a->refs--;
          
          for(e=0;e<num;e++)
          {
    	decode_value2(data);
    	ITEM(a)[e]=sp[-1];
    	sp--;
          }
          ref_push_array(a);
          return;
        }
        
        case T_MAPPING:
        {
          struct mapping *m;
          if(num<0)
    	error("Failed to decode string. (mapping size is negative)\n");
    
          /* Heruetical */
          if(data->ptr + num > data->len)
    	error("Failed to decode mapping. (not enough data)\n");
    
          m=allocate_mapping(num);
          tmp.type=T_MAPPING;
          tmp.u.mapping=m;
          mapping_insert(data->decoded, & data->counter, &tmp);
          data->counter.u.integer++;
          m->refs--;
          
          for(e=0;e<num;e++)
          {
    	decode_value2(data);
    	decode_value2(data);
    	mapping_insert(m, sp-2, sp-1);
    	pop_n_elems(2);
          }
          ref_push_mapping(m);
          return;
        }
        
        case T_MULTISET:
        {
          struct multiset *m;
          if(num<0)
    	error("Failed to decode string. (multiset size is negative)\n");
    
          /* Heruetical */
          if(data->ptr + num > data->len)
    	error("Failed to decode multiset. (not enough data)\n");
    
          m=mkmultiset(low_allocate_array(0, num));
          tmp.type=T_MULTISET;
          tmp.u.multiset=m;
          mapping_insert(data->decoded, & data->counter, &tmp);
          data->counter.u.integer++;
          m->refs--;
          
          for(e=0;e<num;e++)
          {
    	decode_value2(data);
    	multiset_insert(m, sp-1);
    	pop_stack();
          }
          ref_push_multiset(m);
          return;
        }
        
        
        case T_OBJECT:
          tmp=data->counter;
          data->counter.u.integer++;
          decode_value2(data);
          
          switch(num)
          {
    	case 0:
    	  if(data->codec)
    	  {
    	    apply(data->codec,"objectof", 1);
    	  }else{
    	    ref_push_mapping(get_builtin_constants());
    	    stack_swap();
    	    f_index(2);
    	  }
    	  break;
    	  
    	case 1:
    	  if(IS_ZERO(sp-1))
    	  {
    	    mapping_insert(data->decoded, &tmp, sp-1);
    	    decode_value2(data);
    	    pop_stack();
    	  }else{
    	    f_call_function(1);
    	    mapping_insert(data->decoded, &tmp, sp-1);
    	    push_svalue(sp-1);
    	    decode_value2(data);
    	    if(!data->codec)
    	      error("Failed to decode (no codec)\n");
    	    apply(data->codec,"decode_object",2);
    	    pop_stack();
    	  }
    	  if(data->pickyness && sp[-1].type != T_OBJECT)
    	    error("Failed to decode object.\n");
    	  return;
    	  
    	default:
    	  error("Object coding not compatible.\n");
    	  break;
          }
          if(data->pickyness && sp[-1].type != T_OBJECT)
    	error("Failed to decode.\n");
          break;
          
        case T_FUNCTION:
          tmp=data->counter;
          data->counter.u.integer++;
          decode_value2(data);
          
          switch(num)
          {
    	case 0:
    	  if(data->codec)
    	  {
    	    apply(data->codec,"functionof", 1);
    	  }else{
    	    ref_push_mapping(get_builtin_constants());
    	    stack_swap();
    	    f_index(2);
    	  }
    	  break;
    	  
    	case 1:
    	  decode_value2(data);
    	  if(sp[-2].type==T_INT)
    	  {
    	    pop_stack();
    	  }else{
    	    f_arrow(2);
    	  }
    	  break;
    	  
    	default:
    	  error("Function coding not compatible.\n");
    	  break;
          }
          if(data->pickyness && sp[-1].type != T_FUNCTION)
    	error("Failed to decode function.\n");
          break;
          
          
        case T_PROGRAM:
          switch(num)
          {
    	case 0:
    	  tmp=data->counter;
    	  data->counter.u.integer++;
    	  decode_value2(data);
    	  if(data->codec)
    	  {
    	    apply(data->codec,"programof", 1);
    	  }else{
    	    ref_push_mapping(get_builtin_constants());
    	    stack_swap();
    	    f_index(2);
    	  }
    	  if(data->pickyness && sp[-1].type != T_PROGRAM)
    	    error("Failed to decode program.\n");
    	  break;
    
    	case 1:
    	{
    	  int d;
    	  SIZE_T size=0;
    	  char *dat;
    	  struct program *p;
    
    #ifdef _REENTRANT
    	  ONERROR err;
    	  low_init_threads_disable();
    	  SET_ONERROR(err, do_enable_threads, 0);
    #endif
    
    	  p=low_allocate_program();
    	  debug_malloc_touch(p);
    	  tmp.type=T_PROGRAM;
    	  tmp.u.program=p;
    	  mapping_insert(data->decoded, & data->counter, &tmp);
    	  data->counter.u.integer++;
    	  p->refs--;
    	  
    	  decode_value2(data);
    	  f_version(0);
    	  if(!is_eq(sp-1,sp-2))
    	    error("Cannot decode programs encoded with other driver version.\n");
    	  pop_n_elems(2);
    
    	  decode_number(p->flags,data);
    	  p->flags &= ~(PROGRAM_FINISHED | PROGRAM_OPTIMIZED);
    	  decode_number(p->storage_needed,data);
    	  decode_number(p->alignment_needed,data);
    	  decode_number(p->timestamp.tv_sec,data);
    	  decode_number(p->timestamp.tv_usec,data);
    
    #define FOO(X,Y,Z) \
    	  decode_number( p->num_##Z, data);
    #include "program_areas.h"
    	  
    #define FOO(NUMTYPE,TYPE,NAME) \
              size=DO_ALIGN(size, ALIGNOF(TYPE)); \
              size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]);
    #include "program_areas.h"
    
    	  dat=xalloc(size);
    	  debug_malloc_touch(dat);
    	  MEMSET(dat,0,size);
    	  size=0;
    #define FOO(NUMTYPE,TYPE,NAME) \
    	  size=DO_ALIGN(size, ALIGNOF(TYPE)); \
              p->NAME=(TYPE *)(dat+size); \
              size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]);
    #include "program_areas.h"
    
    	  for(e=0;e<p->num_constants;e++)
    	    p->constants[e].sval.type=T_INT;
    
    	  debug_malloc_touch(dat);
    
    	  p->total_size=size + sizeof(struct program);
    
    	  p->flags |= PROGRAM_OPTIMIZED;
    
    	  getdata2(p->program, p->num_program);
    	  getdata2(p->linenumbers, p->num_linenumbers);
    
    	  for(d=0;d<p->num_identifier_index;d++)
    	  {
    	    decode_number(p->identifier_index[d],data);
    	    if(p->identifier_index[d] > p->num_identifier_references)
    	    {
    	      p->identifier_index[d]=0;
    	      error("Malformed program in decode.\n");
    	    }
    	  }
    	  
    	  for(d=0;d<p->num_variable_index;d++)
    	  {
    	    decode_number(p->variable_index[d],data);
    	    if(p->variable_index[d] > p->num_identifiers)
    	    {
    	      p->variable_index[d]=0;
    	      error("Malformed program in decode.\n");
    	    }
    	  }
    	  
    	  for(d=0;d<p->num_identifier_references;d++)
    	  {
    	    decode_number(p->identifier_references[d].inherit_offset,data);
    	    if(p->identifier_references[d].inherit_offset > p->num_inherits)
    	    {
    	      p->identifier_references[d].inherit_offset=0;
    	      error("Malformed program in decode.\n");
    	    }
    	    decode_number(p->identifier_references[d].identifier_offset,data);
    	    decode_number(p->identifier_references[d].id_flags,data);
    	  }
    	  
    	  for(d=0;d<p->num_strings;d++)
    	    getdata(p->strings[d]);
    
    	  debug_malloc_touch(dat);
    
    	  data->pickyness++;
    
    	     
    /*	  p->inherits[0].prog=p;
    	  p->inherits[0].parent_offset=1;
    */
    
    	  for(d=0;d<p->num_inherits;d++)
    	  {
    	    decode_number(p->inherits[d].inherit_level,data);
    	    decode_number(p->inherits[d].identifier_level,data);
    	    decode_number(p->inherits[d].parent_offset,data);
    	    decode_number(p->inherits[d].storage_offset,data);
    	    
    	    decode_value2(data);
    	    if(d==0)
    	    {
    	      if(sp[-1].type != T_PROGRAM ||
    		 sp[-1].u.program != p)
    		error("Program decode failed!\n");
    	      p->refs--;
    	    }
    	      
    	    switch(sp[-1].type)
    	    {
    	      case T_FUNCTION:
    		if(sp[-1].subtype == FUNCTION_BUILTIN)
    		  error("Failed to decode parent.\n");
    		
    		p->inherits[d].parent_identifier=sp[-1].subtype;
    		p->inherits[d].prog=program_from_svalue(sp-1);
    		if(!p->inherits[d].prog)
    		  error("Failed to decode parent.\n");
    		add_ref(p->inherits[d].prog);
    		p->inherits[d].parent=sp[-1].u.object;
    		sp--;
    		break;
    
    	      case T_PROGRAM:
    		p->inherits[d].parent_identifier=0;
    		p->inherits[d].prog=sp[-1].u.program;
    		sp--;
    		break;
    	      default:
    		error("Failed to decode inheritance.\n");
    	    }
    	    
    	    getdata3(p->inherits[d].name);
    	  }
    	  
    	  debug_malloc_touch(dat);
    
    	  for(d=0;d<p->num_identifiers;d++)
    	  {
    	    getdata(p->identifiers[d].name);
    	    decode_type(p->identifiers[d].type,data);
    	    decode_number(p->identifiers[d].identifier_flags,data);
    	    decode_number(p->identifiers[d].run_time_type,data);
    	    decode_number(p->identifiers[d].func.offset,data);
    	  }
    
    	  debug_malloc_touch(dat);
    	  
    	  for(d=0;d<p->num_constants;d++)
    	  {
    	    decode_value2(data);
    	    p->constants[d].sval=*--sp;
    	    getdata3(p->constants[d].name);
    	  }
    	  data->pickyness--;
    
    	  debug_malloc_touch(dat);
    
    	  for(d=0;d<NUM_LFUNS;d++)
    	    decode_number(p->lfuns[d],data);
    
    	  debug_malloc_touch(dat);
    	  
    	  {
    	    struct program *new_program_save=new_program;
    	    new_program=p;
    	    fsort((void *)p->identifier_index,
    		  p->num_identifier_index,
    		  sizeof(unsigned short),(fsortfun)program_function_index_compare);
    	    new_program=new_program_save;
    	  }
    	  p->flags |= PROGRAM_FINISHED;
    	  ref_push_program(p);
    
    #ifdef _REENTRANT
    	  UNSET_ONERROR(err);
    	  exit_threads_disable(NULL);
    #endif
    	  return;
    	}
    
    	default:
    	  error("Cannot decode program encoding type %d\n",num);
          }
          break;
    
      default:
        error("Failed to restore string. (Illegal type)\n");
      }
    
      mapping_insert(data->decoded, & tmp, sp-1);
    }
    
    
    static void free_decode_data(struct decode_data *data)
    {
      free_mapping(data->decoded);
    }
    
    static INT32 my_decode(struct pike_string *tmp,
    		       struct object *codec)
    {
      ONERROR err;
      struct decode_data d, *data;
      data=&d;
      data->counter.type=T_INT;
      data->counter.u.integer=COUNTER_START;
      data->data=(unsigned char *)tmp->str;
      data->len=tmp->len;
      data->ptr=0;
      data->codec=codec;
      data->pickyness=0;
    
      if (tmp->size_shift) return 0;
      if(data->len < 5) return 0;
      if(GETC() != 182 ||
         GETC() != 'k' ||
         GETC() != 'e' ||
         GETC() != '0')
        return 0;
    
      data->decoded=allocate_mapping(128);
    
      SET_ONERROR(err, free_decode_data, data);
      decode_value2(data);
      UNSET_ONERROR(err);
      free_mapping(data->decoded);
      return 1;
    }
    
    /* Compatibilidy decoder */
    
    static unsigned char extract_char(char **v, INT32 *l)
    {
      if(!*l) error("Format error, not enough place for char.\n");
      else (*l)--;
      (*v)++;
      return ((unsigned char *)(*v))[-1];
    }
    
    static INT32 extract_int(char **v, INT32 *l)
    {
      INT32 j,i;
    
      j=extract_char(v,l);
      if(j & 0x80) return (j & 0x7f);
    
      if((j & ~8) > 4)
        error("Format Error: Error in format string, invalid integer.\n");
      i=0;
      while(j & 7) { i=(i<<8) | extract_char(v,l); j--; }
      if(j & 8) return -i;
      return i;
    }
    
    static void rec_restore_value(char **v, INT32 *l)
    {
      INT32 t,i;
    
      i=extract_int(v,l);
      t=extract_int(v,l);
      switch(i)
      {
      case T_INT: push_int(t); return;
        
      case T_FLOAT:
        if(sizeof(INT32) < sizeof(float))  /* FIXME FIXME FIXME FIXME */
          error("Float architecture not supported.\n"); 
        push_int(t); /* WARNING! */
        sp[-1].type = T_FLOAT;
        return;
        
      case T_STRING:
        if(t<0) error("Format error, length of string is negative.\n");
        if(*l < t) error("Format error, string to short\n");
        push_string(make_shared_binary_string(*v, t));
        (*l)-= t; (*v)+= t;
        return;
        
      case T_ARRAY:
        if(t<0) error("Format error, length of array is negative.\n");
        check_stack(t);
        for(i=0;i<t;i++) rec_restore_value(v,l);
        f_aggregate(t);
        return;
    
      case T_MULTISET:
        if(t<0) error("Format error, length of multiset is negative.\n");
        check_stack(t);
        for(i=0;i<t;i++) rec_restore_value(v,l);
        f_aggregate_multiset(t);
        return;
        
      case T_MAPPING:
        if(t<0) error("Format error, length of mapping is negative.\n");
        check_stack(t*2);
        for(i=0;i<t;i++)
        {
          rec_restore_value(v,l);
          rec_restore_value(v,l);
        }
        f_aggregate_mapping(t*2);
        return;
    
      case T_OBJECT:
        if(t<0) error("Format error, length of object is negative.\n");
        if(*l < t) error("Format error, string to short\n");
        push_string(make_shared_binary_string(*v, t));
        (*l) -= t; (*v) += t;
        APPLY_MASTER("objectof", 1);
        return;
        
      case T_FUNCTION:
        if(t<0) error("Format error, length of function is negative.\n");
        if(*l < t) error("Format error, string to short\n");
        push_string(make_shared_binary_string(*v, t));
        (*l) -= t; (*v) += t;
        APPLY_MASTER("functionof", 1);
        return;
         
      case T_PROGRAM:
        if(t<0) error("Format error, length of program is negative.\n");
        if(*l < t) error("Format error, string to short\n");
        push_string(make_shared_binary_string(*v, t));
        (*l) -= t; (*v) += t;
        APPLY_MASTER("programof", 1);
        return;
        
      default:
        error("Format error. Unknown type\n");
      }
    }
    
    void f_decode_value(INT32 args)
    {
      struct pike_string *s;
      struct object *codec;
    
      check_all_args("decode_value", args,
    		 BIT_STRING, BIT_VOID | BIT_OBJECT | BIT_INT, 0);
    
      s = sp[-args].u.string;
      if(args<2)
      {
        codec=get_master();
      }
      else if(sp[1-args].type == T_OBJECT)
      {
        codec=sp[1-args].u.object;
      }
      else
      {
        codec=0;
      }
    
      if(!my_decode(s, codec))
      {
        char *v=s->str;
        INT32 l=s->len;
        rec_restore_value(&v, &l);
      }
      assign_svalue(sp-args-1, sp-1);
      pop_n_elems(args);
    }