aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/encode
diff options
context:
space:
mode:
Diffstat (limited to 'lib/erl_interface/src/encode')
-rw-r--r--lib/erl_interface/src/encode/encode_atom.c66
-rw-r--r--lib/erl_interface/src/encode/encode_binary.c107
-rw-r--r--lib/erl_interface/src/encode/encode_boolean.c10
-rw-r--r--lib/erl_interface/src/encode/encode_fun.c114
4 files changed, 185 insertions, 112 deletions
diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c
index c1817628e5..6117aae37e 100644
--- a/lib/erl_interface/src/encode/encode_atom.c
+++ b/lib/erl_interface/src/encode/encode_atom.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
static int verify_ascii_atom(const char* src, int slen);
static int verify_utf8_atom(const char* src, int slen);
-static int is_latin1_as_utf8(const char *p, int len);
int ei_encode_atom(char *buf, int *index, const char *p)
{
@@ -34,7 +33,7 @@ int ei_encode_atom(char *buf, int *index, const char *p)
if (len >= MAXATOMLEN)
len = MAXATOMLEN - 1;
- return ei_encode_atom_len_as(buf, index, p, len, ERLANG_LATIN1, ERLANG_LATIN1);
+ return ei_encode_atom_len_as(buf, index, p, len, ERLANG_LATIN1, 0);
}
int ei_encode_atom_len(char *buf, int *index, const char *p, int len)
@@ -42,7 +41,7 @@ int ei_encode_atom_len(char *buf, int *index, const char *p, int len)
/* This function is documented to truncate at MAXATOMLEN (256) */
if (len >= MAXATOMLEN)
len = MAXATOMLEN - 1;
- return ei_encode_atom_len_as(buf, index, p, len, ERLANG_LATIN1, ERLANG_LATIN1);
+ return ei_encode_atom_len_as(buf, index, p, len, ERLANG_LATIN1, 0);
}
int ei_encode_atom_as(char *buf, int *index, const char *p,
@@ -64,46 +63,11 @@ int ei_encode_atom_len_as(char *buf, int *index, const char *p, int len,
return -1;
}
- if (to_enc == (ERLANG_LATIN1 | ERLANG_UTF8)) {
- if (from_enc == ERLANG_UTF8) {
- to_enc = is_latin1_as_utf8(p, len) ? ERLANG_LATIN1 : ERLANG_UTF8;
- }
- else {
- to_enc = from_enc;
- }
- }
- switch(to_enc) {
- case ERLANG_LATIN1:
- if (buf) {
- put8(s,ERL_ATOM_EXT);
- switch (from_enc) {
- case ERLANG_UTF8:
- len = utf8_to_latin1(s+2, p, len, MAXATOMLEN-1, NULL);
- if (len < 0) return -1;
- break;
- case ERLANG_ASCII:
- if (verify_ascii_atom(p, len) < 0) return -1;
- memcpy(s+2, p, len);
- break;
- case ERLANG_LATIN1:
- memcpy(s+2, p, len);
- break;
- default:
- return -1;
- }
- put16be(s,len);
- }
- else {
- s += 3;
- if (from_enc == ERLANG_UTF8) {
- len = utf8_to_latin1(NULL, p, len, MAXATOMLEN-1, NULL);
- if (len < 0) return -1;
- } else if (from_enc == ERLANG_ASCII)
- if (verify_ascii_atom(p, len) < 0) return -1;
- }
- break;
-
- case ERLANG_UTF8:
+ /*
+ * Since OTP 20 we totally ignore 'to_enc'
+ * and alway encode as UTF8.
+ */
+ {
offs = 1 + 1;
switch (from_enc) {
case ERLANG_LATIN1:
@@ -133,10 +97,6 @@ int ei_encode_atom_len_as(char *buf, int *index, const char *p, int len,
}
}
else s+= offs;
- break;
-
- default:
- return -1;
}
s += len;
@@ -197,13 +157,3 @@ static int verify_utf8_atom(const char* src, int slen)
return 0;
}
-/* Only latin1 code points in utf8 string?
- */
-static int is_latin1_as_utf8(const char *p, int len)
-{
- int i;
- for (i=0; i<len; i++) {
- if ((unsigned char)p[i] > 0xC3) return 0;
- }
- return 1;
-}
diff --git a/lib/erl_interface/src/encode/encode_binary.c b/lib/erl_interface/src/encode/encode_binary.c
index 4471c51769..0562979417 100644
--- a/lib/erl_interface/src/encode/encode_binary.c
+++ b/lib/erl_interface/src/encode/encode_binary.c
@@ -22,6 +22,10 @@
#include "eiext.h"
#include "putget.h"
+static void copy_bits(const unsigned char* src, size_t soffs,
+ unsigned char* dst, size_t n);
+
+
int ei_encode_binary(char *buf, int *index, const void *p, long len)
{
char *s = buf + *index;
@@ -40,3 +44,106 @@ int ei_encode_binary(char *buf, int *index, const void *p, long len)
return 0;
}
+int ei_encode_bitstring(char *buf, int *index,
+ const char *p,
+ size_t bitoffs,
+ size_t bits)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ size_t bytes = (bits + 7) / 8;
+ char last_bits = bits % 8;
+
+ if (!buf) s += last_bits ? 6 : 5;
+ else {
+ char* tagp = s++;
+ put32be(s, bytes);
+ if (last_bits) {
+ *tagp = ERL_BIT_BINARY_EXT;
+ put8(s, last_bits);
+ }
+ else
+ *tagp = ERL_BINARY_EXT;
+
+ copy_bits((const unsigned char*)p, bitoffs, (unsigned char*)s, bits);
+ }
+ s += bytes;
+
+ *index += s-s0;
+
+ return 0;
+}
+
+
+/*
+ * MAKE_MASK(n) constructs a mask with n bits.
+ * Example: MAKE_MASK(3) returns the binary number 00000111.
+ */
+#define MAKE_MASK(n) ((((unsigned) 1) << (n))-1)
+
+
+static
+void copy_bits(const unsigned char* src, /* Base pointer to source. */
+ size_t soffs, /* Bit offset for source relative to src. */
+ unsigned char* dst, /* Destination. */
+ size_t n) /* Number of bits to copy. */
+{
+ unsigned rmask;
+ unsigned count;
+ unsigned deoffs;
+ unsigned bits;
+ unsigned bits1;
+ unsigned rshift;
+
+ if (n == 0)
+ return;
+
+ deoffs = n & 7;
+ rmask = deoffs ? (MAKE_MASK(deoffs) << (8-deoffs)) : 0;
+
+ if (soffs == 0) {
+ unsigned nbytes = (n + 7) / 8;
+ memcpy(dst, src, nbytes);
+ if (rmask)
+ dst[nbytes-1] &= rmask;
+ return;
+ }
+
+ src += soffs / 8;
+ soffs &= 7;
+
+ if (n < 8) { /* Less than one byte */
+ bits = (*src << soffs);
+ if (soffs+n > 8) {
+ src++;
+ bits |= (*src >> (8 - soffs));
+ }
+ *dst = bits & rmask;
+ return;
+ }
+
+ count = n >> 3;
+
+ rshift = 8 - soffs;
+ bits = *src;
+ if (soffs + n > 8) {
+ src++;
+ }
+
+ while (count--) {
+ bits1 = bits << soffs;
+ bits = *src;
+ src++;
+ *dst = bits1 | (bits >> rshift);
+ dst++;
+ }
+
+ if (rmask) {
+ bits1 = bits << soffs;
+ if ((rmask << rshift) & 0xff) {
+ bits = *src;
+ bits1 |= (bits >> rshift);
+ }
+ *dst = bits1 & rmask;
+ }
+}
diff --git a/lib/erl_interface/src/encode/encode_boolean.c b/lib/erl_interface/src/encode/encode_boolean.c
index 61e7e5e6e7..4350c258ee 100644
--- a/lib/erl_interface/src/encode/encode_boolean.c
+++ b/lib/erl_interface/src/encode/encode_boolean.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,12 +32,12 @@ int ei_encode_boolean(char *buf, int *index, int p)
val = p ? "true" : "false";
len = strlen(val);
- if (!buf) s += 3;
+ if (!buf) s += 2;
else {
- put8(s,ERL_ATOM_EXT);
- put16be(s,len);
+ put8(s, ERL_SMALL_ATOM_UTF8_EXT);
+ put8(s, len);
- memmove(s,val,len); /* unterminated string */
+ memcpy(s,val,len); /* unterminated string */
}
s += len;
diff --git a/lib/erl_interface/src/encode/encode_fun.c b/lib/erl_interface/src/encode/encode_fun.c
index 3bfc7530d1..e29424f9f4 100644
--- a/lib/erl_interface/src/encode/encode_fun.c
+++ b/lib/erl_interface/src/encode/encode_fun.c
@@ -26,56 +26,72 @@ int ei_encode_fun(char *buf, int *index, const erlang_fun *p)
{
int ix = *index;
- if (p->arity == -1) {
- /* ERL_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_FUN_EXT);
- put32be(s, p->n_free_vars);
- }
- ix += sizeof(char) + 4;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- } else {
- char *size_p;
- /* ERL_NEW_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_NEW_FUN_EXT);
- size_p = s;
- s += 4;
- put8(s, p->arity);
- memcpy(s, p->md5, sizeof(p->md5));
- s += sizeof(p->md5);
- put32be(s, p->index);
- put32be(s, p->n_free_vars);
- } else
- size_p = NULL;
- ix += 1 + 4 + 1 + sizeof(p->md5) + 4 + 4;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->old_index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- if (size_p != NULL) {
- int sz = buf + ix - size_p;
- put32be(size_p, sz);
+ switch (p->type) {
+ case EI_FUN_CLOSURE:
+ if (p->arity == -1) {
+ /* ERL_FUN_EXT */
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_FUN_EXT);
+ put32be(s, p->u.closure.n_free_vars);
+ }
+ ix += sizeof(char) + 4;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ } else {
+ char *size_p;
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_NEW_FUN_EXT);
+ size_p = s;
+ s += 4;
+ put8(s, p->arity);
+ memcpy(s, p->u.closure.md5, sizeof(p->u.closure.md5));
+ s += sizeof(p->u.closure.md5);
+ put32be(s, p->u.closure.index);
+ put32be(s, p->u.closure.n_free_vars);
+ } else
+ size_p = NULL;
+ ix += 1 + 4 + 1 + sizeof(p->u.closure.md5) + 4 + 4;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.old_index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ if (size_p != NULL) {
+ int sz = buf + ix - size_p;
+ put32be(size_p, sz);
+ }
}
+ break;
+ case EI_FUN_EXPORT:
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_EXPORT_EXT);
+ }
+ ix++;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->u.exprt.func, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->arity) < 0)
+ return -1;
+ break;
}
*index = ix;
return 0;