├── VERSION ├── .gitignore ├── test ├── z.ber ├── zes.ber ├── zin.ber ├── zpr.ber ├── zr.ber ├── c │ ├── go │ └── Makefile ├── mterm2.asn ├── z39 │ └── Makefile ├── univres.asn ├── check.lua ├── useful.asn ├── oclcui.asn ├── esadmin.asn ├── check.c ├── datetime.asn ├── esupdate.asn └── charneg-3.asn ├── README ├── include └── luaber.h ├── src ├── ber_util.h ├── mmodr.h ├── asn │ ├── map.h │ ├── asn.h │ ├── odr.h │ ├── map.c │ └── asn.c ├── mmodr.c ├── ber.h ├── pdu │ └── pdu.c ├── ber_util.c ├── luaber.c └── ber.c ├── CHANGELOG.md ├── ber-0.3.1-1.rockspec └── Makefile /VERSION: -------------------------------------------------------------------------------- 1 | 0.3 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | /ber.so 3 | /asn2odr 4 | /odr2pdu 5 | /*.rock 6 | -------------------------------------------------------------------------------- /test/z.ber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aperezdc/lua-ber/master/test/z.ber -------------------------------------------------------------------------------- /test/zes.ber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aperezdc/lua-ber/master/test/zes.ber -------------------------------------------------------------------------------- /test/zin.ber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aperezdc/lua-ber/master/test/zin.ber -------------------------------------------------------------------------------- /test/zpr.ber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aperezdc/lua-ber/master/test/zpr.ber -------------------------------------------------------------------------------- /test/zr.ber: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aperezdc/lua-ber/master/test/zr.ber -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Simple Basic Encoding Rules (BER) of Abstract Syntax 2 | Notation One (ASN.1) implementation as library for Lua. 3 | 4 | -- 5 | Nodir Temirhodzhaev, 6 | -------------------------------------------------------------------------------- /include/luaber.h: -------------------------------------------------------------------------------- 1 | #ifndef LUABER_H 2 | #define LUABER_H 3 | 4 | #define LUA_BERLIBNAME "BER" 5 | 6 | LUALIB_API int 7 | luaopen_ber (lua_State *L); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /test/c/go: -------------------------------------------------------------------------------- 1 | #./tst -f../z39/z3950.odr -lz.lua <../tmp/z.ber >/tmp/berout; exit 2 | for BER in ../tmp/*.ber; do 3 | echo $BER 4 | ./tst -f../z39/z3950.odr -lz.lua <$BER >/tmp/berout 5 | done 6 | -------------------------------------------------------------------------------- /src/ber_util.h: -------------------------------------------------------------------------------- 1 | #ifndef BER_UTILS_H 2 | #define BER_UTILS_H 3 | 4 | int oid2str (lua_State *L); 5 | int str2oid (lua_State *L); 6 | int bitstr2num (lua_State *L); 7 | int num2bitstr (lua_State *L); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/mmodr.h: -------------------------------------------------------------------------------- 1 | #ifndef MMODR_H 2 | #define MMODR_H 3 | 4 | #include "asn/odr.h" 5 | 6 | struct mmodr { 7 | struct tmt *odrs, *start; 8 | struct module_id *modules; 9 | char *names; 10 | unsigned char nmodules; 11 | }; 12 | 13 | int mmodr_set (struct mmodr *mo, const void *info, int len); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /test/c/Makefile: -------------------------------------------------------------------------------- 1 | BER= ../.. 2 | 3 | include $(BER)/config 4 | 5 | CFLAGS= $(MYCFLAGS) $(WARN) -I$(INC) -I$(BER)/src $(LUAINCS) 6 | 7 | T= tst 8 | OBJS= $(T).o 9 | SRCS= $(T).c 10 | 11 | all: $T 12 | 13 | $T: $(OBJS) $(HDRS) 14 | $(CC) -o $@ $(CFLAGS) $(OBJS) $(BERLIBS) $(LUALIBS) 15 | 16 | clean: 17 | rm -f $(OBJS) $T 18 | -------------------------------------------------------------------------------- /test/mterm2.asn: -------------------------------------------------------------------------------- 1 | UserInfoFormat-multipleSearchTerms-2 2 | {Z39-50-userInfoFormat MultipleSearchTerms-2 (5)} DEFINITIONS ::= 3 | BEGIN 4 | IMPORTS Term FROM Z39-50-APDU-1995; 5 | 6 | MultipleSearchTerms-2 ::= SEQUENCE OF SEQUENCE{ 7 | term [1] IMPLICIT Term, 8 | flag [2] IMPLICIT BOOLEAN OPTIONAL} 9 | 10 | END 11 | -------------------------------------------------------------------------------- /test/z39/Makefile: -------------------------------------------------------------------------------- 1 | BER= ../.. 2 | 3 | include $(BER)/config 4 | 5 | ASN= z3950v3.asn charneg-3.asn datetime.asn esadmin.asn esupdate.asn\ 6 | mterm2.asn oclcui.asn univres.asn 7 | 8 | T= z3950.odr 9 | PDU= $(T).pdu 10 | 11 | all: $T 12 | 13 | $T: $(ASN) 14 | $(BIN)/asn2odr useful.asn -s $(ASN) 15 | mv asn.odr $(T) 16 | 17 | pdu: $(T) 18 | $(BIN)/odr2pdu $(T) > $(PDU) 19 | 20 | clean: 21 | rm -f $(T) $(PDU) 22 | -------------------------------------------------------------------------------- /src/asn/map.h: -------------------------------------------------------------------------------- 1 | #ifndef MAP_H 2 | #define MAP_H 3 | 4 | int odr_add (const struct tmt *t); 5 | int name_add (const char *s); 6 | void names_del (void); 7 | struct module *module_add (const int opt, const char *mname); 8 | void module_del (struct module *mdel); 9 | struct def *def_add (struct module *m, const int opt, const char *dname); 10 | void def_del (struct module *m, struct def *dend, const unsigned char leave); 11 | void def_req (struct def *fdef, const union comp_addr u, const unsigned char opt); 12 | void *find (const char *name, void *i, const void *end); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /test/univres.asn: -------------------------------------------------------------------------------- 1 | ResourceReport-Format-Universe-1 2 | {Z39-50-resourceReport universe-1 (1000)} DEFINITIONS ::= 3 | BEGIN 4 | IMPORTS StringOrNumeric FROM Z39-50-APDU-1995; 5 | -- 6 | 7 | UniverseReportHits ::= SEQUENCE { 8 | database StringOrNumeric, 9 | hits StringOrNumeric 10 | } 11 | 12 | UniverseReportDuplicate ::= SEQUENCE { 13 | hitno StringOrNumeric 14 | } 15 | 16 | UniverseReport ::= SEQUENCE { 17 | totalHits INTEGER, 18 | report CHOICE { 19 | databaseHits [0] IMPLICIT UniverseReportHits, 20 | duplicate [1] IMPLICIT UniverseReportDuplicate 21 | } 22 | } 23 | END 24 | -------------------------------------------------------------------------------- /test/check.lua: -------------------------------------------------------------------------------- 1 | -- Z39.50 2 | 3 | local CB, t, qi = {}, {}, QI 4 | 5 | -- initResponse 6 | local function initRp(pdu) 7 | t = { 8 | [2] = "\224", 9 | [3] = "\233\162", 10 | [4] = 64536, 11 | [5] = 64536, 12 | [6] = 1, 13 | [8] = "Z3950/LuaBER", 14 | [9] = "0.1" 15 | } 16 | return 2 17 | end 18 | 19 | -- searchResponse 20 | local function searchRp(pdu) 21 | t = { 22 | [2] = 0, 23 | [3] = 0, 24 | [4] = 0, 25 | [5] = 0 26 | } 27 | return 4 28 | end 29 | 30 | CB = {[1] = initRp, [3] = searchRp} 31 | local k, v = next(qi[1]) 32 | --QO = QI 33 | QO = {[1] = {}}; if CB[k] then QO[1][CB[k](v)] = t end 34 | -------------------------------------------------------------------------------- /src/mmodr.c: -------------------------------------------------------------------------------- 1 | /* Set mmodr */ 2 | 3 | #include /* strcmp */ 4 | 5 | #include "mmodr.h" 6 | 7 | int 8 | mmodr_set (struct mmodr *mo, const void * const p, int len) 9 | { 10 | if (len > (int) sizeof (struct odr_info)) { 11 | const struct odr_info * const info = p; 12 | 13 | mo->odrs = (struct tmt *) info; 14 | mo->start = mo->odrs + info->start; 15 | mo->modules = (struct module_id *) (mo->odrs + info->nodrs); 16 | mo->names = (char *) (mo->modules + info->nmodules); 17 | mo->nmodules = (char) info->nmodules; 18 | 19 | return 20 | !(len >= (mo->names - (char *) info) + (int) sizeof (ODR_NAME_STUB) 21 | && !strcmp (mo->names, ODR_NAME_STUB)); 22 | } 23 | return -1; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. This 4 | project adheres to [Semantic Versioning](http://semver.org). 5 | 6 | ## [Unreleased] 7 | 8 | 9 | ## [v0.3.1] - 2016-02-10 10 | 11 | ### Added 12 | - Support building for using LuaRocks, and added a rockspec to the repository. 13 | 14 | ### Fixed 15 | - Now it is possible to build (and use) the module with Lua 5.1, 5.2, and 16 | 5.3. 17 | 18 | 19 | ## v0.3 20 | 21 | ### Added 22 | - Initial import of the old luaber 0.3 code, from the tarball hosted at the 23 | lua-users wiki. 24 | 25 | [Unreleased]: https://github.com/aperezdc/lua-ber/compare/v0.3.1...HEAD 26 | [v0.3.1]: https://github.com/aperezdc/lua-ber/compare/v0.3...v0.3.1 27 | -------------------------------------------------------------------------------- /ber-0.3.1-1.rockspec: -------------------------------------------------------------------------------- 1 | rockspec_format = "1.0" 2 | package = "ber" 3 | version = "0.3.1-1" 4 | source = { 5 | url = "git://github.com/aperezdc/lua-ber", 6 | tag = "v0.3.1" 7 | } 8 | description = { 9 | summary = "BER and ASN.1 encoder and decoder", 10 | homepage = "https://github.com/aperezdc/lua-ber", 11 | license = "Public Domain", 12 | maintainer = "Adrián Pérez de Castro " 13 | } 14 | dependencies = { 15 | "lua >= 5.1" 16 | } 17 | build = { 18 | type = "make", 19 | build_variables = { 20 | CFLAGS = "$(CFLAGS)", 21 | LIBFLAG = "$(LIBFLAG)", 22 | LUA = "$(LUA)", 23 | LUA_BINDIR = "$(LUA_BINDIR)", 24 | LUA_INCDIR = "$(LUA_INCDIR)", 25 | LUA_LIBDIR = "$(LUA_LIBDIR)" 26 | }, 27 | install_variables = { 28 | INST_BINDIR = "$(BINDIR)", 29 | INST_CONFDIR = "$(CONFDIR)", 30 | INST_LIBDIR = "$(LIBDIR)", 31 | INST_LUADIR = "$(LUADIR)", 32 | INST_PREFIX = "$(PREFIX)" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/asn/asn.h: -------------------------------------------------------------------------------- 1 | #ifndef ASN_H 2 | #define ASN_H 3 | 4 | #include "odr.h" 5 | 6 | #define NAMESIZ 36 7 | 8 | struct tmt *odrs; 9 | int odrs_size, odrs_next; 10 | 11 | char *names; 12 | int names_size, names_next; 13 | 14 | struct oid { 15 | char name[NAMESIZ]; 16 | struct oid *next; 17 | unsigned char oid[OIDSIZ]; /* oid[0] - length */ 18 | }; 19 | 20 | union comp_addr { 21 | int addr; 22 | struct def *ncdef; 23 | }; 24 | 25 | /* used to sort component names and odr */ 26 | struct comp { 27 | struct comp *next; 28 | unsigned char opt; /* DEF_INCOMPL -> u.ncdef */ 29 | union comp_addr u; 30 | } *comp_names; /* head of component names */ 31 | 32 | struct def { 33 | char name[NAMESIZ]; 34 | struct def *next; 35 | struct tmt tag; 36 | unsigned short int addr; 37 | #define DEF_EXPORT 1 38 | #define DEF_IMPORT 2 39 | #define DEF_INCOMPL 4 40 | #define FORWARD 8 41 | unsigned char opt; 42 | struct def *type; 43 | struct comp *compn; 44 | }; 45 | 46 | struct module { 47 | char name[NAMESIZ]; 48 | struct module *next; 49 | struct module_id id; 50 | unsigned char opt; 51 | struct def *defn, *imports, *exports; 52 | } *modules; /* head of modules */ 53 | 54 | 55 | void asnError (const char *fmt, ...); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /test/useful.asn: -------------------------------------------------------------------------------- 1 | _USE 2 | DEFINITIONS ::= 3 | BEGIN 4 | EXPORTS ALL; 5 | 6 | ObjectDescriptor ::= [UNIVERSAL 7] IMPLICIT OCTET STRING 7 | EXTERNAL ::= [UNIVERSAL 8] IMPLICIT SEQUENCE { 8 | direct-reference EXT_DREF OPTIONAL, 9 | indirect-reference INTEGER OPTIONAL, 10 | data-value-descriptor ObjectDescriptor OPTIONAL, 11 | encoding CHOICE { 12 | single-ASN1-type [0] IMPLICIT EXT_ASN, 13 | octet-aligned [1] IMPLICIT OCTET STRING, 14 | arbitrary [2] IMPLICIT BIT STRING 15 | } 16 | } 17 | ENUMERATED ::= [UNIVERSAL 10] IMPLICIT INTEGER 18 | NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING 19 | PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING 20 | TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING 21 | T61String ::= [UNIVERSAL 20] IMPLICIT OCTET STRING 22 | VideotexString ::= [UNIVERSAL 21] IMPLICIT OCTET STRING 23 | IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING 24 | UTCTime ::= [UNIVERSAL 23] IMPLICIT OCTET STRING 25 | GeneralizedTime ::= [UNIVERSAL 24] IMPLICIT OCTET STRING 26 | GraphicString ::= [UNIVERSAL 25] IMPLICIT OCTET STRING 27 | VisibleString ::= [UNIVERSAL 26] IMPLICIT OCTET STRING 28 | ISO646String ::= [UNIVERSAL 26] IMPLICIT OCTET STRING 29 | GeneralString ::= [UNIVERSAL 27] IMPLICIT OCTET STRING 30 | 31 | END 32 | -------------------------------------------------------------------------------- /test/oclcui.asn: -------------------------------------------------------------------------------- 1 | UserInfoFormat-oclcUserInformation 2 | {Z39-50-userInfoFormat Local(1000) OCLCUserInformation (7)} DEFINITIONS ::= --!! 3 | BEGIN 4 | 5 | -- $Id: oclcui.asn,v 1.4 2003/09/04 17:44:49 adam Exp $ 6 | -- 7 | -- This format is returned from the server at 8 | -- fsz3950test.oclc.org:210 9 | -- I found the definition at 10 | -- http://www.oclc.org/firstsearch/documentation/z3950/config_guide.htm 11 | -- 12 | -- I have added OPTIONAL modifiers to the `dblist' and and `code' 13 | -- elements because they appear to be admitted from the APDU returned 14 | -- as an Init diagnostic from fsz3950test.oclc.org:210. Adam further 15 | -- removed the SEQUENCE structure, changed failReason to a BOOLEAN and 16 | -- deleted diagnosticSetId altogether, to make the ASN.1 conform to 17 | -- what's actually returned on the wire. Finally, I removed the 18 | -- OPTIONAL on failReason on the advice of OCLC's Keith Neibarger 19 | -- (although he'd also advised me, wrongly, that I 20 | -- could remove the OPTIONAL on dblist). 21 | 22 | OCLC-UserInformation ::= SEQUENCE { 23 | motd [1] IMPLICIT VisibleString OPTIONAL, 24 | dblist SEQUENCE OF DBName OPTIONAL, 25 | failReason [3] IMPLICIT BOOLEAN OPTIONAL, 26 | code [1] IMPLICIT INTEGER OPTIONAL, 27 | text [2] IMPLICIT VisibleString OPTIONAL 28 | } 29 | 30 | DBName ::= [2] IMPLICIT VisibleString 31 | 32 | END 33 | 34 | -------------------------------------------------------------------------------- /src/asn/odr.h: -------------------------------------------------------------------------------- 1 | #ifndef ODR_H 2 | #define ODR_H 3 | 4 | #define ODR_NAME_STUB "NIL" 5 | 6 | #define COMP_START_NUM 1 /* for Lua arrays */ 7 | 8 | enum ber_fun {FUN_OCT, FUN_BIT, FUN_OID, FUN_INT, FUN_BOOL, 9 | FUN_NULL, FUN_EXT_DREF, FUN_EXT_ASN, FUN_OCT_SKIP}; 10 | #ifdef BER_FUN_NAMES 11 | char *ber_fun_names[] = {"Oct", "Bit", "OID", "Int", "Bool", 12 | "Null", "Ext_DRef", "Ext_ASN"}; 13 | #endif 14 | 15 | struct odr_info { 16 | unsigned short start; /* first searching tmt in odrs area */ 17 | unsigned short nodrs, nmodules; /* count of modules have ModuleId */ 18 | }; 19 | 20 | typedef int tag_id_t; 21 | union tag_id { 22 | tag_id_t cn; 23 | struct { 24 | #define CLASS_UNIVERSAL 0 25 | #define CLASS_APPLICATION 64 26 | #define CLASS_CONTEXT 128 27 | #define CLASS_PRIVATE 192 28 | unsigned char classnum; 29 | #define CLASS_NUMSIZ sizeof (tag_id_t) - sizeof (char) 30 | unsigned char number[CLASS_NUMSIZ]; 31 | } id; 32 | }; 33 | 34 | struct tmt { 35 | union tag_id u; 36 | #define TAG_TWO_WORDS 1 37 | #define TAG_IMPLICIT 2 38 | #define TAG_SIMPLE 4 39 | #define TAG_DEFINITION 8 40 | #define TAG_CHOICE 16 41 | #define TAG_COMPONENTS 32 42 | #define TAG_TYPE_OF 64 43 | #define TAG_OPTIONAL 128 44 | unsigned char opt, comp_no; 45 | unsigned short subaddr, comp_next, nameaddr; 46 | }; 47 | 48 | struct module_id { 49 | #define OIDSIZ 12 /* with length byte */ 50 | unsigned char oid[OIDSIZ]; /* oid[0] - length */ 51 | unsigned short addr, nameaddr; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /test/esadmin.asn: -------------------------------------------------------------------------------- 1 | ESFormat-Admin 2 | {Z39-50-extendedService Local(1000) Index-Data(81) AdminES(1)} DEFINITIONS ::= --!! 3 | -- oid is 1.2.840.10003.9.81.1 4 | BEGIN 5 | IMPORTS DiagRec, InternationalString, Segment 6 | FROM Z39-50-APDU-1995; 7 | Admin ::= CHOICE{ 8 | esRequest [1] IMPLICIT SEQUENCE{ 9 | toKeep [1] OriginPartToKeep, 10 | notToKeep [2] OriginPartNotToKeep}, 11 | taskPackage [2] IMPLICIT SEQUENCE{ 12 | originPart [1] 13 | OriginPartToKeep, 14 | targetPart [2] TargetPart}} 15 | 16 | OriginPartToKeep ::= SEQUENCE{ 17 | action [1] CHOICE{ 18 | reIndex [1] NULL, 19 | truncate [2] NULL, 20 | drop [3] NULL, 21 | create [4] NULL, 22 | import [5] ImportParameters, 23 | refresh [6] NULL, -- Review internal representation of records against source files on disk to 24 | -- see if they have been updated. 25 | commit [7] NULL, 26 | shutdown [8] NULL, 27 | start [9] NULL}, 28 | databaseName [2] IMPLICIT InternationalString OPTIONAL} 29 | 30 | OriginPartNotToKeep ::= CHOICE{ 31 | records [1] Segment, 32 | recordsWillFollow [0] NULL} 33 | 34 | TargetPart ::= SEQUENCE{ 35 | updateStatus [1] IMPLICIT INTEGER{ 36 | success (1), 37 | partial (2), 38 | failure (3)}, 39 | globalDiagnostics [2] IMPLICIT SEQUENCE OF 40 | DiagRec OPTIONAL 41 | } 42 | 43 | -- Auxiliary definitions for Admin 44 | 45 | ImportParameters ::= SEQUENCE{ 46 | recordType [1] IMPLICIT InternationalString 47 | } 48 | 49 | END 50 | -------------------------------------------------------------------------------- /src/ber.h: -------------------------------------------------------------------------------- 1 | #ifndef BER_H 2 | #define BER_H 3 | 4 | #include /* jmp_buf */ 5 | 6 | #include 7 | 8 | #include "mmodr.h" 9 | 10 | 11 | #define BERS_MAX 40 /* deep of bers stack */ 12 | #define CHOICES_MAX 8 /* maximum immediately choices */ 13 | #define ENC_BUFRESERVE BERS_MAX * 2 /* sizeof "\0\0" */ 14 | #define ENC_LLEN_MAX sizeof (int) + 1 /* encode length of length */ 15 | /*#define ENC_SIMPLESZ_MAX 1000*/ /* CER */ 16 | 17 | 18 | struct ber { 19 | union tag_id u; 20 | int len; /* defined size */ 21 | union { 22 | int size; /* total size (decode) */ 23 | unsigned char *bufp; /* pointer to length (encode) */ 24 | } v; 25 | #define BER_INCOMPL 1 26 | #define BER_MORE 2 27 | #define BER_CONSTR 32 28 | #define BER_INDEFIN 128 29 | unsigned char opt; /* concurrent to tag.opt (TAG_...) */ 30 | unsigned short int no; /* tag->comp_no | occurence of TYPE_OF */ 31 | struct tmt *tag, *next; 32 | }; 33 | 34 | struct bers { 35 | struct mmodr *odr; 36 | lua_State *L; 37 | jmp_buf *jb; 38 | struct ber stack[BERS_MAX], *top; 39 | unsigned char *buf, *bp, *endp; 40 | struct module_id *ext_mid; /* EXTERNAL */ 41 | }; 42 | 43 | 44 | /* Error codes */ 45 | #define BER_ERRMEM -1 46 | #define BER_ERRTAG -10 47 | #define BER_ERRTAGLEN -11 48 | #define BER_ERRTAGNUM -12 49 | #define BER_ERRTAGODR -13 50 | #define BER_ERROID -20 51 | #define BER_ERROIDMID -21 52 | #define BER_ERREXT -30 53 | #define BER_ERREXTOID -31 54 | #define BER_ERRSTKO -40 55 | #define BER_ERRSTKU -41 56 | #define BER_ERRCHCSO -50 57 | #define BER_ERRLUASTK -60 58 | #define BER_ERRLUAOUT -61 59 | #define BER_ERRSIZE -70 60 | #define BER_ERRODR -80 61 | 62 | const char * 63 | ber_errstr (const int no); 64 | unsigned char 65 | ber_decode (struct bers *bs); 66 | unsigned char 67 | ber_encode (struct bers *bs); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BER_SRCS := src/ber.c src/ber_util.c src/luaber.c src/mmodr.c 2 | BER_OBJS := $(BER_SRCS:.c=.o) 3 | ASN2ODR_SRCS := src/asn/asn.c src/asn/map.c 4 | ASN2ODR_OBJS := $(ASN2ODR_SRCS:.c=.o) 5 | ODR2PDU_SRCS := src/pdu/pdu.c src/mmodr.c 6 | ODR2PDU_OBJS := $(ODR2PDU_SRCS:.c=.o) 7 | 8 | # Makeing a Makefile compatible with LuaRocks: 9 | # https://github.com/keplerproject/luarocks/wiki/Creating-a-Makefile-that-plays-nice-with-LuaRocks 10 | 11 | LUA = lua 12 | LUA_VERSION = 13 | DESTDIR = 14 | INST_PREFIX = /usr/local 15 | INST_BINDIR = $(INST_PREFIX)/bin 16 | INST_LIBDIR = $(INST_PREFIX)/lib/lua/$(LUA_VERSION) 17 | INST_LUADIR = $(INST_PREFIX)/share/lua/$(LUA_VERSION) 18 | INST_CONFDIR = $(INST_PREFIX)/etc 19 | 20 | ifeq ($(strip $(LUA_VERSION)),) 21 | LUA_VERSION = $(shell $(LUA) -e 'print(string.sub(_VERSION, 5))') 22 | endif 23 | 24 | ifeq ($(strip $(LIBFLAG)),) 25 | # XXX May not work everywhere 26 | LIBFLAG = -shared 27 | CFLAGS += -fPIC 28 | endif 29 | 30 | ifneq ($(strip $(LUA_INCDIR)),) 31 | CPPFLAGS += -I$(LUA_INCDIR) 32 | endif 33 | ifneq ($(strip $(LUA_LIBDIR)),) 34 | LDFLAGS += -L$(LUA_LIBDIR) 35 | endif 36 | 37 | all: print-vars ber.so asn2odr odr2pdu 38 | 39 | print-vars: 40 | @echo "CC = $(CC)" 41 | @echo "CFLAGS = $(CFLAGS)" 42 | @echo "CPPFLAGS = $(CPPFLAGS)" 43 | @echo "LDFLAGS = $(LDFLAGS)" 44 | @echo "LIBFLAG = $(LIBFLAG)" 45 | @echo "LUA = $(LUA)" 46 | @echo "LUA_VERSION = $(LUA_VERSION)" 47 | @echo "LUA_INCDIR = $(LUA_INCDIR)" 48 | @echo "DESTDIR = $(DESTDIR)" 49 | @echo "INST_PREFIX = $(INST_PREFIX)" 50 | @echo "INST_BINDIR = $(INST_BINDIR)" 51 | @echo "INST_LIBDIR = $(INST_LIBDIR)" 52 | @echo "INST_LUADIR = $(INST_LUADIR)" 53 | @echo "INST_CONFDIR = $(INST_CONFDIR)" 54 | 55 | .PHONY: print-vars 56 | 57 | ber.so: $(BER_OBJS) 58 | $(CC) $(LIBFLAG) -o $@ $(LDFLAGS) $^ 59 | 60 | asn2odr: $(ASN2ODR_OBJS) 61 | $(CC) -o $@ $(LDFLAGS) $^ 62 | 63 | odr2pdu: $(ODR2PDU_OBJS) 64 | $(CC) -o $@ $(LDFLAGS) $^ 65 | 66 | clean: 67 | $(RM) ber.so $(BER_OBJS) 68 | $(RM) asn2odr $(ASN2ODR_OBJS) 69 | $(RM) odr2pdu $(ODR2PDU_OBJS) 70 | 71 | install: all 72 | install -Dm755 ber.so $(DESTDIR)$(INST_LIBDIR)/ber.so 73 | install -Dm755 asn2odr $(DESTDIR)$(INST_BINDIR)/asn2odr 74 | install -Dm755 odr2pdu $(DESTDIR)$(INST_BINDIR)/odr2pdu 75 | 76 | .PHONY: install 77 | 78 | 79 | TEST_ASN := $(filter-out test/useful.asn,$(wildcard test/*.asn)) 80 | TEST_BER := $(wildcard test/*.ber) 81 | 82 | test/z3950.odr: test/useful.asn $(TEST_ASN) | asn2odr 83 | ./asn2odr test/useful.asn -s $(TEST_ASN) 84 | mv asn.odr $@ 85 | 86 | test/z3950.pdu: test/z3950.odr | odr2pdu 87 | ./odr2pdu $< > $@ 88 | 89 | test/check: CPPFLAGS += -Isrc 90 | test/check: test/check.o $(BER_OBJS) 91 | $(CC) -o $@ $(CFLAGS) $^ -llua 92 | 93 | check: test/z3950.odr test/check test/check.lua 94 | @for i in $(TEST_BER) ; do \ 95 | echo "=== ./test/check -ftest/z3950.odr -ltest/check.lua < $$i ===" ; \ 96 | ./test/check -ftest/z3950.odr -ltest/check.lua < $$i ; \ 97 | done 98 | 99 | .PHONY: check 100 | -------------------------------------------------------------------------------- /src/pdu/pdu.c: -------------------------------------------------------------------------------- 1 | /* Print about PDU's from odr file */ 2 | 3 | #include 4 | #include 5 | 6 | #define BER_FUN_NAMES 7 | #include "../mmodr.h" 8 | 9 | 10 | static const char usage[] = "Usage: odr2pdu FILE\n"; 11 | 12 | static struct mmodr odr; 13 | 14 | static void 15 | err_quit (const char *msg) 16 | { 17 | fprintf (stderr, msg); 18 | exit (EXIT_FAILURE); 19 | } 20 | 21 | /* Print information about components */ 22 | static void 23 | odrNames (struct tmt *t) 24 | { 25 | #define ODR_STACKSIZ 40 26 | struct tmt *stack[ODR_STACKSIZ]; 27 | int level = 0, i, recurs; 28 | 29 | for (; ; ) { 30 | recurs = 0; 31 | putchar ('\n'); 32 | for (i = level; i; --i) putchar ('\t'); 33 | printf ("^%d [0x%x] %s ", 34 | t->comp_no, t->u.cn, odr.names + t->nameaddr); 35 | if (t->opt & TAG_OPTIONAL) printf ("OPT. "); 36 | if (t->opt & TAG_TYPE_OF) printf ("OF "); 37 | if (!(t->opt & TAG_SIMPLE)) { 38 | if (level) 39 | for (i = level - 1; i; --i) 40 | if (t == stack[i]) { 41 | recurs = 1; 42 | break; 43 | } 44 | if (!recurs) { 45 | if (!t->u.cn || (t->opt & TAG_CHOICE)) 46 | printf ("CHOICE "); 47 | putchar ('{'); 48 | if (level >= ODR_STACKSIZ) 49 | err_quit ("Odrs stack overflow\n"); 50 | stack[level++] = t; 51 | t = odr.odrs + t->subaddr; 52 | continue; 53 | } else printf ("LOOP (level %d)", i); 54 | } else 55 | if (t->subaddr < sizeof (ber_fun_names)) 56 | printf ("[%s]", ber_fun_names[t->subaddr]); 57 | else printf ("[%d?] tag.opt=%d", t->subaddr, t->opt); 58 | if (!t->comp_next || recurs) { 59 | do 60 | if (--level >= 0) putchar ('}'); 61 | else return; 62 | while (!stack[level]->comp_next); 63 | t = stack[level]; 64 | } 65 | t = odr.odrs + t->comp_next; 66 | } 67 | } 68 | 69 | static void 70 | odrModules () 71 | { 72 | struct module_id *mid; 73 | int i, num, sub; 74 | 75 | for (mid = odr.modules; (void *) mid != odr.names; ++mid) { 76 | printf ("%c%d %s", (odr.odrs + mid->addr == odr.start) ? '>' : '~', 77 | mid - odr.modules, odr.names + mid->nameaddr); 78 | if (mid->oid[0] > 1) { 79 | num = mid->oid[1]; 80 | sub = num / 40; 81 | if (sub > 2) sub = 2; 82 | num = num - sub * 40; 83 | printf (" {%d.%d", sub, num); 84 | for (i = 2, sub = 0; i <= mid->oid[0]; ++i) { 85 | for (num = 0; mid->oid[i] & 0x80; ++i, num <<= 7) 86 | num |= mid->oid[i] & 0x7F; 87 | num |= mid->oid[i]; 88 | printf (".%d", num); 89 | } 90 | putchar ('}'); 91 | } 92 | odrNames (odr.odrs + mid->addr); 93 | printf ("\n\n"); 94 | } 95 | } 96 | 97 | static int 98 | file_odr_open (struct mmodr *mo, const char *file) 99 | { 100 | FILE *fodr = fopen (file, "rb"); 101 | if (fodr && !fseek (fodr, 0, SEEK_END)) { 102 | int len = ftell (fodr); 103 | if (len != -1 && !fseek (fodr, 0, SEEK_SET)) { 104 | void *mp = malloc (len); 105 | if (mp) { 106 | len = fread (mp, 1, len, fodr); 107 | fclose (fodr); 108 | if (len) return mmodr_set (mo, mp, len); 109 | free (mp); 110 | } 111 | } 112 | } 113 | return -1; 114 | } 115 | 116 | int 117 | main (int argc, char *argv[]) 118 | { 119 | if (argc < 2) err_quit (usage); 120 | if (file_odr_open (&odr, argv[1])) 121 | err_quit ("bad odr file\n"); 122 | odrModules (); 123 | free (odr.odrs); 124 | return EXIT_SUCCESS; 125 | } 126 | -------------------------------------------------------------------------------- /src/ber_util.c: -------------------------------------------------------------------------------- 1 | /* LuaBER utilities */ 2 | 3 | #include /* isdigit */ 4 | #include /* memmove */ 5 | 6 | #include 7 | 8 | 9 | #define atod(cp, num) \ 10 | while (isdigit (*(cp))) \ 11 | (num) = ((num) << 3) + ((num) << 1) + (*((cp)++) & ~'0'); 12 | 13 | #define bytes_count(x) \ 14 | !(x) ? 0 : ((x) & 0xFF000000) ? 4 : ((x) & 0xFF0000) ? 3 \ 15 | : ((x) & 0xFF00) ? 2 : 1 16 | 17 | 18 | static unsigned int 19 | reverse (register unsigned int x) 20 | { 21 | x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 22 | x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 23 | x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 24 | return x; 25 | } 26 | 27 | static int 28 | dtoa (char *s, int len, int num) 29 | { 30 | if (!len) return 0; 31 | if (!num) { 32 | *s = '0'; 33 | len = 1; 34 | } else { 35 | int i = len; 36 | do { 37 | s[--i] = (num % 10) | '0'; 38 | num /= 10; 39 | } while (num && i > 0); 40 | len -= i; 41 | memmove (s, &s[i], len); 42 | } 43 | return len; 44 | } 45 | 46 | /* 47 | * Arguments: string 48 | * Returns: string 49 | */ 50 | int 51 | oid2str (lua_State *L) 52 | { 53 | #define OID_STRSIZE 32 54 | char oid[OID_STRSIZE]; 55 | unsigned int num; 56 | unsigned char sub, oidi = 0; 57 | size_t len = 0; 58 | const char *oidp = lua_tolstring (L, -1, &len); 59 | 60 | if (!oidp) return 0; 61 | num = *oidp++; 62 | sub = num / 40; 63 | if (sub > 2) sub = 2; 64 | num = num - sub * 40; 65 | oidi += dtoa (&oid[oidi], OID_STRSIZE - oidi, sub); 66 | for (; ; ) { 67 | oid[oidi++] = '.'; 68 | oidi += dtoa (&oid[oidi], OID_STRSIZE - oidi, num); 69 | if (!--len || oidi >= OID_STRSIZE) break; 70 | for (num = 0; *oidp & 0x80; --len, ++oidp, num <<= 7) 71 | num |= *oidp & 0x7F; 72 | num |= *oidp++; 73 | } 74 | lua_pushlstring (L, oid, oidi > OID_STRSIZE ? OID_STRSIZE : oidi); 75 | return 1; 76 | } 77 | 78 | /* 79 | * Arguments: string 80 | * Returns: string 81 | */ 82 | int 83 | str2oid (lua_State *L) 84 | { 85 | #define OID_SIZE 24 86 | unsigned int num = 0, number; 87 | unsigned char sub = 0, oid[OID_SIZE], *oidp = oid; 88 | const char *strp = lua_tostring (L, -1); 89 | 90 | if (!strp) return 0; 91 | atod (strp, sub); 92 | if ((sub > 2) || (*strp++ != '.')) return 0; 93 | atod (strp, num); 94 | *oidp++ = sub * 40 + num; 95 | num = 0; 96 | while (*strp == '.') { 97 | ++strp; 98 | atod (strp, num); 99 | number = num & 0x7F; 100 | num >>= 7; 101 | for (sub = 1; num; ++sub) { 102 | number <<= 8; 103 | number |= (unsigned char) num | 0x80; 104 | num >>= 7; 105 | } 106 | /* buffer overflow? */ 107 | if (oidp > oid + OID_SIZE - sub) return 0; 108 | for (; sub; --sub, number >>= 8) 109 | *oidp++ = (unsigned char) number; 110 | } 111 | lua_pushlstring (L, (char *) oid, oidp - oid); 112 | return 1; 113 | } 114 | 115 | 116 | /* 117 | * Arguments: string 118 | * Returns: number 119 | */ 120 | int 121 | bitstr2num (lua_State *L) 122 | { 123 | lua_pushnumber (L, 124 | (lua_Number) reverse (*((unsigned int *) luaL_checkstring (L, 1)))); 125 | return 1; 126 | } 127 | 128 | /* 129 | * Arguments: number 130 | * Returns: string 131 | */ 132 | int 133 | num2bitstr (lua_State *L) 134 | { 135 | unsigned int num = reverse ((int) lua_tonumber (L, 1)); 136 | lua_pushlstring (L, (char *) &num, bytes_count(num)); 137 | return 1; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /test/check.c: -------------------------------------------------------------------------------- 1 | /* Test BER */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lauxlib.h" 10 | #include "lualib.h" 11 | 12 | #include "ber.h" 13 | 14 | #define BUF_SIZ BUFSIZ 15 | 16 | static lua_State *L; 17 | static struct bers bs; 18 | static struct mmodr odr; 19 | 20 | static const char usage[] = "Usage: %s -f FILE -l FILE\n" 21 | "\t-f - odr file\n" 22 | "\t-l - lua file\n"; 23 | static char *progname, *odrfile, *luafile; 24 | 25 | static void 26 | err_quit (const char *fmt, ...) 27 | { 28 | va_list ap; 29 | 30 | va_start (ap, fmt); 31 | vfprintf (stderr, fmt, ap); 32 | va_end (ap); 33 | putc ('\n', stderr); 34 | _exit (EXIT_FAILURE); 35 | } 36 | 37 | static void 38 | event_loop () 39 | { 40 | unsigned char buffer[BUF_SIZ]; 41 | int i, tl = 0; 42 | 43 | bs.L = L; 44 | bs.bp = bs.buf = buffer; 45 | 46 | #if LUA_VERSION_NUM < 503 47 | lua_pushstring (bs.L, "QI"); 48 | #endif 49 | 50 | do { 51 | i = read (0, bs.bp, BUF_SIZ - tl); 52 | if (!i) return; 53 | bs.endp = bs.bp + i; 54 | bs.bp = bs.buf; 55 | 56 | i = ber_decode (&bs); 57 | if (bs.bp < bs.endp) { 58 | tl = bs.endp - bs.bp; 59 | memcpy (bs.buf, bs.bp, tl); 60 | bs.bp = bs.buf + tl; 61 | } else { 62 | tl = 0; 63 | bs.bp = bs.buf; 64 | } 65 | } while (i == BER_INCOMPL); 66 | 67 | #if LUA_VERSION_NUM >= 503 68 | lua_setglobal (bs.L, "QI"); 69 | #else 70 | lua_rawset (bs.L, LUA_GLOBALSINDEX); 71 | #endif 72 | 73 | luaL_dofile (L, luafile); 74 | lua_settop (L, 0); 75 | 76 | bs.endp = bs.buf + BUF_SIZ; 77 | 78 | #if LUA_VERSION_NUM >= 503 79 | lua_getglobal(bs.L, "QO"); 80 | #else 81 | lua_pushstring (bs.L, "QO"); 82 | lua_rawget (bs.L, LUA_GLOBALSINDEX); 83 | #endif 84 | 85 | while ((i = ber_encode (&bs)) == BER_INCOMPL) { 86 | if (!(i = write (1, bs.buf, bs.bp - bs.buf))) 87 | return; 88 | bs.bp = bs.buf; 89 | } 90 | write (1, bs.buf, bs.bp - bs.buf); 91 | } 92 | 93 | /* Initialize Lua */ 94 | static void 95 | lua_init () 96 | { 97 | L = luaL_newstate (); 98 | if (!L) err_quit ("Cannot init Lua"); 99 | luaL_openlibs (L); 100 | lua_settop (L, 0); 101 | } 102 | 103 | /* Parse command line */ 104 | static void 105 | get_args (int argc, char *argv[]) 106 | { 107 | int i; 108 | 109 | progname = argv[0]; 110 | if (argc > 1) for (i = 1; i < argc; ++i) { 111 | if (argv[i][0] == '-') 112 | switch (argv[i][1]) { 113 | case 'f': 114 | if (argv[i][2]) odrfile = &argv[i][2]; 115 | else if (++i < argc) odrfile = argv[i]; 116 | break; 117 | case 'l': 118 | if (argv[i][2]) luafile = &argv[i][2]; 119 | else if (++i < argc) luafile = argv[i]; 120 | break; 121 | } 122 | else err_quit (usage, progname); 123 | } 124 | if (!(odrfile && luafile)) 125 | err_quit (usage, progname); 126 | } 127 | 128 | 129 | static int 130 | file_odr_open (struct mmodr *mo, const char *file) 131 | { 132 | FILE *fodr = fopen (file, "rb"); 133 | if (fodr && !fseek (fodr, 0, SEEK_END)) { 134 | int len = ftell (fodr); 135 | if (len != -1 && !fseek (fodr, 0, SEEK_SET)) { 136 | void *mp = malloc (len); 137 | if (mp) { 138 | len = fread (mp, 1, len, fodr); 139 | fclose (fodr); 140 | if (len) return mmodr_set (mo, mp, len); 141 | free (mp); 142 | } 143 | } 144 | } 145 | return -1; 146 | } 147 | 148 | int 149 | main (int argc, char *argv[]) 150 | { 151 | jmp_buf jb; 152 | int ret; 153 | 154 | get_args (argc, argv); 155 | if (file_odr_open (&odr, odrfile)) 156 | err_quit ("bad odr file"); 157 | bs.odr = &odr; 158 | lua_init (); 159 | 160 | bs.jb = &jb; 161 | ret = setjmp (jb); 162 | if (!ret) event_loop (); 163 | else err_quit ("Error: %s", ber_errstr (ret)); 164 | 165 | free (odr.odrs); 166 | lua_close (L); 167 | return EXIT_SUCCESS; 168 | } 169 | -------------------------------------------------------------------------------- /test/datetime.asn: -------------------------------------------------------------------------------- 1 | UserInfoFormat-dateTime 2 | {Z39-50-userInfoFormat dateTime (6)} DEFINITIONS ::= 3 | BEGIN 4 | IMPORTS IntUnit FROM Z39-50-APDU-1995; 5 | 6 | DateTime ::= SEQUENCE{ 7 | date [1] Z3950Date OPTIONAL, 8 | time [2] Z3950Time OPTIONAL 9 | -- one or the other, or both 10 | } 11 | 12 | Z3950Date ::= SEQUENCE{ 13 | year [1] IMPLICIT INTEGER, 14 | -- For "positive" years, i.e. 1 AD or later, supply 15 | -- the absolute year, e.g. If the year is 1995, supply 16 | -- the integer 1995; the value 95 would indicate the 17 | -- year 0095. 18 | -- For "negative" years, e.g. 1 BC or earlier, -1 19 | -- represents 1 BC, -2 represents 2 BC, etc. Zero is 20 | -- invalid, because there was no year zero. 21 | partOfYear [2] CHOICE{ -- may be omitted if only year is significant 22 | monthAndDay [1] IMPLICIT SEQUENCE{ 23 | month [2] IMPLICIT INTEGER, 24 | -- value 1-12 25 | day [3] IMPLICIT INTEGER OPTIONAL 26 | -- may be omitted if only year and month 27 | -- are significant. Value 1-31. 28 | }, 29 | julianDay [2] IMPLICIT INTEGER, -- Value 1 - 366. 30 | weekNumber [3] IMPLICIT INTEGER, -- Value 1 - 53. 31 | quarter [4] CHOICE{ 32 | first [1] IMPLICIT NULL, 33 | second [2] IMPLICIT NULL, 34 | third [3] IMPLICIT NULL, 35 | fourth [4] IMPLICIT NULL}, 36 | season [5] CHOICE{ 37 | winter [1] IMPLICIT NULL, 38 | spring [2] IMPLICIT NULL, 39 | summer [3] IMPLICIT NULL, 40 | autumn [4] IMPLICIT NULL} 41 | } OPTIONAL, 42 | flags [3] IMPLICIT SEQUENCE{ 43 | circa [1] IMPLICIT NULL OPTIONAL, 44 | -- if this flag is set then the date is "approximate". 45 | era [2] CHOICE{ 46 | -- If era occurs, partOfYear should not occur. 47 | decade [1] IMPLICIT NULL, 48 | -- year must be multiple of 10. 49 | -- For example, 1900 refers to 50 | -- the decade covering the years 51 | -- 1900 through 1909. 52 | century [2] IMPLICIT NULL, 53 | -- year must be multiple of 100. 54 | millennium [3] IMPLICIT NULL 55 | -- year must be multiple of 1000. 56 | } OPTIONAL 57 | } OPTIONAL 58 | } 59 | 60 | 61 | Z3950Time ::= SEQUENCE{ 62 | hour [1] IMPLICIT INTEGER, 63 | -- Value 0-23. 64 | minute [2] IMPLICIT INTEGER OPTIONAL, 65 | -- value 0-59. May be omitted when hour only is 66 | -- significant (in which case second and 67 | -- partOfSecond must also be omitted). 68 | second [3] IMPLICIT INTEGER OPTIONAL, 69 | -- value 0-59. May be omitted when only hour, or 70 | -- hour and minute, is significant (in which case 71 | -- partOfSecond must also be omitted). 72 | partOfSecond [4] IMPLICIT IntUnit OPTIONAL, 73 | -- Use Unit System = 'si', Unit type = 'time'; 74 | -- Unit = 'second', with appropriate value and 75 | -- scale factor. 76 | zone [5] CHOICE{ 77 | local [1] IMPLICIT NULL, 78 | utc [2] IMPLICIT NULL, 79 | utcOffset [3] IMPLICIT INTEGER -- in minutes 80 | }} 81 | END 82 | -------------------------------------------------------------------------------- /test/esupdate.asn: -------------------------------------------------------------------------------- 1 | ESFormat-Update 2 | {Z39-50-extendedService Update (5) revisions (1) revision-1 (1)} DEFINITIONS ::= 3 | -- oid is 1.2.840.10003.9.5.1.1 4 | BEGIN 5 | IMPORTS DiagRec, InternationalString 6 | FROM Z39-50-APDU-1995; 7 | Update ::= CHOICE{ 8 | esRequest [1] IMPLICIT SEQUENCE{ 9 | toKeep [1] OriginPartToKeep, 10 | notToKeep [2] OriginPartNotToKeep}, 11 | taskPackage [2] IMPLICIT SEQUENCE{ 12 | originPart [1] 13 | OriginPartToKeep, 14 | targetPart [2] TargetPart}} 15 | 16 | OriginPartToKeep ::= SEQUENCE{ 17 | action [1] IMPLICIT INTEGER{ 18 | recordInsert (1), 19 | recordReplace (2), 20 | recordDelete (3), 21 | elementUpdate (4), 22 | specialUpdate (5)}, 23 | databaseName [2] IMPLICIT InternationalString, 24 | schema [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL, 25 | elementSetName [4] IMPLICIT InternationalString OPTIONAL, 26 | actionQualifier [5] IMPLICIT EXTERNAL OPTIONAL} 27 | 28 | OriginPartNotToKeep ::= SuppliedRecords 29 | 30 | TargetPart ::= SEQUENCE{ 31 | updateStatus [1] IMPLICIT INTEGER{ 32 | success (1), 33 | partial (2), 34 | failure (3)}, 35 | globalDiagnostics [2] IMPLICIT SEQUENCE OF 36 | DiagRec OPTIONAL, 37 | -- These are non-surrogate 38 | -- diagnosticsrelating to the task, 39 | -- not to individual records. 40 | taskPackageRecords [3] IMPLICIT SEQUENCE OF 41 | TaskPackageRecordStructure 42 | -- There should be a 43 | -- TaskPackageRecordStructure 44 | -- for every record supplied. 45 | -- The target should create 46 | -- such a structure for every 47 | -- record immediately upon 48 | -- creating the task package 49 | -- to include correlation 50 | -- information and status. 51 | -- The record itself would not 52 | -- be included until processing 53 | -- for that record is complete. 54 | } 55 | 56 | -- Auxiliary definitions for Update 57 | SuppliedRecords ::= SEQUENCE OF SEQUENCE{ 58 | recordId [1] CHOICE{ 59 | number [1] IMPLICIT INTEGER, 60 | string [2] IMPLICIT InternationalString, 61 | opaque [3] IMPLICIT OCTET STRING} OPTIONAL, 62 | supplementalId [2] CHOICE{ 63 | timeStamp [1] IMPLICIT GeneralizedTime, 64 | versionNumber [2] IMPLICIT InternationalString, 65 | previousVersion [3] IMPLICIT EXTERNAL} OPTIONAL, 66 | correlationInfo [3] IMPLICIT CorrelationInfo OPTIONAL, 67 | record [4] IMPLICIT EXTERNAL} 68 | 69 | CorrelationInfo ::= SEQUENCE{ 70 | -- origin may supply one or both for any record: 71 | note [1] IMPLICIT InternationalString OPTIONAL, 72 | id [2] IMPLICIT INTEGER OPTIONAL} 73 | 74 | TaskPackageRecordStructure ::= SEQUENCE{ 75 | recordOrSurDiag [1] CHOICE { 76 | record [1] IMPLICIT EXTERNAL, 77 | -- Choose 'record' if 78 | -- recordStatus is 'success', and 79 | -- elementSetName was supplied. 80 | 81 | surrogateDiagnostics [2] IMPLICIT 82 | SEQUENCE OF DiagRec 83 | -- Choose 'SurrogateDiagnostics', if 84 | -- RecordStatus is failure. 85 | } OPTIONAL, 86 | -- The parameter recordOrSurDiag 87 | -- will thus be omitted only if 88 | -- 'elementSetName' was omitted and 89 | -- recordStatus is 'success'; or 90 | --if record status is 'queued' 91 | -- or in 'process'. 92 | correlationInfo [2] IMPLICIT 93 | CorrelationInfo OPTIONAL, 94 | -- This should be included 95 | -- if it was supplied by the origin. 96 | recordStatus [3] IMPLICIT INTEGER{ 97 | success (1), 98 | queued (2), 99 | inProcess (3), 100 | failure (4)}, 101 | supplementalDiagnostics [4] IMPLICIT 102 | SEQUENCE OF DiagRec OPTIONAL} 103 | END 104 | -------------------------------------------------------------------------------- /src/asn/map.c: -------------------------------------------------------------------------------- 1 | /* Utils for ASN.1 compiler */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "asn.h" 8 | #include "map.h" 9 | 10 | /* Add type or component to odrs area. 11 | * Return addr 12 | */ 13 | int 14 | odr_add (const struct tmt *t) 15 | { 16 | int cur = odrs_next++; 17 | 18 | if (odrs_next >= odrs_size) { 19 | odrs = realloc (odrs, (odrs_size += 1024) * sizeof (struct tmt)); 20 | if (!odrs) perror ("Odr realloc"); 21 | } 22 | if (t) odrs[cur] = *t; 23 | return cur; 24 | } 25 | 26 | /* Add string to names area (not duplicate) */ 27 | int 28 | name_add (const char *s) 29 | { 30 | struct comp *cprev = NULL, *c = comp_names, *cnew; 31 | int i, cur = names_next; 32 | 33 | while (c && (i = strcmp (s, names + c->u.addr)) > 0) { 34 | cprev = c; 35 | c = c->next; 36 | } 37 | if (c && !i) return c->u.addr; 38 | cnew = calloc (1, sizeof (struct comp)); 39 | if (!cnew) perror ("Component name malloc"); 40 | cnew->u.addr = cur; 41 | if (cprev) { 42 | cnew->next = c; 43 | cprev->next = cnew; 44 | } else { 45 | cnew->next = comp_names; 46 | comp_names = cnew; 47 | } 48 | i = strlen (s); 49 | names_next += ++i; 50 | if ((names_next > names_size) 51 | && !(names = realloc (names, names_size += 4096))) 52 | perror ("Names realloc"); 53 | strncpy (names + cur, s, i); 54 | return cur; 55 | } 56 | 57 | void 58 | names_del (void) 59 | { 60 | struct comp *c; 61 | 62 | while ((c = comp_names)) { 63 | comp_names = c->next; 64 | free (c); 65 | } 66 | free (names); 67 | } 68 | 69 | struct module * 70 | module_add (const int opt, const char *mname) 71 | { 72 | struct module *m; 73 | 74 | if ((m = find (mname, modules, NULL))) { 75 | if (opt & FORWARD) return m; 76 | if (m->opt & FORWARD) { 77 | m->opt = (m->opt & ~FORWARD) | opt; 78 | return m; 79 | } 80 | asnError ("Duplicate module '%s'\n", mname); 81 | } 82 | m = calloc (1, sizeof (struct module)); 83 | if (!m) perror ("Module malloc"); 84 | strcpy (m->name, mname); 85 | m->opt = opt; 86 | m->next = modules; 87 | modules = m; 88 | return m; 89 | } 90 | 91 | void 92 | module_del (struct module *mdel) 93 | { 94 | struct module *m = modules; 95 | 96 | def_del (mdel, NULL, 0); 97 | if (mdel == modules) { 98 | modules = mdel->next; 99 | } else { 100 | while (m->next && m->next != mdel) m = m->next; 101 | m->next = m->next->next; 102 | m = m->next; 103 | } 104 | if (mdel->opt & FORWARD) 105 | fprintf (stderr, "Missing module '%s'\n", mdel->name); 106 | free (mdel); 107 | } 108 | 109 | /* Add definition to module */ 110 | struct def * 111 | def_add (struct module *m, const int opt, const char *dname) 112 | { 113 | struct def *d = NULL; 114 | 115 | if ((d = find (dname, (opt & DEF_EXPORT) ? m->exports : m->defn, NULL))) { 116 | if (opt & FORWARD) return d; 117 | if (d->opt & FORWARD) { 118 | d->opt = (d->opt & ~FORWARD) | opt; 119 | return d; 120 | } 121 | asnError ("Duplicate definition '%s' in module '%s'\n", 122 | dname, m->name); 123 | } 124 | d = calloc (1, sizeof (struct def)); 125 | if (!d) perror ("Definition malloc"); 126 | strcpy (d->name, dname); 127 | d->opt = opt; 128 | #if COMP_START_NUM 129 | d->tag.comp_no = COMP_START_NUM; 130 | #endif 131 | if (opt & DEF_EXPORT) m->exports = d; 132 | else if (opt & DEF_IMPORT) m->imports = d; 133 | d->next = m->defn; 134 | m->defn = d; 135 | return d; 136 | } 137 | 138 | /* Delete definition from module. 139 | * (Module is neccesary to info) 140 | */ 141 | void 142 | def_del (struct module *m, struct def *dend, const unsigned char leave) 143 | { 144 | struct def *d = m->defn, *ddel, *dhead = NULL, *dprev = NULL; 145 | struct comp *c; 146 | 147 | while (d != dend) { 148 | if (d->opt & leave) { 149 | if (!dhead) dhead = d; 150 | dprev = d; 151 | d = d->next; 152 | continue; 153 | } 154 | while ((c = d->compn)) { 155 | d->compn = c->next; 156 | free (c); 157 | } 158 | if (d->opt & FORWARD) 159 | fprintf (stderr, "Missing definition '%s' in module '%s'" 160 | " (not [defined | exported])\n", d->name, m->name); 161 | else if (d->opt & DEF_INCOMPL) 162 | fprintf (stderr, "Incomplete definition '%s' in module '%s'\n", 163 | d->name, m->name); 164 | ddel = d; 165 | d = d->next; 166 | if (dprev) dprev->next = d; 167 | free (ddel); 168 | } 169 | m->defn = (dhead) ? dhead : dend; 170 | } 171 | 172 | /* Set required component */ 173 | void 174 | def_req (struct def *fdef, const union comp_addr u, const unsigned char opt) 175 | { 176 | struct comp *c; 177 | 178 | c = calloc (1, sizeof (struct comp)); 179 | if (!c) perror ("Req.comp malloc"); 180 | c->u = u; 181 | c->opt = opt; 182 | c->next = fdef->compn; 183 | fdef->compn = c; 184 | } 185 | 186 | /* Generic search of definitions and modules */ 187 | void * 188 | find (const char *name, void *i, const void *end) 189 | { 190 | if (!i) return NULL; 191 | while ((i != end) && strcmp ((char *) i, name)) 192 | i = ((struct def *) i)->next; 193 | return (i == end) ? NULL : i; 194 | } 195 | -------------------------------------------------------------------------------- /src/luaber.c: -------------------------------------------------------------------------------- 1 | /* Lua BER library */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "ber.h" 11 | #include "ber_util.h" 12 | 13 | typedef struct bers *p_bers; 14 | typedef struct mmodr *p_mmodr; 15 | 16 | #define BERHANDLE "bers*" 17 | #define ODRHANDLE "mmodr*" 18 | 19 | #define BUF_SIZ BUFSIZ /* encode out chunk size */ 20 | 21 | /* 22 | * Arguments: odr_udata 23 | * Returns: ber_udata, thread 24 | */ 25 | static int 26 | lber_ber (lua_State *L) 27 | { 28 | p_mmodr mo = lua_touserdata (L, 1); /* ODRHANDLE */ 29 | p_bers bs = lua_newuserdata (L, sizeof (struct bers)); 30 | luaL_getmetatable (L, BERHANDLE); 31 | lua_setmetatable (L, -2); 32 | memset (bs, 0, sizeof (struct bers)); 33 | bs->odr = mo; 34 | bs->L = lua_newthread (L); 35 | return 2; 36 | } 37 | 38 | /* 39 | * Arguments: ber_udata 40 | */ 41 | static int 42 | lber_clear (lua_State *L) 43 | { 44 | p_bers bs = lua_touserdata (L, 1); /* BERHANDLE */ 45 | p_mmodr mo = bs->odr; 46 | lua_State *bsL = bs->L; 47 | lua_settop (bsL, 0); 48 | memset (bs, 0, sizeof (struct bers)); 49 | bs->odr = mo; 50 | bs->L = bsL; 51 | return 0; 52 | } 53 | 54 | /* 55 | * Arguments: ber_udata, string 56 | * Returns: tail (string), table 57 | * nil, errcode 58 | */ 59 | static int 60 | lber_decode (lua_State *L) 61 | { 62 | p_bers bs = lua_touserdata (L, 1); /* BERHANDLE */ 63 | void *strp = NULL; 64 | size_t str_len; 65 | jmp_buf jb; 66 | unsigned char c; 67 | int res; 68 | 69 | luaL_checktype (L, 2, LUA_TSTRING); 70 | strp = (void *) lua_tolstring (L, 2, &str_len); 71 | 72 | bs->jb = &jb; 73 | bs->bp = bs->buf = strp; 74 | bs->endp = (unsigned char *) strp + str_len; 75 | res = setjmp (jb); 76 | if (!res) c = ber_decode (bs); 77 | else { 78 | lua_pushnil (L); 79 | lua_pushinteger (L, res); 80 | return 2; 81 | } 82 | /* tail */ 83 | res = bs->endp - bs->bp; 84 | if (res < 0) res = 0; 85 | lua_pushlstring (L, (char *) bs->bp, res); 86 | /* complete? */ 87 | if (!c || c == BER_MORE) { 88 | lua_xmove (bs->L, L, 1); 89 | return 2; 90 | } 91 | return 1; 92 | } 93 | 94 | /* 95 | * Arguments: ber_udata, table 96 | * Returns: string, [boolean (complete?)] 97 | * nil, errcode 98 | */ 99 | static int 100 | lber_encode (lua_State *L) 101 | { 102 | p_bers bs = lua_touserdata (L, 1); /* BERHANDLE */ 103 | unsigned char buffer[BUF_SIZ]; 104 | jmp_buf jb; 105 | int res; 106 | 107 | if (!lua_istable (L, 2)) 108 | luaL_argerror (L, 2, "Table_out expected"); 109 | /* set table in thread */ 110 | if (!lua_gettop (bs->L)) 111 | lua_xmove (L, bs->L, 1); 112 | 113 | bs->jb = &jb; 114 | bs->bp = bs->buf = buffer; 115 | bs->endp = buffer + BUF_SIZ; 116 | res = setjmp (jb); 117 | if (!res) { 118 | unsigned char c = ber_encode (bs); 119 | lua_pushlstring (L, (char *) buffer, bs->bp - buffer); 120 | lua_pushboolean (L, !c); 121 | } else { 122 | lua_pushnil (L); 123 | lua_pushinteger (L, res); 124 | } 125 | return 2; 126 | } 127 | 128 | /* 129 | * Returns: odr_udata 130 | */ 131 | static int 132 | lodr_new (lua_State *L) 133 | { 134 | p_mmodr mo = lua_newuserdata (L, sizeof (struct mmodr)); 135 | luaL_getmetatable (L, ODRHANDLE); 136 | lua_setmetatable (L, -2); 137 | mo->odrs = NULL; 138 | return 1; 139 | } 140 | 141 | /* 142 | * Arguments: odr_udata, string 143 | * Returns: boolean 144 | * nil, errcode 145 | */ 146 | static int 147 | lodr_set (lua_State *L) 148 | { 149 | p_mmodr mo = lua_touserdata (L, 1); /* ODRHANDLE */ 150 | size_t str_len = 0; 151 | const char *str = luaL_checklstring (L, 2, &str_len); 152 | 153 | if (!mmodr_set (mo, str, str_len)) { 154 | lua_pushboolean (L, 1); 155 | return 1; 156 | } else { 157 | lua_pushnil (L); 158 | lua_pushinteger (L, BER_ERRODR); 159 | return 2; 160 | } 161 | } 162 | 163 | /* 164 | * Arguments: odr_udata 165 | * Returns: table {name => oid} 166 | */ 167 | static int 168 | lodr_names (lua_State *L) 169 | { 170 | struct module_id *mid; 171 | p_mmodr mo = lua_touserdata (L, 1); /* ODRHANDLE */ 172 | lua_newtable (L); 173 | for (mid = mo->modules; (void *) mid != mo->names; ++mid) 174 | if (mid->oid[0] > 1) { 175 | lua_pushstring (L, mo->names + mid->nameaddr); 176 | lua_pushlstring (L, (char *) mid->oid + 1, mid->oid[0]); 177 | lua_rawset (L, -3); 178 | } 179 | return 1; 180 | } 181 | 182 | /* 183 | * Arguments: odr_udata, oid 184 | * Returns: string 185 | * nil, errcode 186 | */ 187 | static int 188 | lodr_oid2name (lua_State *L) 189 | { 190 | p_mmodr mo = lua_touserdata (L, 1); /* ODRHANDLE */ 191 | size_t len = 0; 192 | const char *oidp = luaL_checklstring (L, 2, &len); 193 | unsigned char oid[OIDSIZ]; 194 | struct module_id *mid; 195 | int res; 196 | 197 | if (len > OIDSIZ - 1) { 198 | lua_pushnil (L); 199 | lua_pushinteger (L, BER_ERROID); 200 | return 2; 201 | } 202 | memcpy (oid + 1, oidp, oid[0] = len++); 203 | /* binary search of module by oid */ 204 | { 205 | struct module_id *mbeg = mo->modules; 206 | struct module_id *mend = mbeg + mo->nmodules - 1; 207 | do { 208 | mid = mbeg + ((mend - mbeg) >> 1); 209 | res = *oid - *mid->oid; 210 | if (!res) res = memcmp (oid, mid->oid, len); 211 | if (!res) break; 212 | if (res < 0) mend = mid - 1; 213 | else mbeg = mid + 1; 214 | } while (mbeg <= mend); 215 | } 216 | if (!res) { 217 | lua_pushstring (L, mo->names + mid->nameaddr); 218 | return 1; 219 | } 220 | return 0; 221 | } 222 | 223 | /* 224 | * Arguments: [number] 225 | * Returns: string 226 | */ 227 | static int 228 | lber_strerror (lua_State *L) 229 | { 230 | int err = luaL_checkinteger (L, 1); 231 | lua_pushstring (L, ber_errstr (err)); 232 | return 1; 233 | } 234 | 235 | 236 | static luaL_Reg odrmeth[] = { 237 | {"set", lodr_set}, 238 | {"ber", lber_ber}, 239 | {"names", lodr_names}, 240 | {"oid2name", lodr_oid2name}, 241 | {NULL, NULL} 242 | }; 243 | 244 | static luaL_Reg bermeth[] = { 245 | {"clear", lber_clear}, 246 | {"decode", lber_decode}, 247 | {"encode", lber_encode}, 248 | {NULL, NULL} 249 | }; 250 | 251 | static luaL_Reg berlib[] = { 252 | {"odr", lodr_new}, 253 | {"oid2str", oid2str}, 254 | {"str2oid", str2oid}, 255 | {"num2bitstr", num2bitstr}, 256 | {"bitstr2num", bitstr2num}, 257 | {"strerror", lber_strerror}, 258 | {NULL, NULL} 259 | }; 260 | 261 | 262 | static void 263 | register_functions (lua_State *L, const luaL_Reg *l) 264 | { 265 | for (; l->name; l++) { 266 | lua_pushcfunction (L, l->func); 267 | lua_setfield (L, -2, l->name); 268 | } 269 | } 270 | 271 | 272 | static void 273 | createmeta (lua_State *L) 274 | { 275 | luaL_newmetatable (L, ODRHANDLE); 276 | lua_pushliteral (L, "__index"); 277 | lua_pushvalue (L, -2); /* push metatable */ 278 | lua_rawset (L, -3); /* metatable.__index = metatable */ 279 | register_functions (L, odrmeth); 280 | lua_pop (L, 1); 281 | 282 | luaL_newmetatable (L, BERHANDLE); 283 | lua_pushliteral (L, "__index"); 284 | lua_pushvalue (L, -2); /* push metatable */ 285 | lua_rawset (L, -3); /* metatable.__index = metatable */ 286 | register_functions (L, bermeth); 287 | lua_pop (L, 1); 288 | } 289 | 290 | /* Open BER library */ 291 | LUALIB_API int 292 | luaopen_ber (lua_State *L) 293 | { 294 | lua_newtable (L); 295 | register_functions (L, berlib); 296 | createmeta (L); 297 | return 1; 298 | } 299 | -------------------------------------------------------------------------------- /test/charneg-3.asn: -------------------------------------------------------------------------------- 1 | NegotiationRecordDefinition --!! 2 | {Z39-50-negotiation CharSetandLanguageNegotiation-3 (3)} --!! 3 | DEFINITIONS ::= BEGIN 4 | IMPORTS LanguageCode FROM RecordSyntax-explain; 5 | 6 | CharSetandLanguageNegotiation ::= CHOICE{ 7 | proposal [1] IMPLICIT OriginProposal, 8 | response [2] IMPLICIT TargetResponse} 9 | -- 10 | -- For character sets: 11 | -- Origin proposes one, two, or all three of the following, in order of 12 | -- preference: 13 | -- (a) 2022 character sets. 14 | -- (b) 10646 character set. 15 | -- (c) Private character set. 16 | -- 17 | -- The target responds with one of (a), (b), or (c), indicating the 18 | -- character set(s) to be supported for all name and message strings. 19 | -- 20 | -- If the origin includes (a), 21 | -- the origin proposes: 22 | -- (1) A proposed environment: 7-bit, 8-bit, or no-preference. 23 | -- (2) A set of iso 2022 registration numbers. 24 | -- (3) One or more proposed initial sets of registration numbers, 25 | -- for c0, c1, g0, g1, g2 and g3. These must come from (2). 26 | -- (4) The proposed encoding level. 27 | -- And if the target selects (a), it responds with: 28 | -- (1) A selected environment: 7-bit or 8-bit. 29 | -- (2) A subset of the set of iso 2022 registration numbers proposed 30 | -- by the origin. 31 | -- (3) The initial set of registrations, which must come from (2) 32 | -- but need not be from the set of initial registrations proposed 33 | -- by the origin. 34 | -- (4) The encoding level; less than or equal to that proposed. 35 | -- 36 | -- If the origin includes (b), 37 | -- The origin proposes: 38 | -- (1) (optionally) A list of collections (i.e. subsets of characters from the 39 | -- complete 10646 definition). 40 | -- (2) An implementation level. 41 | -- (3) Syntax/form: e.g. ucs-2, ucs-4, utf-8, utf-16. 42 | -- And if the target selects (b), it responds by choosing a subset of the 43 | -- collections proposed by the origin in (1) and an implementation level less 44 | -- than or equal to that proposed by the origin in (2). 45 | -- 46 | -- If the origin includes (c), the origin proposes one of the following: 47 | -- (1) A list of private character sets, by one or more object 48 | -- identifiers. 49 | -- (2) A list of private character sets, by an EXTERNAL. 50 | -- (3) An indication to use a private, previously agreed upon 51 | -- character set. 52 | -- And if the target selects (c): 53 | -- - If the origin proposed (1), the target should respond with (1), and 54 | -- the list of object identifiers should be a subset of the list that 55 | -- the origin included. 56 | -- - If the origin proposed (2), the target should respond with (2), using 57 | -- the same EXTERNAL definition (but not necessarily the same content) 58 | -- used by the origin. 59 | -- - If the origin proposed (3), the target should respond with (3). 60 | -- 61 | -- For Languages: 62 | -- The origin optionally proposes one or more language codes. The target 63 | -- response may include a single language code, which indicates the 64 | -- language to be used for all message strings. The target may include or 65 | -- omit this, whether or not the origin included a proposed set, and the 66 | -- language code indicated need not be from among those proposed. 67 | -- 68 | -- 69 | 70 | OriginProposal ::= SEQUENCE { 71 | proposedCharSets [1] IMPLICIT SEQUENCE OF CHOICE{ 72 | -- Each should occur at most once, and in order of preference 73 | -- (the "order of preference" is the reason why this is 74 | -- "SEQUENCE OF CHOICE" rather than just "SEQUENCE") 75 | iso2022 [1] Iso2022, 76 | iso10646 [2] IMPLICIT Iso10646, 77 | private [3] PrivateCharacterSet} OPTIONAL, 78 | -- proposedCharSets must be omitted 79 | -- if origin proposes version 2 80 | proposedlanguages [2] IMPLICIT SEQUENCE OF LanguageCode OPTIONAL, 81 | recordsInSelectedCharSets [3] IMPLICIT BOOLEAN OPTIONAL 82 | -- default 'false'. See rule 6 above. 83 | } 84 | 85 | TargetResponse ::= SEQUENCE{ 86 | selectedCharSets [1] CHOICE{ 87 | iso2022 [1] Iso2022, 88 | iso10646 [2] IMPLICIT Iso10646, 89 | private [3] PrivateCharacterSet, 90 | none [4] IMPLICIT NULL 91 | -- If selected, no negotiation 92 | -- is assumed to be in force 93 | -- for character sets. 94 | } OPTIONAL, 95 | -- Omitted if and only if proposedCharSets 96 | -- was Omitted in the request. 97 | selectedLanguage [2] IMPLICIT LanguageCode OPTIONAL, 98 | recordsInSelectedCharSets [3] IMPLICIT BOOLEAN OPTIONAL 99 | -- Omitted if and only if 'recordsInSelectedCharSets' was omitted 100 | -- in the request. See rule 6 above. 101 | } 102 | 103 | 104 | PrivateCharacterSet ::= CHOICE{ 105 | viaOid [1] IMPLICIT SEQUENCE OF OBJECT IDENTIFIER, 106 | externallySpecified [2] IMPLICIT EXTERNAL, 107 | previouslyAgreedUpon [3] IMPLICIT NULL} 108 | 109 | -- IMPORTED 110 | -- LanguageCode ::= GeneralString -- from ANSI Z39.53-1994 111 | 112 | -- Definition of ISO2022 113 | -- For ISO 2022, the following is negotiated: 114 | -- 1) The environment: 7-bit or 8-bit; 115 | -- 2) a set of registration numbers (from the ISO Register of coded 116 | -- character sets) for graphical and control character sets; 117 | -- 3) g0, g1, g2, g3, c0, c1, the registration numbers of the graphical and 118 | -- control character sets that are initially designated to g0, g1, etc. 119 | -- The origin submits one or more sequences of values for 120 | -- g0, g1, g2, g3, c0, c1 (for each sequence: at least one of 121 | -- g0 and g1 must be included; g2 and g3 are optional and 122 | -- may be included only if g1 is included; 123 | -- c0 should be included; and c1 is optional); the target 124 | -- selects one of the proposed sequences. 125 | -- 4) gleft: which of g0, g1, g2 or g3, initially has GL shift status in 126 | -- an 8-bit environment or has shift status in a 7-bit environment; and 127 | -- 5) gright: which of g1, g2 or g3 initially has GR shift status in an 128 | -- 8-bit environment. 129 | 130 | Iso2022 ::= CHOICE{ 131 | originProposal [1] IMPLICIT SEQUENCE{ 132 | proposedEnvironment [0] Environment OPTIONAL, 133 | -- omitted means no preference 134 | proposedSets [1] IMPLICIT SEQUENCE OF INTEGER, 135 | proposedInitialSets [2] IMPLICIT SEQUENCE OF 136 | InitialSet, 137 | proposedLeftAndRight [3] IMPLICIT LeftAndRight}, 138 | targetResponse [2] IMPLICIT SEQUENCE{ 139 | selectedEnvironment [0] Environment, 140 | selectedSets [1] IMPLICIT SEQUENCE OF INTEGER, 141 | selectedinitialSet [2] IMPLICIT InitialSet, 142 | selectedLeftAndRight [3] IMPLICIT LeftAndRight}} 143 | 144 | Environment ::= CHOICE{ 145 | sevenBit [1] IMPLICIT NULL, 146 | eightBit [2] IMPLICIT NULL} 147 | 148 | InitialSet::= SEQUENCE{ 149 | g0 [0] IMPLICIT INTEGER OPTIONAL, 150 | g1 [1] IMPLICIT INTEGER OPTIONAL, 151 | -- one of g0 and g1 must be included 152 | g2 [2] IMPLICIT INTEGER OPTIONAL, 153 | g3 [3] IMPLICIT INTEGER OPTIONAL, 154 | --g2 and/or g3 may be included 155 | -- only if g1 was included 156 | c0 [4] IMPLICIT INTEGER, 157 | c1 [5] IMPLICIT INTEGER OPTIONAL} 158 | 159 | LeftAndRight ::= SEQUENCE{ 160 | gLeft [3] IMPLICIT INTEGER{ 161 | g0 (0), 162 | g1 (1), 163 | g2 (2), 164 | g3 (3)}, 165 | gRight [4] IMPLICIT INTEGER{ 166 | g1 (1), 167 | g2 (2), 168 | g3 (3)} OPTIONAL} 169 | 170 | -- Definition of Iso10646 171 | -- 172 | -- The 10646 object identifier looks like: 173 | -- 1.0.10646.1.implementationLevel.repertoireSubset.arc1.arc2. .... 174 | -- 175 | -- (The second '1' is for "part 1" of 10646.) 176 | -- 177 | -- ImplementationLevel is 1-3 178 | -- 179 | -- repertoireSubset is 0 or 1, for 'all' or 'collections'. 180 | -- The arcs are present only if repertoireSubset is 'collections', 181 | -- in which case arc1, arc2, etc., are the 182 | -- identifiers of collections of character repertoires. 183 | -- 184 | -- There is a second 10646 oid, for specifying syntax/form: 185 | -- 1.0.10646.1.0.form 186 | -- 187 | -- (The second '0' represents "transfer syntax".) 188 | -- 189 | -- where values of form include: 190 | -- 2: ucs-2 191 | -- 4: ucs-4 192 | -- 5: utf-16 193 | -- 8: utf-8 194 | 195 | Iso10646 ::= SEQUENCE{ 196 | collections [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL, 197 | --oid of form 1.0.10646.1.implementationLevel 198 | -- .repertoireSubset.arc1.arc2. .... 199 | -- Target to choose a subset of the collections 200 | -- proposed by the origin, and an implementation level 201 | -- less than or equal to that proposed. 202 | -- 203 | -- when 'collections' is omitted, 204 | -- 'implementationLevel' defaults to 3. 205 | -- 206 | encodingLevel [2] IMPLICIT OBJECT IDENTIFIER 207 | -- oid of form 1.0.10646.1.0.form 208 | -- where value of 'form' is 2, 4, 5, or 8 209 | -- for ucs-2, ucs-4, utf-16, utf-8 210 | } 211 | END -------------------------------------------------------------------------------- /src/ber.c: -------------------------------------------------------------------------------- 1 | /* BER octets <-> Lua tables */ 2 | 3 | #include /* mem* */ 4 | 5 | #include 6 | 7 | #include "ber.h" 8 | 9 | 10 | #define bytes_count(x) \ 11 | !(x) ? 0 : ((x) & 0xFF000000) ? 4 : ((x) & 0xFF0000) ? 3 \ 12 | : ((x) & 0xFF00) ? 2 : 1 13 | 14 | 15 | static int 16 | ber_taglen (struct bers *bs); 17 | static struct ber * 18 | ber_add (struct bers *bs, const unsigned char opt); 19 | 20 | /* <<======================================== 21 | * BER (de|en)coders 22 | */ 23 | 24 | #define UNUSED(x) ((void) (x)) 25 | 26 | #define DEN_ENCODE 1 27 | #define DEN_DECODE 2 28 | #define DEN_SIMPLE 4 29 | 30 | static int ber_oct (struct bers *bs, int len, unsigned char opt); 31 | static int ber_bit (struct bers *bs, int len, unsigned char opt); 32 | static int ber_oid (struct bers *bs, int len, unsigned char opt); 33 | static int ber_int (struct bers *bs, int len, unsigned char opt); 34 | static int ber_bool (struct bers *bs, int len, unsigned char opt); 35 | static int ber_null (struct bers *bs, int len, unsigned char opt); 36 | static int ber_ext_dref (struct bers *bs, int len, unsigned char opt); 37 | static int ber_ext_asn (struct bers *bs, int len, unsigned char opt); 38 | static int ber_oct_skip (struct bers *bs, int len, unsigned char opt); 39 | 40 | static struct { 41 | int (*fun) (struct bers *bs, int len, unsigned char opt); 42 | unsigned char berlen_max; 43 | struct tmt tag; 44 | } simples[] = { 45 | {ber_oct, 0, {{4}, TAG_SIMPLE | TAG_COMPONENTS, COMP_START_NUM, FUN_OCT, 0, 0}}, 46 | {ber_bit, 0, {{3}, TAG_SIMPLE | TAG_COMPONENTS, COMP_START_NUM, FUN_BIT, 0, 0}}, 47 | {ber_oid, OIDSIZ, {{0}, 0, 0, 0, 0, 0}}, 48 | {ber_int, sizeof (int), {{0}, 0, 0, 0, 0, 0}}, 49 | {ber_bool, 1, {{0}, 0, 0, 0, 0, 0}}, 50 | {ber_null, 1, {{0}, 0, 0, 0, 0, 0}}, 51 | {ber_ext_dref, OIDSIZ, {{0}, 0, 0, 0, 0, 0}}, 52 | {ber_ext_asn, 0, {{0}, 0, 0, 0, 0, 0}}, 53 | {ber_oct_skip, 0, {{0}, TAG_SIMPLE, COMP_START_NUM, FUN_OCT_SKIP, 0, 0}}, 54 | }; 55 | 56 | 57 | static int 58 | ber_encstr (struct bers *bs, int pad) 59 | { 60 | struct ber *b = bs->top; 61 | int len; 62 | unsigned char chunk = b->opt & (BER_MORE | BER_INCOMPL); 63 | size_t string_len = 0; 64 | const char *string_ptr = lua_tolstring(bs->L, -1, &string_len); 65 | 66 | if (chunk & BER_MORE) { 67 | len = b->v.size; 68 | b->opt &= ~BER_MORE; 69 | } else { 70 | int lenpad; 71 | len = (int) string_len; 72 | if (chunk) len -= b->len; 73 | else b->len = 0; 74 | lenpad = len + pad; 75 | #ifdef ENC_SIMPLESZ_MAX 76 | /* constructed simples */ 77 | if (lenpad > ENC_SIMPLESZ_MAX) { 78 | struct tmt *t; 79 | lenpad = ENC_SIMPLESZ_MAX; 80 | len = ENC_SIMPLESZ_MAX - pad; 81 | if (!(chunk & BER_INCOMPL)) { 82 | tag_id_t cn; 83 | t = &simples[b->tag->subaddr].tag; 84 | cn = t->u.cn; 85 | b->v.bufp = bs->bp; 86 | { 87 | tag_id_t pre = b->u.cn; 88 | unsigned char *tagp = bs->bp; 89 | tagp -= bytes_count(pre); 90 | *tagp |= BER_CONSTR; 91 | } 92 | *bs->bp++ = 0x80; 93 | b->opt |= BER_CONSTR | BER_INCOMPL; 94 | b = ber_add (bs, DEN_ENCODE); 95 | b->opt = BER_INCOMPL; 96 | b->len = 0; 97 | *((tag_id_t *) bs->bp) = cn; 98 | bs->bp += bytes_count(cn); 99 | b->tag = t; 100 | b->next = NULL; 101 | } 102 | } else if (chunk & BER_INCOMPL) 103 | b->opt &= ~BER_INCOMPL; 104 | #endif 105 | /* set length */ 106 | if (lenpad < 0x80) *bs->bp++ = lenpad; 107 | else { 108 | unsigned int num = lenpad, number = 0; 109 | char llen = 0; /* length of length */ 110 | do { 111 | number <<= 8; 112 | number |= (unsigned char) num; 113 | ++llen; num >>= 8; 114 | } while (num); 115 | *bs->bp++ = BER_INDEFIN | llen; 116 | *((tag_id_t *) bs->bp) = number; 117 | bs->bp += llen; 118 | } 119 | /* set padding bytes */ 120 | if (pad) { 121 | memset (bs->bp, 0, pad); 122 | bs->bp += pad; 123 | } 124 | } 125 | /* cut to chunks? */ 126 | { 127 | int bound = bs->endp - bs->bp; 128 | if (len > bound) { 129 | b->v.size = len - bound; 130 | len = bound; 131 | b->opt |= BER_MORE; 132 | } 133 | } 134 | /* copy (sub)string */ 135 | memcpy (bs->bp, string_ptr + b->len, len); 136 | bs->bp += len; 137 | 138 | if (b->opt & (BER_MORE | BER_INCOMPL)) { 139 | b->len += len; 140 | return BER_MORE; 141 | } 142 | return 0; 143 | } 144 | 145 | static int 146 | ber_oct (struct bers *bs, int len, unsigned char opt) 147 | { 148 | if (opt & DEN_DECODE) { 149 | lua_pushlstring (bs->L, (char *) bs->bp, len); 150 | bs->bp += len; 151 | return 0; 152 | } 153 | return ber_encstr (bs, 0); 154 | } 155 | 156 | static int 157 | ber_bit (struct bers *bs, int len, unsigned char opt) 158 | { 159 | /* unused bits ignored */ 160 | if (opt & DEN_DECODE) { 161 | bs->bp[--len] &= 0xFF >> *bs->bp++; 162 | lua_pushlstring (bs->L, (char *) bs->bp, len); 163 | bs->bp += len; 164 | return 0; 165 | } 166 | return ber_encstr (bs, 1); 167 | } 168 | 169 | static int 170 | ber_oid (struct bers *bs, int len, unsigned char opt) 171 | { 172 | if (opt & DEN_DECODE) { 173 | lua_pushlstring (bs->L, (char *) bs->bp, len); 174 | bs->bp += len; 175 | } else { 176 | size_t slen = 0; 177 | const char *s = lua_tolstring(bs->L, -1, &slen); 178 | *bs->bp++ = slen; 179 | memcpy (bs->bp, s, slen); 180 | bs->bp += slen; 181 | } 182 | return 0; 183 | } 184 | 185 | static int 186 | ber_int (struct bers *bs, int len, unsigned char opt) 187 | { 188 | unsigned int i = 0, num = 0; 189 | 190 | if (opt & DEN_DECODE) { 191 | while (len--) { 192 | i <<= 8; 193 | i |= *bs->bp++; 194 | } 195 | lua_pushnumber (bs->L, i); 196 | } else { 197 | i = (int) lua_tonumber (bs->L, -1); 198 | do { 199 | num <<= 8; 200 | num |= (unsigned char) i; 201 | i >>= 8; 202 | ++len; 203 | } while (i); 204 | *bs->bp++ = len; 205 | for (; len--; num >>= 8) 206 | *bs->bp++ = (unsigned char) num; 207 | } 208 | return 0; 209 | } 210 | 211 | static int 212 | ber_bool (struct bers *bs, int len, unsigned char opt) 213 | { 214 | UNUSED (len); 215 | if (opt & DEN_DECODE) 216 | lua_pushboolean (bs->L, *bs->bp++ != 0); 217 | else { 218 | *bs->bp++ = 1; 219 | *bs->bp++ = lua_toboolean (bs->L, -1); 220 | } 221 | return 0; 222 | } 223 | 224 | static int 225 | ber_null (struct bers *bs, int len, unsigned char opt) 226 | { 227 | UNUSED (len); 228 | if (opt & DEN_DECODE) lua_pushboolean (bs->L, 0); 229 | else *bs->bp++ = 0; 230 | return 0; 231 | } 232 | 233 | static int 234 | ber_ext_dref (struct bers *bs, int len, unsigned char opt) 235 | { 236 | struct module_id *mid; 237 | unsigned char oid[OIDSIZ], *oidp = bs->bp; 238 | int res; 239 | 240 | ber_oid (bs, len, opt); 241 | /* oidp points to len..content of oid */ 242 | if (opt & DEN_DECODE) { 243 | if (bs->bp == bs->buf) { 244 | memcpy (oid + 1, bs->bp, oid[0] = len); 245 | oidp = oid; 246 | } else --oidp; 247 | } else len = *oidp; 248 | ++len; 249 | /* binary search of module by oid */ 250 | { 251 | struct module_id *mbeg = bs->odr->modules; 252 | struct module_id *mend = mbeg + bs->odr->nmodules - 1; 253 | do { 254 | mid = mbeg + ((mend - mbeg) >> 1); 255 | res = *oidp - *mid->oid; 256 | if (!res) res = memcmp (oidp, mid->oid, len); 257 | if (!res) break; 258 | if (res < 0) mend = mid - 1; 259 | else mbeg = mid + 1; 260 | } while (mbeg <= mend); 261 | } 262 | bs->ext_mid = res ? NULL : mid; 263 | return 0; 264 | } 265 | 266 | static int 267 | ber_ext_asn (struct bers *bs, int len, unsigned char opt) 268 | { 269 | struct ber *b = bs->top; 270 | struct module_id *mid = bs->ext_mid; 271 | UNUSED (len); 272 | 273 | if (opt & DEN_DECODE) { 274 | b = ber_add (bs, DEN_DECODE); 275 | b->v.size = b->opt = 0; 276 | b->next = bs->odr->odrs; 277 | if (mid) b->next += mid->addr; 278 | } else { 279 | if (!mid) longjmp (*bs->jb, BER_ERREXTOID); /* Bad Ext.OID */ 280 | *(bs->bp - 1) |= BER_CONSTR; /* Ext_ASN is constructed */ 281 | b->opt |= BER_CONSTR; 282 | b->v.bufp = bs->bp; 283 | *bs->bp++ = 0x80; 284 | 285 | b = ber_add (bs, DEN_ENCODE); 286 | b->opt = 0; 287 | b->next = bs->odr->odrs + mid->addr; 288 | b->no = COMP_START_NUM - 1; 289 | } 290 | bs->ext_mid = NULL; 291 | return BER_INCOMPL; 292 | } 293 | 294 | /* Ignore input octets of unknown Ext.ASN */ 295 | static int 296 | ber_oct_skip (struct bers *bs, int len, unsigned char opt) 297 | { 298 | UNUSED (opt); 299 | lua_pushlstring (bs->L, NULL, 0); 300 | bs->bp += len; 301 | return 0; 302 | } 303 | 304 | /* ========================================>> */ 305 | 306 | 307 | /* Add ber to bers stack */ 308 | static struct ber * 309 | ber_add (struct bers *bs, const unsigned char opt) 310 | { 311 | if (!bs->top) bs->top = bs->stack; 312 | else if (++bs->top - bs->stack >= BERS_MAX) 313 | longjmp (*bs->jb, BER_ERRSTKO); /* Bers stack overflow */ 314 | if ((opt & (DEN_DECODE | DEN_SIMPLE)) == DEN_DECODE) 315 | lua_newtable (bs->L); 316 | return bs->top; 317 | } 318 | 319 | /* Delete top ber's from stack */ 320 | static void 321 | ber_del (struct bers *bs, unsigned char opt) 322 | { 323 | struct ber *bpr = bs->top; 324 | int i; 325 | 326 | if (!bpr) longjmp (*bs->jb, BER_ERRSTKU); /* Bers stack underflow */ 327 | //fprintf (stderr, "- top=%d\n", bpr - bs->stack); 328 | if (bpr-- == bs->stack) { 329 | if (opt & DEN_DECODE) 330 | lua_rawseti (bs->L, -2, bs->top->no); 331 | bs->top = NULL; 332 | return; 333 | } 334 | if (opt & DEN_DECODE) { 335 | do { 336 | struct ber *b; 337 | /* End Of Contents */ 338 | if (bpr->opt & opt & BER_INDEFIN) { 339 | opt &= ~BER_INDEFIN; 340 | bpr->v.size += bs->top->v.size; 341 | --bs->top, --bpr; 342 | } 343 | b = bs->top; 344 | if (b->opt & BER_INCOMPL) 345 | lua_concat (bs->L, 2); 346 | else lua_rawseti (bs->L, -2, b->no); 347 | /* elements of type_of | cutted chunks */ 348 | if ((b->opt & TAG_TYPE_OF) && !b->next) { 349 | i = bpr->tag->subaddr; 350 | b->next = (b->opt & BER_INCOMPL) 351 | ? &simples[i].tag : bs->odr->odrs + i; 352 | ++b->no; 353 | b->opt &= BER_INCOMPL | TAG_TYPE_OF; 354 | } 355 | if (b->opt & TAG_CHOICE) { 356 | for (; bpr >= bs->stack && !bpr->u.cn; --bpr) 357 | lua_rawseti (bs->L, -2, bpr->no); 358 | if (bpr < bs->stack) break; 359 | bs->top = bpr + 1; 360 | *bs->top = *b; 361 | b = bs->top; 362 | b->opt &= ~TAG_CHOICE; 363 | } 364 | i = bpr->len - b->v.size; 365 | if (i > 0) return; 366 | if (i < 0) { 367 | if (bpr->opt & BER_INDEFIN) return; 368 | longjmp (*bs->jb, BER_ERRTAGLEN); /* Bad length */ 369 | } 370 | bpr->v.size += b->v.size; 371 | --bs->top, --bpr; 372 | } while (bs->top > bs->stack); 373 | } else { 374 | #ifdef ENC_SIMPLESZ_MAX 375 | if (bpr->opt & BER_INCOMPL) 376 | bpr->opt &= ~BER_INCOMPL; 377 | else 378 | #endif 379 | lua_pop (bs->L, 1); 380 | /* set length */ 381 | if (bpr->opt & BER_CONSTR) { 382 | if (bpr->opt & BER_INDEFIN) { 383 | *bs->bp++ = '\0'; 384 | *bs->bp++ = '\0'; 385 | } else { 386 | i = bs->bp - bpr->v.bufp - 1; 387 | if (i >= 0x80) { 388 | struct ber *bi = bpr; 389 | while (--bi >= bs->stack 390 | && !(bi->opt & BER_INDEFIN)) 391 | bi->opt |= BER_INDEFIN; 392 | bpr->opt |= BER_INDEFIN; 393 | *bs->bp++ = '\0'; 394 | *bs->bp++ = '\0'; 395 | } else *bpr->v.bufp = i; 396 | } 397 | } 398 | for (; bpr >= bs->stack && !bpr->u.cn; --bpr) 399 | lua_pop (bs->L, 1); 400 | bs->top = bpr; 401 | } 402 | if (bpr < bs->stack) bs->top = NULL; 403 | } 404 | 405 | 406 | /* Find tmt from choice */ 407 | static char 408 | ber_choice (struct bers *bs, const int cn, struct tmt *t) 409 | { 410 | struct ber *b = bs->top; 411 | struct tmt *choices[CHOICES_MAX]; 412 | int ch_i = 0; 413 | 414 | while (cn != t->u.cn) { 415 | if (!t->u.cn) { 416 | choices[ch_i++] = t; 417 | if (ch_i >= CHOICES_MAX) 418 | longjmp (*bs->jb, BER_ERRCHCSO); /* Choices stack overflow */ 419 | t = bs->odr->odrs + t->subaddr; 420 | continue; 421 | } 422 | if (!t->comp_next) { 423 | while (--ch_i >= 0 && !choices[ch_i]->comp_next) 424 | ; 425 | if (ch_i < 0) return 0; 426 | t = choices[ch_i]; 427 | } 428 | t = bs->odr->odrs + t->comp_next; 429 | } 430 | b->tag = t; 431 | if (ch_i) { 432 | struct ber bo = *b; 433 | unsigned char i; 434 | int next = choices[0]->comp_next; 435 | for (i = 0; i < ch_i; ++i) { 436 | b->u.cn = 0; 437 | b->no = choices[i]->comp_no; 438 | b = ber_add (bs, DEN_DECODE); 439 | //fprintf (stderr, "+ >%s addr=%d top=%d\n", bs->odr->names + choices[i]->nameaddr, choices[i] - bs->odr->odrs, b - bs->stack); 440 | } 441 | *b = bo; 442 | b->next = next ? bs->odr->odrs + next : NULL; 443 | b->opt |= TAG_CHOICE; /* end of choices */ 444 | } 445 | return 1; 446 | } 447 | 448 | /* Find tmt in odrs area */ 449 | static void 450 | ber_odr (struct bers *bs) 451 | { 452 | struct ber *b = bs->top; 453 | struct tmt *t = b->next; 454 | const int cn = b->u.cn; 455 | char fnd = 0; 456 | 457 | if (t == bs->odr->odrs) { 458 | b->tag = &simples[b->len > 0 ? FUN_OCT_SKIP : FUN_EXT_ASN].tag; 459 | return; 460 | } 461 | b->tag = b->next = NULL; 462 | if (b->opt & TAG_CHOICE) { 463 | b->opt &= ~TAG_CHOICE; 464 | fnd = ber_choice (bs, cn, t); 465 | } else { 466 | while (t && cn != t->u.cn 467 | && ((t->opt & TAG_OPTIONAL) || !t->u.cn)) { 468 | if (!t->u.cn && (fnd = ber_choice (bs, cn, t))) break; 469 | t = (t->comp_next) ? bs->odr->odrs + t->comp_next : NULL; 470 | } 471 | if (t && cn == t->u.cn) { 472 | if (!fnd) { 473 | b->tag = t; 474 | fnd = 1; 475 | } 476 | /* use bs->top - may be added in ber_choice */ 477 | if (t->comp_next) 478 | bs->top->next = bs->odr->odrs + t->comp_next; 479 | } 480 | } 481 | if (!fnd) longjmp (*bs->jb, BER_ERRTAGODR); /* Missing odr */ 482 | } 483 | 484 | /* Set tag and length of contents. 485 | * Return error code and later check bounds (bp >= endp ?) 486 | */ 487 | static int 488 | ber_taglen (struct bers *bs) 489 | { 490 | struct ber *b = bs->top; 491 | unsigned char c; 492 | unsigned int len; 493 | 494 | if (!(*bs->bp | *(bs->bp + 1))) { 495 | bs->bp += 2; 496 | return BER_INDEFIN; 497 | } 498 | /* tag & tclass */ 499 | b->opt &= BER_INCOMPL | TAG_CHOICE | TAG_TYPE_OF; 500 | b->opt |= *bs->bp & BER_CONSTR; 501 | c = b->u.cn = 0; 502 | b->u.id.classnum = *bs->bp & ~BER_CONSTR; 503 | if ((*bs->bp & 0x1F) == 0x1F) { 504 | ++bs->bp; 505 | for (; (*bs->bp & 0x80) && c < CLASS_NUMSIZ; ++c, ++bs->bp) 506 | b->u.id.number[c] = *bs->bp; 507 | b->u.id.number[c] = *bs->bp; 508 | } 509 | ++bs->bp; 510 | if (c >= CLASS_NUMSIZ) 511 | return BER_ERRTAGNUM; /* Too long tag.number */ 512 | 513 | /* length */ 514 | len = 0; 515 | if (*bs->bp & BER_INDEFIN) { 516 | c = *bs->bp++ & ~BER_INDEFIN; 517 | if (c == 0x7F) c = 0; 518 | else if (c > sizeof (int)) 519 | return BER_ERRTAGLEN; /* Too long length of length */ 520 | while (c--) { 521 | len <<= 8; 522 | len |= *bs->bp++; 523 | } 524 | if (!len) b->opt |= BER_INDEFIN; 525 | } else len = *bs->bp++; 526 | b->len = len; 527 | return 0; 528 | } 529 | 530 | /* Process input ber octets */ 531 | unsigned char 532 | ber_decode (struct bers *bs) 533 | { 534 | struct ber *b; 535 | struct tmt *t; 536 | int i, sub; 537 | unsigned char c, more; 538 | 539 | if (!bs->top) { 540 | b = ber_add (bs, DEN_DECODE); 541 | b->v.size = 0; 542 | b->opt = 0; 543 | b->next = bs->odr->start; 544 | } 545 | while (bs->top) { 546 | b = bs->top; 547 | //fprintf (stderr, "bp=0x%x next=%d top=%d\n", bs->bp - bs->buf, b->next - bs->odr->odrs, b - bs->stack); 548 | more = b->opt & BER_MORE; 549 | if (more) b->opt &= ~BER_MORE; 550 | else { 551 | unsigned char *bufp = bs->bp; 552 | i = ber_taglen (bs); 553 | if (bs->bp > bs->endp) { 554 | bs->bp = bufp; 555 | return BER_INCOMPL; 556 | } 557 | b->v.size += bs->bp - bufp; 558 | if (i) { 559 | if (i == BER_INDEFIN) { 560 | ber_del (bs, DEN_DECODE | BER_INDEFIN); 561 | continue; 562 | } else longjmp (*bs->jb, i); /* BER_ERRTAG* */ 563 | } 564 | ber_odr (bs); 565 | b = bs->top; /* may be added in ber_odr */ 566 | if (!(b->len || (b->opt & BER_INDEFIN) 567 | || b->tag->subaddr == FUN_NULL)) { 568 | lua_pushnil (bs->L); 569 | ber_del (bs, DEN_DECODE); 570 | continue; 571 | } 572 | } 573 | t = b->tag; 574 | sub = t->subaddr; 575 | //fprintf (stderr, " >%s addr=%d bp=0x%x\n", bs->odr->names + t->nameaddr, t - bs->odr->odrs, bs->bp - bs->buf); 576 | 577 | if (!(b->opt & TAG_TYPE_OF)) 578 | b->no = t->comp_no; 579 | if (t->opt & TAG_SIMPLE) { 580 | if (more) /* concat of cutted octets? */ 581 | more = (sub == FUN_OCT || sub == FUN_OCT_SKIP); 582 | else /* constructed simples */ 583 | if ((b->opt & BER_CONSTR) 584 | && (simples[sub].tag.opt & TAG_COMPONENTS)) { 585 | lua_pushlstring (bs->L, NULL, 0); 586 | b = ber_add (bs, DEN_DECODE | DEN_SIMPLE); 587 | b->v.size = 0; 588 | b->opt = BER_INCOMPL | TAG_TYPE_OF; 589 | b->next = &simples[sub].tag; 590 | b->no = COMP_START_NUM; 591 | continue; 592 | } 593 | /* check length */ 594 | if (sub != FUN_EXT_ASN) { 595 | i = b->len; 596 | c = simples[sub].berlen_max; 597 | if (c && i > c) 598 | longjmp (*bs->jb, BER_ERRTAGLEN); /* Too long length */ 599 | if (i > bs->endp - bs->bp) { 600 | b->opt |= BER_MORE; 601 | /* gather only octet strings */ 602 | if (sub != FUN_OCT && sub != FUN_OCT_SKIP) 603 | return BER_INCOMPL; 604 | i = bs->endp - bs->bp; 605 | b->len -= i; 606 | } 607 | b->v.size += i; 608 | } else i = 0; 609 | c = simples[sub].fun (bs, i, DEN_DECODE); 610 | if (more) lua_concat (bs->L, 2); 611 | if (b->opt & BER_MORE) return BER_INCOMPL; 612 | if (!c) ber_del (bs, DEN_DECODE); 613 | } else { 614 | if (!(b->opt & BER_CONSTR)) 615 | longjmp (*bs->jb, BER_ERRTAG); /* BER is primitive */ 616 | b = ber_add (bs, DEN_DECODE); 617 | b->v.size = 0; 618 | b->opt = t->opt & (TAG_CHOICE | TAG_TYPE_OF); 619 | b->next = bs->odr->odrs + sub; 620 | b->no = COMP_START_NUM; 621 | //fprintf (stderr, "+ top=%d\n", bs->top - bs->stack); 622 | } 623 | } 624 | return (bs->bp < bs->endp) ? BER_MORE : 0; 625 | } 626 | 627 | /* Process output lua table */ 628 | unsigned char 629 | ber_encode (struct bers *bs) 630 | { 631 | struct ber *b; 632 | struct tmt *t; 633 | int sub, ltp = LUA_TNONE; 634 | unsigned char chunk, iscons; 635 | 636 | if (!bs->top) { 637 | b = ber_add (bs, DEN_ENCODE); 638 | b->opt = 0; 639 | b->next = bs->odr->start; 640 | b->no = COMP_START_NUM - 1; 641 | } 642 | while (bs->top) { 643 | b = bs->top; 644 | t = b->tag; 645 | chunk = b->opt & (BER_MORE | BER_INCOMPL); 646 | /* find tmt in odrs area */ 647 | if (!chunk) { 648 | lua_rawgeti (bs->L, -1, ++b->no); 649 | ltp = lua_type (bs->L, -1); 650 | t = b->next; 651 | if (b->opt & TAG_TYPE_OF) { 652 | if (ltp != LUA_TNIL) { 653 | b->opt = TAG_TYPE_OF; 654 | t = bs->odr->odrs + (b - 1)->tag->subaddr; 655 | } 656 | } else if (t && ltp == LUA_TNIL) { 657 | int i = t->comp_next; 658 | do { 659 | lua_pop (bs->L, 1); 660 | lua_rawgeti (bs->L, -1, ++b->no); 661 | ltp = lua_type (bs->L, -1); 662 | } while (ltp == LUA_TNIL && (i = bs->odr->odrs[i].comp_next)); 663 | t = (i) ? bs->odr->odrs + i : NULL; 664 | } 665 | if (!t || ltp == LUA_TNIL) { 666 | lua_pop (bs->L, 1); 667 | ber_del (bs, DEN_ENCODE); 668 | continue; 669 | } 670 | /* set next tmt */ 671 | b->tag = t; 672 | b->next = (!(b->opt & TAG_CHOICE) && t->comp_next) 673 | ? bs->odr->odrs + t->comp_next : NULL; 674 | } 675 | sub = t->subaddr; 676 | iscons = !(t->opt & TAG_SIMPLE); 677 | 678 | /* Tag */ 679 | if (!(chunk & BER_MORE) && t->u.cn) { 680 | tag_id_t cn = b->u.cn = t->u.cn; 681 | cn |= (iscons) ? BER_CONSTR : 0; 682 | *((tag_id_t *) bs->bp) = cn; 683 | //for (; cn; cn >>= 8) ++bs->bp; 684 | bs->bp += bytes_count(cn); 685 | if (iscons) { 686 | b->v.bufp = bs->bp; 687 | *bs->bp++ = 0x80; 688 | b->opt |= BER_CONSTR; 689 | } 690 | } 691 | /* Content */ 692 | //fprintf (stderr, ">%s\n", bs->odr->names + b->tag->nameaddr); 693 | if (iscons) { 694 | if (ltp != LUA_TTABLE) 695 | longjmp (*bs->jb, BER_ERRLUAOUT); /* Bad PDU */ 696 | b = ber_add (bs, DEN_ENCODE); 697 | b->opt = t->opt & (TAG_CHOICE | TAG_TYPE_OF); 698 | b->next = bs->odr->odrs + sub; 699 | b->no = COMP_START_NUM - 1; 700 | //fprintf (stderr, "+ top=%d\n", b - bs->stack); 701 | } else 702 | if (!simples[sub].fun (bs, 0, DEN_ENCODE)) 703 | lua_pop (bs->L, 1); 704 | /* Buffer overflow? */ 705 | if (bs->endp - bs->bp < ENC_BUFRESERVE) { 706 | for (b = bs->top; b >= bs->stack 707 | && !(b->opt & BER_INDEFIN); --b) 708 | b->opt |= BER_INDEFIN; 709 | return BER_INCOMPL; 710 | } 711 | } 712 | return 0; 713 | } 714 | 715 | const char * 716 | ber_errstr (const int no) 717 | { 718 | switch (no) { 719 | case BER_ERRMEM: return "memory"; 720 | case BER_ERRTAG: return "bad tag"; 721 | case BER_ERRTAGNUM: return "bad tag.number"; 722 | case BER_ERRTAGLEN: return "bad tag.length"; 723 | case BER_ERRTAGODR: return "bad tag.odr"; 724 | case BER_ERROIDMID: return "unknown ModuleID"; 725 | case BER_ERROID: return "bad OID"; 726 | case BER_ERREXT: return "bad External"; 727 | case BER_ERREXTOID: return "bad Ext.OID"; 728 | case BER_ERRSTKO: return "bers stack overflow"; 729 | case BER_ERRSTKU: return "bers stack underflow"; 730 | case BER_ERRCHCSO: return "choices stack overflow"; 731 | case BER_ERRLUASTK: return "bad Lua stack"; 732 | case BER_ERRLUAOUT: return "bad encode PDU"; 733 | case BER_ERRSIZE: return "transfer limit"; 734 | case BER_ERRODR: return "bad odr file"; 735 | default: return "unknown error"; 736 | } 737 | } 738 | -------------------------------------------------------------------------------- /src/asn/asn.c: -------------------------------------------------------------------------------- 1 | /* ASN.1 Compiler 2 | * Thanks to Index Data/YAZ 3 | * 4 | * Syntax for the ASN.1 supported: 5 | * file -> file module 6 | * | module 7 | * module -> name skip DEFINITIONS ::= BEGIN mbody END 8 | * mbody -> EXPORTS nlist ; 9 | * | EXPORTS ALL ; 10 | * | IMPORTS imlist ; 11 | * | name ::= tmt 12 | * | skip 13 | * tmt -> tag mod type 14 | * type -> SEQUENCE { sqlist } 15 | * | SEQUENCE OF type 16 | * | CHOICE { chlist } 17 | * | simple { enlist } 18 | * 19 | * simple -> INTEGER 20 | * | BOOLEAN 21 | * | OCTET STRING 22 | * | BIT STRING 23 | * | EXTERNAL 24 | * | name 25 | * sqlist -> sqlist , name tmt opt 26 | * | name tmt opt 27 | * chlist -> chlist , name tmt 28 | * | name tmt 29 | * enlist -> enlist , name (n) 30 | * | name (n) 31 | * imlist -> nlist FROM name 32 | * imlist nlist FROM name 33 | * nlist -> name 34 | * | nlist , name 35 | * mod -> IMPLICIT | EXPLICIT | e 36 | * tag -> [tclass n] | [n] | e 37 | * opt -> OPTIONAL | e 38 | * 39 | * name identifier/token 40 | * e epsilon/empty 41 | * skip tokens skipped 42 | * n number 43 | * tclass UNIVERSAL | APPLICATION | PRIVATE | e 44 | */ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "asn.h" 54 | #include "map.h" 55 | 56 | 57 | static const char usage[] = "Usage: asn2odr [-n] [FILE ...] -s FILE ...\n" 58 | "\t-n - don't add names (global)\n" 59 | "\t-s - start file\n"; 60 | 61 | static FILE *fi, *fo; 62 | static char *file, str[BUFSIZ], *val, type; 63 | static int lineno; 64 | static char implicit_tags, exports_all; 65 | 66 | static struct module *mcur; /* current module */ 67 | static struct odr_info info; 68 | 69 | static char is_sfile; /* start from current file? */ 70 | static char is_names = 1; /* add names */ 71 | 72 | 73 | /* Universal tags (simple types) */ 74 | static struct def simple_defn[] = { 75 | {"BOOLEAN", &simple_defn[1], {{1}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_BOOL, 0, 0}, 0, 0, NULL, NULL}, 76 | {"INTEGER", &simple_defn[2], {{2}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_INT, 0, 0}, 0, 0, NULL, NULL}, 77 | {"BIT\0STRING", &simple_defn[3], {{3}, TAG_IMPLICIT | TAG_SIMPLE | TAG_TWO_WORDS, COMP_START_NUM, FUN_BIT, 0, 0}, 0, 0, NULL, NULL}, 78 | {"OCTET\0STRING", &simple_defn[4], {{4}, TAG_IMPLICIT | TAG_SIMPLE | TAG_TWO_WORDS, COMP_START_NUM, FUN_OCT, 0, 0}, 0, 0, NULL, NULL}, 79 | {"ANY", &simple_defn[5], {{4}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_OCT, 0, 0}, 0, 0, NULL, NULL}, 80 | {"NULL", &simple_defn[6], {{5}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_NULL, 0, 0}, 0, 0, NULL, NULL}, 81 | {"OBJECT\0IDENTIFIER", &simple_defn[7], {{6}, TAG_IMPLICIT | TAG_SIMPLE | TAG_TWO_WORDS, COMP_START_NUM, FUN_OID, 0, 0}, 0, 0, NULL, NULL}, 82 | {"REAL", &simple_defn[8], {{9}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_OCT, 0, 0}, 0, 0, NULL, NULL}, 83 | {"SEQUENCE", &simple_defn[9], {{16}, TAG_IMPLICIT | TAG_COMPONENTS, COMP_START_NUM, 0, 0, 0}, 0, 0, NULL, NULL}, 84 | {"SET", &simple_defn[10], {{17}, TAG_IMPLICIT | TAG_COMPONENTS, COMP_START_NUM, 0, 0, 0}, 0, 0, NULL, NULL}, 85 | {"EXT_DREF", &simple_defn[11], {{6}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_EXT_DREF, 0, 0}, 0, 0, NULL, NULL}, 86 | {"EXT_ASN", &simple_defn[12], {{4}, TAG_IMPLICIT | TAG_SIMPLE, COMP_START_NUM, FUN_EXT_ASN, 0, 0}, 0, 0, NULL, NULL}, 87 | {"CHOICE", NULL, {{0}, TAG_CHOICE | TAG_COMPONENTS, COMP_START_NUM, 0, 0, 0}, 0, 0, NULL, NULL} 88 | }; 89 | static struct def *simple_defn_end = simple_defn 90 | + sizeof (simple_defn) / sizeof (struct def) - 1; 91 | 92 | /* Z39-50 OID classes */ 93 | static struct oid oids[] = { 94 | /* Z39-50 {0x2A, 0x86, 0x48, 0xCE, 0x13} */ 95 | {"Z39-50-attributeSet", &oids[1], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 3}}, 96 | {"Z39-50-diagnosticFormat", &oids[2], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 4}}, 97 | {"Z39-50-recordSyntax", &oids[3], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 5}}, 98 | {"Z39-50-resourceReport", &oids[4], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 7}}, 99 | {"Z39-50-accessControl", &oids[5], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 8}}, 100 | {"Z39-50-extendedService", &oids[6], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 9}}, 101 | {"Z39-50-userInfoFormat", &oids[7], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 10}}, 102 | {"Z39-50-elementSpec", &oids[8], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 11}}, 103 | {"Z39-50-variantSet", &oids[9], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 12}}, 104 | {"Z39-50-schema", &oids[10], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 13}}, 105 | {"Z39-50-tagSet", &oids[11], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 14}}, 106 | {"Z39-50-negotiation", &oids[12], {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 15}}, 107 | {"Z39-50-query", NULL, {6, 0x2A, 0x86, 0x48, 0xCE, 0x13, 16}} 108 | }; 109 | 110 | static struct def *asnType (struct tmt *t); 111 | 112 | 113 | /* Report error and die */ 114 | void 115 | asnError (const char *fmt, ...) 116 | { 117 | va_list ap; 118 | 119 | fprintf (stderr, "%s:%d: Error in module '%s'\n> ", 120 | file, lineno, mcur->name); 121 | va_start (ap, fmt); 122 | vfprintf (stderr, fmt, ap); 123 | va_end (ap); 124 | if (errno) perror ("Error"); 125 | exit (EXIT_FAILURE); 126 | } 127 | 128 | /* Report warning and return */ 129 | static void 130 | asnWarning (const char *msg) 131 | { 132 | fprintf (stderr, "%s:%d: Warning: %s\n", file, lineno, msg); 133 | } 134 | 135 | /* Moves input file pointer. 136 | * The globals type and val are set. 137 | * val holds name, if token is normal identifier name. 138 | * Sets type to one of: 139 | * \0 end-of-file 140 | * { left curly brace 141 | * } right curly brace 142 | * , comma 143 | * ; semicolon 144 | * ( (n) 145 | * [ [n] 146 | * : ::= 147 | * n other token n 148 | */ 149 | static void 150 | lex () 151 | { 152 | static char *valend, endchar; 153 | 154 | if (!val) return; 155 | if (type == 'n' && valend) { 156 | *valend = endchar; 157 | val = valend; 158 | } 159 | while (isspace (*val)) ++val; 160 | while (!*val) { 161 | val = fgets (str, BUFSIZ, fi); 162 | if (!val) { 163 | type = '\0'; 164 | return; 165 | } 166 | ++lineno; 167 | if ((valend = strstr (str, "--"))) *valend = '\0'; 168 | while (isspace (*val)) ++val; 169 | } 170 | switch (type = *val) { 171 | case '{': case '}': case ',': case '[': case ']': 172 | case ';': case '(': case ')': val++; break; 173 | case ':': val += 3; break; /* ::= */ 174 | default: 175 | if (!(valend = strpbrk (val, "\f\r\n\t\v ,:;{}()[]"))) 176 | valend = val + strlen (val); 177 | endchar = *valend; 178 | *valend = '\0'; 179 | if (valend - val > NAMESIZ - 1) { 180 | val[NAMESIZ - 1] = '\0'; 181 | val[NAMESIZ - 2] = '|'; 182 | asnWarning ("Long name cutted"); 183 | } 184 | type = 'n'; 185 | } 186 | } 187 | 188 | /* Move pointer and expect token t */ 189 | static void 190 | lex_expect (const char t) 191 | { 192 | lex (); 193 | if (t != type) 194 | asnError ("Expected %c type, got %c\n", t, type); 195 | } 196 | 197 | /* See if token is name; moves pointer and 198 | * returns 1 if it is; returns 0 otherwise */ 199 | static unsigned char 200 | lex_name_move (const char *name) 201 | { 202 | if (type == 'n' && !strcmp (val, name)) { 203 | lex (); 204 | return 1; 205 | } 206 | return 0; 207 | } 208 | 209 | /* Parses enumerated list - { name1 (n), name2 (n), ... } */ 210 | static void 211 | asnEnum () 212 | { 213 | if (type != '{') return; 214 | for (; ; ) { 215 | lex_expect ('n'); 216 | lex_expect ('('); 217 | lex_expect ('n'); 218 | lex_expect (')'); 219 | lex (); 220 | if (type != ',') break; 221 | } 222 | if (type != '}') 223 | asnError ("Missing } in enum list, got %c '%s'\n", type, val); 224 | lex (); 225 | } 226 | 227 | /* Convert values to network byte order */ 228 | static int 229 | hton7 (int num, unsigned char *dest, unsigned int max) 230 | { 231 | unsigned int i, len, number; 232 | 233 | number = num & 0x7F; 234 | num >>= 7; 235 | for (len = 1; num; ++len) { 236 | number <<= 8; 237 | number |= (unsigned char) num | 0x80; 238 | num >>= 7; 239 | } 240 | if (len > max) 241 | asnWarning ("Too long converting number"); 242 | 243 | for (i = 0; len; ++i, --len, number >>= 8) 244 | dest[i] = number; 245 | return i; 246 | } 247 | 248 | /* Parses tag and modifier */ 249 | static void 250 | asnMod (struct tmt *t) 251 | { 252 | t->u.cn = 0; 253 | if (type == '[') { 254 | lex (); 255 | t->u.id.classnum = CLASS_CONTEXT; 256 | if (type == 'n' && isalpha (*val)) { 257 | switch (*val) { 258 | case 'U': t->u.id.classnum = CLASS_UNIVERSAL; break; 259 | case 'A': t->u.id.classnum = CLASS_APPLICATION; break; 260 | case 'P': t->u.id.classnum = CLASS_PRIVATE; break; 261 | default: 262 | asnError ("Bad tag.class: '%s'\n", val); 263 | } 264 | lex (); 265 | } 266 | if (type == 'n' && isdigit (*val)) { 267 | int i = atoi (val); 268 | if (i >= 31) { 269 | t->u.id.classnum |= 31; 270 | hton7 (i, t->u.id.number, CLASS_NUMSIZ); 271 | } else t->u.id.classnum |= i; 272 | } else 273 | asnError ("Bad tag.number: '%s'\n", val); 274 | lex_expect (']'); 275 | lex (); 276 | } 277 | t->opt = implicit_tags; 278 | if (lex_name_move ("EXPLICIT")) t->opt &= ~TAG_IMPLICIT; 279 | else if (lex_name_move ("IMPLICIT")) t->opt |= TAG_IMPLICIT; 280 | } 281 | 282 | /* Parses optional modifier */ 283 | static unsigned char 284 | asnOptional () 285 | { 286 | if (lex_name_move ("OPTIONAL")) return TAG_OPTIONAL; 287 | else if (lex_name_move ("DEFAULT")) { 288 | lex (); 289 | return TAG_OPTIONAL; 290 | } 291 | return 0; 292 | } 293 | 294 | /* Parses the Subtype specification. 295 | * We now it's balanced, i.e. (... ( ... ) .. ) 296 | */ 297 | static void 298 | asnSubtypeSpec () 299 | { 300 | int level = 1; 301 | 302 | if (type != '(') return; 303 | lex (); 304 | while (type && level) { 305 | if (type == '(') ++level; 306 | else if (type == ')') --level; 307 | lex (); 308 | } 309 | if (!type) asnError ("Missing ) in SubtypeSpec\n"); 310 | } 311 | 312 | /* Parses the optional SizeConstraint */ 313 | static void 314 | asnSizeConstraint () 315 | { 316 | if (lex_name_move ("SIZE")) asnSubtypeSpec (); 317 | } 318 | 319 | /* Set type dependencies */ 320 | static struct tmt * 321 | asnTypeDep (struct tmt *t, struct def *d) 322 | { 323 | unsigned char opt_imask = 0; 324 | 325 | if (!t->u.cn) { 326 | t->u = d->tag.u; 327 | t->subaddr = d->tag.subaddr; 328 | } 329 | else { 330 | if ((t->opt & TAG_IMPLICIT) || !d->tag.u.cn) 331 | t->subaddr = d->tag.subaddr; 332 | else { 333 | if (d->tag.opt & (TAG_DEFINITION | TAG_SIMPLE)) { 334 | if (!d->addr) { 335 | if (is_names) 336 | d->tag.nameaddr = name_add (d->name); 337 | d->addr = odr_add (&d->tag); 338 | } 339 | t->subaddr = d->addr; 340 | } else { 341 | if (is_names) 342 | d->tag.nameaddr = name_add (d->name); 343 | t->subaddr = odr_add (&d->tag); 344 | t = odrs + t->subaddr; 345 | } 346 | opt_imask = TAG_IMPLICIT | TAG_SIMPLE; 347 | } 348 | } 349 | t->opt |= d->tag.opt & ~opt_imask; 350 | return t; 351 | } 352 | 353 | /* Parses components. 354 | * Return address of first component 355 | */ 356 | static int 357 | asnSub () 358 | { 359 | static struct def *fdef; 360 | struct tmt *t; 361 | /* paddr - address of previous component to set next */ 362 | int paddr = 0, faddr = 0, addr, comp_no = COMP_START_NUM; 363 | 364 | if (type != '{') 365 | asnError ("Expects { specifier, but got %c\n", type); 366 | lex (); 367 | while (type == 'n') { 368 | union comp_addr ca; 369 | addr = odr_add (NULL); 370 | t = odrs + addr; 371 | if (!paddr) faddr = addr; 372 | else (odrs + paddr)->comp_next = addr; 373 | paddr = addr; 374 | if (is_names) 375 | t->nameaddr = name_add (val); 376 | t->comp_no = comp_no++; 377 | lex (); 378 | asnMod (t); 379 | fdef = asnType (t); 380 | ca.addr = addr; 381 | if (fdef) def_req (fdef, ca, 0); 382 | t->opt |= asnOptional (); 383 | if (type != ',') break; 384 | lex (); 385 | } 386 | if (type != '}') 387 | asnError ("Missing } after COMPONENTS list" 388 | ", got %c '%s'\n", type, val); 389 | lex (); 390 | return faddr; 391 | } 392 | 393 | /* Parses ASN.1 type. 394 | * Return forward definition 395 | */ 396 | static struct def * 397 | asnType (struct tmt *t) 398 | { 399 | static struct def *d; 400 | struct def *fdef = NULL; 401 | 402 | if (type != 'n') 403 | asnError ("Expects type specifier, but got %c\n", type); 404 | if (!(d = find (val, simple_defn, NULL))) { 405 | d = def_add (mcur, FORWARD | exports_all, val); 406 | if (d->opt & DEF_IMPORT) d = d->type; 407 | } 408 | if (d->opt & (FORWARD | DEF_INCOMPL)) fdef = d; 409 | else t = asnTypeDep (t, d); 410 | if (t->opt & TAG_TWO_WORDS) { 411 | lex (); 412 | t->opt &= ~TAG_TWO_WORDS; 413 | } else if (t->opt & TAG_COMPONENTS) asnSizeConstraint (); 414 | if (lex_name_move ("DEFINED")) lex_name_move ("BY"); 415 | lex (); 416 | asnSubtypeSpec (); 417 | if ((t->opt & TAG_COMPONENTS) && lex_name_move ("OF")) { 418 | t->opt &= ~TAG_COMPONENTS; 419 | if (!(t->opt & TAG_IMPLICIT)) { 420 | t->subaddr = odr_add (&d->tag); 421 | t = odrs + t->subaddr; 422 | }; 423 | t->opt = (t->opt & ~TAG_IMPLICIT) | TAG_TYPE_OF; 424 | return asnType (t); 425 | } 426 | if (!(t->opt & TAG_COMPONENTS)) asnEnum (); 427 | else if (!(t->opt & TAG_DEFINITION)) t->subaddr = asnSub (); 428 | return fdef; 429 | } 430 | 431 | /* Parses type definition */ 432 | static void 433 | asnForwardTypes (struct def *d) 434 | { 435 | static struct def *ncdef; 436 | static struct comp *c; 437 | static struct tmt *t; 438 | 439 | while ((c = d->compn)) { 440 | ncdef = NULL; 441 | if (c->opt & DEF_INCOMPL) { 442 | ncdef = c->u.ncdef; 443 | t = &ncdef->tag; 444 | ncdef->opt &= ~DEF_INCOMPL; 445 | } else t = odrs + c->u.addr; 446 | t = asnTypeDep (t, d); 447 | d->compn = c->next; 448 | free (c); 449 | if (ncdef) { 450 | if (ncdef->addr) *(odrs + ncdef->addr) = *t; 451 | asnForwardTypes (ncdef); 452 | } 453 | } 454 | } 455 | 456 | /* Parses type definition (top-level). 457 | * On entry name holds the type we are defining 458 | */ 459 | static void 460 | asnDef (const char *name) 461 | { 462 | struct def *d, *fdef; 463 | union comp_addr ca; 464 | 465 | d = def_add (mcur, exports_all | DEF_INCOMPL, name); 466 | asnMod (&d->tag); 467 | if (!mcur->id.addr && mcur->id.oid[0]) { 468 | if (is_names) 469 | d->tag.nameaddr = name_add (d->name); 470 | mcur->id.addr = d->addr = odr_add (&d->tag); 471 | } 472 | fdef = asnType (&d->tag); 473 | d->tag.opt |= TAG_DEFINITION; /* asnType may set to simple type */ 474 | if (d->addr) *(odrs + d->addr) = d->tag; 475 | ca.ncdef = d; 476 | if (fdef) def_req (fdef, ca, DEF_INCOMPL); 477 | else d->opt &= ~DEF_INCOMPL; 478 | if (d->compn && !fdef) asnForwardTypes (d); 479 | } 480 | 481 | /* Parses i-list in "IMPORTS {i-list};" */ 482 | static void 483 | asnImports () 484 | { 485 | struct module *m; 486 | struct def *d, *imports_end; 487 | 488 | imports_end = mcur->imports = mcur->exports; 489 | if (!lex_name_move ("IMPORTS")) return; 490 | if (type != 'n') 491 | asnError ("Missing name in IMPORTS list\n"); 492 | while (type == 'n') { 493 | def_add (mcur, DEF_IMPORT, val); 494 | lex (); 495 | if (lex_name_move ("FROM")) { 496 | d = mcur->imports; 497 | m = module_add (FORWARD, val); 498 | while (d != imports_end) { 499 | d->type = def_add (m, DEF_EXPORT | FORWARD, d->name); 500 | d = d->next; 501 | } 502 | imports_end = mcur->imports; 503 | } else if (type != ',') break; 504 | lex (); 505 | } 506 | if (imports_end != mcur->imports) 507 | asnError ("Missing FROM in IMPORTS list\n"); 508 | else if (type != ';') 509 | asnError ("Missing ; after IMPORTS list, got %c '%s'\n", 510 | type, val); 511 | lex (); 512 | } 513 | 514 | /* Parses e-list in "EXPORTS {e-list};" */ 515 | static void 516 | asnExports () 517 | { 518 | exports_all = 0; 519 | if (!lex_name_move ("EXPORTS")) return; 520 | if (type != 'n') 521 | asnError ("Missing name in EXPORTS list\n"); 522 | while (type == 'n') { 523 | if (lex_name_move ("ALL")) { 524 | exports_all |= DEF_EXPORT; 525 | break; 526 | } 527 | def_add (mcur, DEF_EXPORT | FORWARD, val); 528 | lex (); 529 | if (type != ',') break; 530 | lex (); 531 | } 532 | if (type != ';') 533 | asnError ("Missing ; after EXPORTS list, got %c '%s'\n", 534 | type, val); 535 | lex (); 536 | } 537 | 538 | /* Parses a module specification. 539 | * Exports lists, imports lists, and type definitions are handled; 540 | * other things are silently ignored 541 | */ 542 | static void 543 | asnModuleBody () 544 | { 545 | char oval[NAMESIZ]; 546 | 547 | asnExports (); 548 | asnImports (); 549 | while (type) { 550 | if (type != 'n') { 551 | lex (); 552 | continue; 553 | } 554 | if (!strcmp (val, "END")) break; 555 | strcpy (oval, val); 556 | lex (); 557 | if (type == ':') { 558 | lex (); 559 | asnDef (oval); 560 | } else if (type == 'n') { 561 | lex (); 562 | if (type) lex (); 563 | } 564 | } 565 | } 566 | 567 | /* Parses TagDefault section */ 568 | static void 569 | asnTagDefault () 570 | { 571 | implicit_tags = 0; 572 | if ((lex_name_move ("IMPLICIT") && (implicit_tags |= TAG_IMPLICIT)) 573 | || lex_name_move ("EXPLICIT")) 574 | if (!lex_name_move ("TAGS")) 575 | asnError ("Bad TagDefault specification"); 576 | } 577 | 578 | /* Parses Module Identifier section */ 579 | static void 580 | asnModuleId (unsigned char *oid) 581 | { 582 | struct oid *o; 583 | int i = 0; 584 | 585 | if (type != '{') return; 586 | lex (); 587 | if (type == 'n') { 588 | if (!(o = find (val, oids, NULL))) 589 | asnError ("Bad ModuleID Class '%s'\n", val); 590 | memcpy (oid + 1, o->oid + 1, i = o->oid[0]); 591 | lex (); 592 | } else 593 | asnError ("Bad Module Identifier specification\n"); 594 | while (type == 'n') { 595 | lex_expect ('('); 596 | lex (); 597 | i += hton7 (atoi (val), oid + i + 1, OIDSIZ - i); 598 | if (i >= OIDSIZ) 599 | asnError ("Too long Module Identifier\n"); 600 | lex_expect (')'); 601 | lex (); 602 | } 603 | oid[0] = i; 604 | info.nmodules++; 605 | if (type != '}') 606 | asnError ("Missing } after ModuleID, got %c '%s'\n", type, val); 607 | lex (); 608 | } 609 | 610 | /* Parses a collection of module specifications */ 611 | static void 612 | asnModules () 613 | { 614 | char oval[NAMESIZ]; 615 | 616 | lex (); 617 | while (type == 'n') { 618 | mcur = module_add (0, val); 619 | strcpy (oval, val); 620 | lex (); 621 | asnModuleId (mcur->id.oid); 622 | if (is_sfile) { 623 | if (!mcur->id.oid[0]) { 624 | mcur->id.oid[0] = 1; 625 | info.nmodules++; 626 | } 627 | is_sfile = 0; /* start from the first module in file */ 628 | } 629 | if (mcur->id.oid[0] && is_names) 630 | mcur->id.nameaddr = name_add (oval); 631 | while (!lex_name_move ("DEFINITIONS")) { 632 | lex (); 633 | if (!type) return; 634 | } 635 | asnTagDefault (); 636 | if (type != ':') 637 | asnError ("::= expected, got %c '%s'\n", type, val); 638 | lex (); 639 | if (!lex_name_move ("BEGIN")) 640 | asnError ("BEGIN expected\n"); 641 | asnModuleBody (); 642 | if (!exports_all) 643 | /* defn -> imports -> exports */ 644 | def_del (mcur, mcur->exports, DEF_INCOMPL | FORWARD); 645 | else if (mcur->imports) { 646 | /* defn -> exports -> imports */ 647 | mcur->defn = mcur->imports; 648 | def_del (mcur, NULL, DEF_INCOMPL | FORWARD); 649 | mcur->defn = mcur->exports; 650 | } 651 | if (!strcmp (mcur->name, "_USE")) { 652 | simple_defn_end->next = mcur->exports; 653 | while (simple_defn_end->next) 654 | simple_defn_end = simple_defn_end->next; 655 | } 656 | if (!(mcur->exports || mcur->id.oid[0])) 657 | module_del (mcur); 658 | lex (); 659 | } 660 | } 661 | 662 | /* Parses an ASN.1 specification file */ 663 | static void 664 | asnFile () 665 | { 666 | lineno = str[0] = 0; 667 | val = str; 668 | fi = fopen (file, "r"); 669 | if (!fi) asnError ("Open ASN.1 file '%s'\n", file); 670 | asnModules (); 671 | fclose (fi); 672 | } 673 | 674 | 675 | /* Compare modules */ 676 | static int 677 | module_cmp (const void *m1, const void *m2) 678 | { 679 | return memcmp (((struct module_id *) m1)->oid, 680 | ((struct module_id *) m2)->oid, OIDSIZ); 681 | } 682 | 683 | /* Write output file */ 684 | static void 685 | asnOut () 686 | { 687 | int i; 688 | 689 | info.nodrs = odrs_next; 690 | *((struct odr_info *) odrs) = info; 691 | fo = fopen ("asn.odr", "wb"); 692 | if (!fo) asnError ("Create odr file\n"); 693 | fwrite (odrs, sizeof (struct tmt), odrs_next, fo); 694 | /* reuse odrs area to sort modules.oid */ 695 | for (i = 0; modules; module_del (modules)) 696 | if (modules->id.oid[0]) 697 | ((struct module_id *) odrs)[i++] = modules->id; 698 | /* i == info.nmodules */ 699 | qsort (odrs, i, sizeof (struct module_id), module_cmp); 700 | fwrite (odrs, sizeof (struct module_id), i, fo); 701 | fwrite (names, sizeof (char), names_next, fo); 702 | fclose (fo); 703 | free (odrs); 704 | names_del (); 705 | } 706 | 707 | 708 | int 709 | main (int argc, char *argv[]) 710 | { 711 | int i = 0; 712 | 713 | if (argc < 2) 714 | fprintf (stderr, usage), exit (EXIT_FAILURE); 715 | odr_add (NULL); /* module->id.addr > 0! */ 716 | name_add (ODR_NAME_STUB); /* stub */ 717 | while (++i < argc) { 718 | file = argv[i]; 719 | if (*file == '-') { 720 | switch (file[1]) { 721 | case 'n': 722 | is_names = 0; 723 | break; 724 | case 's': 725 | info.start = odrs_next; 726 | is_sfile = 1; 727 | break; 728 | } 729 | continue; 730 | } 731 | asnFile (); 732 | } 733 | if (!info.start) 734 | fprintf (stderr, usage), exit (EXIT_FAILURE); 735 | asnOut (); 736 | return EXIT_SUCCESS; 737 | } 738 | --------------------------------------------------------------------------------