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