erl_marshal.c

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

C
1,923
字号
      }      else { /* list: 5 + len(elem1) + len(elem2) ... */	for (len = 5; ERL_TYPE(ep) == ERL_LIST; ep =  TAIL(ep)) {	  len += erl_term_len_helper(HEAD(ep), dist);	}	len += erl_term_len_helper(ep, dist); /* last element */      }      break;    case ERL_TUPLE:      /* (2 or 5) + len(elem1) + len(elem2) ... */      i = ep->uval.tval.size;      if (i <= 0xff) len = 2;      else len = 5;            for (i=0; i<ep->uval.tval.size; i++) {	len += erl_term_len_helper(ep->uval.tval.elems[i], dist);      }      break;    case ERL_FLOAT:      len = 32;      break;    case ERL_BINARY:      i = ep->uval.bval.size;      len = 5 + i;      break;    case ERL_FUNCTION:      if (ERL_FUN_ARITY(ep) == -1) {	  len = 1 + 4;	  len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist);	  len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist);	  len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist);	  len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist);	  for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)	      len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist);      } else {	  len = 1 + 4 + 16 + 4 + 4;	  len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist);	  len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist);	  len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist);	  len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist);	  for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)	      len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist);      }      break;    default:#ifdef DEBUG	fprintf(stderr, "Shouldn't happen: erl_term_len, unknown term type: '%c'\n",ERL_TYPE(ep));#endif      erl_errno = EINVAL;      exit(1);    }  }  return len;}/*  * This one makes it easy to ENCODE several CONSECUTIVE * ETERM's into the same buffer.  */int erl_encode_buf(ETERM *ep, unsigned char **ext){  unsigned char *start=*ext;    *(*ext)++ = ERL_VERSION_MAGIC;  if (erl_encode_it(ep, ext, 0)) {#ifdef DEBUG    erl_err_msg("<ERROR> erl_encode_buf: Error while encoding\n");#endif    return 0;  }  return (*ext - start);} /* erl_encode_buf *//* * A nice macro to make it look cleaner in the  * cases of PID's,PORT's and REF's below.  * It reads the NODE name from a buffer. */#define READ_THE_NODE(ext,cp,len,i) \/* eat first atom, repr. the node */ \if (**ext != ERL_ATOM_EXT) \  return (ETERM *) NULL; \*ext += 1; \i = (**ext << 8) | (*ext)[1]; \cp = (char *) *(ext) + 2; \*ext += (i + 2); \len = i#define STATIC_NODE_BUF_SZ 30#define SET_NODE(node,node_buf,cp,len) \if (len >= STATIC_NODE_BUF_SZ) node = malloc(len+1); \else node = node_buf; \memcpy(node, cp, len); \node[len] = '\0'#define RESET_NODE(node,len) \if (len >= STATIC_NODE_BUF_SZ) free(node)/* * The actual DECODE engine. * Returns NULL in case of failure. */static ETERM *erl_decode_it(unsigned char **ext){    char *cp;    ETERM *ep,*tp,*np;    unsigned int u,sign;    int i,j,len,arity;    double ff;        /* Assume we are going to decode an integer */    ep = erl_alloc_eterm(ERL_INTEGER);    ERL_COUNT(ep) = 1;        switch (*(*ext)++)     {    case ERL_INTEGER_EXT:	i = (int) (**ext << 24) | ((*ext)[1] << 16) |	    ((*ext)[2] << 8) | (*ext)[3];	*ext += 4;	ep->uval.ival.i = i;	return ep;    case ERL_SMALL_INTEGER_EXT:	i = *(*ext)++;	ep->uval.ival.i = i;	return ep;        /* NOTE: The arity below for bigs is not really the arity (= number of digits) */        /*       It is the byte count and this might cause problems in other parts...  */    case ERL_SMALL_BIG_EXT:        arity = *(*ext)++; 	goto big_cont;    case ERL_LARGE_BIG_EXT:	arity = (**ext << 24) | ((*ext)[1])<< 16 | 	    ((*ext)[2]) << 8 |((*ext)[3]); 	*ext += 4;    big_cont:	sign = *(*ext)++; 	if (arity != 4)             	    goto big_truncate;	if ((*ext)[3] & 0x80) { 	    /* MSB already occupied ! */	    if (sign)		goto big_truncate;	    else {                		/* It will fit into an unsigned int !! */		u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext));		ERL_TYPE(ep) = ERL_U_INTEGER;		ep->uval.uival.u = u;		/* *ext += i; */		*ext += arity;		return ep;	    }	}	else {       	    /* It will fit into an int !! 	     * Note: It comes in "one's-complement notation" 	     */	    if (sign)		i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 |			     ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign);	    else		i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |			   ((*ext)[1]) << 8 | (**ext));	    ep->uval.ival.i = i;	    *ext += arity;	    return ep;	}    big_truncate: 	/* truncate to: (+/-) 1 */#ifdef DEBUG	erl_err_msg("<WARNING> erl_decode_it: Integer truncated...");#endif	ep->uval.ival.i = sign?-1:1;	*ext += arity;	return ep;          case ERL_ATOM_EXT:	ERL_TYPE(ep) = ERL_ATOM;	i = (**ext << 8) | (*ext)[1];	cp = (char *) *(ext) + 2;	*ext += (i + 2);	ep->uval.aval.len = i;	ep->uval.aval.a = (char *) erl_malloc(i+1);	memcpy(ep->uval.aval.a, cp, i);	ep->uval.aval.a[i]='\0';	return ep;          case ERL_PID_EXT:	erl_free_term(ep);	{			/* Why not use the constructors? */	    char *node;	    char node_buf[STATIC_NODE_BUF_SZ];	    unsigned int number, serial;	    unsigned char creation;	    ETERM *eterm_p;	    READ_THE_NODE(ext,cp,len,i);	    SET_NODE(node,node_buf,cp,len);	    /* get the integers */#if 0	    /* FIXME: Remove code or whatever....               Ints on the wire are big-endian (== network byte order)               so use ntoh[sl]. (But some are little-endian! Arrrgh!)               Also, the libc authors can be expected to optimize them               heavily. However, the marshalling makes no guarantees               about alignments -- so it won't work at all. */	    number = ntohl(*((unsigned int *)*ext)++);	    serial = ntohl(*((unsigned int *)*ext)++);#else	    number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | 		((*ext)[2]) << 8 | ((*ext)[3]);		    *ext += 4;	    serial = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | 		((*ext)[2]) << 8 | ((*ext)[3]);		    *ext += 4;#endif	    creation =  *(*ext)++; 	    eterm_p = erl_mk_pid(node, number, serial, creation);	    RESET_NODE(node,len);	    return eterm_p;	}    case ERL_REFERENCE_EXT:	erl_free_term(ep);	{	    char *node;	    char node_buf[STATIC_NODE_BUF_SZ];	    unsigned int number;	    unsigned char creation;	    ETERM *eterm_p;	    READ_THE_NODE(ext,cp,len,i);	    SET_NODE(node,node_buf,cp,len);	    /* get the integers */#if 0	    number = ntohl(*((unsigned int *)*ext)++);#else	    number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | 		((*ext)[2]) << 8 | ((*ext)[3]);		    *ext += 4;#endif	    creation =  *(*ext)++; 	    eterm_p = erl_mk_ref(node, number, creation);	    RESET_NODE(node,len);	    return eterm_p;	}    case ERL_NEW_REFERENCE_EXT: 	erl_free_term(ep);	{	    char *node;	    char node_buf[STATIC_NODE_BUF_SZ];	    size_t cnt, i;	    unsigned int n[3];	    unsigned char creation;	    ETERM *eterm_p;#if 0	    cnt = ntohs(*((unsigned short *)*ext)++);#else	    cnt = ((*ext)[0] << 8) | (*ext)[1];	    *ext += 2;#endif	    READ_THE_NODE(ext,cp,len,i);	    SET_NODE(node,node_buf,cp,len);	    /* get the integers */	    creation =  *(*ext)++; 	    for(i = 0; i < cnt; i++)	    {#if 0		n[i] = ntohl(*((unsigned int *)*ext)++);#else		n[i] = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | 		    ((*ext)[2]) << 8 | ((*ext)[3]);			*ext += 4;#endif	    }	    eterm_p = __erl_mk_reference(node, cnt, n, creation);	    RESET_NODE(node,len);	    return eterm_p;	}    case ERL_PORT_EXT:	erl_free_term(ep);	{	    char *node;	    char node_buf[STATIC_NODE_BUF_SZ];	    unsigned int number;	    unsigned char creation;	    ETERM *eterm_p;	    READ_THE_NODE(ext,cp,len,i);	    SET_NODE(node,node_buf,cp,len);	    /* get the integers */#if 0	    number = ntohl(*((unsigned int *)*ext)++);#else	    number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | 		((*ext)[2]) << 8 | ((*ext)[3]);		    *ext += 4;#endif	    creation =  *(*ext)++; 	    eterm_p = erl_mk_port(node, number, creation);	    RESET_NODE(node,len);	    return eterm_p;	}    case ERL_NIL_EXT:	ERL_TYPE(ep) = ERL_EMPTY_LIST;	return ep;    case ERL_LIST_EXT:	ERL_TYPE(ep) = ERL_LIST;	i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];	*ext += 4;		/* ASSERT(i != 0);	*/	/* Should be represented by ERL_NIL_EXT. */	tp = ep;	for (j = 0; j < i; j++) 	    if ((HEAD(tp) = erl_decode_it(ext)) == NULL) 		goto failure;	    else if (j + 1 < i) {		/* We have to watch out for how we allocates the		 * last tail element since we may encounter non-		 * well formed lists.		 */		np = erl_alloc_eterm(ERL_LIST);		ERL_COUNT(np) = 1;		TAIL(tp) = np;		tp = np;	    }	if ((TAIL(tp) = erl_decode_it(ext)) == NULL) 	    goto failure;	return ep;    case ERL_STRING_EXT:	{	    unsigned char* s;	  	    ERL_TYPE(ep) = ERL_EMPTY_LIST;	    i = (**ext << 8) | ((*ext)[1]);	    *ext += 2;	    s = *ext+i;	    while (*ext < s) {		ETERM* integer;		ETERM* cons;		integer = erl_alloc_eterm(ERL_INTEGER);		ERL_COUNT(integer) = 1;		integer->uval.ival.i = *--s;		cons = erl_alloc_eterm(ERL_LIST);		ERL_COUNT(cons) = 1;		HEAD(cons) = integer;		TAIL(cons) = ep;		ep = cons;	    }	    *ext += i;	    return ep;	}    case ERL_SMALL_TUPLE_EXT:	ERL_TYPE(ep) = ERL_TUPLE;	i = *(*ext)++;	goto decode_tuple;    case ERL_LARGE_TUPLE_EXT:	i = (**ext << 24) | ((*ext)[1]) << 16 | 	    ((*ext)[2]) << 8 | ((*ext)[3]) ;		*ext += 4;    decode_tuple:	ep->uval.tval.size = i;	j = (i + 1) * sizeof(ETERM*);	ep->uval.tval.elems = (ETERM**) erl_malloc(j);	memset(ep->uval.tval.elems, 0, j); /* in case of failure below... */	for (i=0; i<ep->uval.tval.size; i++)	    if ((tp = erl_decode_it(ext)) == NULL)		goto failure;	    else		ep->uval.tval.elems[i] = tp;	return ep;    case ERL_FLOAT_EXT:	ERL_TYPE(ep) = ERL_FLOAT;	if (sscanf((char *) *ext, "%lf", &ff) != 1)	    goto failure;	*ext += 31;	ep->uval.fval.f = ff;	return ep;    case ERL_BINARY_EXT:	ERL_TYPE(ep) = ERL_BINARY;	i = (**ext << 24) | ((*ext)[1] << 16) |	    ((*ext)[2] << 8) | (*ext)[3];	*ext += 4;	ep->uval.bval.size = i;	ep->uval.bval.b = (unsigned char *) erl_malloc(i);	memcpy(ep->uval.bval.b, *ext, i);	*ext += i;	return ep;    case ERL_FUN_EXT:		/* FIXME: error checking */	ERL_TYPE(ep) = ERL_FUNCTION;	i = get32be(*ext);	/*i = *(**ext << 24) | ((*ext)[1] << 16) | ((*ext)[2] << 8) | (*ext)[3];	 *ext += 4; */	ERL_FUN_ARITY(ep) = -1;	ERL_CLOSURE_SIZE(ep) = i;	ERL_FUN_CREATOR(ep) = erl_decode_it(ext);	ERL_FUN_MODULE(ep) = erl_decode_it(ext);	ERL_FUN_INDEX(ep) = erl_decode_it(ext);	ERL_FUN_UNIQ(ep) = erl_decode_it(ext);	j = i * sizeof(ETERM*);	ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j);	memset(ERL_CLOSURE(ep), 0, j);	for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)	    ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext);	return ep;    case ERL_NEW_FUN_EXT:	/* FIXME: error checking */	ERL_TYPE(ep) = ERL_FUNCTION;	i = get32be(*ext);	/* size, we don't use it here */	ERL_FUN_ARITY(ep) = get8(*ext);	memcpy(ERL_FUN_MD5(ep), *ext, 16);	*ext += 16;	ERL_FUN_NEW_INDEX(ep) = get32be(*ext);	i = get32be(*ext);	ERL_CLOSURE_SIZE(ep) = i;	ERL_FUN_MODULE(ep) = erl_decode_it(ext);	ERL_FUN_INDEX(ep) = erl_decode_it(ext);	ERL_FUN_UNIQ(ep) = erl_decode_it(ext);	ERL_FUN_CREATOR(ep) = erl_decode_it(ext);	j = i * sizeof(ETERM*);	ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j);	memset(ERL_CLOSURE(ep), 0, j);	for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)	    ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext);	return ep;    } /* switch */     failure:    erl_free_term(ep);    return (ETERM *) NULL;    } /* erl_decode_it *//* * DECODE a buffer of BYTES into an ETERM. * Returns NULL in case of failure. */ETERM *erl_decode(unsigned char *t) {  ETERM *ep;  unsigned char *ext;  ext = t;  /* We ignore the version magic since it might be   * possible that the buffer has been manipulated   * with erl_peek_ext.   */  if (*ext == ERL_VERSION_MAGIC)     ext++;    ep = NULL;  ep = erl_decode_it(&ext);

⌨️ 快捷键说明

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