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