aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/c_src/Makefile31
-rw-r--r--lib/asn1/c_src/asn1_erl_driver.c1677
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c1305
-rw-r--r--lib/asn1/doc/src/asn1_spec.xmlsrc8
-rw-r--r--lib/asn1/doc/src/asn1_ug.xml50
-rw-r--r--lib/asn1/doc/src/asn1ct.xml35
-rw-r--r--lib/asn1/doc/src/asn1rt.xml65
-rw-r--r--lib/asn1/src/Makefile4
-rw-r--r--lib/asn1/src/asn1.app.src5
-rw-r--r--lib/asn1/src/asn1_app.erl2
-rw-r--r--lib/asn1/src/asn1_server.erl107
-rw-r--r--lib/asn1/src/asn1_sup.erl37
-rw-r--r--lib/asn1/src/asn1ct.erl12
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl12
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl116
-rw-r--r--lib/asn1/src/asn1ct_gen.erl35
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl25
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl5
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl5
-rw-r--r--lib/asn1/src/asn1rt.erl40
-rw-r--r--lib/asn1/src/asn1rt_ber_bin_v2.erl160
-rw-r--r--lib/asn1/src/asn1rt_check.erl2
-rw-r--r--lib/asn1/src/asn1rt_driver_handler.erl144
-rw-r--r--lib/asn1/src/asn1rt_nif.erl87
-rw-r--r--lib/asn1/src/asn1rt_per_bin.erl4
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl131
-rw-r--r--lib/asn1/test/asn1.cover1
-rw-r--r--lib/asn1/test/asn1_SUITE.erl.src6
-rw-r--r--lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src270
-rw-r--r--lib/asn1/test/ber_decode_error.erl6
-rw-r--r--lib/asn1/test/testPrim.erl21
-rw-r--r--lib/compiler/src/erl_bifs.erl1
-rw-r--r--lib/debugger/src/dbg_iload.erl1
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl4
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/public_key/asn1/Makefile2
-rw-r--r--lib/public_key/doc/src/introduction.xml8
-rw-r--r--lib/stdlib/src/erl_internal.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl6
-rw-r--r--lib/stdlib/src/supervisor.erl3
-rw-r--r--lib/stdlib/test/supervisor_1.erl6
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl93
-rw-r--r--lib/stdlib/vsn.mk2
43 files changed, 2084 insertions, 2454 deletions
diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile
index 9e9cb18524..60543df355 100644
--- a/lib/asn1/c_src/Makefile
+++ b/lib/asn1/c_src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2010. All Rights Reserved.
+# Copyright Ericsson AB 2002-2011. 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
@@ -51,33 +51,26 @@ EI_LIBDIR = $(ERL_TOP)/lib/erl_interface/obj$(TYPEMARKER)/$(TARGET)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-EI_INCLUDES = -I$(ERL_TOP)/lib/erl_interface/include
CFLAGS = $(DED_INCLUDES) $(EI_INCLUDES) $(DED_CFLAGS)
LDFLAGS += $(DED_LDFLAGS)
-LD_INCL_EI = -L$(EI_LIBDIR)
-
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-C_FILES = asn1_erl_driver.c
+NIF_OBJ_FILES = $(OBJDIR)/asn1_erl_nif.o
ifeq ($(TARGET),win32)
-LD_EI = -lei_md
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.dll
-OBJ_FILES = $(OBJDIR)/asn1_erl_drv.o
+NIF_SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_nif.dll
CLIB_FLAGS =
LN=cp
else
-LD_EI = -lei
-OBJ_FILES = $(OBJDIR)/asn1_erl_drv.o
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.eld
+NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.eld
CLIB_FLAGS =
else
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.so
+NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.so
CLIB_FLAGS = -lc
endif
LN= ln -s
@@ -87,7 +80,7 @@ endif
# Targets
# ----------------------------------------------------
-opt: $(OBJDIR) $(LIBDIR) $(SHARED_OBJ_FILES)
+opt: $(OBJDIR) $(LIBDIR) $(NIF_SHARED_OBJ_FILE)
debug: opt
@@ -103,11 +96,11 @@ docs:
# ----------------------------------------------------
-$(OBJ_FILES): $(C_FILES)
- $(CC) -c $(CFLAGS) -o $(OBJ_FILES) $(C_FILES)
+$(OBJDIR)/%.o: %.c
+ $(CC) -c $(CFLAGS) -O3 -o $@ $<
-$(SHARED_OBJ_FILES): $(OBJ_FILES)
- $(LD) $(LDFLAGS) $(LD_INCL_EI) -o $(SHARED_OBJ_FILES) $(OBJ_FILES) $(LD_EI) $(CLIB_FLAGS) $(LIBS)
+$(NIF_SHARED_OBJ_FILE): $(NIF_OBJ_FILES)
+ $(LD) $(LDFLAGS) -o $(NIF_SHARED_OBJ_FILE) $(NIF_OBJ_FILES) $(CLIB_FLAGS) $(LIBS)
$(LIBDIR):
-mkdir -p $(LIBDIR)
@@ -124,9 +117,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_PROGRAM) $(SHARED_OBJ_FILES) $(RELSYSDIR)/priv/lib
+ $(INSTALL_PROGRAM) $(NIF_SHARED_OBJ_FILE) $(RELSYSDIR)/priv/lib
$(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DATA) $(C_FILES) $(RELSYSDIR)/c_src
+ $(INSTALL_DATA) *.c $(RELSYSDIR)/c_src
release_docs_spec:
diff --git a/lib/asn1/c_src/asn1_erl_driver.c b/lib/asn1/c_src/asn1_erl_driver.c
deleted file mode 100644
index 18d4157941..0000000000
--- a/lib/asn1/c_src/asn1_erl_driver.c
+++ /dev/null
@@ -1,1677 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2011. 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "erl_driver.h"
-#include "ei.h"
-
-
-/* #define ASN1_DEBUG 1 */
-
-#define ASN1_OK 0
-#define ASN1_ERROR -1
-#define ASN1_COMPL_ERROR 1
-#define ASN1_MEMORY_ERROR 0
-#define ASN1_DECODE_ERROR 2
-#define ASN1_TAG_ERROR -3
-#define ASN1_LEN_ERROR -4
-#define ASN1_INDEF_LEN_ERROR -5
-#define ASN1_VALUE_ERROR -6
-
-
-#define ASN1_CLASS 0xc0
-#define ASN1_FORM 0x20
-#define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)
-#define ASN1_TAG 0x1f
-#define ASN1_LONG_TAG 0x7f
-
-#define ASN1_INDEFINITE_LENGTH 0x80
-#define ASN1_SHORT_DEFINITE_LENGTH 0
-
-#define ASN1_PRIMITIVE 0
-#define ASN1_CONSTRUCTED 0x20
-
-#define ASN1_COMPLETE 1
-#define ASN1_BER_TLV_DECODE 2
-#define ASN1_BER_TLV_PARTIAL_DECODE 3
-
-#define ASN1_NOVALUE 0
-
-#define ASN1_SKIPPED 0
-#define ASN1_OPTIONAL 1
-#define ASN1_CHOOSEN 2
-
-
-#define CEIL(X,Y) ((X-1) / Y + 1)
-
-#define INVMASK(X,M) (X & (M ^ 0xff))
-#define MASK(X,M) (X & M)
-
-typedef struct {
- ErlDrvPort port;
- int buffer_size;
-} asn1_data;
-
-/* int min_alloc_bytes; */
-
-
-static ErlDrvData asn1_drv_start(ErlDrvPort, char *);
-
-static void asn1_drv_stop(ErlDrvData);
-
-int asn1_drv_control(ErlDrvData, unsigned int, char *, int, char **, int);
-
-int complete(ErlDrvBinary **,unsigned char *,unsigned char *, int);
-
-int insert_octets(int, unsigned char **, unsigned char **, int *);
-
-int insert_octets_except_unused(int, unsigned char **, unsigned char **,
- int *, int);
-
-int insert_octets_as_bits_exact_len(int, int, unsigned char **,
- unsigned char **, int *);
-
-int insert_octets_as_bits(int, unsigned char **, unsigned char **,int *);
-
-int pad_bits(int, unsigned char **, int *);
-
-int insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
-
-int insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
-
-int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
-
-int insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
-
-int realloc_decode_buf(ErlDrvBinary **,int);
-
-int realloc_memory(ErlDrvBinary **,int,unsigned char **,unsigned char **);
-
-int decode_begin(ErlDrvBinary **,unsigned char *, int, unsigned int *);
-
-int decode(ErlDrvBinary **,int *,unsigned char *,int *, int);
-
-int decode_tag(char *,int *,unsigned char *,int,int *);
-
-int decode_value(int *,unsigned char *,int *,ErlDrvBinary **,int ,int);
-
-
-/* declaration of functions used for partial decode of a BER encoded
- message */
-
-int decode_partial(ErlDrvBinary **,unsigned char *, int);
-
-int skip_tag(unsigned char *,int *,int);
-
-int skip_length_and_value(unsigned char *,int *,int);
-
-int get_tag(unsigned char *,int *,int);
-
-int get_length(unsigned char *,int *,int *,int);
-
-int get_value(char *,unsigned char *,int *,int);
-
-static ErlDrvEntry asn1_drv_entry = {
- NULL, /* init, always NULL for dynamic drivers */
- asn1_drv_start, /* start, called when port is opened */
- asn1_drv_stop, /* stop, called when port is closed */
- NULL, /* output, called when erlang has sent */
- NULL, /* ready_input, called when input descriptor ready */
- NULL, /* ready_output, called when output descriptor ready */
- "asn1_erl_drv", /* char *driver_name, the argument to open_port */
- NULL, /* finish, called when unloaded */
- NULL, /* void * that is not used (BC) */
- asn1_drv_control, /* control, port_control callback */
- NULL, /* timeout, called on timeouts */
- NULL, /* outputv, vector output interface */
-
- NULL, /* ready_async */
- NULL, /* flush */
- NULL, /* call */
- NULL, /* event */
- ERL_DRV_EXTENDED_MARKER,
- ERL_DRV_EXTENDED_MAJOR_VERSION,
- ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING,
- NULL, /* handle2 */
- NULL /* process_exit */
-};
-
-
-
-DRIVER_INIT(asn1_erl_drv) /* must match name in driver_entry */
-{
- return &asn1_drv_entry;
-}
-
-static ErlDrvData asn1_drv_start(ErlDrvPort port, char *buff)
-{
- /* extern int min_alloc_bytes; */
- char *ptr;
- asn1_data* d;
-
- d = (asn1_data*)driver_alloc(sizeof(asn1_data));
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- d->port = port;
-
- if ((ptr = getenv("ASN1_MIN_BUF_SIZE")) == NULL)
- d->buffer_size = 1024;
- else
- d->buffer_size = atoi(ptr);
- return (ErlDrvData)d;
-}
-
-
-static void asn1_drv_stop(ErlDrvData handle)
-{
- driver_free((char*)handle);
-}
-
-
-
-int asn1_drv_control(ErlDrvData handle,
- unsigned int command,
- char *buf,
- int buf_len,
- char **res_buf,
- int res_buf_len)
-{
- unsigned char *complete_buf;
- int complete_len, decode_len;
- ErlDrvBinary *drv_binary;
- ErlDrvBinary **drv_bin_ptr;
- asn1_data* a_data;
- int min_alloc_bytes;
- unsigned int err_pos = 0; /* in case of error, return last correct position */
- int ret_err; /* return value in case of error in TLV decode, i.e. length of list in res_buf */
-
- /* In case previous call to asn1_drv_control resulted in a change of
- return value from binary to integer list */
- a_data = (asn1_data *)handle;
- min_alloc_bytes = a_data->buffer_size;
- set_port_control_flags(a_data->port, PORT_CONTROL_FLAG_BINARY);
-
- if (command == ASN1_COMPLETE)
- {
- if (buf_len==0) {
- return 0; /* Avoid binary buffer overwrite (OTP-8451) */
- }
- /* Do the PER complete encode step */
- if ((drv_binary = driver_alloc_binary(buf_len))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- complete_buf = (unsigned char*) drv_binary->orig_bytes;
- if ((complete_len = complete(&drv_binary,complete_buf,(unsigned char*) buf,buf_len)) == ASN1_ERROR)
- {
- /* error handling due to failure in complete */
- /* printf("error when running complete\n\r"); */
- driver_free_binary(drv_binary);
- set_port_control_flags(a_data->port, 0);
- **res_buf = '1';
- return ASN1_COMPL_ERROR;
- }
- /* printf("complete_len=%dbuf_len=%d,orig_size=%d\n\r",complete_len,buf_len,drv_binary->orig_size); */
- /* now the message is complete packed, return to Erlang */
- /* if (complete_len < buf_len) {*/
- if (complete_len < drv_binary->orig_size) {
- ErlDrvBinary *tmp;
- if ((tmp=driver_realloc_binary(drv_binary,complete_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(drv_binary);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- drv_binary=tmp;
- }
- *res_buf = (char *)drv_binary;
- return complete_len;
- } else if (command == ASN1_BER_TLV_DECODE) { /* control == 2 */
- /* Do the tlv decode,
- return the resulting term encoded on the Erlang
- external format */
-/* printf("driver: buffer_len = %d, min_alloc_bytes = %d\r\n",buf_len,min_alloc_bytes); */
- if ((drv_binary = driver_alloc_binary((buf_len*5)+min_alloc_bytes))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- drv_bin_ptr = &drv_binary;
- if ((decode_len = decode_begin(drv_bin_ptr,(unsigned char*)buf,buf_len,&err_pos)) <= ASN1_ERROR)
- {
- /* error handling due to failure in decode */
- char tmp_res_buf[5];
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
-
- if(decode_len==ASN1_ERROR)
- tmp_res_buf[0]='1';
- else if(decode_len==ASN1_TAG_ERROR)
- tmp_res_buf[0]='2';
- else if(decode_len==ASN1_LEN_ERROR)
- tmp_res_buf[0]='3';
- else if(decode_len==ASN1_INDEF_LEN_ERROR)
- tmp_res_buf[0]='4';
- else if(decode_len==ASN1_VALUE_ERROR)
- tmp_res_buf[0]='5';
-/* printf("err_pos=%d\r\n",err_pos); */
-/* printf("decode_len:%d\r\n",decode_len); */
- ret_err = 1;
- while(err_pos>0){
- tmp_res_buf[ret_err] =(char)err_pos;/* c;*/
- err_pos = err_pos >> 8;
- ret_err++;
- }
- strncpy(*res_buf,tmp_res_buf,ret_err);
- return ret_err;
- }
-/* printf("decode_len=%d\r\n",decode_len); */
- if (decode_len < ((buf_len * 5) + min_alloc_bytes)) {
- /* not all memory was used => we have to reallocate */
- ErlDrvBinary *tmp;
- if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- *drv_bin_ptr=tmp;
- }
- *res_buf = (char *)(*drv_bin_ptr);
- return decode_len;
- } else { /*command == ASN1_BER_TLV_PARTIAL_DECODE */
- if ((drv_binary = driver_alloc_binary(buf_len))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- drv_bin_ptr = &drv_binary;
- if ((decode_len = decode_partial(drv_bin_ptr,(unsigned char*)buf,buf_len))
- <= ASN1_ERROR) {
- /* error handling due to failure in decode */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
-
-/* printf("asn1_drv_control 1: decode_len=%d\r\n",decode_len); */
-
- if(decode_len==ASN1_ERROR)
- **res_buf = '1';
- return ASN1_DECODE_ERROR;
- }
- if (decode_len < buf_len) {
- /* not all memory was used => we have to reallocate */
- ErlDrvBinary *tmp;
-/* printf("asn1_drv_control 2: decode_len=%d\r\n",decode_len); */
- if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- *drv_bin_ptr=tmp;
- }
- *res_buf = (char *)(*drv_bin_ptr);
- return decode_len;
- }
-}
-
-
-
-/*
- *
- * This section defines functionality for the complete encode of a
- * PER encoded message
- *
- */
-
-int complete(ErlDrvBinary **drv_binary,unsigned char *complete_buf,
- unsigned char *in_buf, int in_buf_len)
-{
- int counter = in_buf_len;
- /* counter keeps track of number of bytes left in the
- input buffer */
-
- int buf_space = in_buf_len;
- /* This is the amount of allocated space left of the complete_buf. It
- is possible when padding is applied that more space is needed than
- was originally allocated. */
-
- int buf_size = in_buf_len;
- /* Size of the buffer. May become reallocated and thus other than
- in_buf_len */
-
- unsigned char *in_ptr, *ptr;
- /* in_ptr points at the next byte in in_buf to be moved to
- complete_buf.
- ptr points into the new completed buffer, complete_buf, at the
- position of the next byte that will be set */
- int unused = 8;
- /* unused = [1,...,8] indicates how many of the rigthmost bits of
- the byte that ptr points at that are unassigned */
-
- int no_bits,no_bytes,in_unused,desired_len,ret, saved_mem, needed, pad_bits;
-
- unsigned char val;
-
- in_ptr = in_buf;
- ptr = complete_buf;
- *ptr = 0x00;
- while(counter > 0) {
- counter--;
-/* printf("*in_ptr = %d\n\r",*in_ptr); */
- switch (*in_ptr) {
- case 0:
- /* just one zero-bit should be added to the buffer */
- if(unused == 1){
- unused = 8;
- *++ptr = 0x00;
- buf_space--;
- } else
- unused--;
- break;
-
- case 1:
- /* one one-bit should be added to the buffer */
- if(unused == 1){
- *ptr = *ptr | 1;
- unused = 8;
- *++ptr = 0x00;
- buf_space--;
- } else {
- *ptr = *ptr | (1 << (unused - 1));
- unused--;
- }
- break;
-
- case 2:
- /* align buffer to end of byte */
- if (unused != 8) {
- *++ptr = 0x00;
- buf_space--;
- unused = 8;
- }
- break;
-
- case 10:
- /* next byte in in_buf tells how many bits in the second next
- byte that will be used */
- /* The leftmost unused bits in the value byte are supposed to be
- zero bits */
- no_bits = (int)*(++in_ptr);
- val = *(++in_ptr);
- counter -= 2;
- if ((ret=insert_least_sign_bits(no_bits,val,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 20:
- /* in this case the next value in_ptr points at holds the number
- of following bytes that holds the value that will be inserted
- in the completed buffer */
- no_bytes = (int)*(++in_ptr);
- counter -= (no_bytes + 1);
- if ((counter<0) ||
- (ret=insert_octets(no_bytes,&in_ptr,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 21:
- /* in this case the next two bytes in_ptr points at holds the number
- of following bytes that holds the value that will be inserted
- in the completed buffer */
- no_bytes = (int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
- counter -= (2 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets(no_bytes,&in_ptr,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 30:
- /* If we call the following bytes, in the buffer in_ptr points at,
- By1,By2,Rest then Rest is the value that will be transfered to
- the completed buffer. By1 tells how many of the rightmost bits in
- Rest that should not be used. By2 is the length of Rest in bytes.*/
- in_unused = (int)*(++in_ptr);
- no_bytes = (int)*(++in_ptr);
- counter -= (2 + no_bytes);
-/* printf("%d: case 30: in_unused=%d, no_bytes=%d,counter=%d\n\r",__LINE__,in_unused,no_bytes,counter); */
- ret = -4711;
- if ((counter<0) ||
- (ret=insert_octets_except_unused(no_bytes,&in_ptr,&ptr,&unused,in_unused)) == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("%d: ret=%d\n\r",__LINE__, ret); */
- buf_space -= ret;
- break;
-
- case 31:
- /* If we call the following bytes, in the buffer in_ptr points at,
- By1,By2,By3,Rest then Rest is the value that will be transfered to
- the completed buffer. By1 tells how many of the rightmost bits in
- Rest that should not be used. By2 and By3 is the length of
- Rest in bytes.*/
- in_unused = (int)*(++in_ptr);
- no_bytes = (int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_except_unused(no_bytes,&in_ptr,&ptr,&unused,in_unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 40:
- /* This case implies that next byte,By1,(..,By1,By2,Bin,...)
- is the desired length of the completed value, maybe needs
- padding zero bits or removal of trailing zero bits from Bin.
- By2 is the length of Bin and Bin is the value that will be
- put into the completed buffer. Each byte in Bin has the value
- 1 or 0.*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- /* This is the algorithm for need of memory reallocation:
- Only when padding (cases 40 - 43,45 - 47) more memory may be
- used than allocated. Therefore one has to keep track of how
- much of the allocated memory that has been saved, i.e. the
- difference between the number of parsed bytes of the input buffer
- and the number of used bytes of the output buffer.
- If saved memory is less than needed for the padding then we
- need more memory. */
- saved_mem = buf_space - counter;
- pad_bits = desired_len - no_bytes - unused;
- needed = (pad_bits > 0) ? CEIL(pad_bits,8) : 0;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (2 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 41:
- /* Same as case 40 apart from By2, the length of Bin, which is in
- two bytes*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 42:
- /* Same as case 40 apart from By1, the desired length, which is in
- two bytes*/
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 43:
- /* Same as case 40 apart from By1 and By2, the desired length and
- the length of Bin, which are in two bytes each. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (4 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 45:
- /* This case assumes that the following bytes in the incoming buffer
- (called By1,By2,Bin) is By1, which is the number of bits (n) that
- will be inserted in the completed buffer. By2 is the number of
- bytes in Bin. Each bit in the buffer Bin should be inserted from
- the leftmost until the nth.*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
-/* printf("buf_space=%d, counter=%d, needed=%d",buf_space,counter,needed); */
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (2 + no_bytes);
-/* printf("calling insert_bits_as_bits: desired_len=%d, no_bytes=%d\n\r",desired_len,no_bytes); */
-/* printf("1in_ptr=%d\n\r",in_ptr); */
-
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("2in_ptr=%d, ptr=%d, complete_buf=%d\n\r",in_ptr,ptr,complete_buf); */
-/* printf("buf_space=%d, ret=%d, counter=%d\n\r",buf_space,ret,counter); */
- buf_space -= ret;
- break;
-
- case 46:
- /* Same as case 45 apart from By1, the desired length, which is
- in two bytes. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 47:
- /* Same as case 45 apart from By1 and By2, the desired length
- and the length of Bin, which are in two bytes each. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (4 + no_bytes);
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- default:
- return ASN1_ERROR;
- }
- in_ptr++;
- }
- /* The returned buffer must be at least one byte and
- it must be octet aligned */
- if ((unused == 8) && (ptr != complete_buf))
- return (ptr - complete_buf);
- else {
- ptr++; /* octet align buffer */
- return (ptr - complete_buf);
- }
-}
-
-
-int realloc_memory(ErlDrvBinary **drv_binary,
- int amount,
- unsigned char **ptr,
- unsigned char **complete_buf) {
-
- ErlDrvBinary *tmp_bin;
- int i;
-
-/* printf("realloc_momory: amount = %d\n",amount); */
- if ((tmp_bin=driver_realloc_binary(*drv_binary,amount)) == NULL) {
- /*error handling due to memory allocation failure */
-/* printf("error when allocating memory\n"); */
- return ASN1_ERROR;
- }else {
- i = *ptr - *complete_buf;
- *drv_binary=tmp_bin;
- *complete_buf = (unsigned char*)(*drv_binary)->orig_bytes;
- *ptr = *complete_buf + i;
- }
- return ASN1_OK;
-}
-
-
-int insert_most_sign_bits(int no_bits,
- unsigned char val,
- unsigned char **output_ptr,
- int *unused) {
- unsigned char *ptr = *output_ptr;
-
- if (no_bits < *unused){
- *ptr = *ptr | (val >> (8 - *unused));
- *unused -= no_bits;
- } else if (no_bits == *unused) {
- *ptr = *ptr | (val >> (8 - *unused));
- *unused = 8;
- *++ptr = 0x00;
- } else {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- *ptr = *ptr | (val << *unused);
- *unused = 8 - (no_bits - *unused);
- }
- *output_ptr = ptr;
- return ASN1_OK;
-}
-
-
-int insert_least_sign_bits(int no_bits,
- unsigned char val,
- unsigned char **output_ptr,
- int *unused) {
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- if (no_bits < *unused){
- *ptr = *ptr | (val << (*unused - no_bits));
- *unused -= no_bits;
- } else if (no_bits == *unused){
- *ptr = *ptr | val;
- *unused = 8;
- *++ptr = 0x00;
- ret++;
- } else {
- /* first in the begun byte in the completed buffer insert
- so many bits that fit, then insert the rest in next byte.*/
- *ptr = *ptr | (val >> (no_bits - *unused));
- *++ptr = 0x00;
- ret++;
- *ptr = *ptr | (val << (8 - (no_bits - *unused)));
- *unused = 8 - (no_bits - *unused);
- }
- *output_ptr = ptr;
- return ret;
-}
-
-/* pad_bits adds no_bits bits in the buffer that output_ptr
- points at.
- */
-int pad_bits(int no_bits, unsigned char **output_ptr, int *unused)
- {
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- while (no_bits > 0) {
- if(*unused == 1){
- *unused = 8;
- *++ptr = 0x00;
- ret++;
- } else
- (*unused)--;
- no_bits--;
- }
- *output_ptr = ptr;
- return ret;
- }
-
-
-/* insert_bits_as_bits removes no_bytes bytes from the buffer that in_ptr
- points at and takes the desired_no leftmost bits from those removed
- bytes and inserts them in the buffer(output buffer) that ptr points at.
- The unused parameter tells how many bits that are not set in the
- actual byte in the output buffer. If desired_no is more bits than the
- input buffer has in no_bytes bytes, then zero bits is padded.*/
-int insert_bits_as_bits(int desired_no,
- int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char val;
- int no_bits, ret, ret2;
-
- if (desired_no == (no_bytes * 8)) {
- if(insert_octets_unaligned(no_bytes,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
- ret = no_bytes;
- }
- else if (desired_no < (no_bytes * 8)) {
-/* printf("insert_bits_as_bits 1\n\r"); */
- if(insert_octets_unaligned(desired_no/8,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("insert_bits_as_bits 2\n\r"); */
- val = *++in_ptr;
-/* printf("val = %d\n\r",(int)val); */
- no_bits = desired_no % 8;
-/* printf("no_bits = %d\n\r",no_bits); */
- insert_most_sign_bits(no_bits,val,output_ptr,unused);
- ret = CEIL(desired_no,8);
- }
- else {
- if(insert_octets_unaligned(no_bytes,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
- ret2 = pad_bits(desired_no - (no_bytes * 8),output_ptr,unused);
-/* printf("ret2 = %d\n\r",ret2); */
- ret = CEIL(desired_no,8);
-/* printf("ret = %d\n\r",ret); */
- }
-/* printf("*unused = %d\n\r",*unused); */
- *input_ptr = in_ptr;
- return ret;
-}
-
-
-/* insert_octets_as_bits_exact_len */
-int
-insert_octets_as_bits_exact_len(int desired_len,
- int in_buff_len,
- unsigned char **in_ptr,
- unsigned char **ptr,
- int *unused)
-{
- int ret = 0;
- int ret2 = 0;
-
- if (desired_len == in_buff_len) {
- if ((ret = insert_octets_as_bits(in_buff_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else if(desired_len > in_buff_len) {
- if((ret = insert_octets_as_bits(in_buff_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- /* now pad with zero bits */
-/* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
- if ((ret2=pad_bits(desired_len - in_buff_len,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else {/* desired_len < no_bits */
- if ((ret=insert_octets_as_bits(desired_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- /* now remove no_bits - desired_len bytes from in buffer */
- *in_ptr += (in_buff_len - desired_len);
- }
- return (ret+ret2);
-}
-
-
-
-/* insert_octets_as_bits takes no_bytes bytes from the buffer that input_ptr
- points at and inserts the least significant bit of it in the buffer that
- output_ptr points at. Each byte in the input buffer must be 1 or 0
- otherwise the function returns ASN1_ERROR. The output buffer is concatenated
- without alignment.
- */
-int insert_octets_as_bits(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int used_bits = 8 - *unused;
-
- while (no_bytes > 0) {
- switch (*++in_ptr) {
- case 0:
- if(*unused == 1){
- *unused = 8;
- *++ptr = 0x00;
- } else
- (*unused)--;
- break;
- case 1:
- if(*unused == 1){
- *ptr = *ptr | 1;
- *unused = 8;
- *++ptr = 0x00;
- } else {
- *ptr = *ptr | (1 << (*unused - 1));
- (*unused)--;
- }
- break;
- default:
- return ASN1_ERROR;
- }
- no_bytes--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return ((used_bits+no_bytes) / 8); /*return number of new bytes
- in completed buffer */
-}
-
-/* insert_octets inserts bytes from the input buffer, *input_ptr,
- into the output buffer, *output_ptr. Before the first byte is
- inserted the input buffer is aligned.
- */
-int insert_octets(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- if (*unused != 8) {/* must align before octets are added */
- *++ptr = 0x00;
- ret++;
- *unused = 8;
- }
- while(no_bytes > 0) {
- *ptr = *(++in_ptr);
- *++ptr = 0x00;
- /* *unused = *unused - 1; */
- no_bytes--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return (ret + no_bytes);
-}
-
-/* insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
- into the output buffer, *output_ptr.No alignment is done.
- */
-int insert_octets_unaligned(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int n = no_bytes;
- unsigned char val;
-
- while (n > 0) {
- if (unused == 8) {
- *ptr = *++in_ptr;
- *++ptr = 0x00;
- }else {
- val = *++in_ptr;
- *ptr = *ptr | val >> (8 - unused);
- *++ptr = 0x00;
- *ptr = val << unused;
- }
- n--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return no_bytes;
-}
-
-
-int insert_octets_except_unused(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused,
- int in_unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int val, no_bits;
- int ret = 0;
-
- if (in_unused == 0){
-/* printf("%d: insert_octets_except_unused: if\n\r",__LINE__); */
- if ((ret = insert_octets_unaligned(no_bytes,&in_ptr,&ptr,
- *unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else {
-/* printf("%d: insert_octets_except_unused: else\n\r",__LINE__); */
- if ((ret=insert_octets_unaligned(no_bytes - 1,&in_ptr,&ptr,*unused)) != ASN1_ERROR) {
- val = (int) *(++in_ptr);
- no_bits = 8 - in_unused;
- /* no_bits is always less than *unused since the buffer is
- octet aligned after insert:octets call, so the following
- if clasuse is obsolete I think */
- if(no_bits < *unused){
- *ptr = *ptr | (val >> (8 - *unused));
- *unused = *unused - no_bits;
- } else if (no_bits == *unused) {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- ret++;
- *unused = 8;
- } else {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- ret++;
- *ptr = *ptr | (val << *unused);
- *unused = 8 - (no_bits - *unused);
- }
- } else
- return ASN1_ERROR;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
-/* printf("%d: insert_octets_except_unused: ret=%d\n\r",__LINE__,ret); */
- return ret;
-}
-
-
-
-/*
- *
- * This section defines functionality for the partial decode of a
- * BER encoded message
- *
- */
-
-/*
- * int decode(ErlDrvBinary **drv_binary,unsigned char *decode_buf,
- * unsigned char *in_buf, int in_buf_len)
- * drv_binary is a pointer to a pointer to an allocated driver binary.
- * in_buf is a pointer into the buffer of incoming bytes.
- * in_buf_len is the length of the incoming buffer.
- * The function reads the bytes in the incoming buffer and structures
- * it in a nested way as Erlang terms. The buffer contains data in the
- * order tag - length - value. Tag, length and value has the following
- * format:
- * A tag is normally one byte but may be of any length, if the tag number
- * is greater than 30. +----------+
- * |CL|C|NNNNN|
- * +----------+
- * If NNNNN is 31 then will the 7 l.s.b of each of the following tag number
- * bytes contain the tag number. Each tag number byte that is not the last one
- * has the m.s.b. set to 1.
- * The length can be short definite length (sdl), long definite length (ldl)
- * or indefinite length (il).
- * sdl: +---------+ the L bits is the length
- * |0|LLLLLLL|
- * +---------+
- * ldl: +---------+ +---------+ +---------+ +-----------+
- * |1|lllllll| |first len| | | |the Nth len|
- * +---------+ +---------+ +---------+ ... +-----------+
- * The first byte tells how many len octets will follow, max 127
- * il: +---------+ +----------------------+ +--------+ +--------+
- * |1|0000000| |content octets (Value)| |00000000| |00000000|
- * +---------+ +----------------------+ +--------+ +--------+
- * The value octets are preceded by one octet and followed by two
- * exactly as above. The value must be some tag-length-value encoding.
- *
- * The function returns a value in Erlnag term format:
- * {{TagNo,Value},Rest}
- * TagNo is an integer ((CL bsl 16) + tag number) which limits the tag number
- * to 65535.
- * Value is a binary if the C bit in tag was unset, otherwise (if tag was
- * constructed) Value is a list, List.
- * List is like: [{TagNo,Value},{TagNo,Value},...]
- * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest
- * is the empty binary.
- * If some error occured during the decoding of the in_buf an error is returned.
- */
-int decode_begin(ErlDrvBinary **drv_binary,unsigned char *in_buf, int in_buf_len, unsigned int *err_pos)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- int ei_index = 0;
- int ib_index = 0;
- /* ei_index is the index used by the ei functions to encode an
- Erlang term into the buffer decode_buf */
- /* ib_index is the index were to read the next byte from in_buf */
-
-
-#ifdef ASN1_DEBUG
- printf("decode_begin1: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- /* the first byte must be a "version magic" */
- if(ei_encode_version(decode_buf,&ei_index) == ASN1_ERROR)
- return ASN1_ERROR; /* 1 byte */
-#ifdef ASN1_DEBUG
- printf("decode_begin2: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- if (ei_encode_tuple_header(decode_buf,&ei_index,2) == ASN1_ERROR)
- return ASN1_ERROR; /* 2 bytes */
-#ifdef ASN1_DEBUG
- printf("decode_begin3: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- if((maybe_ret=decode(drv_binary,&ei_index,in_buf,&ib_index,in_buf_len)) <= ASN1_ERROR)
- {
- *err_pos = ib_index;
-#ifdef ASN1_DEBUG
- printf("err_pos=%d,ib_index=%d\r\n",*err_pos,ib_index);
-#endif
- return maybe_ret;
- };
-
- decode_buf = (*drv_binary)->orig_bytes; /* maybe a realloc during decode_value */
-#ifdef ASN1_DEBUG
- printf("decode_begin4: in_buf_len=%d, ei_index=%d, ib_index=%d\n\r",
- in_buf_len,ei_index,ib_index);
-#endif
- /* "{{TagNo,Value},Rest}" */
- if (ei_encode_binary(decode_buf,&ei_index,&(in_buf[ib_index]),in_buf_len-ib_index)
- == ASN1_ERROR) /* at least 5 bytes */
- return ASN1_ERROR;
-#ifdef ASN1_DEBUG
- printf("decode_begin5: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- return ei_index;
-}
-
-int decode(ErlDrvBinary **drv_binary,int *ei_index,unsigned char *in_buf,
- int *ib_index, int in_buf_len)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- int form;
-#ifdef ASN1_DEBUG
- printf("decode 1\n\r");
-#endif
- if (((*drv_binary)->orig_size - *ei_index) < 19) {/* minimum amount of bytes */
- /* allocate more memory */
- if (realloc_decode_buf(drv_binary,(*drv_binary)->orig_size * 2) ==
- ASN1_ERROR)
- return ASN1_ERROR;
- decode_buf = (*drv_binary)->orig_bytes;
- }
-/* printf("decode 2\n\r"); */
- /* "{" */
- if (ei_encode_tuple_header(decode_buf,ei_index,2) == ASN1_ERROR)
- return ASN1_ERROR; /* 2 bytes */
-#ifdef ASN1_DEBUG
- printf("decode 3:orig_size=%ld, ei_index=%d, ib_index=%d\n\r",(*drv_binary)->orig_size,*ei_index,*ib_index);
-#endif
-
- /*buffer must hold at least two bytes*/
- if ((*ib_index +2) > in_buf_len)
- return ASN1_VALUE_ERROR;
- /* "{{TagNo," */
- if ((form = decode_tag(decode_buf,ei_index,in_buf,in_buf_len,ib_index)) <= ASN1_ERROR)
- return form; /* 5 bytes */
-#ifdef ASN1_DEBUG
- printf("i_i=%d,in_buf_len=%d\r\n",*ei_index,in_buf_len);
-#endif
- if (*ib_index >= in_buf_len){
- return ASN1_TAG_ERROR;
- }
-#ifdef ASN1_DEBUG
- printf("decode 5 ib_index=%d\n\r",*ib_index);
-#endif
- /* buffer must hold at least one byte (0 as length and nothing as
- value) */
- /* "{{TagNo,Value}," */
- if ((maybe_ret=decode_value(ei_index,in_buf,ib_index,drv_binary,form,
- in_buf_len)) <= ASN1_ERROR)
- return maybe_ret; /* at least 5 bytes */
-#ifdef ASN1_DEBUG
- printf("decode 7\n\r");
-#endif
- return *ei_index;
-}
-
-/*
- * decode_tag decodes the BER encoded tag in in_buf and puts it in the
- * decode_buf encoded by the Erlang extern format as an Erlang term.
- */
-int decode_tag(char *decode_buf,int *db_index,unsigned char *in_buf,
- int in_buf_len, int *ib_index)
-{
- int tag_no, tmp_tag, form;
-
-
- /* first get the class of tag and bit shift left 16*/
- tag_no = ((MASK(in_buf[*ib_index],ASN1_CLASS)) << 10);
-
- form = (MASK(in_buf[*ib_index],ASN1_FORM));
-#ifdef ASN1_DEBUG
- printf("decode_tag0:ii=%d, tag_no=%d, form=%d.\r\n",
- *ib_index,tag_no,form);
-#endif
-
- /* then get the tag number */
- if((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
- ei_encode_ulong(decode_buf,db_index,tag_no+tmp_tag); /* usual case */
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag1:ii=%d.\r\n",*ib_index);
-#endif
- }
- else
- {
- int n = 0; /* n is used to check that the 64K limit is not
- exceeded*/
-#ifdef ASN1_DEBUG
- printf("decode_tag1:ii=%d, in_buf_len=%d.\r\n",*ib_index,in_buf_len);
-#endif
-
- /* should check that at least three bytes are left in
- in-buffer,at least two tag byte and at least one length byte */
- if ((*ib_index +3) > in_buf_len)
- return ASN1_VALUE_ERROR;
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag2:ii=%d.\r\n",*ib_index);
-#endif
- /* The tag is in the following bytes in in_buf as
- 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
- is the tag number*/
- /* In practice is the tag size limited to 64K, i.e. 16 bits. If
- the tag is greater then 64K return an error */
- while (((tmp_tag = (int)in_buf[*ib_index]) >= 128) && n < 2){
- /* m.s.b. = 1 */
- tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag3:ii=%d.\r\n",*ib_index);
-#endif
- n++;
- };
- if ((n==2) && in_buf[*ib_index] > 3)
- return ASN1_TAG_ERROR; /* tag number > 64K */
- tag_no = tag_no + in_buf[*ib_index];
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag4:ii=%d.\r\n",*ib_index);
-#endif
- ei_encode_ulong(decode_buf,db_index,tag_no);
- }
- return form;
-}
-
-
-/*
- * decode_value decodes the BER encoded length and value fields in the
- * in_buf and puts the value part in the decode_buf as an Erlang term
- * encoded by the Erlang extern format
- */
-int decode_value(int *ei_index,unsigned char *in_buf,
- int *ib_index,ErlDrvBinary **drv_binary,int form,
- int in_buf_len)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- unsigned int len = 0;
- unsigned int lenoflen = 0;
- int indef = 0;
-
-#ifdef ASN1_DEBUG
- printf("decode_value1:ib_index=%d\n\r",*ib_index);
-#endif
- if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
- len = in_buf[*ib_index];
- }
- else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH)
- indef = 1;
- else /* long definite length */ {
- lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */
-#ifdef ASN1_DEBUG
- printf("decode_value,lenoflen:%d\r\n",lenoflen);
-#endif
- if (lenoflen > (in_buf_len - (*ib_index+1)))
- return ASN1_LEN_ERROR;
- len = 0;
- while (lenoflen-- ) {
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_value1:*ib_index=%d, byte = %d.\r\n",*ib_index,in_buf[*ib_index]);
-#endif
- if (!(len < (1 << (sizeof(len)-1)*8)))
- return ASN1_LEN_ERROR; /* length does not fit in 32 bits */
- len = (len << 8) + in_buf[*ib_index];
- }
- }
- if (len > (in_buf_len - (*ib_index + 1)))
- return ASN1_VALUE_ERROR;
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_value2:ii=%d.\r\n",*ib_index);
-#endif
- if (indef == 1)
- { /* in this case it is desireably to check that indefinite length
- end bytes exist in inbuffer */
- while (!(in_buf[*ib_index]==0 && in_buf[*ib_index + 1]==0)) {
-#ifdef ASN1_DEBUG
- printf("decode_value while:ib_index=%d in_buf_len=%d\n\r",
- *ib_index,in_buf_len);
-#endif
- if(*ib_index >= in_buf_len)
- return ASN1_INDEF_LEN_ERROR;
- ei_encode_list_header(decode_buf,ei_index,1); /* 5 bytes */
- if((maybe_ret=decode(drv_binary,ei_index,in_buf,
- ib_index,in_buf_len)) <= ASN1_ERROR)
- return maybe_ret;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- (*ib_index) += 2; /* skip the indefinite length end bytes */
-#ifdef ASN1_DEBUG
- printf("decode_value3:ii=%d.\r\n",*ib_index);
-#endif
- ei_encode_empty_list(decode_buf,ei_index); /* 1 byte */
- }
- else if (form == ASN1_CONSTRUCTED)
- {
- int end_index = *ib_index + len;
- if(end_index > in_buf_len)
- return ASN1_LEN_ERROR;
- while (*ib_index < end_index) {
-
-#ifdef ASN1_DEBUG
- printf("decode_value3:*ib_index=%d, end_index=%d\n\r",*ib_index,end_index);
-#endif
- ei_encode_list_header(decode_buf,ei_index,1); /* 5 bytes */
- if((maybe_ret=decode(drv_binary,ei_index,in_buf,
- ib_index,in_buf_len))<=ASN1_ERROR)
- return maybe_ret;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- ei_encode_empty_list(decode_buf,ei_index); /* 1 byte */
- }
- else
- {
- if (((*drv_binary)->orig_size - *ei_index) < 10+len) { /* 5+len for the binary*/
- if (realloc_decode_buf(drv_binary,(*drv_binary)->orig_size * 2) ==
- ASN1_ERROR)
- return ASN1_ERROR;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- if((*ib_index + len) > in_buf_len)
- return ASN1_LEN_ERROR;
- ei_encode_binary(decode_buf,ei_index,&in_buf[*ib_index],len);
- *ib_index = *ib_index + len;
-#ifdef ASN1_DEBUG
- printf("decode_value4:ii=%d.\r\n",*ib_index);
-#endif
- }
- return ASN1_OK;
-}
-
-int realloc_decode_buf(ErlDrvBinary **drv_binary,int amount) {
- ErlDrvBinary *tmp_bin;
-
- if ((tmp_bin=driver_realloc_binary(*drv_binary,amount)) == NULL)
- return ASN1_ERROR;
- *drv_binary = tmp_bin;
- return ASN1_OK;
-}
-
-
-
-/*
- * int decode_partial(drv_binary,in_buf,in_buf_len)
- */
-/*
- * The in_buf contains two parts: first information about which value
- * will be decoded, as a sequence of tags and tag codes, then the
- * encoded BER value. First of all comes a length field that tells how
- * many following bytes contains the sequence of tags. Then starts the
- * BER encoded message. The tag sequence length field is a single
- * byte. The sequence of tags/tag codes may be one of the codes
- * ASN1_SKIPPED, ASN1_CHOOSEN and a tag or ASN1_OPTIONAL and a
- * tag. ASN1_SKIPPED means that the following tag is mandatory and is
- * skipped. ASN1_CHOOSEN means that the value of this tag shall, if
- * this was the last tag in tag sequence, be returned or be searched
- * in for the next tag. ASN1_OPTIONAL means that this tag shall be
- * skipped but it may be missing. Each tag in the tag sequence
- * correspond to a tag in the BER encoded message. If the decode
- * arives to a position where there is no matching tag, an error is
- * returned (if it wasn't the last tag and it was OPTIONAL). After the
- * right value has been detected it is returned in the out_buf.
- *
- */
-int decode_partial(ErlDrvBinary **drv_binary,unsigned char *in_buf, int in_buf_len)
-{
- char *out_buf = (*drv_binary)->orig_bytes;
- int tag_index_val = 1;
- int msg_index_val;
- int *msg_index, *tag_index, tmp_index;
- int tag_seq_length;
- int wanted_tag, next_tag;
- int buf_end_index = in_buf_len;
- int ret = 0, length, old_index;
-
- tag_index = &tag_index_val;
- tag_seq_length = in_buf[0];
- msg_index = &msg_index_val;
- *msg_index = tag_seq_length + 1;
-
-
-/* printf("decode_partial 1: in_buf_len=%d, tag_index=%d, msg_index=%d\r\n,tag_seq_length=%d\r\n",in_buf_len,*tag_index,*msg_index,tag_seq_length); */
- while(*tag_index < tag_seq_length) {
- switch(in_buf[*tag_index]) {
- case ASN1_SKIPPED:
-/* printf("decode_partial ASN1_SKIPPED: in_buf[*msg_index]=%d\r\n",in_buf[*msg_index]); */
- (*tag_index)++;
-/* printf("decode_partial ASN1_SKIPPED 2: *msg_index=%d\r\n",*msg_index); */
- skip_tag(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_SKIPPED 3: *msg_index=%d\r\n",*msg_index); */
- skip_length_and_value(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_SKIPPED 4: *msg_index=%d\r\n",*msg_index); */
- break;
- case ASN1_OPTIONAL:
- (*tag_index)++;
-/* printf("decode_partial ASN1_OPTIONAL: in_buf[*tag_index]=%d\r\n",in_buf[*tag_index]); */
- wanted_tag = in_buf[*tag_index];
- (*tag_index)++;
- tmp_index = *msg_index;
- next_tag = get_tag(in_buf,msg_index,buf_end_index);
- if (wanted_tag != next_tag) {
- *msg_index = tmp_index;
- } else
- skip_length_and_value(in_buf,msg_index,buf_end_index);
- break;
- case ASN1_CHOOSEN:
-/* printf("decode_partial ASN1_CHOOSEN: in_buf[*msg_index]=%d, *msg_index=%d\r\n",in_buf[*msg_index],*msg_index); */
- (*tag_index)++;
- wanted_tag = in_buf[*tag_index];
- (*tag_index)++;
- old_index = *msg_index;
-/* printf("decode_partial ASN1_CHOOSEN 2: *msg_index=%d\r\n",*msg_index); */
- next_tag = get_tag(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_CHOOSEN 3: *msg_index=%d\r\n,wanted_tag=%d, next_tag=%d\r\n",*msg_index,wanted_tag,next_tag); */
- if (wanted_tag != next_tag)
- return ASN1_NOVALUE; /* an empty binary will be returned to Erlang */
- if (*tag_index == (tag_seq_length + 1)) {
- /* get the value and return*/
- if((ret = get_value(out_buf,in_buf,msg_index,buf_end_index)) <= ASN1_ERROR)
- return ASN1_ERROR;
- return ret;
- }
- else {
- /* calculate the length of the sub buffer and let *msg_index
- be at the value part of this BER encoded type*/
- int indef;
- indef = 0;
- length = get_length(in_buf,msg_index,&indef,buf_end_index);
-/* printf("decode_partial ASN1_CHOOSEN 4: length=%d, *msg_index=%d\r\n",length,*msg_index); */
- if ((length == 0) && (indef == 1)) {
- /* indefinite length of value */
- old_index = *msg_index;
- length = skip_length_and_value(in_buf,msg_index,buf_end_index);
- *msg_index = old_index;
- buf_end_index = *msg_index + length - 2;
- /* remove two bytes due to indefinete length end zeros */
- } else
- buf_end_index = (*msg_index + length);
- }
- break;
- default:
- return ASN1_ERROR;
- }
- }
- return ASN1_ERROR;
-}
-
-
-/*
- * int skip_tag(unsigned char *in_buf,int *index,int buf_len)
- * steps past the BER encoded tag in in_buf and updates *index.
- * Returns the number of skipped bytes.
- */
-int skip_tag(unsigned char *in_buf,int *index,int buf_len)
-{
- int start_index = *index;
- if ((MASK(in_buf[*index],ASN1_TAG)) == 31){
- do {
- (*index)++;
- if (*index >= buf_len)
- return ASN1_ERROR;
- }
- while(in_buf[*index] >=128);
- }
- (*index)++;
- return (*index - start_index);
-}
-
-
-/*
- * int skip_length_and_value(unsigned char *in_buf,int *index,int buf_len)
- * steps past the BER encoded length and value in in_buf and updates *index.
- * returns the length if the skipped "length value".
- * Returns the number of skipped bytes.
- */
-int skip_length_and_value(unsigned char *in_buf,int *index,int buf_len)
-{
- long len;
- int indef = 0, lenoflen;
- int start_index = *index;
-
- if ((MASK(in_buf[*index],0x80)) == ASN1_SHORT_DEFINITE_LENGTH){
- len = in_buf[*index];
- if (len > (buf_len - (*index + 1)))
- return ASN1_LEN_ERROR;
- } else if (in_buf[*index] == ASN1_INDEFINITE_LENGTH)
- indef = 1;
- else /* long definite length */ {
- lenoflen = (in_buf[*index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*index)++;
- len = (len << 8) + in_buf[*index];
- }
- if (len > (buf_len - (*index + 1)))
- return ASN1_LEN_ERROR;
- }
- (*index)++;
- if (indef == 1)
- {
- while(!(in_buf[*index]==0 && in_buf[*index + 1]==0)) {
- skip_tag(in_buf,index,buf_len);
- skip_length_and_value(in_buf,index,buf_len);
- }
- (*index) += 2;
- }
- else
- (*index) += len;
- return (*index - start_index);
-}
-
-/* int get_tag(unsigned char *in_buf,int *index)
- *
- * assumes next byte/bytes in in_buf is an encoded BER tag. A tag
- * number has theoretically no upper limit in size. Here the tag
- * number is assumed to be less than 64K. Returns an integer value
- * on the format:
- * xxxxxxxx xxxxxxcc tttttttt tttttttt
- * the x-bits are 0 (insignificant)
- * the c-bits are the class of the tag
- * the t-bits are the tag number. This implies that the tag number
- * is limited to 64K-1
- *
- */
-int get_tag(unsigned char *in_buf,int *index,int buf_len)
-{
- int tag_no = 0,tmp_tag = 0;
-
- tag_no = (MASK(in_buf[*index],ASN1_CLASSFORM));
- if ((MASK(in_buf[*index],ASN1_TAG)) == ASN1_TAG) {
- /* long form of tag */
- do {
- (*index)++;
- if (*index >= buf_len)
- return ASN1_TAG_ERROR;
- tmp_tag = tmp_tag << 7;
- tmp_tag += (MASK(in_buf[*index],ASN1_LONG_TAG));
- } while (in_buf[*index] >= 128);
- (*index)++;
- tag_no = tag_no + tmp_tag;
- } else {
- tag_no += (MASK(in_buf[*index],ASN1_TAG));
- (*index)++;
- }
- if (*index >= buf_len)
- return ASN1_TAG_ERROR;
- return tag_no;
-}
-
-
-/*
- * int get_value(char *out_buf,unsigned char *in_buf,
- * int *msg_index,int in_buf_len)
- */
-/* assumes next byte/bytes in in_buf is an encoded BER value preceeded by a BER encoded length. Puts value in out_buf.
- */
-int get_value(char *out_buf,
- unsigned char *in_buf,
- int *msg_index,
- int in_buf_len)
-{
- int len, lenoflen, indef=0, skip_len;
- int ret=0;
- int start_index;
-
-/* printf("get_value 1\n\r"); */
- if (in_buf[*msg_index] < 0x80){ /* short definite length */
- len = in_buf[*msg_index];
-/* printf("short definite length\r\n"); */
- } else if (in_buf[*msg_index] > 0x80) { /* long definite length */
- lenoflen = (in_buf[*msg_index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*msg_index)++;
- len = (len << 8) + in_buf[*msg_index];
- }
- if (len > (in_buf_len - (*msg_index + 1)))
- return ASN1_LEN_ERROR;
- } else
- indef = 1;
- (*msg_index)++;
-/* printf("get_value 2: len = %d, *msg_index = %d\r\n",len,*msg_index); */
- if (indef == 1) {
- while(!(in_buf[*msg_index]==0 && in_buf[*msg_index + 1]==0)) {
- start_index = *msg_index;
- skip_len = skip_tag(in_buf,msg_index,in_buf_len);
-/* printf("get_value 3: skip_len=%d,start_index=%d,*msg_index=%d\n\r", */
-/* skip_len,start_index,*msg_index); */
- memcpy(&out_buf[ret],&in_buf[start_index],skip_len);
- ret += skip_len;
- start_index = *msg_index;
- skip_len = skip_length_and_value(in_buf,msg_index,in_buf_len);
-/* printf("get_value 4: skip_len=%d,start_index=%d,*msg_index=%d\n\r", */
-/* skip_len,start_index,*msg_index); */
- memcpy(&out_buf[ret],&in_buf[start_index],skip_len);
- ret += skip_len;
- }
- return ret;
- }
- else
- memcpy(&out_buf[ret],&in_buf[*msg_index],len);
- return len;
-}
-
-
-/*
- * int get_length(unsigned char *in_buf,int *msg_index)
- * assumes next byte/bytes contain a BER encoded length field,
- * which is decoded. The value of the length is returned. If it
- * is an indefinite length the *indef is set to one.
- */
-int get_length(unsigned char *in_buf,int *msg_index,
- int *indef,int in_buf_len)
-{
- int len=0, lenoflen;
-
- if (in_buf[*msg_index] < 0x80) /* short definite length */
- len = in_buf[*msg_index];
- else if (in_buf[*msg_index] > 0x80) { /* long definite length */
- lenoflen = (in_buf[*msg_index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*msg_index)++;
- len = (len << 8) + in_buf[*msg_index];
- }
- if (len > (in_buf_len - (*msg_index + 1)))
- return ASN1_LEN_ERROR;
- } else
- *indef = 1;
- (*msg_index)++;
- return len;
-}
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
new file mode 100644
index 0000000000..9c9f83bc2a
--- /dev/null
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -0,0 +1,1305 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2002-2011. 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "erl_nif.h"
+
+/* #define ASN1_DEBUG 1 */
+
+#define ASN1_OK 0
+#define ASN1_ERROR -1
+#define ASN1_COMPL_ERROR 1
+#define ASN1_MEMORY_ERROR 0
+#define ASN1_DECODE_ERROR 2
+#define ASN1_TAG_ERROR -3
+#define ASN1_LEN_ERROR -4
+#define ASN1_INDEF_LEN_ERROR -5
+#define ASN1_VALUE_ERROR -6
+
+#define ASN1_CLASS 0xc0
+#define ASN1_FORM 0x20
+#define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)
+#define ASN1_TAG 0x1f
+#define ASN1_LONG_TAG 0x7f
+
+#define ASN1_INDEFINITE_LENGTH 0x80
+#define ASN1_SHORT_DEFINITE_LENGTH 0
+
+#define ASN1_PRIMITIVE 0
+#define ASN1_CONSTRUCTED 0x20
+
+#define ASN1_NOVALUE 0
+
+#define ASN1_SKIPPED 0
+#define ASN1_OPTIONAL 1
+#define ASN1_CHOOSEN 2
+
+#define CEIL(X,Y) ((X-1) / Y + 1)
+
+#define INVMASK(X,M) (X & (M ^ 0xff))
+#define MASK(X,M) (X & M)
+
+/* PER COMPLETE */
+int per_complete(ErlNifBinary *, unsigned char *, int);
+
+int per_insert_octets(int, unsigned char **, unsigned char **, int *);
+
+int per_insert_octets_except_unused(int, unsigned char **, unsigned char **,
+ int *, int);
+
+int per_insert_octets_as_bits_exact_len(int, int, unsigned char **,
+ unsigned char **, int *);
+
+int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *);
+
+int per_pad_bits(int, unsigned char **, int *);
+
+int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
+
+int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
+
+int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
+
+int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
+
+int per_realloc_memory(ErlNifBinary *, int, unsigned char **);
+
+/* BER DECODE */
+int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int,
+ unsigned int *);
+
+int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int);
+
+int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *);
+
+int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int,
+ int);
+
+/* BER ENCODE */
+typedef struct ber_encode_mem_chunk mem_chunk_t;
+
+int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *);
+
+void ber_free_chunks(mem_chunk_t *chunk);
+mem_chunk_t *ber_new_chunk(unsigned int length);
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed);
+
+int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int ,
+ mem_chunk_t **, unsigned int *);
+
+int ber_encode_length(size_t , mem_chunk_t **, unsigned int *);
+
+/*
+ *
+ * This section defines functionality for the complete encode of a
+ * PER encoded message
+ *
+ */
+
+int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf,
+ int in_buf_len) {
+ int counter = in_buf_len;
+ /* counter keeps track of number of bytes left in the
+ input buffer */
+
+ int buf_space = in_buf_len;
+ /* This is the amount of allocated space left of the out_binary. It
+ is possible when padding is applied that more space is needed than
+ was originally allocated. */
+
+ int buf_size = in_buf_len;
+ /* Size of the buffer. May become reallocated and thus other than
+ in_buf_len */
+
+ unsigned char *in_ptr, *ptr;
+ /* in_ptr points at the next byte in in_buf to be moved to
+ complete_buf.
+ ptr points into the new completed buffer, complete_buf, at the
+ position of the next byte that will be set */
+ int unused = 8;
+ /* unused = [1,...,8] indicates how many of the rigthmost bits of
+ the byte that ptr points at that are unassigned */
+
+ int no_bits, no_bytes, in_unused, desired_len, ret, saved_mem, needed,
+ pad_bits;
+
+ unsigned char val;
+
+ in_ptr = in_buf;
+ ptr = out_binary->data;
+ *ptr = 0x00;
+ while (counter > 0) {
+ counter--;
+ switch (*in_ptr) {
+ case 0:
+ /* just one zero-bit should be added to the buffer */
+ if (unused == 1) {
+ unused = 8;
+ *++ptr = 0x00;
+ buf_space--;
+ } else
+ unused--;
+ break;
+
+ case 1:
+ /* one one-bit should be added to the buffer */
+ if (unused == 1) {
+ *ptr = *ptr | 1;
+ unused = 8;
+ *++ptr = 0x00;
+ buf_space--;
+ } else {
+ *ptr = *ptr | (1 << (unused - 1));
+ unused--;
+ }
+ break;
+
+ case 2:
+ /* align buffer to end of byte */
+ if (unused != 8) {
+ *++ptr = 0x00;
+ buf_space--;
+ unused = 8;
+ }
+ break;
+
+ case 10:
+ /* next byte in in_buf tells how many bits in the second next
+ byte that will be used */
+ /* The leftmost unused bits in the value byte are supposed to be
+ zero bits */
+ no_bits = (int) *(++in_ptr);
+ val = *(++in_ptr);
+ counter -= 2;
+ if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 20:
+ /* in this case the next value in_ptr points at holds the number
+ of following bytes that holds the value that will be inserted
+ in the completed buffer */
+ no_bytes = (int) *(++in_ptr);
+ counter -= (no_bytes + 1);
+ if ((counter < 0)
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 21:
+ /* in this case the next two bytes in_ptr points at holds the number
+ of following bytes that holds the value that will be inserted
+ in the completed buffer */
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+ counter -= (2 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 30:
+ /* If we call the following bytes, in the buffer in_ptr points at,
+ By1,By2,Rest then Rest is the value that will be transfered to
+ the completed buffer. By1 tells how many of the rightmost bits in
+ Rest that should not be used. By2 is the length of Rest in bytes.*/
+ in_unused = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ counter -= (2 + no_bytes);
+ ret = -4711;
+ if ((counter < 0)
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
+ &ptr, &unused, in_unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 31:
+ /* If we call the following bytes, in the buffer in_ptr points at,
+ By1,By2,By3,Rest then Rest is the value that will be transfered to
+ the completed buffer. By1 tells how many of the rightmost bits in
+ Rest that should not be used. By2 and By3 is the length of
+ Rest in bytes.*/
+ in_unused = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
+ &ptr, &unused, in_unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 40:
+ /* This case implies that next byte,By1,(..,By1,By2,Bin,...)
+ is the desired length of the completed value, maybe needs
+ padding zero bits or removal of trailing zero bits from Bin.
+ By2 is the length of Bin and Bin is the value that will be
+ put into the completed buffer. Each byte in Bin has the value
+ 1 or 0.*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ /* This is the algorithm for need of memory reallocation:
+ Only when padding (cases 40 - 43,45 - 47) more memory may be
+ used than allocated. Therefore one has to keep track of how
+ much of the allocated memory that has been saved, i.e. the
+ difference between the number of parsed bytes of the input buffer
+ and the number of used bytes of the output buffer.
+ If saved memory is less than needed for the padding then we
+ need more memory. */
+ saved_mem = buf_space - counter;
+ pad_bits = desired_len - no_bytes - unused;
+ needed = (pad_bits > 0) ? CEIL(pad_bits,8) : 0;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (2 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 41:
+ /* Same as case 40 apart from By2, the length of Bin, which is in
+ two bytes*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 42:
+ /* Same as case 40 apart from By1, the desired length, which is in
+ two bytes*/
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 43:
+ /* Same as case 40 apart from By1 and By2, the desired length and
+ the length of Bin, which are in two bytes each. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (4 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 45:
+ /* This case assumes that the following bytes in the incoming buffer
+ (called By1,By2,Bin) is By1, which is the number of bits (n) that
+ will be inserted in the completed buffer. By2 is the number of
+ bytes in Bin. Each bit in the buffer Bin should be inserted from
+ the leftmost until the nth.*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (2 + no_bytes);
+
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 46:
+ /* Same as case 45 apart from By1, the desired length, which is
+ in two bytes. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 47:
+ /* Same as case 45 apart from By1 and By2, the desired length
+ and the length of Bin, which are in two bytes each. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (4 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ default:
+ return ASN1_ERROR;
+ }
+ in_ptr++;
+ }
+ /* The returned buffer must be at least one byte and
+ it must be octet aligned */
+ if ((unused == 8) && (ptr != out_binary->data))
+ return (ptr - out_binary->data);
+ else {
+ ptr++; /* octet align buffer */
+ return (ptr - out_binary->data);
+ }
+}
+
+int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
+
+ int i = *ptr - binary->data;
+
+ if (!enif_realloc_binary(binary, amount)) {
+ /*error handling due to memory allocation failure */
+ return ASN1_ERROR;
+ } else {
+ *ptr = binary->data + i;
+ }
+ return ASN1_OK;
+}
+
+int per_insert_most_sign_bits(int no_bits, unsigned char val,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused -= no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused = 8;
+ *++ptr = 0x00;
+ } else {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ *ptr = *ptr | (val << *unused);
+ *unused = 8 - (no_bits - *unused);
+ }
+ *output_ptr = ptr;
+ return ASN1_OK;
+}
+
+int per_insert_least_sign_bits(int no_bits, unsigned char val,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val << (*unused - no_bits));
+ *unused -= no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | val;
+ *unused = 8;
+ *++ptr = 0x00;
+ ret++;
+ } else {
+ /* first in the begun byte in the completed buffer insert
+ so many bits that fit, then insert the rest in next byte.*/
+ *ptr = *ptr | (val >> (no_bits - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *ptr = *ptr | (val << (8 - (no_bits - *unused)));
+ *unused = 8 - (no_bits - *unused);
+ }
+ *output_ptr = ptr;
+ return ret;
+}
+
+/* per_pad_bits adds no_bits bits in the buffer that output_ptr
+ points at.
+ */
+int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ while (no_bits > 0) {
+ if (*unused == 1) {
+ *unused = 8;
+ *++ptr = 0x00;
+ ret++;
+ } else
+ (*unused)--;
+ no_bits--;
+ }
+ *output_ptr = ptr;
+ return ret;
+}
+
+/* insert_bits_as_bits removes no_bytes bytes from the buffer that in_ptr
+ points at and takes the desired_no leftmost bits from those removed
+ bytes and inserts them in the buffer(output buffer) that ptr points at.
+ The unused parameter tells how many bits that are not set in the
+ actual byte in the output buffer. If desired_no is more bits than the
+ input buffer has in no_bytes bytes, then zero bits is padded.*/
+int per_insert_bits_as_bits(int desired_no, int no_bytes,
+ unsigned char **input_ptr, unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char val;
+ int no_bits, ret, ret2;
+
+ if (desired_no == (no_bytes * 8)) {
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ ret = no_bytes;
+ } else if (desired_no < (no_bytes * 8)) {
+ /* printf("per_insert_bits_as_bits 1\n\r"); */
+ if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr,
+ *unused) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* printf("per_insert_bits_as_bits 2\n\r"); */
+ val = *++in_ptr;
+ /* printf("val = %d\n\r",(int)val); */
+ no_bits = desired_no % 8;
+ /* printf("no_bits = %d\n\r",no_bits); */
+ per_insert_most_sign_bits(no_bits, val, output_ptr, unused);
+ ret = CEIL(desired_no,8);
+ } else {
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
+ /* printf("ret2 = %d\n\r",ret2); */
+ ret = CEIL(desired_no,8);
+ /* printf("ret = %d\n\r",ret); */
+ }
+ /* printf("*unused = %d\n\r",*unused); */
+ *input_ptr = in_ptr;
+ return ret;
+}
+
+/* per_insert_octets_as_bits_exact_len */
+int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
+ unsigned char **in_ptr, unsigned char **ptr, int *unused) {
+ int ret = 0;
+ int ret2 = 0;
+
+ if (desired_len == in_buff_len) {
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else if (desired_len > in_buff_len) {
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* now pad with zero bits */
+ /* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
+ if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else {/* desired_len < no_bits */
+ if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* now remove no_bits - desired_len bytes from in buffer */
+ *in_ptr += (in_buff_len - desired_len);
+ }
+ return (ret + ret2);
+}
+
+/* insert_octets_as_bits takes no_bytes bytes from the buffer that input_ptr
+ points at and inserts the least significant bit of it in the buffer that
+ output_ptr points at. Each byte in the input buffer must be 1 or 0
+ otherwise the function returns ASN1_ERROR. The output buffer is concatenated
+ without alignment.
+ */
+int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int used_bits = 8 - *unused;
+
+ while (no_bytes > 0) {
+ switch (*++in_ptr) {
+ case 0:
+ if (*unused == 1) {
+ *unused = 8;
+ *++ptr = 0x00;
+ } else
+ (*unused)--;
+ break;
+ case 1:
+ if (*unused == 1) {
+ *ptr = *ptr | 1;
+ *unused = 8;
+ *++ptr = 0x00;
+ } else {
+ *ptr = *ptr | (1 << (*unused - 1));
+ (*unused)--;
+ }
+ break;
+ default:
+ return ASN1_ERROR;
+ }
+ no_bytes--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return ((used_bits + no_bytes) / 8); /*return number of new bytes
+ in completed buffer */
+}
+
+/* insert_octets inserts bytes from the input buffer, *input_ptr,
+ into the output buffer, *output_ptr. Before the first byte is
+ inserted the input buffer is aligned.
+ */
+int per_insert_octets(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ if (*unused != 8) {/* must align before octets are added */
+ *++ptr = 0x00;
+ ret++;
+ *unused = 8;
+ }
+ while (no_bytes > 0) {
+ *ptr = *(++in_ptr);
+ *++ptr = 0x00;
+ /* *unused = *unused - 1; */
+ no_bytes--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return (ret + no_bytes);
+}
+
+/* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
+ into the output buffer, *output_ptr.No alignment is done.
+ */
+int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int n = no_bytes;
+ unsigned char val;
+
+ while (n > 0) {
+ if (unused == 8) {
+ *ptr = *++in_ptr;
+ *++ptr = 0x00;
+ } else {
+ val = *++in_ptr;
+ *ptr = *ptr | val >> (8 - unused);
+ *++ptr = 0x00;
+ *ptr = val << unused;
+ }
+ n--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return no_bytes;
+}
+
+int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused, int in_unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int val, no_bits;
+ int ret = 0;
+
+ if (in_unused == 0) {
+ if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else {
+ if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused))
+ != ASN1_ERROR) {
+ val = (int) *(++in_ptr);
+ no_bits = 8 - in_unused;
+ /* no_bits is always less than *unused since the buffer is
+ octet aligned after insert:octets call, so the following
+ if clasuse is obsolete I think */
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused = *unused - no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *unused = 8;
+ } else {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *ptr = *ptr | (val << *unused);
+ *unused = 8 - (no_bits - *unused);
+ }
+ } else
+ return ASN1_ERROR;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return ret;
+}
+
+/*
+ *
+ * This section defines functionality for the partial decode of a
+ * BER encoded message
+ *
+ */
+
+/*
+ * int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int in_buf_len, unsigned int *err_pos)
+ * term is a pointer to the term which is to be returned to erlang
+ * in_buf is a pointer into the buffer of incoming bytes.
+ * in_buf_len is the length of the incoming buffer.
+ * The function reads the bytes in the incoming buffer and structures
+ * it in a nested way as Erlang terms. The buffer contains data in the
+ * order tag - length - value. Tag, length and value has the following
+ * format:
+ * A tag is normally one byte but may be of any length, if the tag number
+ * is greater than 30. +----------+
+ * |CL|C|NNNNN|
+ * +----------+
+ * If NNNNN is 31 then will the 7 l.s.b of each of the following tag number
+ * bytes contain the tag number. Each tag number byte that is not the last one
+ * has the m.s.b. set to 1.
+ * The length can be short definite length (sdl), long definite length (ldl)
+ * or indefinite length (il).
+ * sdl: +---------+ the L bits is the length
+ * |0|LLLLLLL|
+ * +---------+
+ * ldl: +---------+ +---------+ +---------+ +-----------+
+ * |1|lllllll| |first len| | | |the Nth len|
+ * +---------+ +---------+ +---------+ ... +-----------+
+ * The first byte tells how many len octets will follow, max 127
+ * il: +---------+ +----------------------+ +--------+ +--------+
+ * |1|0000000| |content octets (Value)| |00000000| |00000000|
+ * +---------+ +----------------------+ +--------+ +--------+
+ * The value octets are preceded by one octet and followed by two
+ * exactly as above. The value must be some tag-length-value encoding.
+ *
+ * The function returns a value in Erlang nif term format:
+ * {{TagNo,Value},Rest}
+ * TagNo is an integer ((CL bsl 16) + tag number) which limits the tag number
+ * to 65535.
+ * Value is a binary if the C bit in tag was unset, otherwise (if tag was
+ * constructed) Value is a list, List.
+ * List is like: [{TagNo,Value},{TagNo,Value},...]
+ * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest
+ * is the empty binary.
+ * If some error occured during the decoding of the in_buf an error is returned.
+ */
+int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int in_buf_len, unsigned int *err_pos) {
+ int maybe_ret;
+ int ib_index = 0;
+ unsigned char *rest_data;
+ ERL_NIF_TERM decoded_term, rest;
+
+ if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index,
+ in_buf_len)) <= ASN1_ERROR)
+ {
+ *err_pos = ib_index;
+ return maybe_ret;
+ };
+
+ // The remaining binary after one ASN1 segment has been decoded
+ if ((rest_data = enif_make_new_binary(env, in_buf_len - ib_index, &rest))
+ == NULL) {
+ *term = enif_make_atom(env, "could_not_alloc_binary");
+ return ASN1_ERROR;
+ }
+
+ *term = enif_make_tuple2(env, decoded_term, rest);
+ return ASN1_OK;
+}
+
+int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int *ib_index, int in_buf_len) {
+ int maybe_ret;
+ int form;
+ ERL_NIF_TERM tag, value;
+
+ /*buffer must hold at least two bytes*/
+ if ((*ib_index + 2) > in_buf_len)
+ return ASN1_VALUE_ERROR;
+ /* "{{TagNo," */
+ if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index))
+ <= ASN1_ERROR
+ )
+ return form; /* 5 bytes */
+ if (*ib_index >= in_buf_len) {
+ return ASN1_TAG_ERROR;
+ }
+ /* buffer must hold at least one byte (0 as length and nothing as
+ value) */
+ /* "{{TagNo,Value}," */
+ if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form,
+ in_buf_len)) <= ASN1_ERROR
+ )
+ return maybe_ret; /* at least 5 bytes */
+ *term = enif_make_tuple2(env, tag, value);
+ return ASN1_OK;
+}
+
+/*
+ * decode_tag decodes the BER encoded tag in in_buf and creates an
+ * nif term tag
+ */
+int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
+ int in_buf_len, int *ib_index) {
+ int tag_no, tmp_tag, form;
+
+ /* first get the class of tag and bit shift left 16*/
+ tag_no = ((MASK(in_buf[*ib_index],ASN1_CLASS)) << 10);
+
+ form = (MASK(in_buf[*ib_index],ASN1_FORM));
+
+ /* then get the tag number */
+ if ((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
+ *tag = enif_make_uint(env, tag_no + tmp_tag);
+ (*ib_index)++;
+ } else {
+ int n = 0; /* n is used to check that the 64K limit is not
+ exceeded*/
+
+ /* should check that at least three bytes are left in
+ in-buffer,at least two tag byte and at least one length byte */
+ if ((*ib_index + 3) > in_buf_len)
+ return ASN1_VALUE_ERROR;
+ (*ib_index)++;
+ /* The tag is in the following bytes in in_buf as
+ 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
+ is the tag number*/
+ /* In practice is the tag size limited to 64K, i.e. 16 bits. If
+ the tag is greater then 64K return an error */
+ while (((tmp_tag = (int) in_buf[*ib_index]) >= 128) && n < 2) {
+ /* m.s.b. = 1 */
+ tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
+ (*ib_index)++;
+ n++;
+ };
+ if ((n == 2) && in_buf[*ib_index] > 3)
+ return ASN1_TAG_ERROR; /* tag number > 64K */
+ tag_no = tag_no + in_buf[*ib_index];
+ (*ib_index)++;
+ *tag = enif_make_uint(env, tag_no);
+ }
+ return form;
+}
+
+/*
+ * ber_decode_value decodes the BER encoded length and value fields in the
+ * in_buf and puts the value part in the decode_buf as an Erlang
+ * nif term into value
+ */
+int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
+ int *ib_index, int form, int in_buf_len) {
+ int maybe_ret;
+ unsigned int len = 0;
+ unsigned int lenoflen = 0;
+ int indef = 0;
+ unsigned char *tmp_out_buff;
+ ERL_NIF_TERM term = 0, curr_head = 0;
+
+ if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
+ len = in_buf[*ib_index];
+ } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH
+ )
+ indef = 1;
+ else /* long definite length */{
+ lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */
+ if (lenoflen > (in_buf_len - (*ib_index + 1)))
+ return ASN1_LEN_ERROR;
+ len = 0;
+ while (lenoflen--) {
+ (*ib_index)++;
+ if (!(len < (1 << (sizeof(len) - 1) * 8)))
+ return ASN1_LEN_ERROR; /* length does not fit in 32 bits */
+ len = (len << 8) + in_buf[*ib_index];
+ }
+ }
+ if (len > (in_buf_len - (*ib_index + 1)))
+ return ASN1_VALUE_ERROR;
+ (*ib_index)++;
+ if (indef == 1) { /* in this case it is desireably to check that indefinite length
+ end bytes exist in inbuffer */
+ curr_head = enif_make_list(env, 0);
+ while (!(in_buf[*ib_index] == 0 && in_buf[*ib_index + 1] == 0)) {
+ if (*ib_index >= in_buf_len)
+ return ASN1_INDEF_LEN_ERROR;
+
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len))
+ <= ASN1_ERROR
+ )
+ return maybe_ret;
+ curr_head = enif_make_list_cell(env, term, curr_head);
+ }
+ enif_make_reverse_list(env, curr_head, value);
+ (*ib_index) += 2; /* skip the indefinite length end bytes */
+ } else if (form == ASN1_CONSTRUCTED)
+ {
+ int end_index = *ib_index + len;
+ if (end_index > in_buf_len)
+ return ASN1_LEN_ERROR;
+ curr_head = enif_make_list(env, 0);
+ while (*ib_index < end_index) {
+
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
+ in_buf_len)) <= ASN1_ERROR
+ )
+ return maybe_ret;
+ curr_head = enif_make_list_cell(env, term, curr_head);
+ }
+ enif_make_reverse_list(env, curr_head, value);
+ } else {
+ if ((*ib_index + len) > in_buf_len)
+ return ASN1_LEN_ERROR;
+ tmp_out_buff = enif_make_new_binary(env, len, value);
+ memcpy(tmp_out_buff, in_buf + *ib_index, len);
+ *ib_index = *ib_index + len;
+ }
+ return ASN1_OK;
+}
+
+struct ber_encode_mem_chunk {
+ mem_chunk_t *next;
+ int length;
+ char *top;
+ char *curr;
+};
+
+int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) {
+
+ const ERL_NIF_TERM *tv;
+ unsigned int form;
+ int arity;
+
+ if (!enif_get_tuple(env, term, &arity, &tv))
+ return ASN1_ERROR;
+
+ form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE;
+
+ switch (form) {
+ case ASN1_PRIMITIVE: {
+ ErlNifBinary value;
+ if (!enif_inspect_binary(env, tv[1], &value))
+ return ASN1_ERROR;
+
+ if (ber_check_memory(curr, value.size))
+ return ASN1_ERROR;
+ memcpy((*curr)->curr - value.size + 1, value.data, value.size);
+ (*curr)->curr -= value.size;
+ *count += value.size;
+
+ if (ber_encode_length(value.size, curr, count))
+ return ASN1_ERROR;
+
+ break;
+ }
+ case ASN1_CONSTRUCTED: {
+ ERL_NIF_TERM head, tail;
+ unsigned int tmp_cnt;
+
+ if(!enif_make_reverse_list(env, tv[1], &head))
+ return ASN1_ERROR;
+
+ if (!enif_get_list_cell(env, head, &head, &tail)) {
+ if (enif_is_empty_list(env, tv[1])) {
+ *((*curr)->curr) = 0;
+ (*curr)->curr -= 1;
+ (*count)++;
+ break;
+ } else
+ return ASN1_ERROR;
+ }
+
+ do {
+ tmp_cnt = 0;
+ if (ber_encode(env, head, curr, &tmp_cnt)) {
+ return ASN1_ERROR;
+ }
+ *count += tmp_cnt;
+ } while (enif_get_list_cell(env, tail, &head, &tail));
+
+ if (ber_check_memory(curr, *count)) {
+ return ASN1_ERROR;
+ }
+
+ if (ber_encode_length(*count, curr, count)) {
+ return ASN1_ERROR;
+ }
+
+ break;
+ }
+ }
+
+ // We need atleast 5 bytes to encode the next tlv
+ if (ber_check_memory(curr, 3))
+ return ASN1_ERROR;
+
+ if (ber_encode_tag(env, tv[0], form, curr, count))
+ return ASN1_ERROR;
+
+ return ASN1_OK;
+}
+
+int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form,
+ mem_chunk_t **curr, unsigned int *count) {
+ unsigned int class_tag_no, head_tag;
+ if (!enif_get_uint(env, tag, &class_tag_no))
+ return ASN1_ERROR;
+
+ head_tag = form | ((class_tag_no & 0x30000) >> 10);
+ class_tag_no = class_tag_no & 0xFFFF;
+
+ if (class_tag_no <= 30) {
+ *(*curr)->curr = head_tag | class_tag_no;
+ (*curr)->curr -= 1;
+ (*count)++;
+ return ASN1_OK;
+ } else {
+ *(*curr)->curr = class_tag_no & 127;
+ class_tag_no = class_tag_no >> 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ while (class_tag_no > 0) {
+ *(*curr)->curr = (class_tag_no & 127) | 0x80;
+ class_tag_no >>= 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = head_tag | 0x1F;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ return ASN1_OK;
+ }
+}
+
+int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) {
+ if (size < 128) {
+ if (ber_check_memory(curr, 1u))
+ return ASN1_ERROR;
+ *(*curr)->curr = size;
+ (*curr)->curr -= 1;
+ (*count)++;
+ } else {
+ int chunks = size / 256 + 1;
+ if (ber_check_memory(curr, chunks + 1))
+ return ASN1_ERROR;
+
+ while (size > 0)
+ {
+ *(*curr)->curr = size & 0xFF;
+ size >>= 8;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = chunks | 0x80;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+ return ASN1_OK;
+}
+
+mem_chunk_t *ber_new_chunk(unsigned int length) {
+ mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t));
+ if (new == NULL)
+ return NULL;
+ new->next = NULL;
+ new->top = enif_alloc(sizeof(char) * length);
+ if (new->top == NULL) {
+ free(new);
+ return NULL;
+ }
+ new->curr = new->top + length - 1;
+ new->length = length;
+ return new;
+}
+
+void ber_free_chunks(mem_chunk_t *chunk) {
+ mem_chunk_t *curr, *next = chunk;
+ while (next != NULL) {
+ curr = next;
+ next = curr->next;
+ enif_free(curr->top);
+ enif_free(curr);
+ }
+}
+
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed) {
+ mem_chunk_t *new;
+ if ((*curr)->curr-needed >= (*curr)->top)
+ return ASN1_OK;
+
+ if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL)
+ return ASN1_ERROR;
+ new->next = *curr;
+ *curr = new;
+ return ASN1_OK;
+}
+
+static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ERL_NIF_TERM err_code;
+ ErlNifBinary in_binary;
+ ErlNifBinary out_binary;
+ int complete_len;
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
+ return enif_make_atom(env, "badarg");
+
+ if (!enif_alloc_binary(in_binary.size, &out_binary))
+ return enif_make_atom(env, "alloc_binary_failed");
+
+ if (in_binary.size == 0)
+ return enif_make_binary(env, &out_binary);
+
+ if ((complete_len = per_complete(&out_binary, in_binary.data,
+ in_binary.size)) <= ASN1_ERROR) {
+ enif_release_binary(&out_binary);
+ if (complete_len == ASN1_ERROR
+ )
+ err_code = enif_make_uint(env, '1');
+ else
+ err_code = enif_make_uint(env, 0);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
+ }
+ if (complete_len < out_binary.size)
+ enif_realloc_binary(&out_binary, complete_len);
+
+ return enif_make_binary(env, &out_binary);
+}
+
+static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ErlNifBinary in_binary;
+ ERL_NIF_TERM return_term;
+ unsigned int err_pos = 0, return_code;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
+ return enif_make_badarg(env);
+
+ if ((return_code = ber_decode_begin(env, &return_term, in_binary.data,
+ in_binary.size, &err_pos)) != ASN1_OK
+ )
+ return enif_make_tuple2(env, enif_make_atom(env,"error"), enif_make_tuple2(env,
+ enif_make_int(env, return_code),enif_make_int(env, err_pos)));
+ return return_term;
+}
+
+static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ErlNifBinary out_binary;
+ unsigned int length = 0, pos = 0;
+ int encode_err;
+ mem_chunk_t *curr, *top;
+ ERL_NIF_TERM err_code;
+
+ curr = ber_new_chunk(40);
+
+ if ((encode_err = ber_encode(env, argv[0], &curr, &length))
+ <= ASN1_ERROR) {
+ ber_free_chunks(curr);
+ err_code = enif_make_int(env, encode_err);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
+ }
+
+ if (!enif_alloc_binary(length, &out_binary)) {
+ ber_free_chunks(curr);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env,"oom"));
+ }
+
+ top = curr;
+
+ while (curr != NULL) {
+ length = curr->length - (curr->curr-curr->top) -1;
+ if (length > 0)
+ memcpy(out_binary.data + pos, curr->curr+1, length);
+ pos += length;
+ curr = curr->next;
+ }
+
+ ber_free_chunks(top);
+
+ return enif_make_binary(env, &out_binary);
+}
+
+static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) {
+ int i;
+ return enif_get_int(env, load_info, &i) && i == 1;
+}
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) {
+ if (!is_ok_load_info(env, load_info))
+ return -1;
+ return 0;
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info) {
+ if (!is_ok_load_info(env, load_info))
+ return -1;
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data) {
+
+}
+
+static ErlNifFunc nif_funcs[] = { { "encode_per_complete", 1,
+ encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv }, {
+ "encode_ber_tlv", 1, encode_ber_tlv } };
+
+ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload)
diff --git a/lib/asn1/doc/src/asn1_spec.xmlsrc b/lib/asn1/doc/src/asn1_spec.xmlsrc
index 8d61834da8..07cba17816 100644
--- a/lib/asn1/doc/src/asn1_spec.xmlsrc
+++ b/lib/asn1/doc/src/asn1_spec.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,7 +43,7 @@
<p>So far this functionality is only provided when using the
optimized BER_BIN version, that is when compiling with the
options <c>ber_bin</c> and <c>optimize</c>. It does also work
- using the <c>driver</c> option. We have no intent to make this
+ using the <c>nif</c> option. We have no intent to make this
available on the default BER version, but maybe in the PER_BIN
version (<c>per_bin</c>).
</p>
@@ -661,7 +661,9 @@ ValAction = {'Action',17,{'Button',4711,false}}.
<p>The ASN.1 specs in the test are compiled with the options
<c>ber_bin, optimize, driver</c> and <c>asn1config</c>. If the
<c>driver</c> option had been omitted there should have been
- higher values for <c>decode</c> and <c>decode_part</c>.
+ higher values for <c>decode</c> and <c>decode_part</c>. These tests have
+ not been re-run using nifs, but are expected to perform about 5% better
+ than the linked-in driver.
</p>
<p>The test program runs 10000 decodes on the value, resulting
in a printout with the elapsed time in microseconds for the
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml
index 12d986308f..1b399fb641 100644
--- a/lib/asn1/doc/src/asn1_ug.xml
+++ b/lib/asn1/doc/src/asn1_ug.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -347,7 +347,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
<p>This flag has effect only when used together with one of
<c>per_bin</c> or <c>ber_bin</c> flags. It gives time optimized
code in the generated modules and it uses another runtime module.
- In the <c>per_bin</c> case a linked-in driver is used. The
+ In the <c>per_bin</c> case a nif is used. The
result from an encode is a binary.</p>
<p><em>When this flag is used you cannot use the old format</em><c>{TypeName,Value}</c> when you encode values. Since it is
an unnecessary construct it has been removed in favor of
@@ -362,9 +362,14 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>+driver</c></tag>
<item>
- <p>Together with the flags <c>ber_bin</c> and <c>optimize</c>
- you choose to use a linked in driver for considerable faster
- decode.</p>
+ <p>As of R15B this means the same as the <c>nif</c> option. Kept for
+ backwards compatability reasons.</p>
+ </item>
+ <tag><c>+nif</c></tag>
+ <item>
+ <p>Together with the flags <c>ber_bin</c>
+ and <c>optimize</c> you choose to use a nif for considerable
+ faster encode and decode. </p>
</item>
<tag><c>+asn1config</c></tag>
<item>
@@ -492,7 +497,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</row>
<row>
<cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
<cell align="left" valign="middle">EAVF</cell>
<cell align="left" valign="middle">iolist</cell>
<cell align="left" valign="middle">iolist / binary</cell>
@@ -557,7 +562,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</row>
<row>
<cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver, der]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
<cell align="left" valign="middle">EAVF</cell>
<cell align="left" valign="middle">iolist</cell>
<cell align="left" valign="middle">binary</cell>
@@ -626,23 +631,24 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</table>
<p>
- The sole compile options <c>ber</c>, <c>ber_bin</c> and <c>per</c>
- are kept for backwards compatibility and should not be used in
- new code.
+ The compile options <c>ber</c>, <c>per</c> and
+ <c>driver</c> are kept for backwards compatibility and should not be
+ used in new code. The nif implementation which replaces the linked-in
+ driver has been shown to be about 5-15% faster.
</p>
<p>
You are strongly recommended to use the appropriate alternative
of the bold typed options. The <c>optimize</c> and
- <c>driver</c> options does not affect the encode or decode
+ <c>nif</c> options does not affect the encode or decode
result, just the time spent in run-time. When <c>ber_bin</c> and
- <c>driver</c> or <c>per_bin, optimize</c> and <c>driver</c> is
- combined the C-code driver is used in chosen parts of encode /
+ <c>nif</c> or <c>per_bin</c> and <c>optimize</c> is
+ combined the C-code nif is used in chosen parts of encode /
decode procedure.
</p>
<table>
<row>
<cell align="left" valign="middle"><em>Compile options, allowed combinations</em></cell>
- <cell align="left" valign="middle"><em>use of linked-in driver</em></cell>
+ <cell align="left" valign="middle"><em>use of nif</em></cell>
</row>
<row>
<cell align="left" valign="middle">[ber]</cell>
@@ -657,7 +663,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<cell align="left" valign="middle">no</cell>
</row>
<row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
<cell align="left" valign="middle">yes</cell>
</row>
<row>
@@ -690,12 +696,12 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<cell align="left" valign="middle">no</cell>
</row>
<row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver, der]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
<cell align="left" valign="middle">yes</cell>
</row>
- <tcaption>When the ASN1 linked-in driver is used.</tcaption>
+ <tcaption>When the ASN1 nif is used.</tcaption>
</table>
</section>
@@ -712,14 +718,14 @@ asn1rt:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<pre>
'H323-MESSAGES':encode('SomeChoiceType',{call,"octetstring"}).
'H323-MESSAGES':decode('SomeChoiceType',Bytes). </pre>
- <p>The asn1 linked-in driver is enabled in two occasions: encoding of
+ <p>The asn1 nif is enabled in two occasions: encoding of
asn1 values when the asn1 spec is compiled with <c>per_bin</c> and
<c>optimize</c> or decode of encoded asn1 values when the asn1 spec is
- compiled with <c>ber_bin</c>, <c>optimize</c> and <c>driver</c>. In
- those cases the driver will be loaded automatically at the first call
+ compiled with <c>ber_bin</c>, <c>optimize</c> and <c>nif</c>. In
+ those cases the nif will be loaded automatically at the first call
to <c>encode</c>/<c>decode</c>. If one doesn't want the performance
- overhead of the driver being loaded at the first call it is possible
- to load the driver separately by <c>asn1rt:load_driver()</c>. </p>
+ overhead of the nif being loaded at the first call it is possible
+ to load the nif separately by loading the <c>asn1rt_nif</c> module.</p>
<p>By invoking the function <c>info/0</c> in a generated module, one
gets information about which compiler options were used.</p>
</section>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 265f8735c2..13e6977419 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -52,7 +52,7 @@
<v>Options = [Option| OldOption]</v>
<v>Option = ber_bin | per_bin | uper_bin | der | compact_bit_string |
noobj | {n2n,EnumTypeName} |{outdir,Dir} | {i,IncludeDir} | optimize |
- driver | asn1config | undec_rest | {inline,OutputName} | inline |
+ nif | asn1config | undec_rest | {inline,OutputName} | inline |
{macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose</v>
<v>OldOption = ber | per</v>
<v>Reason = term()</v>
@@ -212,16 +212,21 @@ Binary = binary()
<c>per_bin</c>
or <c>ber_bin</c> option. It gives time optimized code
generated and it uses another runtime module and
- in the <c>per_bin</c> case a linked-in driver. The result
+ in the <c>per_bin</c> case a nif. The result
in the <c>per_bin</c> case from an encode when compiled
with this option will be a binary.</p>
</item>
<tag><c>driver</c></tag>
<item>
+ <p>As of R15B this means the same as the <c>nif</c> option. Kept for
+ backwards compatability reasons.</p>
+ </item>
+ <tag><c>nif</c></tag>
+ <item>
<p>Option valid together with <c>ber_bin</c> and <c>optimize</c>
- options. It enables the use of a linked-in driver that gives
- considerable faster decode. In <c>ber_bin</c> the driver is
- enabled only by explicit use of the option <c>driver</c>.</p>
+ options. It enables the use of several nifs that gives faster
+ encode and decode. Nifs are only enabled by the explicit use of
+ the option <c>nif</c></p>
</item>
<tag><c>asn1config</c></tag>
<item>
@@ -264,7 +269,11 @@ Binary = binary()
<c>.set.asn</c> are exported, unless a
<c>{export,[atom()]}</c> or <c>{export_all,true}</c> option
are provided. The list of atoms are names of chosen asn1
- specs from the <c>.set.asn</c> file.</p>
+ specs from the <c>.set.asn</c> file. </p>
+ <p>When used together with <c>nif</c> for <c>ber_bin</c>, the
+ asn1 nifs will be used if the <c>asn1rt_nif</c> module is
+ available. If it is not available, a slower erlang fallback
+ will be used.</p>
</item>
<tag><c>inline</c></tag>
<item>
@@ -343,18 +352,6 @@ Binary = binary()
</desc>
</func>
<func>
- <name>validate(Module,Type,Value) -> ok | {error,Reason}</name>
- <fsummary>Validate an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- </type>
- <desc>
- <p>Validates that <c>Value</c> conforms to <c>Type</c>
- from <c>Module</c>. <em>Not implemented in this version of the ASN.1 application.</em></p>
- </desc>
- </func>
- <func>
<name>value(Module ,Type) -> {ok,Value} | {error,Reason}</name>
<fsummary>Create an ASN.1 value for test purposes.</fsummary>
<type>
diff --git a/lib/asn1/doc/src/asn1rt.xml b/lib/asn1/doc/src/asn1rt.xml
index 1217a07e9b..0c3c257189 100644
--- a/lib/asn1/doc/src/asn1rt.xml
+++ b/lib/asn1/doc/src/asn1rt.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,36 +42,6 @@
<funcs>
<func>
- <name>start() -> ok |{error,Reason}</name>
- <fsummary>Starts the asn1 server.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Starts the asn1 server that loads the drivers.</p>
- <p>The server schedules a driver that is not blocked by
- another caller. The driver is used by the asn1 application if
- specs are compiled with options <c>[per_bin, optimize]</c> or
- <c>[ber_bin, optimize, driver]</c>. The server will be started
- automatically at encode/decode if it isn't done explicitly. If
- encode/decode with driver is used in test or industrial code
- it is a performance gain to start it explicitly to avoid the
- one time load in run-time.</p>
- </desc>
- </func>
-
- <func>
- <name>stop() -> ok |{error,Reason}</name>
- <fsummary>Stops the asn1 server.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Stops the asn1 server and unloads the drivers.</p>
- </desc>
- </func>
-
- <func>
<name>decode(Module,Type,Bytes) -> {ok,Value}|{error,Reason}</name>
<fsummary>Decode from bytes into an ASN.1 value.</fsummary>
<type>
@@ -126,35 +96,23 @@
<func>
<name>load_driver() -> ok | {error,Reason}</name>
- <fsummary>Loads the linked-in driver.</fsummary>
+ <fsummary>Loads the linked-in driver. (deprecated)</fsummary>
<type>
<v>Reason = term()</v>
</type>
<desc>
- <p>This function loads the linked-in driver before the first call
- to encode. If this function is not called the driver will be loaded
- automatically at the first call to encode. If one doesn't want the
- performance cost of a driver load when the application is running,
- this function makes it possible to load the driver in an
- initialization.</p>
- <p>The driver is only used when encoding/decoding ASN.1 files that
- were compiled with the options <c>per_bin</c> and <c>optimize</c>.</p>
+ <p>This function is obsolete and will be removed in R16A</p>
</desc>
</func>
<func>
<name>unload_driver() -> ok | {error,Reason}</name>
- <fsummary>Unloads the linked-in driver.</fsummary>
+ <fsummary>Unloads the linked-in driver. (deprecated)</fsummary>
<type>
<v>Reason = term()</v>
</type>
<desc>
- <p>This function unloads the linked-in driver.
- When the driver has been loaded it remains in the environment until
- it is unloaded. Normally the driver should remain loaded, it is
- crucial for the performance of ASN.1 encoding. </p>
- <p>The driver is only used when ASN.1 modules have been compiled
- with the flags <c>per_bin</c> and <c>optimize</c>.</p>
+ <p>This function is obsolete and will be removed in R16A</p>
</desc>
</func>
@@ -188,19 +146,6 @@
value, to a UTF8 encoded binary.</p>
</desc>
</func>
-
- <func>
- <name>validate(Module,Type,Value) -> ok | {error,Reason}</name>
- <fsummary>Validate an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- </type>
- <desc>
- <p>Validates that <c>Value</c> conforms to <c>Type</c>
- from <c>Module</c>. <em>Not implemented in this version of the ASN.1 application.</em></p>
- </desc>
- </func>
</funcs>
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 2733cde3f8..3a59773d93 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-2011. 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
@@ -68,7 +68,7 @@ RT_MODULES= \
asn1rt_per_bin_rt2ct \
asn1rt_uper_bin \
asn1rt_check \
- asn1rt_driver_handler
+ asn1rt_nif
# asn1_sup \
# asn1_app \
# asn1_server
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index abacb0a1e9..09144ba2f7 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -9,12 +9,11 @@
asn1rt_ber_bin,
asn1rt_ber_bin_v2,
asn1rt_check,
- asn1rt_driver_handler
+ asn1rt_nif
]},
{registered, [
asn1_ns,
- asn1db,
- asn1_driver_owner
+ asn1db
]},
{env, []},
{applications, [kernel, stdlib]}
diff --git a/lib/asn1/src/asn1_app.erl b/lib/asn1/src/asn1_app.erl
index 2d3eed1743..9fff96e0bf 100644
--- a/lib/asn1/src/asn1_app.erl
+++ b/lib/asn1/src/asn1_app.erl
@@ -28,7 +28,7 @@
%% {error, Reason}
%%
start(_Type, _StartArgs) ->
- asn1_sup:start_link().
+ {ok, self()}.
%% stop(State)
%%
diff --git a/lib/asn1/src/asn1_server.erl b/lib/asn1/src/asn1_server.erl
deleted file mode 100644
index aeb59d8b0c..0000000000
--- a/lib/asn1/src/asn1_server.erl
+++ /dev/null
@@ -1,107 +0,0 @@
-%% ``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 via the world wide web 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.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-
-%% Purpose: Provide complete encode/and pre-decode of asn1.
--module(asn1_server).
-
-
-
--behaviour(gen_server).
-
--export([start_link/0,client_port/0]).
-
-%% Internal exports, call-back functions.
--export([init/1,handle_call/3,handle_cast/2,handle_info/2,code_change/3,
- terminate/2]).
-
-
-%% Macros
--define(port_names,
- { asn1_drv01, asn1_drv02, asn1_drv03, asn1_drv04,
- asn1_drv05, asn1_drv06, asn1_drv07, asn1_drv08,
- asn1_drv09, asn1_drv10, asn1_drv11, asn1_drv12,
- asn1_drv13, asn1_drv14, asn1_drv15, asn1_drv16 }).
-%%% --------------------------------------------------------
-%%% Interface Functions.
-%%% --------------------------------------------------------
-
-start_link() ->
- gen_server:start_link({local, asn1_server}, asn1_server, [], []).
-
-init([]) ->
- process_flag(trap_exit, true),
- erl_ddll:start(),
- PrivDir = code:priv_dir(asn1),
- LibDir1 = filename:join([PrivDir, "lib"]),
- case erl_ddll:load_driver(LibDir1, asn1_erl_drv) of
- ok -> ok;
- {error,_} ->
- LibDir2 =
- filename:join(LibDir1,
- erlang:system_info(system_architecture)),
- erl_ddll:load_driver(LibDir2, asn1_erl_drv)
- end,
- open_ports("asn1_erl_drv",size(?port_names)).
-
-open_ports(_,0) ->
- {ok, []};
-open_ports(Cmd,N) ->
- Port = open_port({spawn, Cmd}, []),
- %% check that driver is loaded, linked and working
- case catch port_control(Port, 0, []) of
- {'EXIT', _} ->
- {stop, nodriver};
- _ ->
- register(element(N,?port_names), Port),
- open_ports(Cmd,N-1)
- end.
-
-client_port() ->
- element(erlang:system_info(scheduler_id) rem size(?port_names) + 1,
- ?port_names).
-
-
-%%% --------------------------------------------------------
-%%% The call-back functions.
-%%% --------------------------------------------------------
-
-handle_call(_, _, State) ->
- {noreply, State}.
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
- {noreply, State};
-
-handle_info({'EXIT', Port, Reason}, State) when is_port(Port) ->
- {stop, {port_died, Reason}, State};
-handle_info(_, State) ->
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-terminate(_Reason, _State) ->
- close_ports(size(?port_names)).
-
-close_ports(0) ->
- ok;
-close_ports(N) ->
- element(N,?port_names) ! {self(), close}, %% almost same as port_close(Name)
- close_ports(N-1).
diff --git a/lib/asn1/src/asn1_sup.erl b/lib/asn1/src/asn1_sup.erl
deleted file mode 100644
index a241dec6f4..0000000000
--- a/lib/asn1/src/asn1_sup.erl
+++ /dev/null
@@ -1,37 +0,0 @@
-%% ``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 via the world wide web 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.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-
-%% Purpose: Main supervisor in asn1 application.
-
--module(asn1_sup).
-
--behaviour(supervisor).
-
--export([start_link/0, init/1]).
-
-start_link() ->
- supervisor:start_link({local, asn1_sup}, asn1_sup, []).
-
-
-%% init([])
-%% Returns: {ok, {SupFlags, [ChildSpec]}}
-%%
-init([]) ->
- Child = {asn1_server, {asn1_server, start_link, []},
- permanent, 2000, worker, [asn1_server]},
- {ok, {{one_for_all, 10, 3600}, [Child]}}.
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index a167d27f82..a170dd8660 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -47,6 +47,10 @@
-import(asn1ct_gen_ber_bin_v2,[encode_tag_val/3,decode_class/1]).
+-ifndef(vsn).
+-define(vsn,"0.0.1").
+-endif.
+
-define(unique_names,0).
-define(dupl_uniquedefs,1).
-define(dupl_equaldefs,2).
@@ -81,6 +85,12 @@ compile(File) ->
compile(File,[]).
compile(File,Options) when is_list(Options) ->
+ case lists:member(driver, Options) of %% remove me in R16A!
+ true ->
+ io:format("Warning: driver option is obsolete and will be removed in R16A, use nif instead!");
+ false ->
+ ok
+ end,
Options1 = optimize_ber_bin(Options),
Options2 = includes(File,Options1),
Includes=[I||{i,I}<-Options2],
@@ -1082,7 +1092,7 @@ get_runtime_mod(Options) ->
ber_bin_v2 -> ["asn1rt_ber_bin_v2.erl"];
uper_bin -> ["asn1rt_uper_bin.erl"]
end,
- RtMod1++["asn1rt_check.erl","asn1rt_driver_handler.erl","asn1rt.erl"].
+ RtMod1++["asn1rt_check.erl","asn1rt.erl"].
erl_compile(OutFile,Options) ->
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index e3be914af4..243ff234a7 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -877,13 +877,13 @@ gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) ->
emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,",
{curr,else},"}}})",nl]);
_ ->
- emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},")}",nl])
+ emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},
+ asn1ct_gen:nif_parameter(),")}",nl])
end,
emit([indent(3),"end",nl]),
asn1ct_name:new(tag),
asn1ct_name:new(else).
-
gen_dec_choice_cases(_Erules,_TopType, []) ->
ok;
gen_dec_choice_cases(Erules,TopType, [H|T]) ->
@@ -1227,7 +1227,7 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
emit([nl,indent(6),"begin",nl]),
% emit([indent(9),{curr,opendec}," = ?RT_BER:decode_open_type(",
emit([indent(9),{curr,tmptlv}," = ?RT_BER:decode_open_type(",
- BytesVar,",",{asis,Tag},"),",nl]),
+ BytesVar,",",{asis,Tag},asn1ct_gen:nif_parameter(),"),",nl]),
% emit([indent(9),"{",{curr,tmptlv},",_} = ?RT_BER:decode(",
% {curr,opendec},"),",nl]),
@@ -1242,7 +1242,8 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
emit([indent(9),"end",nl,indent(6),"end",nl]),
[];
gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},")"]),
+ emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},
+ asn1ct_gen:nif_parameter(),")"]),
RefedFieldName =
% asn1ct_gen:get_constraint(Type#type.constraint,
% tableconstraint_info),
@@ -1250,7 +1251,8 @@ gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandC
[{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call({objectfield,PrimFieldName,PFNList},_,_,Cname,_,BytesVar,Tag,_,_,_,OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},")"]),
+ emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},
+ asn1ct_gen:nif_parameter(),")"]),
[{Cname,{PrimFieldName,PFNList},asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index c1b6aa5713..e07680f10b 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -73,16 +73,23 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
_ ->
ok
end,
- case {Optionals = optionals(to_textual_order(CompList)),CompList} of
- {[],EmptyCL} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
+ case {Optionals = optionals(to_textual_order(CompList)),CompList,
+ is_optimized(Erule)} of
+ {[],EmptyCL,_} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
emit(["%%Variable setting just to eliminate ",
"compiler warning for unused vars!",nl,
"_Val = ",{curr,val},",",nl]);
- {[],_} ->
+ {[],_,_} ->
emit([{next,val}," = ?RT_PER:list_to_record("]),
emit(["'",asn1ct_gen:list2rname(Typename),"'"]),
emit([", ",{curr,val},"),",nl]);
- _ ->
+ {_,_,true} ->
+ gen_fixoptionals(Optionals),
+ FixOpts = param_map(fun(Var) ->
+ {var,Var}
+ end,asn1ct_name:all(fixopt)),
+ emit({"{",{next,val},",Opt} = {",{curr,val},",[",FixOpts,"]},",nl});
+ {_,_,false} ->
Fixoptcall = ",Opt} = ?RT_PER:fixoptionals(",
emit({"{",{next,val},Fixoptcall,
{asis,Optionals},",",length(Optionals),
@@ -439,9 +446,7 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_->
""
end,
- emit({nl,indent(3),"?RT_PER:encode_length(",
- {asis,SizeConstraint},
- ",length(Val)),",nl}),
+ gen_encode_length(SizeConstraint, is_optimized(Erule)),
emit({indent(3),"'enc_",asn1ct_gen:list2name(Typename),
"_components'(Val",ObjFun,", [])"}),
emit({nl,"].",nl}),
@@ -453,6 +458,42 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,NewComponentType).
+
+%% Logic copied from asn1_per_bin_rt2ct:encode_constrained_number
+gen_encode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
+ Range = Ub - Lb + 1,
+ V2 = ["(length(Val) - ",Lb,")"],
+ Encode = if
+ Range == 1 ->
+ "[]";
+ Range == 2 ->
+ {"[",V2,"]"};
+ Range =< 4 ->
+ {"[10,2,",V2,"]"};
+ Range =< 8 ->
+ {"[10,3,",V2,"]"};
+ Range =< 16 ->
+ {"[10,4,",V2,"]"};
+ Range =< 32 ->
+ {"[10,5,",V2,"]"};
+ Range =< 64 ->
+ {"[10,6,",V2,"]"};
+ Range =< 128 ->
+ {"[10,7,",V2,"]"};
+ Range =< 255 ->
+ {"[10,8,",V2,"]"};
+ Range =< 256 ->
+ {"[20,1,",V2,"]"};
+ Range =< 65536 ->
+ {"[20,2,<<",V2,":16>>]"};
+ true ->
+ {"?RT_PER:encode_length(",{asis,{Lb,Ub}},",length(Val))"}
+ end,
+ emit({nl,Encode,",",nl});
+gen_encode_length(SizeConstraint,_) ->
+ emit({nl,indent(3),"?RT_PER:encode_length(",
+ {asis,SizeConstraint},",length(Val)),",nl}).
+
gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
asn1ct_name:start(),
{_SeqOrSetOf,ComponentType} = D#type.def,
@@ -469,7 +510,8 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_ ->
""
end,
- emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",{asis,SizeConstraint},"),",nl}),
+ gen_decode_length(SizeConstraint,
+ is_optimized(Erules)),
emit({"'dec_",asn1ct_gen:list2name(Typename),
"_components'(Num, Bytes1, telltype",ObjFun,", []).",nl}),
NewComponentType =
@@ -480,6 +522,41 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_decode_sof_components(Erules,Typename,SeqOrSetOf,NewComponentType).
+%% Logic copied from asn1_per_bin_rt2ct:decode_constrained_number
+gen_decode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
+ Range = Ub - Lb + 1,
+ Call = if
+ Range == 1 ->
+ "{0,Bytes}";
+ Range == 2 ->
+ "?RT_PER:getbits(Bytes,1)";
+ Range =< 4 ->
+ "?RT_PER:getbits(Bytes,2)";
+ Range =< 8 ->
+ "?RT_PER:getbits(Bytes,3)";
+ Range =< 16 ->
+ "?RT_PER:getbits(Bytes,4)";
+ Range =< 32 ->
+ "?RT_PER:getbits(Bytes,5)";
+ Range =< 64 ->
+ "?RT_PER:getbits(Bytes,6)";
+ Range =< 128 ->
+ "?RT_PER:getbits(Bytes,7)";
+ Range =< 255 ->
+ "?RT_PER:getbits(Bytes,8)";
+ Range =< 256 ->
+ "?RT_PER:getoctets(Bytes,1)";
+ Range =< 65536 ->
+ "?RT_PER:getoctets(Bytes,2)";
+ true ->
+ ["exit({not_supported,{integer_range,",Range,"}}"]
+ end,
+ emit({nl,"{Val,Remain} = ",Call,",",nl}),
+ emit({nl,"{Num,Bytes1} = {Val+",Lb,",Remain},",nl});
+gen_decode_length(SizeConstraint,_) ->
+ emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",
+ {asis,SizeConstraint},"),",nl}).
+
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{ObjFun,ObjFun_Var} =
case Cont#type.tablecinf of
@@ -636,6 +713,27 @@ gen_dec_extension_value(_) ->
emit({"{Ext,",{next,bytes},"} = ?RT_PER:getext(",{curr,bytes},")"}),
asn1ct_name:new(bytes).
+gen_fixoptionals([{Pos,Def}|R]) ->
+ asn1ct_name:new(fixopt),
+ emit({{curr,fixopt}," = case element(",{asis,Pos},",",{curr,val},") of",nl,
+ "asn1_DEFAULT -> 0;",nl,
+ {asis,Def}," -> 0;",nl,
+ "_ -> 1",nl,
+ "end,",nl}),
+ gen_fixoptionals(R);
+gen_fixoptionals([Pos|R]) ->
+ gen_fixoptionals([{Pos,asn1_NOVALUE}|R]);
+gen_fixoptionals([]) ->
+ ok.
+
+
+param_map(Fun, [H]) ->
+ [Fun(H)];
+param_map(Fun, [H|T]) ->
+ [Fun(H),","|param_map(Fun,T)].
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Produce a list with positions (in the Value record) where
%% there are optional components, start with 2 because first element
@@ -922,7 +1020,7 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
end,
case Ext of
{ext,_Ep2,_} ->
- emit(["))"]);
+ emit("))");
_ -> true
end.
gen_dec_components_call(Erule,TopType,{Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index e49829d82f..0f8833f716 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -47,6 +47,7 @@
un_hyphen_var/1]).
-export([gen_encode_constructed/4,
gen_decode_constructed/4]).
+-export([nif_parameter/0]).
%% pgen(Outfile, Erules, Module, TypeOrVal, Options)
%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
@@ -938,13 +939,13 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
NoFinalPadding = lists:member(no_final_padding,get(encoding_options)),
Call = case Erules of
per -> "?RT_PER:complete(encode_disp(Type,Data))";
- per_bin -> "?RT_PER:complete(encode_disp(Type,Data))";
+ per_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"];
ber -> "encode_disp(Type,Data)";
ber_bin -> "encode_disp(Type,Data)";
ber_bin_v2 -> "encode_disp(Type,Data)";
uper_bin when NoFinalPadding == true ->
"?RT_PER:complete_NFP(encode_disp(Type,Data))";
- uper_bin -> "?RT_PER:complete(encode_disp(Type,Data))"
+ uper_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"]
end,
EncWrap = case Erules of
ber -> "wrap_encode(Bytes)";
@@ -974,7 +975,7 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
% case Erules of
% ber_bin_v2 ->
% emit(["decode(Type,Data0) ->",nl]),
-% emit(["{Data,_RestBin} = ?RT_BER:decode(Data0",driver_parameter(),"),",nl]);
+% emit(["{Data,_RestBin} = ?RT_BER:decode(Data0",nif_parameter(),"),",nl]);
% _ ->
% emit(["decode(Type,Data) ->",nl])
% end,
@@ -991,10 +992,10 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
{ber_bin_v2,false} ->
io_lib:format("~s~s~s~n",
["element(1,?RT_BER:decode(Data",
- driver_parameter(),"))"]);
+ nif_parameter(),"))"]);
{ber_bin_v2,true} ->
emit(["{Data,Rest} = ?RT_BER:decode(Data0",
- driver_parameter(),"),",nl]),
+ nif_parameter(),"),",nl]),
"Data";
_ ->
"Data"
@@ -1130,13 +1131,8 @@ gen_decode_partial_incomplete(Erule) when Erule == ber;Erule==ber_bin;
"Data) of",nl]),
EmitCaseClauses(),
emit(["decode_part(Type,Data0) ->",nl]),
- Driver =
- case lists:member(driver,get(encoding_options)) of
- true ->
- ",driver";
- _ -> ""
- end,
- emit([" case catch decode_inc_disp(Type,element(1,?RT_BER:decode(Data0",Driver,"))) of",nl]),
+ emit([" case catch decode_inc_disp(Type,element(1,"
+ "?RT_BER:decode(Data0",nif_parameter(),"))) of",nl]),
% " {Data,_RestBin} = ?RT_BER:decode(Data0),",nl,
% " case catch decode_inc_disp(Type,Data) of",nl]),
EmitCaseClauses();
@@ -1179,12 +1175,12 @@ gen_partial_inc_dispatcher([],_) ->
emit(["decode_partial_inc_disp(Type,_Data) ->",nl,
" exit({error,{asn1,{undefined_type,Type}}}).",nl]).
-driver_parameter() ->
+nif_parameter() ->
Options = get(encoding_options),
- case lists:member(driver,Options) of
- true ->
- ",driver";
- _ -> ""
+ case {lists:member(driver,Options),lists:member(nif,Options)} of
+ {true,_} -> ",nif";
+ {_,true} -> ",nif";
+ _ -> ""
end.
gen_wrapper() ->
@@ -1525,8 +1521,9 @@ gen_head(Erules,Mod,Hrl) ->
emit({"-module('",Mod,"').",nl}),
put(currmod,Mod),
%emit({"-compile(export_all).",nl}),
- case Hrl of
- 0 -> true;
+ case {Hrl,lists:member(inline,get(encoding_options))} of
+ {0,_} -> true;
+ {_,true} -> true;
_ ->
emit({"-include(\"",Mod,".hrl\").",nl})
end,
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index 9ec458e351..781271bae7 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -416,7 +416,7 @@ gen_decode_selected(Erules,Type,FuncName) ->
end,
emit([" case ?RT_BER:decode_selective(",{asis,Pattern},",Bin) of",nl,
" {ok,Bin2} when is_binary(Bin2) ->",nl,
- " {Tlv,_} = ?RT_BER:decode(Bin2),",nl]),
+ " {Tlv,_} = ?RT_BER:decode(Bin2",asn1ct_gen:nif_parameter(),"),",nl]),
emit("{ok,"),
gen_decode_selected_type(Erules,Type),
emit(["};",nl," Err -> exit({error,{selctive_decode,Err}})",nl,
@@ -708,7 +708,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'ASN1_OPEN_TYPE' ->
emit(["?RT_BER:decode_open_type_as_binary(",
BytesVar,","]),
- add_func({decode_open_type_as_binary,2});
+ add_func({decode_open_type_as_binary,3});
#'ObjectClassFieldType'{} ->
case asn1ct_gen:get_inner(Att#type.def) of
{fixedtypevaluefield,_,InnerType} ->
@@ -716,7 +716,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'ASN1_OPEN_TYPE' ->
emit(["?RT_BER:decode_open_type_as_binary(",
BytesVar,","]),
- add_func({decode_open_type_as_binary,2});
+ add_func({decode_open_type_as_binary,3});
Other ->
exit({'can not decode' ,Other})
end;
@@ -728,13 +728,13 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
{_,#'ObjectClassFieldType'{}} ->
case asn1ct_gen:get_inner(Att#type.def) of
'ASN1_OPEN_TYPE' ->
- emit([{asis,DoTag},")"]);
+ emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]);
_ -> ok
end;
{{string,TagStr},'ASN1_OPEN_TYPE'} ->
- emit([TagStr,")"]);
+ emit([TagStr,asn1ct_gen:nif_parameter(),")"]);
{_,'ASN1_OPEN_TYPE'} ->
- emit([{asis,DoTag},")"]);
+ emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]);
{{string,TagStr},_} ->
emit([TagStr,")"]);
_ when is_list(DoTag) ->
@@ -1064,7 +1064,7 @@ emit_tlv_format_function() ->
end.
emit_tlv_format_function1() ->
emit(["tlv_format(Bytes) when is_binary(Bytes) ->",nl,
- " {Tlv,_}=?RT_BER:decode(Bytes),",nl,
+ " {Tlv,_}=?RT_BER:decode(Bytes",asn1ct_gen:nif_parameter(),"),",nl,
" Tlv;",nl,
"tlv_format(Bytes) ->",nl,
" Bytes.",nl]).
@@ -1502,13 +1502,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj) ->
emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]),
emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]),
+
case Erules of
ber_bin_v2 ->
emit([indent(4),"case Bytes of",nl,
indent(6),"Bin when is_binary(Bin) -> ",nl,
indent(8),"Bin;",nl,
indent(6),"_ ->",nl,
- indent(8),"?RT_BER:encode(Bytes)",nl,
+ indent(8),"?RT_BER:encode(Bytes",driver_parameter(),")",nl,
indent(4),"end",nl]);
_ ->
emit([indent(6),"Len = case Bytes of",nl,indent(9),
@@ -1521,6 +1522,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
gen_objset_dec(_,_,_,[],_,_,_) ->
ok.
+driver_parameter() ->
+ Options = get(encoding_options),
+ case {lists:member(driver,Options),lists:member(nif,Options)} of
+ {true,_} -> ",nif";
+ {_,true} -> ",nif";
+ _ -> ",erlang"
+ end.
+
emit_default_getdec(ObjSetName,UniqueName) ->
emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]),
emit([indent(2), "fun(C,V,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 8313cf1b60..b90a0adf81 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. 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
@@ -238,7 +238,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
"?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
[#type{def=#'Externaltypereference'{type=Tname}}] ->
io_lib:format(
- "?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
+ "?RT_PER:complete(enc_~s(~s))",
+ [Tname,Value]);
_ -> Value
end,
emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",",
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 4f4fcfafc3..1a0a0e211d 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. 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
@@ -230,7 +230,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
"?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
[#type{def=#'Externaltypereference'{type=Tname}}] ->
io_lib:format(
- "?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
+ "?RT_PER:complete(enc_~s(~s))",
+ [Tname,Value]);
_ -> Value
end,
emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",",
diff --git a/lib/asn1/src/asn1rt.erl b/lib/asn1/src/asn1rt.erl
index 9ef68efab5..d18f81346a 100644
--- a/lib/asn1/src/asn1rt.erl
+++ b/lib/asn1/src/asn1rt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. 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
@@ -21,12 +21,12 @@
%% Runtime functions for ASN.1 (i.e encode, decode)
--include("asn1_records.hrl").
-
-export([encode/2,encode/3,decode/3,load_driver/0,unload_driver/0,info/1]).
-export([utf8_binary_to_list/1,utf8_list_to_binary/1]).
+-deprecated([load_driver/0,unload_driver/0]).
+
encode(Module,{Type,Term}) ->
encode(Module,Type,Term).
@@ -46,38 +46,12 @@ decode(Module,Type,Bytes) ->
Result
end.
-%% asn1-1.6.8.1
-%% load_driver() ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% ok;
-%% Err={error,_Reason} ->
-%% Err;
-%% Error ->
-%% {error,Error}
-%% end.
-
-%% asn1-1.6.9
- load_driver() ->
- case catch asn1rt_driver_handler:load_driver() of
- ok ->
- ok;
- {error,{already_started,asn1}} ->
- ok;
- Err ->
- {error,Err}
- end.
-
+%% Remove in R16A
+load_driver() ->
+ ok.
unload_driver() ->
- case catch asn1rt_driver_handler:unload_driver() of
- ok ->
- ok;
- Error ->
- {error,Error}
- end.
-
+ ok.
info(Module) ->
case catch apply(Module,info,[]) of
diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl
index a3bb570282..17e66f77c9 100644
--- a/lib/asn1/src/asn1rt_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. 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
@@ -21,7 +21,7 @@
%% encoding / decoding of BER
--export([decode/1, decode/2, match_tags/2, encode/1]).
+-export([decode/1, decode/2, match_tags/2, encode/1, encode/2]).
-export([fixoptionals/2, cindex/3,
list_to_record/2,
encode_tag_val/1,
@@ -49,11 +49,13 @@
decode_tag_and_length/1]).
-export([encode_open_type/1,encode_open_type/2,
- decode_open_type/2,decode_open_type_as_binary/2]).
+ decode_open_type/2,decode_open_type/3,
+ decode_open_type_as_binary/2,
+ decode_open_type_as_binary/3]).
-export([decode_primitive_incomplete/2,decode_selective/2]).
-
--include("asn1_records.hrl").
+
+-export([is_nif_loadable/0]).
% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
@@ -125,15 +127,28 @@
% encode(Tlv) ->
% encode_constructed(Tlv).
-encode([Tlv]) ->
- encode(Tlv);
-encode({TlvTag,TlvVal}) when is_list(TlvVal) ->
+encode(Tlv) ->
+ encode(Tlv,erlang).
+
+encode(Tlv,_) when is_binary(Tlv) ->
+ Tlv;
+encode([Tlv],Method) ->
+ encode(Tlv,Method);
+encode(Tlv, nif) ->
+ case is_nif_loadable() of
+ true ->
+ asn1rt_nif:encode_ber_tlv(Tlv);
+ false ->
+ encode_erl(Tlv)
+ end;
+encode(Tlv, _) ->
+ encode_erl(Tlv).
+
+encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) ->
%% constructed form of value
encode_tlv(TlvTag,TlvVal,?CONSTRUCTED);
-encode({TlvTag,TlvVal}) ->
- encode_tlv(TlvTag,TlvVal,?PRIMITIVE);
-encode(Bin) when is_binary(Bin) ->
- Bin.
+encode_erl({TlvTag,TlvVal}) ->
+ encode_tlv(TlvTag,TlvVal,?PRIMITIVE).
encode_tlv(TlvTag,TlvVal,Form) ->
Tag = encode_tlv_tag(TlvTag,Form),
@@ -152,70 +167,61 @@ encode_tlv_val(Bin) ->
{Bin,size(Bin)}.
encode_tlv_list([Tlv|Tlvs],Acc) ->
- EncTlv = encode(Tlv),
+ EncTlv = encode_erl(Tlv),
encode_tlv_list(Tlvs,[EncTlv|Acc]);
encode_tlv_list([],Acc) ->
Bin=list_to_binary(lists:reverse(Acc)),
{Bin,size(Bin)}.
-%% asn1-1.6.8.1
-%% decode(B,driver) ->
-%% case catch port_control(asn1_driver_port,2,B) of
-%% Bin when is_binary(Bin) ->
-%% binary_to_term(Bin);
-%% List when is_list(List) -> handle_error(List,B);
-%% {'EXIT',{badarg,Reason}} ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% case catch port_control(asn1_driver_port,2,B) of
-%% Bin2 when is_binary(Bin2) -> binary_to_term(Bin2);
-%% List when is_list(List) -> handle_error(List,B);
-%% Error -> exit(Error)
-%% end;
-%% {error,Error} -> % error when loading driver
-%% %% the driver could not be loaded
-%% exit(Error);
-%% Error={port_error,Reason} ->
-%% exit(Error)
-%% end;
-%% {'EXIT',Reason} ->
-%% exit(Reason)
-%% end.
-
-%% asn1-1.6.9
-decode(B,driver) ->
- case catch control(?TLV_DECODE,B) of
- Bin when is_binary(Bin) ->
- binary_to_term(Bin);
- List when is_list(List) -> handle_error(List,B);
- {'EXIT',{badarg,_Reason}} ->
- case asn1rt:load_driver() of
- ok ->
- case control(?TLV_DECODE,B) of
- Bin when is_binary(Bin) -> binary_to_term(Bin);
- List when is_list(List) -> handle_error(List,B)
- end;
- Err ->
- Err
- end
- end.
+decode(B) ->
+ decode(B, erlang).
+%% asn1-1.7
+decode(B, nif) ->
+ case is_nif_loadable() of
+ true ->
+ case asn1rt_nif:decode_ber_tlv(B) of
+ {error, Reason} -> handle_error(Reason, B);
+ Else -> Else
+ end;
+ false ->
+ decode(B)
+ end;
+decode(B,erlang) when is_binary(B) ->
+ decode_primitive(B);
+decode(Tlv,erlang) ->
+ {Tlv,<<>>}.
+
+%% Have to check this since asn1 is not guaranteed to be available
+is_nif_loadable() ->
+ case application:get_env(asn1, nif_loadable) of
+ {ok,R} ->
+ R;
+ undefined ->
+ case catch code:load_file(asn1rt_nif) of
+ {module, asn1rt_nif} ->
+ application:set_env(asn1, nif_loadable, true),
+ true;
+ _Else ->
+ application:set_env(asn1, nif_loadable, false),
+ false
+ end
+ end.
handle_error([],_)->
exit({error,{asn1,{"memory allocation problem"}}});
-handle_error([$1|_],L) -> % error in driver
+handle_error({$1,_},L) -> % error in nif
exit({error,{asn1,L}});
-handle_error([$2|T],L) -> % error in driver due to wrong tag
+handle_error({$2,T},L) -> % error in nif due to wrong tag
exit({error,{asn1,{"bad tag after byte:",error_pos(T),L}}});
-handle_error([$3|T],L) -> % error in driver due to length error
+handle_error({$3,T},L) -> % error in driver due to length error
exit({error,{asn1,{"bad length field after byte:",
error_pos(T),L}}});
-handle_error([$4|T],L) -> % error in driver due to indefinite length error
+handle_error({$4,T},L) -> % error in driver due to indefinite length error
exit({error,{asn1,
{"indefinite length without end bytes after byte:",
error_pos(T),L}}});
-handle_error([$5|T],L) -> % error in driver due to indefinite length error
+handle_error({$5,T},L) -> % error in driver due to indefinite length error
exit({error,{asn1,{"bad encoded value after byte:",
error_pos(T),L}}});
handle_error(ErrL,L) ->
@@ -228,16 +234,6 @@ error_pos([B])->
error_pos([B|Bs]) ->
BS = 8 * length(Bs),
B bsl BS + error_pos(Bs).
-%% asn1-1.6.9
-control(Cmd, Data) ->
- Port = asn1rt_driver_handler:client_port(),
- erlang:port_control(Port, Cmd, Data).
-
-decode(Bin) when is_binary(Bin) ->
- decode_primitive(Bin);
-decode(Tlv) -> % assume it is a tlv
- {Tlv,<<>>}.
-
decode_primitive(Bin) ->
{Form,TagNo,V,Rest} = decode_tag_and_length(Bin),
@@ -796,20 +792,24 @@ encode_open_type(Val,Tag) ->
%% Value = binary with decoded data (which must be decoded again as some type)
%%
decode_open_type(Tlv, TagIn) ->
+ decode_open_type(Tlv, TagIn, erlang).
+decode_open_type(Tlv, TagIn, Method) ->
case match_tags(Tlv,TagIn) of
Bin when is_binary(Bin) ->
- {InnerTlv,_} = decode(Bin),
+ {InnerTlv,_} = decode(Bin,Method),
InnerTlv;
TlvBytes -> TlvBytes
end.
-decode_open_type_as_binary(Tlv,TagIn)->
+decode_open_type_as_binary(Tlv, TagIn) ->
+ decode_open_type_as_binary(Tlv, TagIn, erlang).
+decode_open_type_as_binary(Tlv,TagIn, Method)->
case match_tags(Tlv,TagIn) of
V when is_binary(V) ->
V;
- [Tlv2] -> encode(Tlv2);
- Tlv2 -> encode(Tlv2)
+ [Tlv2] -> encode(Tlv2, Method);
+ Tlv2 -> encode(Tlv2, Method)
end.
%%===============================================================================
@@ -1056,7 +1056,7 @@ encode_real(C,Val, TagIn) when is_tuple(Val); is_list(Val) ->
encode_real(C,Val) ->
- ?RT_COMMON:encode_real(C,Val).
+ asn1rt_ber_bin:encode_real(C,Val).
%%============================================================================
@@ -1081,7 +1081,7 @@ decode_real_notag(Buffer) ->
{_T,_V} ->
exit({error,{asn1,{real_not_in_primitive_form,Buffer}}})
end,
- {Val,_Rest,Len} = ?RT_COMMON:decode_real(Buffer,Len),
+ {Val,_Rest,Len} = asn1rt_ber_bin:decode_real(Buffer,Len),
Val.
%% exit({error,{asn1, {unimplemented,real}}}).
%% decode_real2(Buffer, Form, size(Buffer)).
@@ -1577,14 +1577,12 @@ e_object_identifier(V) when is_tuple(V) ->
e_object_identifier([E1, E2 | Tail]) ->
Head = 40*E1 + E2, % wow!
{H,Lh} = mk_object_val(Head),
- {R,Lr} = enc_obj_id_tail(Tail, [], 0),
+ {R,Lr} = lists:mapfoldl(fun enc_obj_id_tail/2,0,Tail),
{[H|R], Lh+Lr}.
-enc_obj_id_tail([], Ack, Len) ->
- {lists:reverse(Ack), Len};
-enc_obj_id_tail([H|T], Ack, Len) ->
+enc_obj_id_tail(H, Len) ->
{B, L} = mk_object_val(H),
- enc_obj_id_tail(T, [B|Ack], Len+L).
+ {B,Len+L}.
%%%%%%%%%%%
diff --git a/lib/asn1/src/asn1rt_check.erl b/lib/asn1/src/asn1rt_check.erl
index 24a2a3802d..d9856901b8 100644
--- a/lib/asn1/src/asn1rt_check.erl
+++ b/lib/asn1/src/asn1rt_check.erl
@@ -19,8 +19,6 @@
%%
-module(asn1rt_check).
--include("asn1_records.hrl").
-
-export([check_bool/2,
check_int/3,
check_bitstring/3,
diff --git a/lib/asn1/src/asn1rt_driver_handler.erl b/lib/asn1/src/asn1rt_driver_handler.erl
deleted file mode 100644
index 146d0043f9..0000000000
--- a/lib/asn1/src/asn1rt_driver_handler.erl
+++ /dev/null
@@ -1,144 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2011. 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%
-%%
-%%
-
--module(asn1rt_driver_handler).
-
--include("asn1_records.hrl").
-
--export([load_driver/0,unload_driver/0,client_port/0]).
-
-%% Internal exports
--export([init/2]).
-
-%% Macros
--define(port_names,
- { asn1_drv01, asn1_drv02, asn1_drv03, asn1_drv04,
- asn1_drv05, asn1_drv06, asn1_drv07, asn1_drv08,
- asn1_drv09, asn1_drv10, asn1_drv11, asn1_drv12,
- asn1_drv13, asn1_drv14, asn1_drv15, asn1_drv16 }).
-
-%%% --------------------------------------------------------
-%%% Interface Functions.
-%%% --------------------------------------------------------
-load_driver() ->
- load_driver(noreason).
-
-load_driver(Reason) ->
- Ref = make_ref(),
- case whereis(asn1_driver_owner) of % to prevent unnecessary spawn
- Pid when is_pid(Pid) ->
- asn1_driver_owner ! {self(),Ref,are_you_ready},
- receive
- {Ref,driver_ready} ->
- ok
- after 10000 ->
- {error,{timeout,waiting_for_drivers}}
- end;
- _ ->
- {_,Mref} = spawn_monitor(asn1rt_driver_handler, init, [self(),Ref]),
- receive
- {'DOWN', Mref, _, _, NewReason} ->
- case NewReason of
- Reason -> {error,Reason};
- _ -> load_driver(NewReason)
- end;
- {Ref,driver_ready} ->
- erlang:demonitor(Mref),
- ok;
- {Ref,Error = {error,_Reason}} ->
- erlang:demonitor(Mref),
- Error
- after 10000 -> %% 10 seconds
- {error,{timeout,waiting_for_drivers}}
- end
- end.
-
-init(FromPid,FromRef) ->
- case catch register(asn1_driver_owner,self()) of
- true -> true;
- _Other -> exit(normal)
- end,
- Dir = filename:join([code:priv_dir(asn1),"lib"]),
- case catch erl_ddll:load_driver(Dir,asn1_erl_drv) of
- ok ->
- Result = open_named_ports(),
- catch (FromPid ! {FromRef,Result}),
- loop(Result);
- {error,Err} -> % if erl_ddll:load_driver fails
- ForErr = erl_ddll:format_error(Err),
- OSDir = filename:join(Dir,erlang:system_info(system_architecture)),
- case catch erl_ddll:load_driver(OSDir,asn1_erl_drv) of
- ok ->
- Result = open_named_ports(),
- catch (FromPid ! {FromRef,Result}),
- loop(Result);
- {error,Err2} ->
-% catch (FromPid ! {FromRef,Error})
- ForErr2 = erl_ddll:format_error(Err2),
- catch (FromPid ! {FromRef,{error,{{Dir,ForErr},{OSDir,ForErr2}}}})
- end
- end.
-
-
-open_named_ports() ->
- open_named_ports(size(?port_names)).
-
-open_named_ports(0) ->
- driver_ready;
-open_named_ports(N) ->
- case catch open_port({spawn,"asn1_erl_drv"},[]) of
- {'EXIT',Reason} ->
- {error,{port_error,Reason}};
- Port ->
- register(element(N,?port_names),Port),
- open_named_ports(N-1)
- end.
-
-loop(Result) ->
- receive
- {_FromPid,_FromRef,unload} ->
- close_ports(size(?port_names)),
- erl_ddll:unload_driver(asn1_erl_drv),
- ok;
- {FromPid,FromRef,are_you_ready} ->
- catch (FromPid ! {FromRef,driver_ready}),
- loop(Result);
- _ ->
- loop(Result)
- end.
-
-unload_driver() ->
- case whereis(asn1_driver_owner) of
- Pid when is_pid(Pid) ->
- Pid ! {self(),make_ref(),unload},
- ok;
- _ ->
- ok
- end.
-
-close_ports(0) ->
- ok;
-close_ports(N) ->
- element(N,?port_names) ! {self(), close}, %% almost same as port_close(Name)
- close_ports(N-1).
-
-client_port() ->
- element(erlang:system_info(scheduler_id) rem size(?port_names) + 1,
- ?port_names).
diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl
new file mode 100644
index 0000000000..de1fb94816
--- /dev/null
+++ b/lib/asn1/src/asn1rt_nif.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2011. 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%
+%%
+%%
+-module(asn1rt_nif).
+
+%% Nif interface for asn1
+
+-export([encode_per_complete/1,
+ decode_ber_tlv/1,
+ encode_ber_tlv/1]).
+
+-on_load(load_nif/0).
+
+-define(ASN1_NIF_VSN,1).
+
+load_nif() ->
+ LibBaseName = "asn1_erl_nif",
+ PrivDir = code:priv_dir(asn1),
+ LibName = case erlang:system_info(build_type) of
+ opt ->
+ LibBaseName;
+ Type ->
+ LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type),
+ case (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ LibTypeName ++ "*"])) /= []) orelse
+ (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ erlang:system_info(system_architecture),
+ LibTypeName ++ "*"])) /= []) of
+ true -> LibTypeName;
+ false -> LibBaseName
+ end
+ end,
+ Lib = filename:join([PrivDir, "lib", LibName]),
+ Status = case erlang:load_nif(Lib, ?ASN1_NIF_VSN) of
+ ok -> ok;
+ {error, {load_failed, _}}=Error1 ->
+ ArchLibDir =
+ filename:join([PrivDir, "lib",
+ erlang:system_info(system_architecture)]),
+ Candidate =
+ filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])),
+ case Candidate of
+ [] -> Error1;
+ _ ->
+ ArchLib = filename:join([ArchLibDir, LibName]),
+ erlang:load_nif(ArchLib, ?ASN1_NIF_VSN)
+ end;
+ Error1 -> Error1
+ end,
+ case Status of
+ ok -> ok;
+ {error, {E, Str}} ->
+ error_logger:error_msg("Unable to load asn1 nif library. "
+ "Failed with error:~n\"~p, ~s\"~n",[E,Str]),
+ Status
+ end.
+
+encode_per_complete(_TagValueList) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
+
+decode_ber_tlv(_Binary) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
+
+encode_ber_tlv(_TagValueList) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl
index 6bbca26209..a124c7553d 100644
--- a/lib/asn1/src/asn1rt_per_bin.erl
+++ b/lib/asn1/src/asn1rt_per_bin.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. 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
@@ -57,7 +57,7 @@
encode_NumericString/2, decode_NumericString/2,
encode_ObjectDescriptor/2, decode_ObjectDescriptor/1
]).
--export([complete_bytes/1]).
+-export([complete_bytes/1, getbits/2, getoctets/2]).
-define('16K',16384).
-define('32K',32768).
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index f4aecf9322..c7ead680ce 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -1734,143 +1734,24 @@ get_constraint(C,Key) ->
-ifdef(nodriver).
complete(L) ->
- case complete1(L) of
- {[],[]} ->
- <<0>>;
- {Acc,[]} ->
- Acc;
- {Acc,Bacc} ->
- [Acc|complete_bytes(Bacc)]
- end.
-
-
-% this function builds the ugly form of lists [E1|E2] to avoid having to reverse it at the end.
-% this is done because it is efficient and that the result always will be sent on a port or
-% converted by means of list_to_binary/1
- complete1(InList) when is_list(InList) ->
- complete1(InList,[],[]);
- complete1(InList) ->
- complete1([InList],[],[]).
-
- complete1([],Acc,Bacc) ->
- {Acc,Bacc};
- complete1([H|T],Acc,Bacc) when is_list(H) ->
- {NewH,NewBacc} = complete1(H,Acc,Bacc),
- complete1(T,NewH,NewBacc);
-
- complete1([{octets,Bin}|T],Acc,[]) ->
- complete1(T,[Acc|Bin],[]);
-
- complete1([{octets,Bin}|T],Acc,Bacc) ->
- complete1(T,[Acc|[complete_bytes(Bacc),Bin]],[]);
-
- complete1([{debug,_}|T], Acc,Bacc) ->
- complete1(T,Acc,Bacc);
-
- complete1([{bits,N,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,N));
-
- complete1([{bit,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,1));
-
- complete1([align|T],Acc,[]) ->
- complete1(T,Acc,[]);
- complete1([align|T],Acc,Bacc) ->
- complete1(T,[Acc|complete_bytes(Bacc)],[]);
- complete1([{0,Bin}|T],Acc,[]) when is_binary(Bin) ->
- complete1(T,[Acc|Bin],[]);
- complete1([{Unused,Bin}|T],Acc,[]) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8-Unused,
- complete1(T,[Acc|Bs],[[B bsr Unused]|NumBits]);
- complete1([{Unused,Bin}|T],Acc,Bacc) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8 - Unused,
- Bf = complete_bytes(Bacc),
- complete1(T,[Acc|[Bf,Bs]],[[B bsr Unused]|NumBits]).
-
-
- complete_update_byte([],Val,Len) ->
- complete_update_byte([[0]|0],Val,Len);
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len == 8 ->
- [[0,((Byte bsl Len) + Val) band 255|Bacc]|0];
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len > 8 ->
- Rem = 8 - NumBits,
- Rest = Len - Rem,
- complete_update_byte([[0,((Byte bsl Rem) + (Val bsr Rest)) band 255 |Bacc]|0],Val,Rest);
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) ->
- [[((Byte bsl Len) + Val) band 255|Bacc]|NumBits+Len].
-
-
- complete_bytes([[Byte|Bacc]|0]) ->
- lists:reverse(Bacc);
- complete_bytes([[Byte|Bacc]|NumBytes]) ->
- lists:reverse([(Byte bsl (8-NumBytes)) band 255|Bacc]);
- complete_bytes([]) ->
- [].
+ erlang_complete(L).
-else.
-%% asn1-1.6.8.1_dev
-%% complete(L) ->
-%% case catch port_control(asn1_driver_port,1,L) of
-%% Bin when is_binary(Bin) ->
-%% Bin;
-%% List when is_list(List) -> handle_error(List,L);
-%% {'EXIT',{badarg,Reason}} ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% case catch port_control(asn1_driver_port,1,L) of
-%% Bin2 when is_binary(Bin2) -> Bin2;
-%% List when is_list(List) -> handle_error(List,L);
-%% {'EXIT',Reason2={badarg,_R}} ->
-%% exit({"failed to call driver probably due to bad asn1 value",Reason2});
-%% Reason2 -> exit(Reason2)
-%% end;
-%% {error,Error} -> % error when loading driver
-%% %% the driver could not be loaded
-%% exit(Error);
-%% Error={port_error,Reason} ->
-%% exit(Error)
-%% end;
-%% {'EXIT',Reason} ->
-%% exit(Reason)
-%% end.
-
-%% asn1-1.6.9
+%% asn1-1.7
complete(L) ->
- case catch control(?COMPLETE_ENCODE,L) of
- Bin when is_binary(Bin) ->
- Bin;
- List when is_list(List) -> handle_error(List,L);
- {'EXIT',{badarg,_Reason}} ->
- case asn1rt:load_driver() of
- ok ->
- case control(?COMPLETE_ENCODE,L) of
- Bin when is_binary(Bin) ->Bin;
- List when is_list(List) -> handle_error(List,L)
- end;
- Err ->
- Err
- end
+ case asn1rt_nif:encode_per_complete(L) of
+ {error, Reason} -> handle_error(Reason, L);
+ Else when is_binary(Else) -> Else
end.
-
handle_error([],_)->
exit({error,{asn1,{"memory allocation problem in driver"}}});
-handle_error("1",L) -> % error in complete in driver
+handle_error($1,L) -> % error in complete in driver
exit({error,{asn1,L}});
handle_error(ErrL,L) ->
exit({error,{asn1,ErrL,L}}).
-%% asn1-1.6.9
-control(Cmd, Data) ->
- Port = asn1rt_driver_handler:client_port(),
- erlang:port_control(Port, Cmd, Data).
-
-endif.
diff --git a/lib/asn1/test/asn1.cover b/lib/asn1/test/asn1.cover
index 589a8b7e3d..ad3a0f3db9 100644
--- a/lib/asn1/test/asn1.cover
+++ b/lib/asn1/test/asn1.cover
@@ -1,2 +1,3 @@
{incl_app,asn1,details}.
+{excl_mods, asn1, [asn1rt_nif]}. \ No newline at end of file
diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src
index 582ccd877c..5339ad78c7 100644
--- a/lib/asn1/test/asn1_SUITE.erl.src
+++ b/lib/asn1/test/asn1_SUITE.erl.src
@@ -2036,11 +2036,7 @@ rtUI(Config) ->
?line {ok,_} = asn1rt:info('Prim'),
?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?PER]),
- ?line {ok,_} = asn1rt:info('Prim'),
-
- ?line ok = asn1rt:load_driver(),
- ?line ok = asn1rt:load_driver(),
- ?line ok = asn1rt:unload_driver().
+ ?line {ok,_} = asn1rt:info('Prim').
testROSE(suite) -> [];
testROSE(Config) ->
diff --git a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
index abd21b0d78..4c3c8c7808 100644
--- a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
+++ b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
@@ -11,37 +11,219 @@ smp(Config) ->
?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
?line ok = testNBAPsystem:compile(Config,per_bin,[optimize]),
-
- Parent = self(),
- ?line ok = asn1rt:load_driver(),
-
- smp2(Parent,NumOfProcs,Msg,2),
+ enc_dec(NumOfProcs,Msg,2),
N = 10000,
- ?line {Time1,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]),
- ?line {Time1S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]),
+ ?line {Time1,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
+ ?line {Time1S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
- ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,driver]),
- ?line {Time2,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]),
+ ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]),
+ ?line {Time3,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
- ?line {Time2S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]),
+ ?line {Time3S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
- {comment,lists:flatten(io_lib:format("Encode/decode time parallell with ~p cores: ~p [microsecs]~nEncode/decode time sequential: ~p [microsecs]",[NumOfProcs,Time1+Time2,Time1S+Time2S]))};
+ {comment,lists:flatten(
+ io_lib:format(
+ "Encode/decode time parallell with ~p cores: ~p [microsecs]~n"
+ "Encode/decode time sequential: ~p [microsecs]",
+ [NumOfProcs,Time1+Time3,Time1S+Time3S]))};
false ->
{skipped,"No smp support"}
end.
-smp2(Parent,NumOfProcs,Msg, N) ->
- Pids = [spawn_link(fun() -> worker(Msg,Parent, N) end)
- || _ <- lists:seq(1,NumOfProcs)],
- ?line ok = wait_pids(Pids).
+per_performance(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ NifDir = filename:join(PrivDir,"nif"),
+ ErlDir = filename:join(PrivDir,"erl"),
+ file:make_dir(NifDir),file:make_dir(ErlDir),
+
+ ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
+ ?line ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config],per_bin,
+ [optimize]),
+ ?line ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config],per_bin,
+ []),
+
+ Modules = ['NBAP-CommonDataTypes',
+ 'NBAP-Constants',
+ 'NBAP-Containers',
+ 'NBAP-IEs',
+ 'NBAP-PDU-Contents',
+ 'NBAP-PDU-Discriptions'],
+
+
+ PreNif = fun() ->
+ code:add_patha(NifDir),
+ lists:foreach(fun(M) ->
+ code:purge(M),
+ code:load_file(M)
+ end,Modules)
+ end,
+
+ PreErl = fun() ->
+ code:add_patha(ErlDir),
+ lists:foreach(fun(M) ->
+ code:purge(M),
+ code:load_file(M)
+ end,Modules)
+ end,
+
+ Func = fun() ->
+ element(1,timer:tc(
+ asn1_wrapper,encode,['NBAP-PDU-Discriptions',
+ 'NBAP-PDU',
+ Msg]))
+ end,
+
+ nif_vs_erlang_performance({{{PreNif,Func},{PreErl,Func}},100000,32}).
+
+ber_performance(Config) ->
+
+ ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
+ ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]),
+
+
+ BerFun = fun() ->
+ {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions',
+ 'NBAP-PDU', Msg),
+ asn1_wrapper:decode(
+ 'NBAP-PDU-Discriptions',
+ 'NBAP-PDU',
+ B)
+ end,
+ nif_vs_erlang_performance({BerFun,100000,32}).
+
+cert_pem_performance(Config) when is_list(Config) ->
+ cert_pem_performance({100000, 32});
+cert_pem_performance({N,S}) ->
+ nif_vs_erlang_performance({fun cert_pem/0,N,S}).
+
+dsa_pem_performance(Config) when is_list(Config) ->
+ cert_pem_performance({100000, 32});
+dsa_pem_performance({N,S}) ->
+ nif_vs_erlang_performance({fun dsa_pem/0,N,S}).
+
+
+nif_vs_erlang_performance({{TC1,TC2},N,Sched}) ->
+ random:seed({123,456,789}),
+ io:format("Running a ~p sample with ~p max procs...~n~n",[N,Sched]),
+
+ {True,False} = exec(TC1,TC2,Sched,N+1),
+
+ io:format("~ndone!~n"),
+
+ io:format("~n"),TStats = print_stats(strip(True,N div 20)),
+ io:format("~n"),FStats = print_stats(strip(False,N div 20)),
+ Str = io_lib:format("~nNifs are ~.3f% faster than erlang!~n",
+ [(element(2,FStats) - element(2,TStats)) /
+ element(2,FStats) * 100]),
+ io:format(Str),
+ {comment, lists:flatten(Str)};
+nif_vs_erlang_performance({T,N,Sched}) ->
+ PTC1 = fun() ->
+ application:set_env(asn1, nif_loadable, true)
+ end,
+ PTC2 = fun() ->
+ application:set_env(asn1, nif_loadable, false)
+ end,
+ TC = fun() ->
+ element(1,timer:tc(T))
+ end,
+ nif_vs_erlang_performance({{{PTC1,TC},{PTC2,TC}},N,Sched}).
+
+
+print_stats(Data) ->
+ Length = length(Data),
+ Mean = lists:sum(Data) / Length,
+ Variance = lists:foldl(fun(N,Acc) -> math:pow(N - Mean, 2)+Acc end, 0, Data),
+ StdDev = math:sqrt(Variance / Length),
+ Median = lists:nth(round(Length/2),Data),
+ Min = lists:min(Data),
+ Max = lists:max(Data),
+ if Length < 20 ->
+ io:format("Data: ~w~n",[Data]);
+ true ->
+ ok
+ end,
+ io:format("Length: ~p~nMean: ~p~nStdDev: ~p~nMedian: ~p~nMin: ~p~nMax: ~p~n",
+ [Length,Mean,StdDev,Median,Min,Max]),
+ {Length,Mean,StdDev,Median,Min,Max}.
+
+collect(Acc) ->
+ receive
+ {Tag,Val} ->
+ Prev = proplists:get_value(Tag,Acc,[]),
+ collect(lists:keystore(Tag,1,Acc,{Tag,[Val|Prev]}))
+ after 100 ->
+ Acc
+ end.
+
+exec(One,Two,Max,N) ->
+ exec(One,Two,Max,N,{[],[]}).
+exec(_,_,_,1,{D1,D2}) ->
+ {lists:flatten(D1),lists:flatten(D2)};
+exec({PreOne,One} = O,{PreTwo,Two} = T,MaxProcs, N, {D1,D2}) ->
+ Num = random:uniform(round(N/2)),
+ if Num rem 3 == 0 ->
+ timer:sleep(Num rem 1000);
+ true ->
+ ok
+ end,
+ Procs = random:uniform(MaxProcs),
+ io:format("\tBatch: ~p items in ~p processes, ~p left~n",[Num,Procs,N-Num]),
+ if Num rem 2 == 1 ->
+ erlang:garbage_collect(),
+ PreOne(),
+ MoreOne = pexec(One, Num, Procs, []),
+ erlang:garbage_collect(),
+ PreTwo(),
+ MoreTwo = pexec(Two, Num, Procs, []);
+ true ->
+ erlang:garbage_collect(),
+ PreTwo(),
+ MoreTwo = pexec(Two, Num, Procs, []),
+ erlang:garbage_collect(),
+ PreOne(),
+ MoreOne = pexec(One, Num, Procs, [])
+ end,
+ exec(O,T,MaxProcs,N-Num,{[MoreOne|D1],
+ [MoreTwo|D2]}).
+
+pexec(_Fun, _, 0, []) ->
+ [];
+pexec(Fun, _, 0, [{Ref,Pid}|Rest]) ->
+ receive
+ {data,D} ->
+ [D|pexec(Fun,0,0,[{Ref,Pid}|Rest])];
+ {'DOWN', Ref, process, Pid, normal} ->
+ pexec(Fun, 0,0,Rest)
+ end;
+pexec(Fun, 0, 1, AccProcs) ->
+ pexec(Fun, 0, 0, AccProcs);
+pexec(Fun, N, 1, AccProcs) ->
+ [Fun()|pexec(Fun, N - 1, 1, AccProcs)];
+pexec(Fun, N, Procs, AccProcs) ->
+ S = self(),
+ Pid = spawn(fun() ->
+ S ! {data,pexec(Fun,N,1,[])}
+ end),
+ Ref = erlang:monitor(process, Pid),
+ pexec(Fun, N, Procs - 1, [{Ref,Pid}|AccProcs]).
-worker(Msg, Parent, N) ->
- %% io:format("smp worker ~p with ~p worker loops.~n",[self(), N]),
- worker_loop(N, Msg),
- Parent ! self().
+strip(Data,Num) ->
+ {_,R} = lists:split(Num,lists:sort(Data)),
+ element(2,lists:split(Num,lists:reverse(R))).
+
+faster(A,B) ->
+ (B - A)/B * 100.
+
+enc_dec(1, Msg, N) ->
+ worker_loop(N, Msg);
+enc_dec(NumOfProcs,Msg, N) ->
+ pforeach(fun(_) ->
+ worker_loop(N, Msg)
+ end, [I || I <- lists:seq(1,NumOfProcs)]).
worker_loop(0, _Msg) ->
ok;
@@ -50,28 +232,24 @@ worker_loop(N, Msg) ->
'NBAP-PDU',
Msg),
?line {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- B),
+ 'NBAP-PDU',
+ B),
worker_loop(N - 1, Msg).
-wait_pids([]) ->
- ok;
-wait_pids(Pids) ->
+pforeach(Fun, List) ->
+ pforeach(Fun, List, []).
+pforeach(Fun, [], [{Pid,Ref}|Pids]) ->
receive
- Pid when is_pid(Pid) ->
- ?line true = lists:member(Pid,Pids),
- Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
- wait_pids(Others);
- Err ->
- io:format("Err: ~p~n",[Err]),
- ?line exit(Err)
- end.
-
-sequential(N,Msg) ->
- %%io:format("sequential encode/decode with N = ~p~n",[N]),
- worker_loop(N,Msg).
+ {'DOWN', Ref, process, Pid, normal} ->
+ pforeach(Fun, [], Pids)
+ end;
+pforeach(Fun, [H|T], Pids) ->
+ Pid = spawn(fun() -> Fun(H) end),
+ Ref = erlang:monitor(process, Pid),
+ pforeach(Fun, T, [{Pid, Ref}|Pids]);
+pforeach(_Fun,[],[]) ->
+ ok.
-record('InitiatingMessage',{procedureCode,criticality,value}).
-record('Iu-ReleaseCommand',{first,second}).
@@ -93,3 +271,21 @@ ticket7904(Config) ->
?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1),
asn1rt:unload_driver(),
?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1).
+
+cert_pem() ->
+ 'OTP-PUB-KEY':decode('Certificate',<<48,130,3,184,48,130,3,33,160,3,2,1,2,2,1,1,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,131,49,14,48,12,6,3,85,4,3,19,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,30,23,13,48,56,48,49,48,57,48,56,50,57,51,48,90,23,13,49,55,49,49,49,55,48,56,50,57,51,48,90,48,129,132,49,15,48,13,6,3,85,4,3,19,6,99,108,105,101,110,116,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,245,56,68,254,220,239,193,190,63,221,182,60,67,77,121,163,214,136,137,183,139,8,166,30,100,27,45,17,126,58,15,173,151,218,75,224,148,14,22,164,10,100,186,183,104,175,197,97,96,182,146,150,106,129,140,100,194,106,90,62,133,233,155,46,155,33,101,220,83,193,182,232,240,99,253,249,114,8,159,172,143,77,179,132,229,205,29,110,185,233,224,52,25,149,249,100,80,229,199,125,23,106,146,233,159,26,13,8,161,206,221,43,240,149,42,45,194,190,85,6,235,152,220,219,160,32,144,67,2,3,1,0,1,163,130,1,55,48,130,1,51,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,224,48,29,6,3,85,29,14,4,22,4,20,26,59,44,5,72,211,158,214,23,34,30,241,125,27,123,115,93,163,231,120,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,6,171,128,52,58,164,184,118,178,189,157,46,40,229,109,145,222,125,1,155,161,129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,19,8,101,114,108,97,110,103,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,1,1,48,33,6,3,85,29,17,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,129,129,0,93,11,112,227,121,15,121,179,247,135,110,216,17,197,84,18,149,166,147,142,190,178,0,209,190,0,142,233,144,100,194,205,220,182,73,204,108,42,95,23,48,63,4,120,239,42,194,25,184,35,117,107,96,229,18,45,76,122,125,40,171,210,132,50,146,178,160,55,17,35,255,208,114,30,47,55,185,154,155,165,204,180,14,143,20,234,6,234,201,225,72,235,5,87,61,255,250,23,217,1,144,246,98,221,223,102,49,168,177,13,70,241,26,27,254,251,217,14,244,18,242,197,151,50,186,214,15,42>>).
+
+dsa_pem() ->
+ 'OTP-PUB-KEY':decode('DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135,2,20,89,128,159,14,187,249,182,172,15,88,162,110,211,71,179,209,29,125,217,38>>),
+ 'OTP-PUB-KEY':decode('SubjectPublicKeyInfo',<<48,130,1,183,48,130,1,44,6,7,42,134,72,206,56,4,1,48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,3,129,132,0,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
+ 'OTP-PUB-KEY':decode('DSAParams',<<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>),
+ 'OTP-PUB-KEY':decode('DSAPublicKey',<<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
+ 'OTP-PUB-KEY':encode('DSAParams',{params,{'Dss-Parms',129000451850199666185842362389296595317127259539517666765336291347244303954511451744518587442120964433734460998523119938005801396466878889993179871123036311260456172022864663021425348874648247531097042575063545128239655736096045972718934778583429973433661785691086624069991876932064334822608460064613803976593,1216700114794736143432235288305776850295620488937,104420402274523493329542694749036577763086597934731674202966304958550599470165597750883637440049774107540742087494301536297571301945349213110548764383811017178451900599240379681904765817950545426764751538502808499880604633364255316249231153053427235538288687666086821781456733226598288985591031656134573747213}}),
+ 'OTP-PUB-KEY':encode(
+ 'SubjectPublicKeyInfo',
+ {'SubjectPublicKeyInfo',
+ {'AlgorithmIdentifier',
+ {1,2,840,10040,4,1},
+ <<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>},
+ {0,
+ <<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>}}).
diff --git a/lib/asn1/test/ber_decode_error.erl b/lib/asn1/test/ber_decode_error.erl
index 96d6545636..a566e0b07f 100644
--- a/lib/asn1/test/ber_decode_error.erl
+++ b/lib/asn1/test/ber_decode_error.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. 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
@@ -45,6 +45,10 @@ run([]) ->
run([driver]) ->
%% test of OTP-4797, bad indata to driver does not cause an EXIT
?line {error,_Reason} = asn1rt:decode('Constructed','S3',[3,5]),
+ ok;
+run([nif]) ->
+ %% test of OTP-4797, bad indata to driver does not cause an EXIT
+ ?line {error,_Reason} = asn1rt:decode('Constructed','S3',[3,5]),
ok.
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index 97f99e7b1c..39c1e4d1d8 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. 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
@@ -37,21 +37,10 @@ compile(Config,Rules,Opt) ->
?line DataDir = ?config(data_dir,Config),
?line OutDir = ?config(priv_dir,Config),
?line true = code:add_patha(?config(priv_dir,Config)),
- case Opt of
- [optimize] ->
- ?line ok = asn1ct:compile(DataDir ++ "Prim",
- [Rules,optimize,{outdir,OutDir}]),
- ?line ok = asn1ct:compile(DataDir ++ "Real",
- [Rules,optimize,{outdir,OutDir}]);
- __ ->
- ?line ok = asn1ct:compile(DataDir ++ "Prim",
- [Rules,{outdir,OutDir}]),
- ?line ok = asn1ct:compile(DataDir ++ "Real",
- [Rules,{outdir,OutDir}])
- end.
-
-
-
+ ?line ok = asn1ct:compile(DataDir ++ "Prim",
+ [Rules,{outdir,OutDir}] ++ Opt),
+ ?line ok = asn1ct:compile(DataDir ++ "Real",
+ [Rules,{outdir,OutDir}] ++ Opt).
bool(Rules) ->
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index f8128702dd..2514c06360 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -72,7 +72,6 @@ is_pure(erlang, binary_to_list, 1) -> true;
is_pure(erlang, binary_to_list, 3) -> true;
is_pure(erlang, bit_size, 1) -> true;
is_pure(erlang, byte_size, 1) -> true;
-is_pure(erlang, concat_binary, 1) -> true;
is_pure(erlang, element, 2) -> true;
is_pure(erlang, float, 1) -> true;
is_pure(erlang, float_to_list, 1) -> true;
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index 2ae0c333da..db5a17ad2e 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -635,7 +635,6 @@ bif_type(disconnect_node) -> safe;
bif_type(binary_to_list) -> safe;
bif_type(list_to_binary) -> safe;
bif_type(split_binary) -> safe;
-bif_type(concat_binary) -> safe;
bif_type(term_to_atom) -> safe;
bif_type(hash) -> safe;
bif_type(pre_loaded) -> safe;
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index f1be658054..64a695129b 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -675,8 +675,6 @@ type(erlang, cancel_timer, 1, Xs) ->
type(erlang, check_process_code, 2, Xs) ->
strict(arg_types(erlang, check_process_code, 2), Xs,
fun (_) -> t_boolean() end);
-type(erlang, concat_binary, 1, Xs) ->
- strict(arg_types(erlang, concat_binary, 1), Xs, fun (_) -> t_binary() end);
type(erlang, crc32, 1, Xs) ->
strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_crc32() end);
type(erlang, crc32, 2, Xs) ->
@@ -3397,8 +3395,6 @@ arg_types(erlang, cancel_timer, 1) ->
[t_reference()];
arg_types(erlang, check_process_code, 2) ->
[t_pid(), t_atom()];
-arg_types(erlang, concat_binary, 1) ->
- [t_list(t_binary())];
arg_types(erlang, crc32, 1) ->
[t_iodata()];
arg_types(erlang, crc32, 2) ->
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 8be265e79d..76c62ece67 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.14.5
+KERNEL_VSN = 2.15
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index 94abec083c..6b2a2bc3d9 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -65,7 +65,7 @@ EBIN = ../ebin
EXTRA_ERLC_FLAGS =
ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS)
-ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +asn1config +inline
+ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +asn1config +inline +nif
# ----------------------------------------------------
# Targets
diff --git a/lib/public_key/doc/src/introduction.xml b/lib/public_key/doc/src/introduction.xml
index 8cf11ee10e..a21fcf3576 100644
--- a/lib/public_key/doc/src/introduction.xml
+++ b/lib/public_key/doc/src/introduction.xml
@@ -48,5 +48,13 @@
of the concepts of using public keys.</p>
</section>
+ <section>
+ <title>Performance tips</title>
+ <p>The public_key decode and encode functions will try to use the nifs
+ which are in the asn1 compilers runtime modules if they can be found.
+ So for the best performance you want to have the asn1 application in the
+ path of your system. </p>
+ </section>
+
</chapter>
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 478f05e792..0b9b8b8e17 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -263,7 +263,6 @@ bif(bit_size, 1) -> true;
bif(bitstring_to_list, 1) -> true;
bif(byte_size, 1) -> true;
bif(check_process_code, 2) -> true;
-bif(concat_binary, 1) -> true;
bif(date, 0) -> true;
bif(delete_module, 1) -> true;
bif(demonitor, 1) -> true;
@@ -405,7 +404,6 @@ old_bif(bit_size, 1) -> true;
old_bif(bitstring_to_list, 1) -> true;
old_bif(byte_size, 1) -> true;
old_bif(check_process_code, 2) -> true;
-old_bif(concat_binary, 1) -> true;
old_bif(date, 0) -> true;
old_bif(delete_module, 1) -> true;
old_bif(disconnect_node, 1) -> true;
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 39d017d430..db46670f61 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -449,7 +449,7 @@ obsolete_1(ssl_pkix, decode_cert, A) when A =:= 1; A =:= 2 ->
%% Added in R13B04.
obsolete_1(erlang, concat_binary, 1) ->
- {deprecated,{erlang,list_to_binary,1},"R15B"};
+ {removed,{erlang,list_to_binary,1},"R15B"};
%% Added in R14A.
obsolete_1(ssl, peercert, 2) ->
@@ -461,6 +461,10 @@ obsolete_1(public_key, pem_to_der, 1) ->
obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
{deprecated,{public_key,pem_entry_decode,1},"R15A"};
+%% Added in R15B
+obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
+ {deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index e60706ed05..023183c5f0 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -661,6 +661,9 @@ do_restart(_, normal, Child, State) ->
do_restart(_, shutdown, Child, State) ->
NState = state_del_child(Child, State),
{ok, NState};
+do_restart(_, {shutdown, _Term}, Child, State) ->
+ NState = state_del_child(Child, State),
+ {ok, NState};
do_restart(transient, Reason, Child, State) ->
report_error(child_terminated, Reason, Child, State#state.name),
restart(Child, State);
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
index 3198be0fed..f819594c46 100644
--- a/lib/stdlib/test/supervisor_1.erl
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -62,6 +62,12 @@ handle_info(die, State) ->
handle_info(stop, State) ->
{stop, normal, State};
+handle_info({'EXIT',_,shutdown}, State) ->
+ {stop, shutdown, State};
+
+handle_info({'EXIT',_,{shutdown,Term}}, State) ->
+ {stop, {shutdown,Term}, State};
+
handle_info({sleep, Time}, State) ->
io:format("FOO: ~p~n", [Time]),
timer:sleep(Time),
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index ff5e4c629a..7a75114cb6 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -41,6 +41,8 @@
%% Tests concept permanent, transient and temporary
-export([ permanent_normal/1, transient_normal/1,
temporary_normal/1,
+ permanent_shutdown/1, transient_shutdown/1,
+ temporary_shutdown/1,
permanent_abnormal/1, transient_abnormal/1,
temporary_abnormal/1]).
@@ -71,6 +73,7 @@ all() ->
{group, restart_simple_one_for_one},
{group, restart_rest_for_one},
{group, normal_termination},
+ {group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
count_children_memory, do_not_save_start_parameters_for_temporary_children,
do_not_save_child_specs_for_temporary_children,
@@ -86,6 +89,8 @@ groups() ->
sup_stop_brutal_kill]},
{normal_termination, [],
[permanent_normal, transient_normal, temporary_normal]},
+ {shutdown_termination, [],
+ [permanent_shutdown, transient_shutdown, temporary_shutdown]},
{abnormal_termination, [],
[permanent_abnormal, transient_abnormal,
temporary_abnormal]},
@@ -549,6 +554,87 @@ temporary_normal(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+permanent_shutdown(doc) ->
+ ["A permanent child should always be restarted"];
+permanent_shutdown(suite) -> [];
+permanent_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1, CPid2 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid2) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+ [1,1,0,1] = get_child_counts(sup_test),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1, CPid3 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid3) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+transient_shutdown(doc) ->
+ ["A transient child should not be restarted if it exits with "
+ "reason shutdown or {shutdown,Term}"];
+transient_shutdown(suite) -> [];
+transient_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:restart_child(sup_test, child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+temporary_shutdown(doc) ->
+ ["A temporary process should never be restarted"];
+temporary_shutdown(suite) -> [];
+temporary_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
permanent_abnormal(doc) ->
["A permanent child should always be restarted"];
permanent_abnormal(suite) -> [];
@@ -1251,6 +1337,13 @@ terminate(_, ChildPid, _, shutdown) ->
{'DOWN', Ref, process, ChildPid, shutdown} ->
ok
end;
+terminate(_, ChildPid, _, {shutdown, Term}) ->
+ Ref = erlang:monitor(process, ChildPid),
+ exit(ChildPid, {shutdown, Term}),
+ receive
+ {'DOWN', Ref, process, ChildPid, {shutdown, Term}} ->
+ ok
+ end;
terminate(_, ChildPid, _, normal) ->
Ref = erlang:monitor(process, ChildPid),
ChildPid ! stop,
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 9d4ed17774..2f0ecd3863 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.17.5
+STDLIB_VSN = 1.18