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 + -
显示快捷键?