erl_marshal.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,923 行 · 第 1/4 页

C
1,923
字号
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//* * Purpose: Decoding and encoding Erlang terms. */  #include "eidef.h"#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <sys/types.h>#include <string.h>#include "erl_interface.h"#include "erl_marshal.h"#include "erl_eterm.h"#include "erl_malloc.h"#include "erl_error.h"#include "erl_internal.h"#include "eiext.h" /* replaces external.h */#include "putget.h"static int is_string(ETERM* term);#if defined(VXWORKS) && CPU == PPC860int erl_fp_compare(unsigned *a, unsigned *b);static void erl_long_to_fp(long l, unsigned *d);#endif/* Used when comparing two encoded byte arrays *//* this global data is ok (from threading point of view) since it is * initialized once and never changed */#define CMP_ARRAY_SIZE 256/* FIXME problem for threaded ? */static char cmp_array[CMP_ARRAY_SIZE]; static int init_cmp_array_p=1; /* initialize array, the first time */#if defined(VXWORKS) && CPU == PPC860#include <limits.h>#endif#if defined(__GNUC__)#  define INLINE __inline__#elif defined(__WIN32__)#  define INLINE __inline#else#  define INLINE#endifstatic int cmp_floats(double f1, double f2);static INLINE double to_float(long l);#define ERL_NUM_CMP 1#define ERL_REF_CMP 3#define IS_ERL_NUM(t) (cmp_array[t]==ERL_NUM_CMP)#define CMP_NUM_CLASS_SIZE 256static unsigned char cmp_num_class[CMP_NUM_CLASS_SIZE]; static int init_cmp_num_class_p=1; /* initialize array, the first time */#define MK_CMP_NUM_CODE(x,y)    (((x)<<2)|(y))#define CMP_NUM_CLASS(x)        (cmp_num_class[x] & 0x03)#define CMP_NUM_CODE(x,y)       (MK_CMP_NUM_CODE(CMP_NUM_CLASS(x),CMP_NUM_CLASS(y)))#define SMALL 1#define FLOAT 2#define BIG   3#define SMALL_SMALL    MK_CMP_NUM_CODE(SMALL,SMALL)#define SMALL_FLOAT    MK_CMP_NUM_CODE(SMALL,FLOAT)#define SMALL_BIG      MK_CMP_NUM_CODE(SMALL,BIG)#define FLOAT_SMALL    MK_CMP_NUM_CODE(FLOAT,SMALL)#define FLOAT_FLOAT    MK_CMP_NUM_CODE(FLOAT,FLOAT)#define FLOAT_BIG      MK_CMP_NUM_CODE(FLOAT,BIG)#define BIG_SMALL      MK_CMP_NUM_CODE(BIG,SMALL)#define BIG_FLOAT      MK_CMP_NUM_CODE(BIG,FLOAT)#define BIG_BIG        MK_CMP_NUM_CODE(BIG,BIG)void erl_init_marshal(void){  if (init_cmp_array_p) {    memset(cmp_array, 0, CMP_ARRAY_SIZE);    cmp_array[ERL_SMALL_INTEGER_EXT] = 1;    cmp_array[ERL_INTEGER_EXT]       = 1;    cmp_array[ERL_FLOAT_EXT]         = 1;    cmp_array[ERL_SMALL_BIG_EXT]     = 1;    cmp_array[ERL_LARGE_BIG_EXT]     = 1;    cmp_array[ERL_ATOM_EXT]          = 2;    cmp_array[ERL_REFERENCE_EXT]     = 3;    cmp_array[ERL_NEW_REFERENCE_EXT] = 3;    cmp_array[ERL_FUN_EXT]           = 4;    cmp_array[ERL_NEW_FUN_EXT]       = 4;    cmp_array[ERL_PORT_EXT]          = 5;    cmp_array[ERL_PID_EXT]           = 6;    cmp_array[ERL_SMALL_TUPLE_EXT]   = 7;    cmp_array[ERL_LARGE_TUPLE_EXT]   = 7;    cmp_array[ERL_NIL_EXT]           = 8;    cmp_array[ERL_STRING_EXT]        = 9;    cmp_array[ERL_LIST_EXT]          = 9;    cmp_array[ERL_BINARY_EXT]        = 10;    init_cmp_array_p = 0;  }  if (init_cmp_num_class_p) {    memset(cmp_num_class, 0, CMP_NUM_CLASS_SIZE);    cmp_num_class[ERL_SMALL_INTEGER_EXT] = SMALL;    cmp_num_class[ERL_INTEGER_EXT]       = SMALL;    cmp_num_class[ERL_FLOAT_EXT]         = FLOAT;    cmp_num_class[ERL_SMALL_BIG_EXT]     = BIG;    cmp_num_class[ERL_LARGE_BIG_EXT]     = BIG;    init_cmp_num_class_p = 0;  }}/*============================================================== * Marshalling routines. *============================================================== *//*  * The actual ENCODE engine. * Returns 0 on success, otherwise 1. */int erl_encode_it(ETERM *ep, unsigned char **ext, int dist){    int i;    unsigned int u;        switch(ERL_TYPE(ep))     {    case ERL_ATOM:	i =  ep->uval.aval.len;	*(*ext)++ = ERL_ATOM_EXT;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	memcpy((void *) *ext, (const void *) ep->uval.aval.a, i);	*ext += i;	return 0;    case ERL_INTEGER:	i = ep->uval.ival.i;	/* ERL_SMALL_BIG */	if ((i > ERL_MAX) || (i < ERL_MIN)) { 	    *(*ext)++ = ERL_SMALL_BIG_EXT;	    *(*ext)++ = 4;		/* four bytes */	    if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte  */ 	      i = -i;	    *(*ext)++ = i  & 0xff;	/* LSB first  */	    *(*ext)++ = (i >> 8) & 0xff;	    *(*ext)++ = (i >> 16) & 0xff;	    *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */	    return 0;	} 	/* SMALL_INTEGER */	if ((i < 256) && (i >= 0)) {	    *(*ext)++ = ERL_SMALL_INTEGER_EXT;	    *(*ext)++ = i & 0xff;	    return 0;	}	/* INTEGER */	*(*ext)++ = ERL_INTEGER_EXT;	*(*ext)++ = (i >> 24) & 0xff;	*(*ext)++ = (i >> 16) & 0xff;	*(*ext)++ = (i >> 8) & 0xff;	*(*ext)++ = i  & 0xff;	return 0;    case ERL_U_INTEGER:	u = ep->uval.uival.u;	/* ERL_U_SMALL_BIG */	if (u > ERL_MAX) {	*(*ext)++ = ERL_SMALL_BIG_EXT;	*(*ext)++ = 4;		/* four bytes */	*(*ext)++ = 0;		/* sign byte  */ 	*(*ext)++ = u  & 0xff;	/* LSB first  */	*(*ext)++ = (u >> 8) & 0xff;	*(*ext)++ = (u >> 16) & 0xff;	*(*ext)++ = (u >> 24) & 0xff; 	return 0;	}	/* SMALL_INTEGER */	if ((u < 256) && (u >= 0)) {	    *(*ext)++ = ERL_SMALL_INTEGER_EXT;	    *(*ext)++ = u & 0xff;	    return 0;	}	/* INTEGER */	*(*ext)++ = ERL_INTEGER_EXT;	*(*ext)++ = (u >> 24) & 0xff;	*(*ext)++ = (u >> 16) & 0xff;	*(*ext)++ = (u >> 8) & 0xff;	*(*ext)++ = u  & 0xff;	return 0;    case ERL_PID:	*(*ext)++ = ERL_PID_EXT;    	/* First poke in node as an atom */    	i = strlen(ERL_PID_NODE(ep));	*(*ext)++ = ERL_ATOM_EXT;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	memcpy(*ext, ERL_PID_NODE(ep), i);	*ext += i;	/* And then fill in the integer fields */	i = ERL_PID_NUMBER(ep);	*(*ext)++ = (i >>24) &0xff;	*(*ext)++ = (i >>16) &0xff;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	i = ERL_PID_SERIAL(ep);	*(*ext)++ = (i >>24) &0xff;	*(*ext)++ = (i >>16) &0xff;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	*(*ext)++ = ERL_PID_CREATION(ep);	return 0;    case ERL_REF: {	    int len, j;	    /* Always encode as an extended reference; all	       participating parties are now expected to be	       able to decode extended references. */	    *(*ext)++ = ERL_NEW_REFERENCE_EXT;	    i = strlen(ERL_REF_NODE(ep));	    len = ERL_REF_LEN(ep);	    *(*ext)++ = (len >>8) &0xff;	    *(*ext)++ = len &0xff;	    *(*ext)++ = ERL_ATOM_EXT;	    *(*ext)++ = (i >>8) &0xff;	    *(*ext)++ = i &0xff;	    memcpy(*ext, ERL_REF_NODE(ep), i);	    *ext += i;	    *(*ext)++ = ERL_REF_CREATION(ep);	    /* Then the integer fields */	    for (j = 0; j < ERL_REF_LEN(ep); j++) {		i = ERL_REF_NUMBERS(ep)[j];		*(*ext)++ = (i >>24) &0xff;		*(*ext)++ = (i >>16) &0xff;		*(*ext)++ = (i >>8) &0xff;		*(*ext)++ = i &0xff;	    }	}	return 0;    case ERL_PORT:	*(*ext)++ = ERL_PORT_EXT;	/* First poke in node as an atom */	i = strlen(ERL_PORT_NODE(ep));	*(*ext)++ = ERL_ATOM_EXT;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	memcpy(*ext, ERL_PORT_NODE(ep), i);	*ext += i;	/* Then the integer fields */	i = ERL_PORT_NUMBER(ep);	*(*ext)++ = (i >>24) &0xff;	*(*ext)++ = (i >>16) &0xff;	*(*ext)++ = (i >>8) &0xff;	*(*ext)++ = i &0xff;	*(*ext)++ = ERL_PORT_CREATION(ep);	return 0;    case ERL_EMPTY_LIST:	*(*ext)++ = ERL_NIL_EXT;	break;    case ERL_LIST:	i = is_string(ep);	if (0 < i && i < 0x10000) { /* String. */	    *(*ext)++ = ERL_STRING_EXT;	    *(*ext)++ = (i >>8) &0xff;	    *(*ext)++ = i &0xff;	    while (ERL_TYPE(ep) == ERL_LIST) {		*(*ext)++ = HEAD(ep)->uval.ival.i;		ep = TAIL(ep);	    }	    break;	} else {		/* List. */	    i = erl_length(ep);	    *(*ext)++ = ERL_LIST_EXT;	    *(*ext)++ = (i >>24) &0xff;	    *(*ext)++ = (i >>16) &0xff;	    *(*ext)++ = (i >>8) &0xff;	    *(*ext)++ = i &0xff;	    while (ERL_TYPE(ep) == ERL_LIST) {		if (erl_encode_it(HEAD(ep), ext, dist))		    return 1;		ep = TAIL(ep);	    }	    i = erl_encode_it(ep, ext, dist);	    return i;	}    case ERL_TUPLE:	i = ep->uval.tval.size;	if (i <= 0xff) {	    *(*ext)++ = ERL_SMALL_TUPLE_EXT;	    *(*ext)++ = i & 0xff;	}	else {	    *(*ext)++ = ERL_LARGE_TUPLE_EXT;	    *(*ext)++ = (i >> 24) & 0xff;	    *(*ext)++ = (i >> 16 ) & 0xff;	    *(*ext)++ = (i >> 8) & 0xff;	    *(*ext)++ = i & 0xff;	}	for (i=0; i<ep->uval.tval.size; i++)	    if (erl_encode_it(ep->uval.tval.elems[i], ext, dist))		return 1;	break;    case ERL_FLOAT:	*(*ext)++ = ERL_FLOAT_EXT;	memset(*ext, 0, 31);	sprintf((char *) *ext, "%.20e", ep->uval.fval.f);	*ext += 31;	break;    case ERL_BINARY:	*(*ext)++ = ERL_BINARY_EXT;	i = ep->uval.bval.size;	*(*ext)++ = (i >> 24) & 0xff;	*(*ext)++ = (i >> 16) & 0xff;	*(*ext)++ = (i >> 8) & 0xff;	*(*ext)++ = i  & 0xff;	memcpy((char *) *ext, (char*) ep->uval.bval.b, i);	*ext += i;	break;    case ERL_FUNCTION:	if (ERL_FUN_ARITY(ep) != -1) {	    unsigned char *size_p = *ext + 1;	    *(*ext)++ = ERL_NEW_FUN_EXT;	    *ext += 4;	    i = ERL_FUN_ARITY(ep);	    put8(*ext, i);	    memcpy(*ext, ERL_FUN_MD5(ep), 16);	    *ext += 16;	    i = ERL_FUN_NEW_INDEX(ep);	    put32be(*ext, i);	    i = ERL_CLOSURE_SIZE(ep);	    put32be(*ext, i);	    erl_encode_it(ERL_FUN_MODULE(ep), ext, dist);	    erl_encode_it(ERL_FUN_INDEX(ep), ext, dist);	    erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist);	    erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist);	    for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)		erl_encode_it(ep->uval.funcval.closure[i], ext, dist);	    if (size_p != NULL) {		i = *ext - size_p;		put32be(size_p, i);	    }	} else {	    *(*ext)++ = ERL_FUN_EXT;	    i = ERL_CLOSURE_SIZE(ep);	    *(*ext)++ = (i >> 24) & 0xff;	    *(*ext)++ = (i >> 16) & 0xff;	    *(*ext)++ = (i >> 8) & 0xff;	    *(*ext)++ = i  & 0xff;	    erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist);	    erl_encode_it(ERL_FUN_MODULE(ep), ext, dist);	    erl_encode_it(ERL_FUN_INDEX(ep), ext, dist);	    erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist);	    for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)		erl_encode_it(ep->uval.funcval.closure[i], ext, dist);	}	break;    default:	return 1;    }    return 0;}/*  * ENCODE an ETERM into a BUFFER, assuming BUFFER is of  * enough size. At success return number of bytes written  * into it, otherwise return 0. */static int erl_encode3(ETERM *ep, unsigned char *t, int dist){  unsigned char *x = t;    *x++ = ERL_VERSION_MAGIC;  if (erl_encode_it(ep, &x, dist)) {#ifdef DEBUG    erl_err_msg("<ERROR> erl_encode: Error while encoding");#endif    return 0;  }  return (x - t);}/* API */int erl_encode(ETERM *ep, unsigned char *t){    return erl_encode3(ep, t, 4);}/* determine the buffer size that will be required for the eterm */static int erl_term_len_helper(ETERM *ep, int dist);/* FIXME hard coded dist version */int erl_term_len(ETERM *ep){  return 1+erl_term_len_helper(ep, 4);}static int erl_term_len_helper(ETERM *ep, int dist){  int len = 0;  int i;  unsigned int u;  if (ep) {    switch (ERL_TYPE(ep)) {    case ERL_ATOM:      i = ep->uval.aval.len;      len = i + 3;      break;    case ERL_INTEGER:      i = ep->uval.ival.i;      if ((i > ERL_MAX) || (i < ERL_MIN)) len = 7;      else if ((i < 256) && (i >= 0)) len = 2;       else len = 5;      break;    case ERL_U_INTEGER:      u = ep->uval.uival.u;      if (u > ERL_MAX) len = 7;      else if (u  < 256) len = 2;      else len = 5;      break;    case ERL_PID:      /* 1 + N + 4 + 4 + 1 where N = 3 + strlen */      i = strlen(ERL_PID_NODE(ep));      len = 13 + i;      break;    case ERL_REF:      i = strlen(ERL_REF_NODE(ep));      if (dist >= 4 && ERL_REF_LEN(ep) > 1) {	  len = 1 + 2 + (i+3) + 1 + ERL_REF_LEN(ep) * 4;      } else {	  /* 1 + N + 4 + 1 where N = 3 + strlen */	  len = 9 + i;      }      break;    case ERL_PORT:      /* 1 + N + 4 + 1 where N = 3 + strlen */      i = strlen(ERL_PORT_NODE(ep));      len = 9 + i;      break;    case ERL_EMPTY_LIST:      len = 1;      break;    case ERL_LIST:      i = is_string(ep);      if ((i > 0) && (i < 0x10000)) { /* string: 3 + strlen */	for (len = 3; ERL_TYPE(ep) == ERL_LIST; ep =  TAIL(ep)) {	  len++;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?