erl_marshal.c

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

C
1,923
字号
#ifdef DEBUG  if (!ep) erl_err_msg("<ERROR> erl_decode: Error while decoding");#endif  return ep;} /* erl_decode *//*  * This one makes it possible to DECODE two CONSECUTIVE  * ETERM's in the same buffer.  */ETERM *erl_decode_buf(unsigned char **ext) {  ETERM *ep;    /* 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);#ifdef DEBUG    if (!ep) erl_err_msg("<ERROR> erl_decode_buf: Error while decoding");#endif  return ep;} /* erl_decode_buf *//*============================================================== * Ok, here comes routines for inspecting/manipulating  * an encoded buffer of bytes. *============================================================== *//* * Return 1 if the VERSION MAGIC in the BUFFER is the * same as the this library version. */int erl_verify_magic(unsigned char *ext){  if (*ext == ERL_VERSION_MAGIC)     return 1;  else    return 0;} /* erl_verify_magic *//* * Return the TYPE of an ENCODED ETERM. * At failure, return 0. */ unsigned char erl_ext_type(unsigned char *ext){    /* FIXME old code could skip multiple magic */    /* Move over magic number if any */    if (*ext == ERL_VERSION_MAGIC) ext++;      switch (*ext) {    case ERL_SMALL_INTEGER_EXT:    case ERL_INTEGER_EXT:	return ERL_INTEGER;    case ERL_ATOM_EXT:	return ERL_ATOM;    case ERL_PID_EXT:	return ERL_PID;    case ERL_PORT_EXT:	return ERL_PORT;    case ERL_REFERENCE_EXT:    case ERL_NEW_REFERENCE_EXT:	return ERL_REF;    case ERL_NIL_EXT: 	return ERL_EMPTY_LIST;    case ERL_LIST_EXT:	return ERL_LIST;    case ERL_SMALL_TUPLE_EXT:    case ERL_LARGE_TUPLE_EXT:	return ERL_TUPLE;    case ERL_FLOAT_EXT:	return ERL_FLOAT;    case ERL_BINARY_EXT:	return ERL_BINARY;    case ERL_FUN_EXT:    case ERL_NEW_FUN_EXT:	return ERL_FUNCTION;    case ERL_SMALL_BIG_EXT:    case ERL_LARGE_BIG_EXT:        return ERL_BIG;    default:	return 0;    } /* switch */} /* erl_ext_type *//*  * Returns the number of elements in compund * terms. For other kind of terms zero is returned. * At failure -1 is returned. */int erl_ext_size(unsigned char *t){    int i;    unsigned char *v;    if (*t == ERL_VERSION_MAGIC) 	return erl_ext_size(t+1);     v = t+1;    switch(*t) {    case ERL_SMALL_INTEGER_EXT:    case ERL_INTEGER_EXT:    case ERL_ATOM_EXT:    case ERL_PID_EXT:    case ERL_PORT_EXT:    case ERL_REFERENCE_EXT:    case ERL_NEW_REFERENCE_EXT:    case ERL_NIL_EXT:     case ERL_BINARY_EXT:    case ERL_STRING_EXT:    case ERL_FLOAT_EXT:    case ERL_SMALL_BIG_EXT:    case ERL_LARGE_BIG_EXT:	return 0;	break;    case ERL_SMALL_TUPLE_EXT:	i = v[0];	return i;	break;    case ERL_LIST_EXT:    case ERL_LARGE_TUPLE_EXT:	i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];	return i;	break;    case ERL_FUN_EXT:	i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];	return i+4;	break;    case ERL_NEW_FUN_EXT:        v += 4 + 1 + 16 + 4;	i = get32be(v);	return i + 4;	break;    default:	return -1;	break;    } /* switch */} /* ext_size *//* * A nice macro that eats up the atom pointed to. */#define JUMP_ATOM(ext,i) \if (**ext != ERL_ATOM_EXT) \  return 0; \*ext += 1; \i = (**ext << 8) | (*ext)[1]; \*ext += (i + 2)/* * MOVE the POINTER PAST the ENCODED ETERM we * are currently pointing at. Returns 1 at * success, otherwise 0. */static int jump(unsigned char **ext) {    int j,k,i=0;    int n;        switch (*(*ext)++) {    case ERL_VERSION_MAGIC:	return jump(ext);    case ERL_INTEGER_EXT:	*ext += 4;	break;    case ERL_SMALL_INTEGER_EXT:	*ext += 1;	break;    case ERL_ATOM_EXT:	i = (**ext << 8) | (*ext)[1];	*ext += (i + 2);	break;    case ERL_PID_EXT:	/* eat first atom */	JUMP_ATOM(ext,i);	*ext += 9;		/* Two int's and the creation field */	break;    case ERL_REFERENCE_EXT:    case ERL_PORT_EXT:	/* first field is an atom */	JUMP_ATOM(ext,i);	*ext += 5;		/* One int and the creation field */	break;    case ERL_NEW_REFERENCE_EXT:	n = (**ext << 8) | (*ext)[1];	*ext += 2;	/* first field is an atom */	JUMP_ATOM(ext,i);	*ext += 4*n+1;	break;    case ERL_NIL_EXT:	/* We just passed it... */	break;    case ERL_LIST_EXT:	i = j = 0;	j = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];	*ext += 4;		for(k=0; k<j; k++) 	    if ((i = jump(ext)) == 0)		return(0);	if (**ext == ERL_NIL_EXT) {	    *ext += 1;	    break;	}	if (jump(ext) == 0) return 0;	break;    case ERL_STRING_EXT:	i = **ext << 8 | (*ext)[1];	*ext += 2 + i;	break;    case ERL_SMALL_TUPLE_EXT:	i = *(*ext)++;	goto jump_tuple;    case ERL_LARGE_TUPLE_EXT:	i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];	*ext += 4;    jump_tuple:	for (j = 0; j < i; j++) 	    if ((k = jump(ext)) == 0)		return(0);	break;    case ERL_FLOAT_EXT:	*ext += 31;	break;    case ERL_BINARY_EXT:	i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];	*ext += 4+i;	break;    case ERL_FUN_EXT:	i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];	*ext += 4;	i += 4;	for (j = 0; j < i; j++)	    if ((k = jump(ext)) == 0)		return(0);	break;    case ERL_NEW_FUN_EXT:	i = get32be(*ext);	*ext += i + 4;	break;    case ERL_SMALL_BIG_EXT:        i = *(*ext);        *ext += i + 1;        break;    case ERL_LARGE_BIG_EXT:	i = get32be(*ext);        *ext += i + 4;        break;    default:	return 0;    } /* switch */    return 1;} /* jump *//*  * The actual PEEK engine. */static unsigned char *peek_ext(unsigned char **ext, int jumps){  int i;  switch (*(*ext)++)     {    case ERL_VERSION_MAGIC:      return peek_ext(ext, jumps);    case ERL_SMALL_TUPLE_EXT:      i = *(*ext)++;      goto do_the_peek_stuff;    case ERL_LARGE_TUPLE_EXT:    case ERL_LIST_EXT:      i = (**ext << 24) | ((*ext)[1]) << 16| ((*ext)[2]) << 8| ((*ext)[3]) ;        *ext += 4;    do_the_peek_stuff:      if (i <= jumps)   {#ifdef DEBUG	erl_err_msg("<ERROR> peek_ext: Out of range"); #endif	return NULL;      }      for(i=0; i<jumps; i++)	if (!jump(ext)) {#ifdef DEBUG	  erl_err_msg("<ERROR> peek_ext: Bad data"); #endif	  return NULL;	}      return *ext;    default:#ifdef DEBUG      erl_err_msg("<ERROR> peek_ext: Can't peek in non list/tuple type");#endif      return NULL;    } /* switch */} /* peek_ext */	/* * Return a POINTER TO the N:TH ELEMENT in a * COMPUND ENCODED ETERM. */unsigned char *erl_peek_ext(unsigned char *ext, int jumps){  unsigned char *x=ext;  return peek_ext(&x, jumps);  } /* erl_peek_ext *//*  * Lexically compare two strings of bytes, * (string s1 length l1 and s2 l2). * Return: -1 if s1 < s2 *	    0 if s1 = s2 *	    1 if s1 > s2  */static int cmpbytes(unsigned char* s1,int l1,unsigned char* s2,int l2){  int i;  i = 0;  while((i < l1) && (i < l2)) {    if (s1[i] < s2[i]) return(-1);    if (s1[i] > s2[i]) return(1);    i++;  }  if (l1 < l2) return(-1);  if (l1 > l2) return(1);  return(0);} /* cmpbytes */#define CMP_EXT_ERROR_CODE 4711#define CMP_EXT_INT32_BE(AP, BP)				\do {								\    if ((AP)[0] != (BP)[0]) return (AP)[0] < (BP)[0] ? -1 : 1;	\    if ((AP)[1] != (BP)[1]) return (AP)[1] < (BP)[1] ? -1 : 1;	\    if ((AP)[2] != (BP)[2]) return (AP)[2] < (BP)[2] ? -1 : 1;	\    if ((AP)[3] != (BP)[3]) return (AP)[3] < (BP)[3] ? -1 : 1;	\} while (0)#define CMP_EXT_SKIP_ATOM(EP)					\do {								\    if ((EP)[0] != ERL_ATOM_EXT)				\	return CMP_EXT_ERROR_CODE;				\    (EP) += 3 + ((EP)[1] << 8 | (EP)[2]);			\} while (0)/*  * We now know that both byte arrays are of the same type. */static int compare_top_ext(unsigned char**, unsigned char **); /* forward */static int cmp_exe2(unsigned char **e1, unsigned char **e2);static int cmp_refs(unsigned char **e1, unsigned char **e2){    int tmp, n1, n2;    unsigned char *node1, *node2, *id1, *id2, cre1, cre2;    if (*((*e1)++) == ERL_REFERENCE_EXT) {	node1 = *e1;	CMP_EXT_SKIP_ATOM(*e1);	n1 = 1;	id1 = *e1;	cre1 = (*e1)[4];	*e1 += 5;    } else {	n1 = get16be(*e1);	node1 = *e1;	CMP_EXT_SKIP_ATOM(*e1);	cre1 = **e1;	id1 = (*e1) + 1 + (n1 - 1)*4;	*e1 = id1 + 4;    }    if (*((*e2)++) == ERL_REFERENCE_EXT) {	node2 = *e2;	CMP_EXT_SKIP_ATOM(*e2);	n2 = 1;	id2 = *e2;	cre2 = (*e2)[4];	*e2 += 5;    } else {	n2 = get16be(*e2);	node2 = *e2;	CMP_EXT_SKIP_ATOM(*e2);	cre2 = **e2;	id2 = (*e2) + 1 + (n2 - 1)*4;	*e2 = id2 + 4;    }    /* First compare node names... */    tmp = cmp_exe2(&node1, &node2);    if (tmp != 0)	return tmp;    /* ... then creations ... */    if (cre1 != cre2)	return cre1 < cre2 ? -1 : 1;    /* ... and then finaly ids. */    if (n1 != n2) {	unsigned char zero[] = {0, 0, 0, 0};	if (n1 > n2)	    do {		CMP_EXT_INT32_BE(id1, zero);		id1 -= 4;		n1--;	    } while (n1 > n2);	else	    do {		CMP_EXT_INT32_BE(zero, id2);		id2 -= 4;		n2--;	    } while (n2 > n1);    }        for (; n1 > 0; n1--, id1 -= 4, id2 -= 4)	CMP_EXT_INT32_BE(id1, id2);    return 0;}static int cmp_exe2(unsigned char **e1, unsigned char **e2){  int min,  ret,i,j,k;  double ff1, ff2;  unsigned char *tmp1, *tmp2;  *e2 += 1;  switch (*(*e1)++)     {    case ERL_SMALL_INTEGER_EXT:      if (**e1 < **e2) ret = -1;      else if (**e1 > **e2) ret = 1;      else ret = 0;      *e1 += 1; *e2 += 1;      return ret;    case ERL_INTEGER_EXT:      i = (int) (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3];      j = (int) (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3];      if ( i < j) 	ret = -1;      else if ( i > j) 	ret = 1;      else 	ret = 0;      *e1 += 4; *e2 += 4;      return ret;    case ERL_ATOM_EXT:      i = (**e1 << 8) | (*e1)[1];      j = (**e2 << 8) | (*e2)[1];      ret = cmpbytes(*e1 +2, i, *e2 +2, j);      *e1 += (i + 2);      *e2 += (j + 2);      return ret;    case ERL_PID_EXT: {      unsigned char *n1 = *e1;      unsigned char *n2 = *e2;      CMP_EXT_SKIP_ATOM(*e1); CMP_EXT_SKIP_ATOM(*e2);      *e1 += 9; *e2 += 9;      /* First compare serials ... */      tmp1 = *e1 - 5; tmp2 = *e2 - 5;

⌨️ 快捷键说明

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