aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/misc/ei_decode_term.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/erl_interface/src/misc/ei_decode_term.c')
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
new file mode 100644
index 0000000000..7b95ff232f
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -0,0 +1,156 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2009. All Rights Reserved.
+ *
+ * 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 online 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.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#include <string.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_decode_term.h"
+#include "putget.h"
+
+/* Returns 1 if term is decoded, 0 if term is OK, but not decoded here
+ and -1 if something is wrong.
+ ONLY changes index if term is decoded (return value 1)! */
+
+int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
+{
+ const char* s = buf + *index, * s0 = s;
+ int len, i, n, sign;
+ char c;
+ double f;
+
+ if (term == NULL) return -1;
+ c = term->ei_type = get8(s);
+ switch (c) {
+ case ERL_SMALL_INTEGER_EXT:
+ term->value.i_val = get8(s);
+ break;
+ case ERL_INTEGER_EXT:
+ term->value.i_val = get32be(s);
+ break;
+ case ERL_FLOAT_EXT:
+ if (s[30]) return -1;
+ if (sscanf(s, "%lf", &f) != 1) return -1;
+ s += 31;
+ term->value.d_val = f;
+ break;
+ case ERL_ATOM_EXT:
+ len = get16be(s);
+ memcpy(term->value.atom_name, s, len);
+ term->value.atom_name[len] = '\0';
+ s += len;
+ break;
+ case ERL_REFERENCE_EXT:
+ /* first the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.ref.node, s, len);
+ term->value.ref.node[len] = '\0';
+ s += len;
+ /* now the numbers: num (4), creation (1) */
+ term->value.ref.n[0] = get32be(s);
+ term->value.ref.len = 1;
+ term->value.ref.creation = get8(s) & 0x03;
+ break;
+ case ERL_NEW_REFERENCE_EXT:
+ /* first the integer count */
+ term->value.ref.len = get16be(s);
+ /* then the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.ref.node, s, len);
+ term->value.ref.node[len] = '\0';
+ s += len;
+ /* creation */
+ term->value.ref.creation = get8(s) & 0x03;
+ /* finally the id integers */
+ for (i = 0; (i<term->value.ref.len) && (i<3); i++) {
+ term->value.ref.n[i] = get32be(s);
+ }
+ if (term->value.ref.len > 3) {
+ s += 4 * (term->value.ref.len - 3);
+ }
+ break;
+ case ERL_PORT_EXT:
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.port.node, s, len);
+ term->value.port.node[len] = '\0';
+ term->value.port.id = get32be(s) & 0x0fffffff; /* 28 bits */;
+ term->value.port.creation = get8(s) & 0x03;
+ break;
+ case ERL_PID_EXT:
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ /* name first */
+ len = get16be(s);
+ memcpy(term->value.pid.node, s, len);
+ term->value.pid.node[len] = '\0';
+ s += len;
+ /* now the numbers: num (4), serial (4), creation (1) */
+ term->value.pid.num = get32be(s) & 0x7fff; /* 15 bits */
+ term->value.pid.serial = get32be(s) & 0x1fff; /* 13 bits */
+ term->value.pid.creation = get8(s) & 0x03; /* 2 bits */
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ term->arity = get8(s);
+ break; /*return 0;*/
+ case ERL_LARGE_TUPLE_EXT:
+ term->arity = get32be(s);
+ break; /*return 0;*/
+ case ERL_NIL_EXT:
+ term->arity = 0;
+ break;
+ case ERL_STRING_EXT:
+ term->size = get16be(s);
+ return 0;
+ case ERL_LIST_EXT:
+ term->arity = get32be(s);
+ break; /*return 0;*/
+ case ERL_BINARY_EXT:
+ term->size = get32be(s);
+ return 0;
+ case ERL_SMALL_BIG_EXT:
+ if ((term->arity = get8(s)) != 4) return -1;
+ sign = get8(s);
+ /* Little Endian, and n always positive, except for LONG_MIN */
+ n = get32le(s);
+ if (sign) {
+ /* check for overflow */
+ if ((n - 1) < 0) return -1;
+ n = -n;
+ } else {
+ /* check for overflow */
+ if (n < 0) return -1;
+ }
+ break;
+ case ERL_LARGE_BIG_EXT:
+ return 0;
+ case ERL_PASS_THROUGH:
+ return 0;
+ case ERL_NEW_CACHE:
+ return -1;
+ case ERL_CACHED_ATOM:
+ return -1;
+ default:
+ return -1;
+ }
+ *index += s-s0;
+ return 1;
+}