aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1fix
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-06-03 03:38:44 +0000
committerLev Walkin <vlm@lionet.info>2004-06-03 03:38:44 +0000
commitf15320bf6b50a0c02636405561ac8323ae901abd (patch)
tree33461d45122896c6dde35f82f5c7d19b62004a6b /libasn1fix
parent746cb60bbccf47019563665f4aec4b6c462c4163 (diff)
Initial revision
Diffstat (limited to 'libasn1fix')
-rw-r--r--libasn1fix/Makefile.am36
-rw-r--r--libasn1fix/Makefile.in454
-rw-r--r--libasn1fix/asn1fix.c354
-rw-r--r--libasn1fix/asn1fix.h30
-rw-r--r--libasn1fix/asn1fix_bitstring.c230
-rw-r--r--libasn1fix/asn1fix_bitstring.h6
-rw-r--r--libasn1fix/asn1fix_class.c237
-rw-r--r--libasn1fix/asn1fix_class.h16
-rw-r--r--libasn1fix/asn1fix_compat.c132
-rw-r--r--libasn1fix/asn1fix_compat.h14
-rw-r--r--libasn1fix/asn1fix_constr.c364
-rw-r--r--libasn1fix/asn1fix_constr.h24
-rw-r--r--libasn1fix/asn1fix_cstring.c73
-rw-r--r--libasn1fix/asn1fix_cstring.h6
-rw-r--r--libasn1fix/asn1fix_dereft.c68
-rw-r--r--libasn1fix/asn1fix_dereft.h6
-rw-r--r--libasn1fix/asn1fix_derefv.c56
-rw-r--r--libasn1fix/asn1fix_derefv.h6
-rw-r--r--libasn1fix/asn1fix_enum.c136
-rw-r--r--libasn1fix/asn1fix_enum.h6
-rw-r--r--libasn1fix/asn1fix_export.c48
-rw-r--r--libasn1fix/asn1fix_export.h32
-rw-r--r--libasn1fix/asn1fix_integer.c161
-rw-r--r--libasn1fix/asn1fix_integer.h6
-rw-r--r--libasn1fix/asn1fix_internal.h106
-rw-r--r--libasn1fix/asn1fix_misc.c276
-rw-r--r--libasn1fix/asn1fix_misc.h47
-rw-r--r--libasn1fix/asn1fix_param.c165
-rw-r--r--libasn1fix/asn1fix_param.h6
-rw-r--r--libasn1fix/asn1fix_retrieve.c366
-rw-r--r--libasn1fix/asn1fix_retrieve.h73
-rw-r--r--libasn1fix/asn1fix_tags.c47
-rw-r--r--libasn1fix/asn1fix_tags.h6
-rw-r--r--libasn1fix/asn1fix_value.c159
-rw-r--r--libasn1fix/asn1fix_value.h28
-rw-r--r--libasn1fix/check_fixer.c313
36 files changed, 4093 insertions, 0 deletions
diff --git a/libasn1fix/Makefile.am b/libasn1fix/Makefile.am
new file mode 100644
index 00000000..0e52b4f3
--- /dev/null
+++ b/libasn1fix/Makefile.am
@@ -0,0 +1,36 @@
+
+
+AM_CFLAGS = @ADD_CFLAGS@
+AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
+
+noinst_LTLIBRARIES = libasn1fix.la
+
+libasn1fix_la_LDFLAGS = -all-static
+libasn1fix_la_SOURCES = \
+ asn1fix.c asn1fix.h \
+ asn1fix_internal.h \
+ asn1fix_misc.c asn1fix_misc.h \
+ asn1fix_value.c asn1fix_value.h \
+ asn1fix_compat.c asn1fix_compat.h \
+ asn1fix_constr.c asn1fix_constr.h \
+ asn1fix_cstring.c asn1fix_cstring.h \
+ asn1fix_retrieve.c asn1fix_retrieve.h \
+ asn1fix_bitstring.c asn1fix_bitstring.h \
+ asn1fix_integer.c asn1fix_integer.h \
+ asn1fix_dereft.c asn1fix_dereft.h \
+ asn1fix_derefv.c asn1fix_derefv.h \
+ asn1fix_export.c asn1fix_export.h \
+ asn1fix_param.c asn1fix_param.h \
+ asn1fix_class.c asn1fix_class.h \
+ asn1fix_tags.c asn1fix_tags.h \
+ asn1fix_enum.c asn1fix_enum.h
+libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
+
+check_PROGRAMS = check_fixer
+
+LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
+DEPENDENCIES = ${LDADD}
+
+TESTS_ENVIRONMENT= ./check_fixer
+TESTS = ${top_srcdir}/tests/*.asn1
+## TESTS = ${check_PROGRAMS} # This is an alternate form of testing
diff --git a/libasn1fix/Makefile.in b/libasn1fix/Makefile.in
new file mode 100644
index 00000000..8d919c20
--- /dev/null
+++ b/libasn1fix/Makefile.in
@@ -0,0 +1,454 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+ADD_CFLAGS = @ADD_CFLAGS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CONFIGURE_DEPENDS = @CONFIGURE_DEPENDS@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PATH = @PATH@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+AM_CFLAGS = @ADD_CFLAGS@
+AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
+
+noinst_LTLIBRARIES = libasn1fix.la
+
+libasn1fix_la_LDFLAGS = -all-static
+libasn1fix_la_SOURCES = \
+ asn1fix.c asn1fix.h \
+ asn1fix_internal.h \
+ asn1fix_misc.c asn1fix_misc.h \
+ asn1fix_value.c asn1fix_value.h \
+ asn1fix_compat.c asn1fix_compat.h \
+ asn1fix_constr.c asn1fix_constr.h \
+ asn1fix_cstring.c asn1fix_cstring.h \
+ asn1fix_retrieve.c asn1fix_retrieve.h \
+ asn1fix_bitstring.c asn1fix_bitstring.h \
+ asn1fix_integer.c asn1fix_integer.h \
+ asn1fix_dereft.c asn1fix_dereft.h \
+ asn1fix_derefv.c asn1fix_derefv.h \
+ asn1fix_export.c asn1fix_export.h \
+ asn1fix_param.c asn1fix_param.h \
+ asn1fix_class.c asn1fix_class.h \
+ asn1fix_tags.c asn1fix_tags.h \
+ asn1fix_enum.c asn1fix_enum.h
+
+libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
+
+check_PROGRAMS = check_fixer
+
+LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
+DEPENDENCIES = ${LDADD}
+
+TESTS_ENVIRONMENT = ./check_fixer
+TESTS = ${top_srcdir}/tests/*.asn1
+subdir = libasn1fix
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+libasn1fix_la_DEPENDENCIES = \
+ ${top_builddir}/libasn1parser/libasn1parser.la
+am_libasn1fix_la_OBJECTS = asn1fix.lo asn1fix_misc.lo asn1fix_value.lo \
+ asn1fix_compat.lo asn1fix_constr.lo asn1fix_cstring.lo \
+ asn1fix_retrieve.lo asn1fix_bitstring.lo asn1fix_integer.lo \
+ asn1fix_dereft.lo asn1fix_derefv.lo asn1fix_export.lo \
+ asn1fix_param.lo asn1fix_class.lo asn1fix_tags.lo \
+ asn1fix_enum.lo
+libasn1fix_la_OBJECTS = $(am_libasn1fix_la_OBJECTS)
+check_PROGRAMS = check_fixer$(EXEEXT)
+check_fixer_SOURCES = check_fixer.c
+check_fixer_OBJECTS = check_fixer.$(OBJEXT)
+check_fixer_LDADD = $(LDADD)
+check_fixer_DEPENDENCIES = libasn1fix.la \
+ ${top_builddir}/libasn1parser/libasn1parser.la
+check_fixer_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/asn1fix.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_bitstring.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_class.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_compat.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_constr.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_cstring.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_dereft.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_derefv.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_enum.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_export.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_integer.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_misc.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_param.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_retrieve.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_tags.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/asn1fix_value.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/check_fixer.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(libasn1fix_la_SOURCES) check_fixer.c
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(libasn1fix_la_SOURCES) check_fixer.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libasn1fix/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+libasn1fix.la: $(libasn1fix_la_OBJECTS) $(libasn1fix_la_DEPENDENCIES)
+ $(LINK) $(libasn1fix_la_LDFLAGS) $(libasn1fix_la_OBJECTS) $(libasn1fix_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+ -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS)
+check_fixer$(EXEEXT): $(check_fixer_OBJECTS) $(check_fixer_DEPENDENCIES)
+ @rm -f check_fixer$(EXEEXT)
+ $(LINK) $(check_fixer_LDFLAGS) $(check_fixer_OBJECTS) $(check_fixer_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_bitstring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_class.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_compat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_constr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_cstring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_dereft.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_derefv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_enum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_export.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_integer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_param.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_retrieve.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_tags.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_value.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check_fixer.Po@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list='$(TESTS)'; \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ echo "XPASS: $$tst"; \
+ ;; \
+ *) \
+ echo "PASS: $$tst"; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *" $$tst "*) \
+ xfail=`expr $$xfail + 1`; \
+ echo "XFAIL: $$tst"; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ echo "FAIL: $$tst"; \
+ ;; \
+ esac; \
+ fi; \
+ done; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="All $$all tests passed"; \
+ else \
+ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all tests failed"; \
+ else \
+ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+ fi; \
+ fi; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"; \
+ test "$$failed" -eq 0; \
+ fi
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES distclean distclean-compile \
+ distclean-depend distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ tags uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c
new file mode 100644
index 00000000..af110999
--- /dev/null
+++ b/libasn1fix/asn1fix.c
@@ -0,0 +1,354 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "asn1fix.h"
+#include "asn1fix_internal.h"
+
+/* Print everything to stderr */
+static void _default_error_logger(int _severity, const char *fmt, ...);
+
+/*
+ * Internal check functions.
+ */
+static int asn1f_fix_module(arg_t *arg);
+static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
+static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
+static int asn1f_fix_constraints(arg_t *arg); /* For subtype constraints */
+
+
+/*
+ * Scan every module defined here in search for inconsistences.
+ */
+int
+asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
+ error_logger_f error_logger) {
+ arg_t arg;
+ int fatals = 0;
+ int warnings = 0;
+
+ /*
+ * Check validity of arguments.
+ */
+ if(asn == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * If errors handler is not specified, default to internal one.
+ */
+ if(error_logger == 0) {
+ error_logger = _default_error_logger;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ arg.asn = asn;
+ arg.eh = error_logger;
+
+ if(flags & A1F_DEBUG) {
+ arg.debug = arg.eh;
+ arg.debug(-1, "Called %s() with flags %d", __func__, flags);
+ flags &= ~A1F_DEBUG;
+ }
+
+ /*
+ * Check that we haven't missed an unknown flag.
+ */
+ if(flags) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Process each module in the list.
+ */
+ TQ_FOR(arg.mod, &(asn->modules), mod_next) {
+ int ret = asn1f_fix_module(&arg);
+ /*
+ * These lines are used for illustration purposes.
+ * RET2RVAL() is used everywhere else.
+ */
+ if(ret == -1) fatals++;
+ if(ret == 1) warnings++;
+ }
+
+ /*
+ * Compute a return value.
+ */
+ return fatals?-1:warnings?1:0;
+}
+
+/*
+ * Check the internals of a single module.
+ */
+static int
+asn1f_fix_module(arg_t *arg) {
+ asn1p_expr_t *expr;
+ int rvalue = 0;
+
+ switch((arg->mod->module_flags
+ & (MSF_EXPLICIT_TAGS | MSF_IMPLICIT_TAGS | MSF_AUTOMATIC_TAGS))) {
+ case MSF_NOFLAGS:
+ case MSF_EXPLICIT_TAGS:
+ case MSF_IMPLICIT_TAGS:
+ case MSF_AUTOMATIC_TAGS:
+ break;
+ default:
+ FATAL("Module %s defined with ambiguous global tagging mode",
+ arg->mod->Identifier);
+ RET2RVAL(-1, rvalue);
+ }
+
+ /*
+ * Do various non-recursive transformations.
+ * Order is not important.
+ */
+ TQ_FOR(expr, &(arg->mod->members), next) {
+ int ret;
+ arg->expr = expr;
+
+ if(expr->meta_type == AMT_PARAMTYPE)
+ /* Do not process the parametrized type just yet */
+ continue;
+
+ DEBUG("=== Now processing \"%s\" at line %d ===",
+ expr->Identifier, expr->_lineno);
+ assert(expr->meta_type != AMT_INVALID);
+
+ /*
+ * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
+ */
+ ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * 2.[234] Process SEQUENCE/SET/CHOICE types.
+ */
+ ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * 2.5.4
+ */
+ ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * 2.5.5
+ */
+ ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * Resolve references in constraints.
+ */
+ ret = asn1f_recurse_expr(arg, asn1f_fix_constraints);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * 6. INTEGER value processed at 2.5.4.
+ */
+
+ /*
+ * Make sure everybody's behaving well.
+ */
+ assert(arg->expr == expr);
+ }
+
+ /*
+ * 5. Automatic tagging
+ */
+ TQ_FOR(expr, &(arg->mod->members), next) {
+ int ret;
+
+ arg->expr = expr;
+
+ ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
+ RET2RVAL(ret, rvalue);
+
+ assert(arg->expr == expr);
+ }
+
+ /*
+ * 8. fix BIT STRING
+ * 9. fix spaces in cstrings
+ */
+ TQ_FOR(expr, &(arg->mod->members), next) {
+ int ret;
+ arg->expr = expr;
+
+ ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
+ RET2RVAL(ret, rvalue);
+
+ ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
+ RET2RVAL(ret, rvalue);
+
+ assert(arg->expr == expr);
+ }
+
+ /*
+ * ... Check for tags distinctness.
+ */
+ TQ_FOR(expr, &(arg->mod->members), next) {
+ int ret;
+ arg->expr = expr;
+
+ ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
+ RET2RVAL(ret, rvalue);
+
+ assert(arg->expr == expr);
+ }
+
+ return rvalue;
+}
+
+
+static int
+asn1f_fix_simple(arg_t *arg) {
+ int rvalue = 0;
+ int ret;
+
+ ret = asn1f_fix_enum(arg);
+ RET2RVAL(ret, rvalue);
+
+ ret = asn1f_fix_integer(arg);
+ RET2RVAL(ret, rvalue);
+
+ return rvalue;
+}
+
+static int
+asn1f_fix_constructed(arg_t *arg) {
+ int rvalue = 0;
+ int ret;
+
+ switch(arg->expr->expr_type) {
+ case ASN_CONSTR_SEQUENCE:
+ case ASN_CONSTR_SET:
+ case ASN_CONSTR_CHOICE:
+ break;
+ default:
+ return 0;
+ }
+
+ /* Check identifier distinctness */
+ ret = asn1f_check_unique_expr(arg, NULL);
+ RET2RVAL(ret, rvalue);
+
+ /* Fix extensibility */
+ ret = asn1f_fix_constr_ext(arg);
+ RET2RVAL(ret, rvalue);
+
+ /* Fix tagging */
+ ret = asn1f_fix_constr_tag(arg);
+ RET2RVAL(ret, rvalue);
+
+ return rvalue;
+}
+
+static int
+_constraint_value_resolve(arg_t *arg, asn1p_value_t **value) {
+ asn1p_expr_t expr;
+ asn1p_expr_t *tmp_expr;
+ asn1p_module_t *tmp_mod;
+ asn1p_module_t *mod_r = NULL;
+ int rvalue = 0;
+ int ret;
+
+ tmp_expr = asn1f_lookup_symbol(arg, (*value)->value.reference, &mod_r);
+ if(tmp_expr == NULL) {
+ FATAL("Cannot find symbol %s "
+ "used in %s subtype constraint at line %d",
+ asn1f_printable_reference((*value)->value.reference),
+ arg->expr->Identifier, arg->expr->_lineno);
+ assert((*value)->type == ATV_REFERENCED);
+ return -1;
+ }
+
+ memset(&expr, 0, sizeof(expr));
+ expr.meta_type = tmp_expr->meta_type;
+ expr.expr_type = tmp_expr->expr_type;
+ expr.Identifier = tmp_expr->Identifier;
+ expr.value = *value;
+ tmp_expr = arg->expr;
+ tmp_mod = arg->mod;
+ arg->expr = &expr;
+ arg->mod = mod_r;
+ ret = asn1f_fix_dereference_values(arg);
+ RET2RVAL(ret, rvalue);
+ arg->expr = tmp_expr;
+ arg->mod = tmp_mod;
+ assert(expr.value);
+ *value = expr.value;
+
+ return rvalue;
+}
+
+static int
+_resolve_constraints(arg_t *arg, asn1p_constraint_t *ct) {
+ int rvalue = 0;
+ int ret;
+ int el;
+
+ /* Don't touch information object classes */
+ if(ct->type == ACT_CT_WCOMP
+ || ct->type == ACT_CT_WCOMPS
+ || ct->type == ACT_CA_CRC)
+ return 0;
+
+ if(ct->value && ct->value->type == ATV_REFERENCED) {
+ ret = _constraint_value_resolve(arg, &ct->value);
+ RET2RVAL(ret, rvalue);
+ }
+ if(ct->range_start && ct->range_start->type == ATV_REFERENCED) {
+ ret = _constraint_value_resolve(arg, &ct->range_start);
+ RET2RVAL(ret, rvalue);
+ }
+ if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) {
+ ret = _constraint_value_resolve(arg, &ct->range_stop);
+ RET2RVAL(ret, rvalue);
+ }
+
+ for(el = 0; el < ct->el_count; el++) {
+ ret = _resolve_constraints(arg, ct->elements[el]);
+ RET2RVAL(ret, rvalue);
+ }
+
+ return rvalue;
+}
+
+static int
+asn1f_fix_constraints(arg_t *arg) {
+ int rvalue = 0;
+ int ret;
+
+ if(arg->expr->constraints) {
+ ret = _resolve_constraints(arg, arg->expr->constraints);
+ RET2RVAL(ret, rvalue);
+ }
+
+ return rvalue;
+}
+
+/*
+ * Print everything to stderr
+ */
+static void
+_default_error_logger(int _severity, const char *fmt, ...) {
+ va_list ap;
+ char *pfx = "";
+
+ switch(_severity) {
+ case -1: pfx = "DEBUG: "; break;
+ case 0: pfx = "WARNING: "; break;
+ case 1: pfx = "FATAL: "; break;
+ }
+
+ fprintf(stderr, "%s", pfx);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
diff --git a/libasn1fix/asn1fix.h b/libasn1fix/asn1fix.h
new file mode 100644
index 00000000..4847330a
--- /dev/null
+++ b/libasn1fix/asn1fix.h
@@ -0,0 +1,30 @@
+/*
+ * This is the public interface for the processor (fixer) of the ASN.1 tree
+ * produced by the libasn1parser.
+ */
+#ifndef ASN1FIX_H
+#define ASN1FIX_H
+
+#include <asn1parser.h>
+
+/*
+ * Operation flags for the function below.
+ */
+enum asn1f_flags {
+ A1F_NOFLAGS,
+ A1F_DEBUG, /* Print debugging output using (_is_fatal = -1) */
+};
+
+/*
+ * Perform a set of semantics checks, transformations and small fixes
+ * on the given tree.
+ * RETURN VALUES:
+ * -1: Some fatal problems were encountered.
+ * 0: No inconsistencies were found.
+ * 1: Some warnings were issued, but no fatal problems encountered.
+ */
+int asn1f_process(asn1p_t *_asn,
+ enum asn1f_flags,
+ void (*error_log_callback)(int _severity, const char *fmt, ...));
+
+#endif /* ASN1FIX_H */
diff --git a/libasn1fix/asn1fix_bitstring.c b/libasn1fix/asn1fix_bitstring.c
new file mode 100644
index 00000000..0d3961d4
--- /dev/null
+++ b/libasn1fix/asn1fix_bitstring.c
@@ -0,0 +1,230 @@
+#include "asn1fix_internal.h"
+
+int asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype);
+static void asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value);
+static int asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype);
+
+int
+asn1f_fix_bit_string(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ int r_value = 0;
+ int ret;
+
+ if(expr->meta_type == AMT_VALUE) {
+ asn1p_expr_t *ttype;
+
+ DEBUG("%s(%s) for line %d", __func__,
+ expr->Identifier, expr->_lineno);
+
+ ttype = asn1f_find_terminal_type(arg, expr, 0);
+ if(ttype && ttype->expr_type == ASN_BASIC_BIT_STRING) {
+ ret = asn1f_fix_bit_string_value(arg, ttype);
+ RET2RVAL(ret, r_value);
+ }
+ }
+
+ return r_value;
+}
+
+int
+asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype) {
+ asn1p_expr_t *expr = arg->expr;
+ int r_value = 0;
+
+ DEBUG("%s(%s) for line %d", __func__,
+ expr->Identifier, expr->_lineno);
+
+ switch(expr->value->type) {
+ case ATV_UNPARSED:
+ /*
+ * Most definitely we have something like
+ * value BitStringType1 ::= { a, b, c }
+ * which could not be parsed by the LALR parser, mostly
+ * because it requires knowledge about BitStringType1
+ * during the parsing. So, here's a little hack: we create
+ * a buffer containing the full specification of a module,
+ * which contains some pre-defined INTEGER type with the
+ * opaque definition "{ a, b, c }" from the bit string.
+ */
+ if(asn1f_BS_unparsed_convert(arg, expr->value, ttype)) {
+ r_value = -1;
+ break;
+ }
+ /* Fall through: remove trailing zero bits */
+ case ATV_BITVECTOR:
+ asn1f_BS_remove_trailing_zero_bits(expr->value);
+ break;
+ default:
+ break;
+ }
+
+ return r_value;
+}
+
+static void
+asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value) {
+ int lmfb = -1; /* Last meaningful byte position */
+ int bits; /* Number of bits in the BIT STRING value */
+ int b;
+
+ assert(value->type == ATV_BITVECTOR);
+
+ bits = value->value.binary_vector.size_in_bits;
+ /*
+ * Figure out the rightmost meaningful byte.
+ */
+ for(b = 0; b < ((bits + 7) >> 3); b++) {
+ uint8_t uc = value->value.binary_vector.bits[b];
+ if(uc && b > lmfb)
+ lmfb = b;
+ }
+ if(lmfb == -1) {
+ bits = 0;
+ } else {
+ uint8_t uc;
+ uc = value->value.binary_vector.bits[lmfb];
+ bits = (lmfb+1) * 8;
+ /*
+ * Squeeze the bit string width until the rightmost
+ * bit is set.
+ */
+ for(; uc && (uc & 1) == 0; uc >>= 1)
+ bits--;
+ if(uc == 0) {
+ bits = lmfb * 8;
+ }
+ }
+ value->value.binary_vector.size_in_bits = bits;
+}
+
+static int
+asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype) {
+ asn1p_t *asn;
+ asn1p_module_t *mod;
+ asn1p_expr_t *V;
+ asn1p_expr_t *bit;
+ asn1_integer_t aI;
+ uint8_t *bitbuf;
+ int bits;
+ int psize;
+ char *p;
+ int ret;
+ int r_value = 0;
+
+ assert(value->type == ATV_UNPARSED);
+
+ psize = value->value.string.size + 64;
+ p = malloc(psize);
+ if(p == NULL)
+ return -1;
+
+ ret = snprintf(p, psize,
+ "M DEFINITIONS ::=\nBEGIN\n"
+ "V ::= INTEGER %s\n"
+ "END\n",
+ value->value.string.buf
+ );
+ assert(ret < psize);
+ psize = ret;
+
+ asn = asn1p_parse_buffer(p, psize, A1P_NOFLAGS);
+ free(p);
+ if(asn == NULL) {
+ FATAL("Cannot parse BIT STRING value %s "
+ "defined as %s at line %d",
+ arg->expr->Identifier,
+ value->value.string.buf,
+ arg->expr->_lineno
+ );
+ return -1;
+ }
+
+ mod = TQ_FIRST(&(asn->modules));
+ assert(mod);
+ V = TQ_FIRST(&(mod->members));
+ assert(V);
+ assert(strcmp(V->Identifier, "V") == 0);
+ assert(TQ_FIRST(&(V->members)));
+
+ /*
+ * Simple loop just to fetch the maximal bit position
+ * out of the BIT STRING value defined as NamedBitList.
+ */
+ aI = -1;
+ TQ_FOR(bit, &(V->members), next) {
+ asn1p_expr_t *bitdef;
+ bitdef = asn1f_lookup_child(ttype, bit->Identifier);
+ if(bitdef && bitdef->value
+ && bitdef->value->type == ATV_INTEGER) {
+ if(bitdef->value->value.v_integer > aI)
+ aI = bitdef->value->value.v_integer;
+ }
+ }
+
+ if(aI > 1024 * 1024 * 8) { /* One megabyte */
+ FATAL("Unsupportedly large BIT STRING value \"%s\" "
+ "defined at line %d "
+ "(larger than 1MByte)",
+ arg->expr->Identifier,
+ arg->expr->_lineno
+ );
+ asn1p_free(asn);
+ return -1;
+ }
+
+ bits = aI + 1; /* Number of bits is more than a last bit position */
+ bitbuf = calloc(1, 1 + ((bits + 7) / 8));
+ if(bitbuf == NULL) {
+ asn1p_free(asn);
+ return -1;
+ }
+
+ TQ_FOR(bit, &(V->members), next) {
+ asn1p_expr_t *bitdef;
+ int set_bit_pos;
+
+ if(bit->value) {
+ WARNING("Identifier \"%s\" at line %d "
+ "must not have a value",
+ bit->Identifier, bit->_lineno);
+ RET2RVAL(1, r_value);
+ }
+ bitdef = asn1f_lookup_child(ttype, bit->Identifier);
+ if(bitdef == NULL) {
+ FATAL("Identifier \"%s\" at line %d is not defined "
+ "in the \"%s\" type definition at line %d",
+ bit->Identifier,
+ bit->_lineno,
+ ttype->Identifier,
+ ttype->_lineno
+ );
+ RET2RVAL(-1, r_value);
+ continue;
+ }
+ if(bitdef->value == NULL
+ || bitdef->value->type != ATV_INTEGER) {
+ FATAL("Broken identifier "
+ "\"%s\" at line %d "
+ "referenced by \"%s\" at line %d",
+ bitdef->Identifier,
+ bitdef->_lineno,
+ arg->expr->Identifier,
+ arg->expr->_lineno
+ );
+ RET2RVAL(-1, r_value);
+ continue;
+ }
+
+ assert(bitdef->value->value.v_integer < bits);
+ set_bit_pos = bitdef->value->value.v_integer;
+ bitbuf[set_bit_pos>>3] |= 1 << (7-(set_bit_pos % 8));
+ }
+
+ asn1p_free(asn);
+ free(value->value.string.buf);
+ value->type = ATV_BITVECTOR;
+ value->value.binary_vector.bits = bitbuf;
+ value->value.binary_vector.size_in_bits = bits;
+
+ return r_value;
+}
diff --git a/libasn1fix/asn1fix_bitstring.h b/libasn1fix/asn1fix_bitstring.h
new file mode 100644
index 00000000..1230856f
--- /dev/null
+++ b/libasn1fix/asn1fix_bitstring.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_BIT_STRING_H_
+#define _ASN1FIX_BIT_STRING_H_
+
+int asn1f_fix_bit_string(arg_t *);
+
+#endif /* _ASN1FIX_BIT_STRING_H_ */
diff --git a/libasn1fix/asn1fix_class.c b/libasn1fix/asn1fix_class.c
new file mode 100644
index 00000000..c541fd62
--- /dev/null
+++ b/libasn1fix/asn1fix_class.c
@@ -0,0 +1,237 @@
+#include "asn1fix_internal.h"
+
+typedef enum field_category {
+ OFC_INVALID, /* Invalid object field category */
+ OFC_TYPE,
+ OFC_FIXED_TYPE_VALUE,
+ OFC_VARIABLE_TYPE_VALUE,
+ OFC_FIXED_TYPE_VALUE_SET,
+ OFC_VARIABLE_TYPE_VALUE_SET,
+ OFC_INFORMATION_OBJECT,
+ OFC_INFORMATION_OBJECT_SET,
+} field_category_e;
+
+typedef enum object_category {
+ OC_INVALID,
+ OC_OBJECT,
+ OC_OBJECTSET,
+} object_category_e;
+
+static field_category_e asn1f_class_field_category(asn1p_expr_t *ofield);
+static object_category_e asn1f_class_object_category(asn1p_expr_t *expr);
+static asn1p_expr_t *
+asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref);
+
+asn1p_expr_t *
+asn1f_class_access(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **mod_r) {
+ asn1p_expr_t *obj; /* Information Object or Object Set */
+ object_category_e obj_cat; /* Object category */
+ //field_category_e field_cat; /* Field category */
+ asn1p_expr_t *result;
+ asn1p_ref_t tmpref;
+
+ assert(ref->comp_count > 1);
+
+ DEBUG("%s(%s) for line %d", __func__,
+ asn1f_printable_reference(ref),
+ ref->_lineno);
+
+ /*
+ * Fetch the first part of the reference (OBJECT or ObjectSet).
+ * OBJECT.&<something>...
+ * ObjectSet.&<something>...
+ */
+ assert(isupper(ref->components[0].name[0]));
+
+ tmpref = *ref;
+ tmpref.comp_count = 1;
+ obj = asn1f_lookup_symbol(arg, &tmpref, 0);
+ if(obj == NULL) {
+ errno = ESRCH;
+ return NULL;
+ }
+
+ /*
+ * Make sure the symbol lexical property (upper-case, lower-case)
+ * corresponds to the type of the expression returned by
+ * lookup_symbol().
+ */
+ obj_cat = asn1f_class_object_category(obj);
+ switch(obj_cat) {
+ case OC_OBJECT:
+ case OC_OBJECTSET:
+ if(ref->components[0].lex_type
+ == (obj_cat==OC_OBJECT)
+ ? RLT_CAPITALS
+ : RLT_Uppercase)
+ break;
+ /* Fall through */
+ case OC_INVALID:
+ WARNING("Symbol \"%s\" is not compatible "
+ "with referenced expression \"%s\" at line %d",
+ ref->components[0].name,
+ obj->Identifier, obj->_lineno);
+ errno = EPERM;
+ return NULL;
+ }
+
+ /*
+ * Find the specified field within the object.
+ */
+ result = asn1f_class_dot_lookup(arg, obj, ref);
+ if(result == NULL) {
+ return NULL;
+ }
+
+ //field_cat = asn1f_class_field_category(result);
+
+ DEBUG("FILLME: %s", result->Identifier);
+
+ return result;
+}
+
+static object_category_e
+asn1f_class_object_category(asn1p_expr_t *expr) {
+
+ switch(expr->meta_type) {
+ case AMT_OBJECT:
+ return OC_OBJECT;
+ case AMT_OBJECTSET:
+ return OC_OBJECTSET;
+ case AMT_VALUESET:
+ if(expr->expr_type == A1TC_REFERENCE
+ && expr->reference
+ && expr->reference->comp_count == 1
+ && expr->reference->components[0].lex_type == RLT_CAPITALS)
+ {
+ /* FIXME: use find_terminal_type instead! */
+ return OC_OBJECTSET;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return OC_INVALID;
+}
+
+static field_category_e
+asn1f_class_field_category(asn1p_expr_t *ofield) {
+ if(ofield->Identifier[0] != '&') {
+ assert(ofield->Identifier[0] == '&');
+ return OFC_INVALID;
+ }
+
+ if(isupper(ofield->Identifier[1])) {
+ if(ofield->reference) {
+ enum asn1p_ref_lex_type_e lex_type
+ = ofield->reference->components[0].lex_type;
+
+ switch(lex_type) {
+ case RLT_CAPITALS:
+ return OFC_INFORMATION_OBJECT_SET;
+ case RLT_Uppercase:
+ return OFC_FIXED_TYPE_VALUE_SET;
+ case RLT_AmpUppercase:
+ return OFC_VARIABLE_TYPE_VALUE_SET;
+ default:
+ break;
+ }
+ } else {
+ if(ofield->expr_type == A1TC_CLASSFIELD)
+ return OFC_TYPE;
+
+ switch(ofield->meta_type) {
+ case AMT_TYPE:
+ case AMT_TYPEREF:
+ return OFC_FIXED_TYPE_VALUE_SET;
+ default:
+ break;
+ }
+
+ }
+ } else {
+ if(ofield->reference) {
+ enum asn1p_ref_lex_type_e lex_type
+ = ofield->reference->components[0].lex_type;
+
+ switch(lex_type) {
+ case RLT_CAPITALS:
+ return OFC_INFORMATION_OBJECT;
+ case RLT_Uppercase:
+ return OFC_FIXED_TYPE_VALUE;
+ case RLT_AmpUppercase:
+ return OFC_VARIABLE_TYPE_VALUE;
+ default:
+ break;
+ }
+ } else {
+ switch(ofield->meta_type) {
+ case AMT_TYPE:
+ case AMT_TYPEREF:
+ return OFC_FIXED_TYPE_VALUE;
+ default:
+ break;
+ }
+ }
+ }
+
+ return OFC_INVALID;
+}
+
+
+static asn1p_expr_t *
+asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref) {
+ asn1p_expr_t *ofield = NULL; /* Information Object's Field */
+ field_category_e field_cat; /* Field category */
+ int comp;
+
+ assert(ref->comp_count >= 2);
+
+ for(comp = 1 /* sic! */; comp < ref->comp_count; comp++) {
+ int is_last_component = (comp + 1 == ref->comp_count);
+ char *comp_name = ref->components[comp].name;
+
+ ofield = asn1f_lookup_child(obj, comp_name);
+ if(ofield == NULL) {
+ DEBUG("Cannot find field \"%s\" in \"%s\" at line %d",
+ ref->components[1].name,
+ obj->Identifier,
+ obj->_lineno);
+ }
+
+ /*
+ * Compute the category of the field of
+ * the information object class.
+ */
+ field_cat = asn1f_class_field_category(ofield);
+
+ switch(field_cat) {
+ case OFC_INVALID:
+ WARNING("Invalid field category of \"%s\" at line %d",
+ ofield->Identifier, ofield->_lineno);
+ errno = EPERM;
+ return NULL;
+ case OFC_TYPE:
+ case OFC_FIXED_TYPE_VALUE:
+ case OFC_VARIABLE_TYPE_VALUE:
+ case OFC_FIXED_TYPE_VALUE_SET:
+ case OFC_VARIABLE_TYPE_VALUE_SET:
+ if(!is_last_component) {
+ FATAL("Field name component \"%s\" at line %d "
+ "specifies non-dereferenceable thing",
+ comp_name, ref->_lineno);
+ errno = EPERM;
+ return NULL;
+ }
+ break;
+ case OFC_INFORMATION_OBJECT:
+ case OFC_INFORMATION_OBJECT_SET:
+ obj = ofield;
+ break;
+ }
+ }
+
+ assert(ofield);
+ return ofield;
+}
diff --git a/libasn1fix/asn1fix_class.h b/libasn1fix/asn1fix_class.h
new file mode 100644
index 00000000..c849b2b3
--- /dev/null
+++ b/libasn1fix/asn1fix_class.h
@@ -0,0 +1,16 @@
+#ifndef _ASN1FIX_CLASS_H_
+#define _ASN1FIX_CLASS_H_
+
+/*
+ * Fetch the element from the class-related stuff (thing) by its reference.
+ */
+asn1p_expr_t *
+asn1f_class_access(arg_t *, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+/*
+ * Externally accessible version of above function.
+ */
+asn1p_expr_t *asn1f_class_access2(asn1p_t *asn, asn1p_module_t *mod,
+ asn1p_expr_t *expr, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+#endif /* _ASN1FIX_CLASS_H_ */
diff --git a/libasn1fix/asn1fix_compat.c b/libasn1fix/asn1fix_compat.c
new file mode 100644
index 00000000..aef26c0b
--- /dev/null
+++ b/libasn1fix/asn1fix_compat.c
@@ -0,0 +1,132 @@
+#include "asn1fix_internal.h"
+
+static int asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
+
+/*
+ * Check that the expressions given are compatible in their type.
+ * ORDER DOES MATTER! (See .h).
+ */
+int
+asn1f_check_type_compatibility(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+ asn1p_expr_type_e atype, btype;
+
+ atype = a->expr_type;
+ btype = b->expr_type;
+
+ DEBUG("%s(%s:%x@%d, %s:%x@%d)", __func__,
+ a->Identifier, atype, a->_lineno,
+ b->Identifier, btype, b->_lineno);
+
+ /*
+ * Expected terminal type!
+ */
+ assert(atype != A1TC_REFERENCE);
+ assert(btype != A1TC_REFERENCE);
+
+ if(atype != btype) {
+ /*
+ * Limited compatibility.
+ */
+ if((atype == A1TC_UNIVERVAL && btype == ASN_BASIC_INTEGER)
+ || (atype == A1TC_UNIVERVAL && btype == ASN_BASIC_ENUMERATED)
+ )
+ return 0;
+ DEBUG("\t%s and %s are not compatible",
+ a->Identifier, b->Identifier);
+ return -1; /* Fairly obviously */
+ }
+
+ if(a == b)
+ return 0; /* Fairly obviously */
+
+ switch(atype) {
+ case ASN_BASIC_INTEGER:
+ /* All integers are compatible */
+ return 0;
+ case ASN_BASIC_ENUMERATED:
+ /*
+ * Enumerations are not compatible
+ * unless their definitions are the same.
+ */
+ if(asn1f_check_same_children(arg, a, b)) {
+ DEBUG("\tEnumerations are different %s and %s",
+ a->Identifier, b->Identifier);
+ return -1;
+ }
+ return 0;
+ default:
+ /* Compatibility is not defined yet */
+ DEBUG("\tCompatibility rule is not defined for %s and %s",
+ a->Identifier, b->Identifier);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check that the children are exactly same.
+ */
+static int
+asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+ asn1p_expr_t *achild;
+ asn1p_expr_t *bchild;
+
+ achild = TQ_FIRST(&(a->members));
+ bchild = TQ_FIRST(&(b->members));
+
+ while(1) {
+ if(achild->expr_type != bchild->expr_type)
+ return -1;
+
+ if(achild->Identifier && bchild->Identifier) {
+ if(strcmp(achild->Identifier, bchild->Identifier))
+ return -1;
+ } else if(!(!achild->Identifier && !bchild->Identifier)) {
+ return -1;
+ }
+
+ if(achild->value && bchild->value) {
+ if(achild->value->type != bchild->value->type)
+ return -1;
+ switch(achild->value->type) {
+ case ATV_INTEGER:
+ if(achild->value->value.v_integer
+ != bchild->value->value.v_integer)
+ return -1;
+ break;
+ case ATV_REFERENCED:
+ default:
+ DEBUG("Value %s at lines %d and "
+ "%d cannot be used in "
+ "semantical equality check",
+ asn1f_printable_value(achild->value),
+ achild->value->value.reference->_lineno,
+ bchild->value->value.reference->_lineno
+ );
+ return -1;
+ }
+ } else if(!(!achild->value && !bchild->value)) {
+ /* One of values is defined, and another is not */
+ return -1;
+ }
+
+ achild = TQ_NEXT(achild, next);
+ bchild = TQ_NEXT(bchild, next);
+
+ if(achild && bchild)
+ continue;
+ else if(!achild && !bchild)
+ break;
+ else
+ return -1;
+ }
+
+ DEBUG("\t%s:%x@%d and %s:%x@%d are semantically equivalent",
+ a->Identifier, a->expr_type, a->_lineno,
+ b->Identifier, b->expr_type, b->_lineno);
+
+ return 0;
+}
+
+
diff --git a/libasn1fix/asn1fix_compat.h b/libasn1fix/asn1fix_compat.h
new file mode 100644
index 00000000..429e7dd8
--- /dev/null
+++ b/libasn1fix/asn1fix_compat.h
@@ -0,0 +1,14 @@
+#ifndef _ASN1FIX_COMPAT_H_
+#define _ASN1FIX_COMPAT_H_
+
+/*
+ * Check that the expressions given are compatible in their type.
+ * ORDER DOES MATTER!
+ * The compatibility is being checked as if the value of b were used
+ * to assign it to type a.
+ */
+int asn1f_check_type_compatibility(arg_t *arg,
+ asn1p_expr_t *a,
+ asn1p_expr_t *b);
+
+#endif /* _ASN1FIX_COMPAT_H_ */
diff --git a/libasn1fix/asn1fix_constr.c b/libasn1fix/asn1fix_constr.c
new file mode 100644
index 00000000..2aa79827
--- /dev/null
+++ b/libasn1fix/asn1fix_constr.c
@@ -0,0 +1,364 @@
+#include "asn1fix_internal.h"
+
+static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v);
+static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
+
+
+int
+asn1f_fix_constr_ext(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *v;
+ TQ_HEAD(asn1p_expr_t) root_list;
+ TQ_HEAD(asn1p_expr_t) ext_list;
+ TQ_HEAD(asn1p_expr_t) *cur_list;
+ int r_value = 0;
+ int ext_count = 0;
+
+ switch(expr->expr_type) {
+ case ASN_CONSTR_SEQUENCE:
+ case ASN_CONSTR_SET:
+ case ASN_CONSTR_CHOICE:
+ break;
+ default:
+ return 0;
+ }
+
+ DEBUG("%s(%s) for line %d", __func__,
+ expr->Identifier, expr->_lineno);
+
+ TQ_INIT(&root_list);
+ TQ_INIT(&ext_list);
+ cur_list = (void *)&root_list;
+
+ while((v = TQ_REMOVE(&(expr->members), next))) {
+ if(v->expr_type == A1TC_EXTENSIBLE) {
+ ext_count++;
+ switch(ext_count) {
+ case 1: cur_list = (void *)&ext_list; break;
+ case 2:
+ cur_list = (void *)&root_list;
+ if(v->value) {
+ FATAL("Optional extension marker "
+ "must not contain "
+ "an exception mark "
+ "at line %d", v->_lineno);
+ r_value = -1;
+ }
+ asn1p_expr_free(v);
+ continue;
+ case 3:
+ FATAL("Third extension marker "
+ "is not allowed at line %d", v->_lineno);
+ default:
+ r_value = -1;
+ }
+ }
+
+ TQ_ADD(cur_list, v, next);
+ }
+
+ /*
+ * Copy the root list and extension list back into the main list.
+ */
+ TQ_HEAD_COPY(&(expr->members), &root_list);
+ while((v = TQ_REMOVE(&ext_list, next)))
+ TQ_ADD(&(expr->members), v, next);
+
+ if(arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED
+ && ext_count < 1) {
+ v = asn1p_expr_new(0);
+ if(v) {
+ v->Identifier = strdup("...");
+ v->expr_type = A1TC_EXTENSIBLE;
+ v->meta_type = AMT_TYPE;
+ if(v->Identifier == NULL) {
+ asn1p_expr_free(v);
+ r_value = -1;
+ } else {
+ TQ_ADD(&(expr->members), v, next);
+ }
+ } else {
+ r_value = -1;
+ }
+ }
+
+ return r_value;
+}
+
+
+int
+asn1f_fix_constr_tag(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *v;
+ int fl_impl_tags = 0;
+ int fl_auto_tags = 0;
+ int root_tagged = 0; /* The root component is manually tagged */
+ int ext_tagged = 0; /* The extensions are manually tagged */
+ int component_number = 0;
+ int r_value = 0;
+
+ switch(expr->expr_type) {
+ case ASN_CONSTR_SEQUENCE:
+ case ASN_CONSTR_SET:
+ case ASN_CONSTR_CHOICE:
+ break;
+ default:
+ return 0;
+ }
+
+ fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS);
+ fl_auto_tags = (arg->mod->module_flags & MSF_AUTOMATIC_TAGS);
+
+ DEBUG("%s(%s) {%d, %d} for line %d", __func__,
+ expr->Identifier, fl_impl_tags, fl_auto_tags, expr->_lineno);
+
+ TQ_FOR(v, &(expr->members), next) {
+ int must_explicit = 0;
+
+ if(v->expr_type == A1TC_EXTENSIBLE) {
+ component_number++;
+ continue;
+ }
+
+ if(v->tag.tag_class == TC_NOCLASS) {
+ continue;
+ } else {
+ switch(component_number) {
+ case 0: case 2:
+ root_tagged = 1; break;
+ default:
+ ext_tagged = 1; break;
+ }
+ }
+
+ must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
+
+ if(fl_impl_tags) {
+ if(v->tag.tag_mode != TM_EXPLICIT) {
+ if(must_explicit)
+ v->tag.tag_mode = TM_EXPLICIT;
+ else
+ v->tag.tag_mode = TM_IMPLICIT;
+ }
+ } else {
+ if(v->tag.tag_mode == TM_DEFAULT) {
+ v->tag.tag_mode = TM_EXPLICIT;
+ }
+ }
+
+ /*
+ * Perform a final sanity check.
+ */
+ if(must_explicit) {
+ if(v->tag.tag_mode == TM_IMPLICIT) {
+ FATAL("%s tagged in IMPLICIT mode "
+ "but must be EXPLICIT at line %d",
+ v->Identifier, v->_lineno);
+ r_value = -1;
+ } else {
+ v->tag.tag_mode = TM_EXPLICIT;
+ }
+ }
+ }
+
+ if(ext_tagged && !root_tagged) {
+ FATAL("In %s at line %d: "
+ "extensions are tagged "
+ "but root components are not",
+ expr->Identifier, expr->_lineno);
+ r_value = -1;
+ } else if(!root_tagged && !ext_tagged && fl_auto_tags) {
+ expr->auto_tags_OK = 1;
+ }
+
+ return r_value;
+}
+
+int
+asn1f_fix_constr_autotag(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *v;
+ asn1_integer_t tag_value = 0;
+ int r_value = 0;
+
+ switch(expr->expr_type) {
+ case ASN_CONSTR_SEQUENCE:
+ case ASN_CONSTR_SET:
+ case ASN_CONSTR_CHOICE:
+ if(expr->auto_tags_OK)
+ break;
+ /* Automatic tagging is not applicable */
+ /* Fall through */
+ default:
+ return 0;
+ }
+
+ DEBUG("%s(%s) for line %d", __func__,
+ expr->Identifier, expr->_lineno);
+
+ TQ_FOR(v, &(expr->members), next) {
+ int must_explicit;
+
+ if(v->expr_type == A1TC_EXTENSIBLE)
+ break;
+
+ assert(v->tag.tag_class == TC_NOCLASS);
+
+ must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
+
+ v->tag.tag_class = TC_CONTEXT_SPECIFIC;
+ v->tag.tag_mode = must_explicit ? TM_EXPLICIT : TM_IMPLICIT;
+ v->tag.tag_value = tag_value++;
+ }
+
+ return r_value;
+}
+
+/*
+ * Check that tags are distinct.
+ */
+int
+asn1f_check_constr_tags_distinct(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *v;
+ int r_value = 0;
+
+ switch(expr->expr_type) {
+ case ASN_CONSTR_SEQUENCE:
+ case ASN_CONSTR_SET:
+ case ASN_CONSTR_CHOICE:
+ break;
+ default:
+ return 0;
+ }
+
+ TQ_FOR(v, &(expr->members), next) {
+ /*
+ * In every series of non-mandatory components,
+ * the tags must be distinct from each other AND the
+ * tag of the following mandatory component.
+ * For SET and CHOICE treat everything as a big set of
+ * non-mandatory components.
+ */
+ if(expr->expr_type != ASN_CONSTR_SEQUENCE || v->marker) {
+ asn1p_expr_t *nv;
+ for(nv = v; (nv = TQ_NEXT(nv, next));) {
+ if(_asn1f_compare_tags(arg, v, nv))
+ r_value = -1;
+ if(expr->expr_type == ASN_CONSTR_SEQUENCE
+ && !nv->marker) break;
+ }
+ }
+ }
+
+ return r_value;
+}
+
+static int
+_asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) {
+ asn1p_expr_t *reft;
+
+ reft = asn1f_find_terminal_type(arg, v, 0);
+ if(reft) {
+ switch(reft->expr_type) {
+ case ASN_CONSTR_CHOICE:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check that the tags are distinct.
+ */
+static int
+_asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+ struct asn1p_type_tag_s ta, tb;
+ int ra, rb;
+ int ret;
+
+ ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta);
+ rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb);
+
+ /*
+ * If both tags are explicitly or implicitly given, use them.
+ */
+ if(ra == 0 && rb == 0) {
+ /*
+ * Simple case: fetched both tags.
+ */
+ if(ta.tag_value == tb.tag_value
+ && ta.tag_class == tb.tag_class) {
+ char *p = (a->expr_type == A1TC_EXTENSIBLE)
+ ?"potentially ":"";
+ FATAL("Component \"%s\" at line %d %shas the same tag "
+ "with component \"%s\" at line %d",
+ a->Identifier,
+ a->_lineno,
+ p,
+ b->Identifier,
+ b->_lineno
+ );
+ return -1;
+ } else {
+ /* Tags are distinct */
+ return 0;
+ }
+ }
+
+ /**********************************************************
+ * Now we must perform some very funny recursion to check
+ * multiple components of CHOICE type, etc.
+ */
+
+ DEBUG("Comparing tags %s:%x <-> %s:%x",
+ a->Identifier, a->expr_type,
+ b->Identifier, b->expr_type);
+
+ if(a->meta_type == AMT_TYPEREF) {
+ asn1p_module_t *mod;
+
+ DEBUG(" %s is a type reference", a->Identifier);
+
+ a = asn1f_lookup_symbol(arg, a->reference, &mod);
+ if(!a) return 0; /* Already FATAL()'ed somewhere else */
+ WITH_MODULE(mod, ret = _asn1f_compare_tags(arg, a, b));
+ return ret;
+ }
+
+ if(a->expr_type == ASN_CONSTR_CHOICE) {
+ asn1p_expr_t *v;
+
+ DEBUG(" %s is a choice type (%d)", a->Identifier, a->_mark);
+
+ /*
+ * Iterate over members of CHOICE.
+ */
+ //if(a->_mark & TM_RECURSION) return 0;
+ TQ_FOR(v, &(a->members), next) {
+ //a->_mark |= TM_RECURSION;
+ ret = _asn1f_compare_tags(arg, v, b);
+ //a->_mark &= ~TM_RECURSION;
+ if(ret) return ret;
+ }
+ return 0;
+ }
+
+ if(b->expr_type == ASN_CONSTR_CHOICE) {
+ return _asn1f_compare_tags(arg, b, a);
+ }
+
+ if(a->_mark & TM_RECURSION) return 0;
+ if(b->_mark & TM_RECURSION) return 0;
+ a->_mark |= TM_RECURSION;
+ b->_mark |= TM_RECURSION;
+ ret = _asn1f_compare_tags(arg, b, a);
+ a->_mark &= ~TM_RECURSION;
+ b->_mark &= ~TM_RECURSION;
+
+ return ret;
+}
+
diff --git a/libasn1fix/asn1fix_constr.h b/libasn1fix/asn1fix_constr.h
new file mode 100644
index 00000000..aeb05c0a
--- /dev/null
+++ b/libasn1fix/asn1fix_constr.h
@@ -0,0 +1,24 @@
+#ifndef _ASN1FIX_CONSTRUCTED_H_
+#define _ASN1FIX_CONSTRUCTED_H_
+
+/*
+ * Fix extensions in constructed types.
+ */
+int asn1f_fix_constr_ext(arg_t *);
+
+/*
+ * Fix tagging in constructed types.
+ */
+int asn1f_fix_constr_tag(arg_t *);
+
+/*
+ * Check distinctive tagging in constructed types.
+ */
+int asn1f_check_constr_tags_distinct(arg_t *);
+
+/*
+ * Perform automatic tagging.
+ */
+int asn1f_fix_constr_autotag(arg_t *);
+
+#endif /* _ASN1FIX_CONSTRUCTED_H_ */
diff --git a/libasn1fix/asn1fix_cstring.c b/libasn1fix/asn1fix_cstring.c
new file mode 100644
index 00000000..b8a38833
--- /dev/null
+++ b/libasn1fix/asn1fix_cstring.c
@@ -0,0 +1,73 @@
+#include "asn1fix_internal.h"
+
+struct _cstring_pattern {
+ char *start;
+ int length;
+};
+static int _asn1f_cstring_find_line_pattern(char *s, struct _cstring_pattern *);
+
+int
+asn1f_fix_cstring(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ int r_value = 0;
+
+ if(expr->value && expr->value->type == ATV_STRING) {
+ struct _cstring_pattern cp;
+ char *buf = expr->value->value.string.buf;
+ int buflen = expr->value->value.string.size;
+ int start = 0;
+
+ DEBUG("%s(%s) for line %d", __func__,
+ expr->Identifier, expr->_lineno);
+
+ while(_asn1f_cstring_find_line_pattern(buf + start, &cp)) {
+ assert(cp.length);
+ memmove(cp.start, cp.start + cp.length,
+ buflen - ((cp.start + cp.length) - buf));
+ buflen -= cp.length;
+ start = cp.start - buf;
+ buf[buflen] = '\0';
+ }
+ }
+
+ return r_value;
+}
+
+/*
+ * If a string has a newline, the tabulation and spaces before and
+ * after it must be eliminated.
+ */
+static int
+_asn1f_cstring_find_line_pattern(char *s, struct _cstring_pattern *cp) {
+ int newline_found = 0;
+
+ cp->start = NULL;
+
+ for(;;s++) {
+ switch(*s) {
+ case '\r': case '\n':
+ newline_found = 1;
+ /* Fall through */
+ case ' ': case '\t':
+ if(cp->start == NULL)
+ cp->start = s;
+ continue;
+ case '\0':
+ default:
+ if(newline_found) {
+ cp->length = s - cp->start;
+ return 1;
+ }
+
+ cp->start = NULL;
+ if(*s == '\0')
+ break;
+ continue;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
diff --git a/libasn1fix/asn1fix_cstring.h b/libasn1fix/asn1fix_cstring.h
new file mode 100644
index 00000000..bd647abe
--- /dev/null
+++ b/libasn1fix/asn1fix_cstring.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_CSTRING_H_
+#define _ASN1FIX_CSTRING_H_
+
+int asn1f_fix_cstring(arg_t *);
+
+#endif /* _ASN1FIX_CSTRING_H_ */
diff --git a/libasn1fix/asn1fix_dereft.c b/libasn1fix/asn1fix_dereft.c
new file mode 100644
index 00000000..f0ec9a6c
--- /dev/null
+++ b/libasn1fix/asn1fix_dereft.c
@@ -0,0 +1,68 @@
+#include "asn1fix_internal.h"
+
+int
+asn1f_fix_dereference_types(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *type_expr;
+ int r_value = 0;
+
+ if(expr->expr_type == A1TC_PARAMETRIZED)
+ return asn1f_fix_parametrized_assignment(arg);
+
+ if(expr->expr_type != A1TC_REFERENCE
+ || expr->meta_type != AMT_TYPEREF) {
+ //assert(expr->reference == 0);
+ return 0; /* Just ignore it */
+ }
+
+ DEBUG("%s(\"%s\":%x ::= \"%s\") for line %d",
+ __func__, expr->Identifier, expr->expr_type,
+ asn1f_printable_value(expr->value),
+ expr->_lineno);
+
+ assert(TQ_FIRST(&(expr->members)) == 0);
+ assert(expr->reference);
+
+ /*
+ * Follow the reference.
+ */
+ type_expr = asn1f_find_terminal_type(arg, expr, 0);
+ if(type_expr == NULL) {
+ FATAL("Unknown type \"%s\" referenced by \"%s\" at line %d",
+ asn1f_printable_reference(expr->reference),
+ expr->Identifier, expr->_lineno);
+ return -1;
+ }
+
+ /*
+ * Copying members of the source expression
+ * into the current expression.
+ */
+ if(0) {
+ asn1p_expr_t *tmp_clone;
+
+ tmp_clone = asn1p_expr_clone(type_expr);
+ if(tmp_clone == NULL) {
+ FATAL("Could not clone \"%s\" at line %d",
+ type_expr->Identifier, type_expr->_lineno);
+ return -1;
+ }
+
+ /*
+ * Replace the referenced type with its definition.
+ */
+ DEBUG("\tChanging type of \"%s\":%x to %x for line %d",
+ expr->Identifier,
+ expr->expr_type,
+ type_expr->expr_type,
+ expr->_lineno
+ );
+ expr->expr_type = type_expr->expr_type;
+ expr->members = tmp_clone->members;
+ memset(&tmp_clone->members, 0, sizeof(tmp_clone->members));
+ asn1p_expr_free(tmp_clone);
+ }
+
+ return r_value;
+}
+
diff --git a/libasn1fix/asn1fix_dereft.h b/libasn1fix/asn1fix_dereft.h
new file mode 100644
index 00000000..bee8151a
--- /dev/null
+++ b/libasn1fix/asn1fix_dereft.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_DEREFT_H_
+#define _ASN1FIX_DEREFT_H_
+
+int asn1f_fix_dereference_types(arg_t *);
+
+#endif /* _ASN1FIX_DEREFT_H_ */
diff --git a/libasn1fix/asn1fix_derefv.c b/libasn1fix/asn1fix_derefv.c
new file mode 100644
index 00000000..7be9d6d2
--- /dev/null
+++ b/libasn1fix/asn1fix_derefv.c
@@ -0,0 +1,56 @@
+#include "asn1fix_internal.h"
+
+/*
+ * Dereference DefinedValues:
+ */
+int
+asn1f_fix_dereference_values(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ int r_value = 0;
+
+ if(expr->meta_type != AMT_VALUE)
+ return 0; /* Just ignore it */
+
+ if(expr->value == NULL)
+ return 0; /* Just ignore it */
+
+ if(expr->value && expr->value->type != ATV_REFERENCED)
+ return 0; /* Not a reference */
+
+ DEBUG("%s(%s %x ::= %s) for line %d", __func__,
+ expr->Identifier, expr->expr_type,
+ asn1f_printable_value(expr->value), expr->_lineno);
+
+ /*
+ * If this integer has a value, check that this value
+ * is an integer. If it is a reference, resolve it.
+ */
+ if(expr->value) {
+
+ if(asn1f_value_resolve(arg, expr)) {
+ /* This function will emit messages */
+ r_value = -1;
+ }
+
+ if(expr->value->type != ATV_INTEGER) {
+ FATAL(
+ "INTEGER value %s at line %d: "
+ "Incompatible value specified: %s",
+ expr->Identifier,
+ expr->_lineno,
+ asn1f_printable_value(expr->value)
+ );
+ r_value = -1;
+ }
+ } else {
+ FATAL("Value of \"%s\" at line %d: "
+ "Incompatible value specified",
+ expr->Identifier,
+ expr->_lineno
+ );
+ r_value = -1;
+ }
+
+ return r_value;
+}
+
diff --git a/libasn1fix/asn1fix_derefv.h b/libasn1fix/asn1fix_derefv.h
new file mode 100644
index 00000000..93153851
--- /dev/null
+++ b/libasn1fix/asn1fix_derefv.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_DEREFV_H_
+#define _ASN1FIX_DEREFV_H_
+
+int asn1f_fix_dereference_values(arg_t *);
+
+#endif /* _ASN1FIX_DEREFV_H_ */
diff --git a/libasn1fix/asn1fix_enum.c b/libasn1fix/asn1fix_enum.c
new file mode 100644
index 00000000..8a90a435
--- /dev/null
+++ b/libasn1fix/asn1fix_enum.c
@@ -0,0 +1,136 @@
+#include "asn1fix_internal.h"
+
+/*
+ * Check the validity of an enumeration.
+ */
+int
+asn1f_fix_enum(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *ev;
+ asn1_integer_t max_value = -1;
+ int rvalue = 0;
+ asn1p_expr_t *ext_marker = NULL; /* "..." position */
+ int ret;
+
+ if(expr->expr_type != ASN_BASIC_ENUMERATED)
+ return 0; /* Just ignore it */
+
+ DEBUG("%s(%s)", __func__, expr->Identifier);
+
+ /*
+ * 1. Scan the enumeration values in search for inconsistencies.
+ */
+ TQ_FOR(ev, &(expr->members), next) {
+ asn1_integer_t eval;
+
+ if(ev->value)
+ DEBUG("\tItem %s(%s)", ev->Identifier,
+ asn1f_printable_value(ev->value));
+ else
+ DEBUG("\tItem %s", ev->Identifier);
+
+ /*
+ * 1.1 Found an extension mark "...", check correctness.
+ */
+ if(ev->expr_type == A1TC_EXTENSIBLE) {
+ if(ext_marker) {
+ arg->eh(1,
+ "Enumeration %s at line %d: "
+ "Second extension marker is not allowed",
+ expr->Identifier,
+ ev->_lineno);
+ rvalue = -1;
+ } else {
+ /*
+ * Remember the marker's position.
+ */
+ ext_marker = ev;
+ }
+ continue;
+ } else if(ev->Identifier == NULL
+ || ev->expr_type != A1TC_UNIVERVAL) {
+ FATAL(
+ "Enumeration %s at line %d: "
+ "Unsupported enumeration element %s",
+ expr->Identifier,
+ ev->_lineno,
+ ev->Identifier?ev->Identifier:"<anonymous>");
+ rvalue = -1;
+ continue;
+ }
+
+ /*
+ * 1.2 Compute the value of the enumeration element.
+ */
+ if(ev->value) {
+ switch(ev->value->type) {
+ case ATV_INTEGER:
+ eval = ev->value->value.v_integer;
+ break;
+ case ATV_REFERENCED:
+ FATAL("HERE HERE HERE", 1);
+ rvalue = -1;
+ continue;
+ break;
+ default:
+ FATAL("ENUMERATED type %s at line %d "
+ "contain element %s(%s) at line %d",
+ expr->Identifier, expr->_lineno,
+ ev->Identifier,
+ asn1f_printable_value(ev->value),
+ ev->_lineno);
+ rvalue = -1;
+ continue;
+ }
+ } else {
+ eval = max_value + 1;
+ ev->value = asn1p_value_fromint(eval);
+ if(ev->value == NULL) {
+ rvalue = -1;
+ continue;
+ }
+ }
+
+ /*
+ * 1.3 Check the applicability of this value.
+ */
+ if(eval <= max_value) {
+ if(ext_marker) {
+ /*
+ * Enumeration is allowed to be unordered
+ * before the first marker.
+ */
+ FATAL(
+ "Enumeration %s at line %d: "
+ "Explicit value \"%s(%lld)\" "
+ "is not greater "
+ "than previous values (max %lld)",
+ expr->Identifier,
+ ev->_lineno,
+ ev->Identifier,
+ eval,
+ max_value);
+ rvalue = -1;
+ }
+ } else if(eval > max_value) {
+ max_value = eval;
+ }
+
+ /*
+ * 1.4 Check that all identifiers before the current one
+ * differs from it.
+ */
+ ret = asn1f_check_unique_expr_child(arg, ev, NULL);
+ RET2RVAL(ret, rvalue);
+ }
+
+
+ /*
+ * 2. Reorder the first half (before optional "...") of the
+ * identifiers alphabetically.
+ */
+ // TODO
+
+ return rvalue;
+}
+
diff --git a/libasn1fix/asn1fix_enum.h b/libasn1fix/asn1fix_enum.h
new file mode 100644
index 00000000..14c6fb52
--- /dev/null
+++ b/libasn1fix/asn1fix_enum.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_ENUM_H_
+#define _ASN1FIX_ENUM_H_
+
+int asn1f_fix_enum(arg_t *); /* Enumeration ::= ENUMERATED { a(1), b(2) } */
+
+#endif /* _ASN1FIX_ENUM_H_ */
diff --git a/libasn1fix/asn1fix_export.c b/libasn1fix/asn1fix_export.c
new file mode 100644
index 00000000..d6bb37b4
--- /dev/null
+++ b/libasn1fix/asn1fix_export.c
@@ -0,0 +1,48 @@
+#include "asn1fix_internal.h"
+#include "asn1fix_export.h"
+
+asn1p_expr_t *
+asn1f_lookup_symbol_ex(
+ asn1p_t *asn,
+ asn1p_module_t **module_rw,
+ asn1p_expr_t *expr,
+ asn1p_ref_t *ref) {
+ arg_t arg;
+
+ memset(&arg, 0, sizeof(arg));
+
+ arg.asn = asn;
+ arg.mod = *module_rw;
+ arg.expr = expr;
+
+ return asn1f_lookup_symbol(&arg, ref, module_rw);
+}
+
+asn1p_expr_t *
+asn1f_class_access_ex(asn1p_t *asn,
+ asn1p_module_t *mod,
+ asn1p_expr_t *expr,
+ asn1p_ref_t *ref,
+ asn1p_module_t **mod_r) {
+ static arg_t arg;
+
+ arg.asn = asn;
+ arg.mod = mod;
+ arg.expr = expr;
+
+ return asn1f_class_access(&arg, ref, mod_r);
+}
+
+asn1p_expr_t *
+asn1f_find_terminal_type_ex(asn1p_t *asn,
+ asn1p_module_t *mod,
+ asn1p_expr_t *expr,
+ asn1p_module_t **mod_r) {
+ static arg_t arg;
+
+ arg.asn = asn;
+ arg.mod = mod;
+ arg.expr = expr;
+
+ return asn1f_find_terminal_type(&arg, expr, mod_r);
+}
diff --git a/libasn1fix/asn1fix_export.h b/libasn1fix/asn1fix_export.h
new file mode 100644
index 00000000..2ade0c9a
--- /dev/null
+++ b/libasn1fix/asn1fix_export.h
@@ -0,0 +1,32 @@
+/*
+ * This header exports fixer procedures that are common enough to be used
+ * in other modules.
+ */
+#ifndef _ASN1FIX_EXPORT_H_
+#define _ASN1FIX_EXPORT_H_
+
+#include <asn1fix_tags.h>
+
+/*
+ * Exportable version of an asn1f_lookup_symbol().
+ */
+asn1p_expr_t *asn1f_lookup_symbol_ex(
+ asn1p_t *asn,
+ asn1p_module_t **module_rw,
+ asn1p_expr_t *expr,
+ asn1p_ref_t *ref);
+
+/*
+ * Exportable version of an asn1f_class_access().
+ */
+asn1p_expr_t *asn1f_class_access_ex(asn1p_t *asn, asn1p_module_t *mod,
+ asn1p_expr_t *expr, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+/*
+ * Exportable version of asn1f_find_terminal_type().
+ */
+asn1p_expr_t *asn1f_find_terminal_type_ex(asn1p_t *asn, asn1p_module_t *mod,
+ asn1p_expr_t *tc, asn1p_module_t **opt_module_r);
+
+#endif /* _ASN1FIX_EXPORT_H_ */
+
diff --git a/libasn1fix/asn1fix_integer.c b/libasn1fix/asn1fix_integer.c
new file mode 100644
index 00000000..514ab70e
--- /dev/null
+++ b/libasn1fix/asn1fix_integer.c
@@ -0,0 +1,161 @@
+#include "asn1fix_internal.h"
+
+static int _compare_value(asn1p_expr_t *expr1, asn1p_expr_t *expr2) {
+ if(expr2->value->type == ATV_INTEGER
+ && expr1->value->type == ATV_INTEGER) {
+ return expr2->value->value.v_integer
+ - expr1->value->value.v_integer;
+ } else {
+ return -1;
+ }
+}
+
+/*
+ * Check the validity of an INTEGER type.
+ */
+int
+asn1f_fix_integer(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *iv;
+ int rvalue = 0;
+ int ret;
+
+ if(expr->expr_type != ASN_BASIC_INTEGER)
+ return 0; /* Just ignore it */
+
+ DEBUG("%s(\"%s\", %x) for line %d", __func__,
+ expr->Identifier, expr->expr_type, expr->_lineno);
+
+ /*
+ * Scan the integer values in search for inconsistencies.
+ */
+ TQ_FOR(iv, &(expr->members), next) {
+
+ DEBUG("\tItem %s(%s)", iv->Identifier,
+ asn1f_printable_value(iv->value));
+
+ /*
+ * Found "...", check correctness.
+ */
+ if(iv->expr_type == A1TC_EXTENSIBLE) {
+ arg->eh(1,
+ "INTEGER %s at line %d: "
+ "Extension marker is not allowed",
+ expr->Identifier,
+ iv->_lineno
+ );
+ rvalue = -1;
+ continue;
+ }
+
+ if(iv->Identifier == NULL
+ || iv->expr_type != A1TC_UNIVERVAL) {
+ arg->eh(1,
+ "INTEGER %s at line %d: "
+ "Unsupported enumeration element %s",
+ expr->Identifier,
+ iv->_lineno,
+ iv->Identifier?iv->Identifier:"<Anonymous>"
+ );
+ rvalue = -1;
+ continue;
+ }
+
+ if(iv->value == NULL) {
+ arg->eh(1,
+ "INTEGER %s at line %d: "
+ "Value for the identifier %s "
+ "must be set explicitly",
+ expr->Identifier,
+ iv->_lineno,
+ iv->Identifier
+ );
+ rvalue = -1;
+ continue;
+ } else if(iv->value->type == ATV_REFERENCED) {
+ /*
+ * Resolve the value, once and for all.
+ */
+ if(asn1f_value_resolve(arg, iv)) {
+ /* This function will emit messages */
+ rvalue = -1;
+ continue;
+ }
+ }
+
+ if(iv->value->type != ATV_INTEGER) {
+ arg->eh(1,
+ "INTEGER %s at line %d: "
+ "Value for the identifier %s "
+ "is not compatible with INTEGER type",
+ expr->Identifier,
+ iv->_lineno);
+ rvalue = -1;
+ continue;
+ }
+
+ /*
+ * Check that all identifiers are distinct.
+ */
+ ret = asn1f_check_unique_expr_child(arg, iv, NULL);
+ RET2RVAL(ret, rvalue);
+ /*
+ * Check that all values are distinct.
+ */
+ ret = asn1f_check_unique_expr_child(arg, iv, _compare_value);
+ RET2RVAL(ret, rvalue);
+ }
+
+
+ return rvalue;
+}
+
+static int
+_asn1f_make_sure_type_is(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_type_e type) {
+ asn1p_module_t *mod = NULL;
+ asn1p_expr_t *next_expr;
+ int expr_type;
+ int ret;
+
+ expr_type = expr->expr_type;
+
+ /*
+ * Here we're trying to make sure that the type of the given
+ * expression is really what is expected.
+ * This is ensured in two ways.
+ * First, if the immediate type matches the provided one,
+ * this is a clear hit.
+ */
+ if(expr_type == type)
+ return 0;
+
+ /*
+ * Otherwise, it must be either a reference or a different type.
+ */
+ if(expr_type != A1TC_REFERENCE) {
+ errno = EPERM;
+ return -1;
+ }
+
+ assert(expr_type == A1TC_REFERENCE);
+ assert(expr->reference);
+
+ /*
+ * Then, it is a reference. For a reference, try to resolve type
+ * and try again.
+ */
+ next_expr = asn1f_lookup_symbol(arg, expr->reference, &mod);
+ if(next_expr == NULL) {
+ errno = ESRCH;
+ return -1;
+ }
+
+ /*
+ * If symbol is here, recursively check that it conforms to the type.
+ */
+ WITH_MODULE(mod, ret = _asn1f_make_sure_type_is(arg, next_expr, type));
+
+ return ret;
+}
+
+
diff --git a/libasn1fix/asn1fix_integer.h b/libasn1fix/asn1fix_integer.h
new file mode 100644
index 00000000..d306fc03
--- /dev/null
+++ b/libasn1fix/asn1fix_integer.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_INTEGER_H_
+#define _ASN1FIX_INTEGER_H_
+
+int asn1f_fix_integer(arg_t *); /* Type1 ::= INTEGER { a(1), b(2) } */
+
+#endif /* _ASN1FIX_INTEGER_H_ */
diff --git a/libasn1fix/asn1fix_internal.h b/libasn1fix/asn1fix_internal.h
new file mode 100644
index 00000000..ff3b4e96
--- /dev/null
+++ b/libasn1fix/asn1fix_internal.h
@@ -0,0 +1,106 @@
+#ifndef _ASN1FIX_INTERNAL_H_
+#define _ASN1FIX_INTERNAL_H_
+
+/*
+ * System headers required in various modules.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> /* isupper() */
+#include <errno.h>
+#include <assert.h>
+
+#include <asn1parser.h> /* Our lovely ASN.1 parser module */
+
+/*
+ * A definition of a function that will log error messages.
+ */
+typedef void (*error_logger_f)(int _is_fatal, const char *fmt, ...);
+
+/*
+ * Universal argument.
+ */
+typedef struct arg_s {
+ asn1p_t *asn;
+ asn1p_module_t *mod;
+ asn1p_expr_t *expr;
+ error_logger_f eh;
+ error_logger_f debug;
+ void *key; /* The next level key */
+} arg_t;
+
+/*
+ * Functions performing normalization of various types.
+ */
+#include "asn1fix_misc.h" /* Support functions */
+#include "asn1fix_value.h" /* Value processing */
+#include "asn1fix_cstring.h" /* Fix cstring values */
+#include "asn1fix_compat.h" /* Data compatibility */
+#include "asn1fix_constr.h" /* Constructed types */
+#include "asn1fix_class.h" /* CLASS support */
+#include "asn1fix_param.h" /* Parametrization */
+#include "asn1fix_retrieve.h" /* Data retrieval */
+#include "asn1fix_enum.h" /* Process ENUMERATED */
+#include "asn1fix_integer.h" /* Process INTEGER */
+#include "asn1fix_bitstring.h" /* Process BIT STRING */
+#include "asn1fix_dereft.h" /* Dereference types */
+#include "asn1fix_derefv.h" /* Dereference values */
+#include "asn1fix_tags.h" /* Tags-related stuff */
+
+
+/*
+ * Merge the return value of the called function with the already
+ * partially computed return value of the current function.
+ */
+#define RET2RVAL(ret,rv) do { \
+ int __ret = ret; \
+ switch(__ret) { \
+ case 0: break; \
+ case 1: if(rv) break; \
+ case -1: rv = __ret; break; \
+ default: \
+ assert(__ret >= -1 && __ret <= 1); \
+ rv = -1; \
+ } \
+ } while(0)
+
+/*
+ * Temporary substitute module for the purposes of evaluating expression.
+ */
+#define WITH_MODULE(tmp_mod, expr) do { \
+ void *_saved_mod = arg->mod; \
+ arg->mod = tmp_mod; \
+ do { expr; } while(0); \
+ arg->mod = _saved_mod; \
+ } while(0)
+
+#define LOG(code, fmt, args...) do { \
+ int _save_errno = errno; \
+ if(code < 0) { \
+ if(arg->debug) \
+ arg->debug(code, fmt, ##args); \
+ } else { \
+ arg->eh(code, fmt " in %s", ##args, \
+ arg->mod->source_file_name); \
+ } \
+ errno = _save_errno; \
+ } while(0)
+
+#define DEBUG(fmt, args...) LOG(-1, fmt, ##args)
+#define FATAL(fmt, args...) LOG( 1, fmt, ##args)
+#define WARNING(fmt, args...) LOG( 0, fmt, ##args)
+
+
+/*
+ * Define the symbol corresponding to the name of the current function.
+ */
+#if __STDC_VERSION__ < 199901
+#if !(__GNUC__ == 2 && __GNUC_MINOR__ >= 7 || __GNUC__ >= 3)
+#define __func__ (char *)0 /* Name of the current function */
+#endif /* GNUC */
+/* __func__ is supposed to be defined */
+#endif
+
+
+#endif /* _ASN1FIX_INTERNAL_H_ */
diff --git a/libasn1fix/asn1fix_misc.c b/libasn1fix/asn1fix_misc.c
new file mode 100644
index 00000000..5fe69034
--- /dev/null
+++ b/libasn1fix/asn1fix_misc.c
@@ -0,0 +1,276 @@
+#include "asn1fix_internal.h"
+
+
+char const *
+asn1f_printable_reference(asn1p_ref_t *ref) {
+ if(ref) {
+ asn1p_value_t v;
+
+ v.type = ATV_REFERENCED;
+ v.value.reference = ref;
+
+ return asn1f_printable_value(&v);
+ } else {
+ return "<no ref>";
+ }
+}
+
+char const *
+asn1f_printable_value(asn1p_value_t *v) {
+ static char buf[128];
+ static char *managedptr;
+ static int managedptr_len;
+ int ret;
+
+#define ENSURE(len) do { \
+ if(len >= managedptr_len) { \
+ if(managedptr) \
+ free(managedptr); \
+ managedptr = malloc(len + 1); \
+ if(managedptr) { \
+ managedptr_len = len; \
+ } else { \
+ managedptr_len = 0; \
+ return "<memory allocation error>"; \
+ } \
+ } \
+ } while(0)
+
+ if(v == NULL)
+ return "<no value>";
+
+ switch(v->type) {
+ case ATV_NOVALUE:
+ return "<NO VALUE>";
+ case ATV_REFERENCED:
+ {
+ asn1p_ref_t *ref;
+ char reflen;
+ char *ptr;
+ int i;
+
+ assert(v->value.reference);
+ ref = v->value.reference;
+ reflen = ref->comp_count; /* Number of dots */
+ for(i = 0; i < ref->comp_count; i++)
+ reflen += strlen(ref->components[i].name);
+ /*
+ * Make sure we have a buffer of this size.
+ */
+ ENSURE(reflen);
+
+ /*
+ * Fill-up the buffer.
+ */
+ ptr = managedptr;
+ for(i = 0; i < ref->comp_count; i++) {
+ char *nc;
+ if(i) *ptr++ = '.';
+ for(nc = ref->components[i].name; *nc; nc++)
+ *ptr++ = *nc;
+ }
+ *ptr++ = '\0';
+ assert(reflen == (ptr - managedptr));
+ return managedptr;
+ }
+ case ATV_REAL:
+ ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double);
+ if(ret >= sizeof(buf))
+ memcpy(buf + sizeof(buf) - 4, "...", 4);
+ return buf;
+ case ATV_INTEGER:
+ ret = snprintf(buf, sizeof(buf), "%lld",
+ (long long)v->value.v_integer);
+ if(ret >= sizeof(buf))
+ memcpy(buf + sizeof(buf) - 4, "...", 4);
+ return buf;
+ case ATV_MIN: return "MIN";
+ case ATV_MAX: return "MAX";
+ case ATV_FALSE: return "FALSE";
+ case ATV_TRUE: return "TRUE";
+ case ATV_STRING:
+ case ATV_UNPARSED:
+ /* Buffer is guaranteed to be null-terminated */
+ assert(v->value.string.buf[v->value.string.size] == '\0');
+ return v->value.string.buf;
+ case ATV_BITVECTOR:
+ {
+ uint8_t *bitvector;
+ char *ptr;
+ int len;
+ int i;
+ /*
+ * Compute number of bytes necessary
+ * to represend the binary value.
+ */
+ int bits = v->value.binary_vector.size_in_bits;
+ len = ((bits%8)?bits:(bits >> 2)) + sizeof("''H");
+ /*
+ * Reallocate managed buffer
+ */
+ ENSURE(len);
+
+ /*
+ * Fill the buffer.
+ */
+ ptr = managedptr;
+ bitvector = v->value.binary_vector.bits;
+ *ptr++ = '\'';
+ if(bits%8) {
+ /*
+ * Dump bit by bit.
+ */
+ for(i = 0; i < bits; i++) {
+ uint8_t uc;
+ uc = bitvector[i>>3];
+ *ptr++ = ((uc >> (7-(i%8)))&1)?'1':'0';
+ }
+ } else {
+ char hextable[16] = "0123456789ABCDEF";
+ /*
+ * Dump byte by byte.
+ */
+ for(i = 0; i < (bits >> 3); i++) {
+ *ptr++ = hextable[bitvector[i] >> 4];
+ *ptr++ = hextable[bitvector[i] & 0x0f];
+ }
+ }
+ *ptr++ = '\'';
+ *ptr++ = (bits%8)?'B':'H';
+ *ptr++ = 'H';
+ assert((ptr - managedptr) == len);
+ return managedptr;
+ }
+ }
+
+ return "<some complex value>";
+}
+
+
+/*
+ * Recursively invoke a given function over the given expr and all its
+ * children.
+ */
+int
+asn1f_recurse_expr(arg_t *arg, int (*callback)(arg_t *arg)) {
+ asn1p_expr_t *expr = arg->expr;
+ int rvalue = 0;
+ int ret;
+
+ assert(expr);
+
+ /*
+ * Invoke the callback at this very level.
+ */
+ ret = callback(arg);
+ RET2RVAL(ret, rvalue);
+
+ /*
+ * Recursively invoke myself
+ * to iterate over each element in the tree.
+ */
+ TQ_FOR(arg->expr, &(expr->members), next) {
+ assert(arg->expr->expr_type != A1TC_INVALID);
+ ret = asn1f_recurse_expr(arg, callback);
+ RET2RVAL(ret, rvalue);
+ }
+
+ arg->expr = expr; /* Restore original position */
+
+ return rvalue;
+}
+
+
+/*
+ * Check that every child of a given expr has unique name or does not have any.
+ */
+int
+asn1f_check_unique_expr(arg_t *arg,
+ int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
+ asn1p_expr_t *expr;
+ int rvalue = 0;
+
+ TQ_FOR(expr, &(arg->expr->members), next) {
+ if(expr->Identifier) {
+ int ret = asn1f_check_unique_expr_child(arg, expr,
+ opt_compare);
+ if(ret) rvalue = -1;
+ } else {
+ /*
+ * No point of comparing this child with any other:
+ * this one does not have a name.
+ */
+ }
+ }
+
+ return rvalue;
+}
+
+/*
+ * Check that every preceeding child of the given expr is not
+ * having the name of the given one.
+ */
+int
+asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
+ int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
+ asn1p_expr_t *expr;
+ int rvalue = 0;
+
+ assert(child);
+ assert(opt_compare || child->Identifier);
+
+ TQ_FOR(expr, &(arg->expr->members), next) {
+ int ret;
+
+ if(expr == child)
+ break;
+
+ /*
+ * Compare according to the custom rule or default
+ * names comparisons.
+ */
+ if(opt_compare) {
+ ret = opt_compare(expr, child);
+ } else {
+ if(expr->Identifier == NULL
+ || expr->expr_type == A1TC_EXTENSIBLE)
+ continue;
+ ret = strcasecmp(expr->Identifier, child->Identifier);
+ }
+
+ if(ret == 0) {
+ char *msg;
+ msg = opt_compare
+ ?"Expressions clash"
+ :"Identifiers name clash";
+ arg->eh(1,
+ "%s: "
+ "\"%s\" at line %d has similar %s with "
+ "\"%s\" at line %d",
+ msg,
+ expr->Identifier,
+ expr->_lineno,
+ opt_compare?"property":"name",
+ child->Identifier,
+ child->_lineno
+ );
+
+ rvalue = -1;
+ }
+ }
+
+ return rvalue;
+}
+
+int
+asn1f_count_children(asn1p_expr_t *expr) {
+ asn1p_expr_t *child;
+ int count = 0;
+
+ TQ_FOR(child, &(expr->members), next) {
+ count++;
+ }
+
+ return count;
+}
+
diff --git a/libasn1fix/asn1fix_misc.h b/libasn1fix/asn1fix_misc.h
new file mode 100644
index 00000000..e88e4322
--- /dev/null
+++ b/libasn1fix/asn1fix_misc.h
@@ -0,0 +1,47 @@
+/*
+ * Miscellaneous functions necessary for several other modules.
+ */
+#ifndef _ASN1FIX_MISC_H_
+#define _ASN1FIX_MISC_H_
+
+/*
+ * Return a pointer to the locally held string with human-readable
+ * definition of the value.
+ */
+char const *asn1f_printable_value(asn1p_value_t *);
+
+/*
+ * Return a pointer to the locally held string with human-readable
+ * definition of the reference.
+ */
+char const *asn1f_printable_reference(asn1p_ref_t *);
+
+/*
+ * Recursively invoke a given function over the given expr and all its
+ * children.
+ */
+int asn1f_recurse_expr(arg_t *arg, int (*f)(arg_t *arg));
+
+/*
+ * Check that every child of a given expr has unique name or does not have any.
+ * If opt_compare == NULL, the default comparison of the argument's
+ * names (identifiers) will be performed.
+ */
+int asn1f_check_unique_expr(arg_t *arg,
+ int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b));
+
+/*
+ * Check that every preceeding child of the given expr is not
+ * having the name of the given one.
+ * If opt_compare == NULL, the default comparison of the argument's
+ * names (identifiers) will be performed.
+ */
+int asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
+ int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b));
+
+/*
+ * Return number of children.
+ */
+int asn1f_count_children(asn1p_expr_t *parent);
+
+#endif /* _ASN1FIX_MISC_H_ */
diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c
new file mode 100644
index 00000000..0c838cc5
--- /dev/null
+++ b/libasn1fix/asn1fix_param.c
@@ -0,0 +1,165 @@
+#include "asn1fix_internal.h"
+
+static int asn1f_parametrize(arg_t *arg, asn1p_expr_t *ex, asn1p_expr_t *ptype);
+static int asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+static asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+
+int
+asn1f_fix_parametrized_assignment(arg_t *arg) {
+ asn1p_expr_t *expr = arg->expr;
+ asn1p_expr_t *ptype;
+
+ assert(expr->expr_type == A1TC_PARAMETRIZED);
+ assert(expr->reference);
+
+ DEBUG("%s(\"%s\" ::= \"%s\" { %s }) for line %d",
+ __func__, expr->Identifier,
+ asn1f_printable_reference(expr->reference),
+ asn1f_printable_value(expr->value),
+ expr->_lineno);
+
+ /*
+ * Find the corresponding parametrized type definition.
+ */
+ DEBUG("Looking for parametrized type definition \"%s\"",
+ asn1f_printable_reference(expr->reference));
+ ptype = asn1f_lookup_symbol(arg, expr->reference, 0);
+ if(ptype == NULL) {
+ DEBUG("%s: missing parametrized type declaration",
+ asn1f_printable_reference(expr->reference));
+ return -1;
+ }
+
+ /*
+ * Check that the number of arguments which are expected by
+ * the parametrized type declaration is consistent with the
+ * number of arguments supplied by the parametrized assignment.
+ */
+ if(asn1f_count_children(expr) != ptype->params->params_count) {
+ FATAL("Number of actual arguments %d in %s at line %d "
+ "is not equal to number of expected arguments "
+ "%d in %s at line %d",
+ asn1f_count_children(expr),
+ asn1f_printable_reference(expr->reference),
+ expr->_lineno,
+ ptype->params->params_count,
+ ptype->Identifier,
+ ptype->_lineno
+ );
+ return -1;
+ }
+
+ /*
+ * Perform an expansion of a parametrized assignment.
+ */
+ return asn1f_parametrize(arg, expr, ptype);
+}
+
+#define SUBSTITUTE(to, from) do { \
+ asn1p_expr_t tmp; \
+ tmp = *(to); \
+ *(to) = *(from); \
+ *(from) = tmp; \
+ (to)->next = tmp.next; \
+ memset(&((from)->next), 0, \
+ sizeof((from)->next)); \
+ asn1p_expr_free(from); \
+ } while(0)
+
+static int
+asn1f_parametrize(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype) {
+ asn1p_expr_t *nex;
+ void *p;
+ int ret;
+
+ /*
+ * The algorithm goes like that:
+ * 1. Replace the expression's type with parametrized type.
+ * 2. For every child in the parametrized type, import it
+ * as a child of the expression, replacing all occurences of
+ * symbols which are defined as parametrized type arguments
+ * with the actual values.
+ */
+
+ nex = asn1p_expr_clone(ptype);
+ if(nex == NULL) return -1;
+
+ /*
+ * Cleanup the new expression so there is no ptype-related
+ * stuff hanging around.
+ */
+ p = strdup(expr->Identifier);
+ if(p) {
+ free(nex->Identifier);
+ nex->Identifier = p;
+ } else {
+ asn1p_expr_free(nex);
+ return -1;
+ }
+ asn1p_paramlist_free(nex->params);
+ nex->params = NULL;
+ nex->meta_type = expr->meta_type;
+
+ ret = asn1f_param_process_recursive(arg, nex, ptype, expr);
+ if(ret != 0) {
+ asn1p_expr_free(nex);
+ return ret;
+ }
+
+ SUBSTITUTE(expr, nex);
+
+ return ret;
+}
+
+static int
+asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+ asn1p_expr_t *child;
+
+ TQ_FOR(child, &(expr->members), next) {
+ asn1p_expr_t *ra;
+ asn1p_expr_t *ne;
+
+ ra = _referenced_argument(child->reference, ptype, actargs);
+ if(ra == NULL) continue;
+
+ DEBUG("Substituting parameter for %s %s at line %d",
+ child->Identifier,
+ asn1f_printable_reference(child->reference),
+ child->_lineno
+ );
+
+ assert(child->meta_type == AMT_TYPEREF);
+ assert(child->expr_type == A1TC_REFERENCE);
+
+ ne = asn1p_expr_clone(ra);
+ if(ne == NULL) return -1;
+ assert(ne->Identifier == 0);
+ ne->Identifier = strdup(child->Identifier);
+ if(ne->Identifier == 0) {
+ asn1p_expr_free(ne);
+ return -1;
+ }
+ SUBSTITUTE(child, ne);
+ }
+
+ return 0;
+}
+
+static asn1p_expr_t *
+_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+ asn1p_expr_t *aa;
+ int i;
+
+ if(ref == NULL || ref->comp_count != 1)
+ return NULL;
+
+ aa = TQ_FIRST(&(actargs->members));
+ for(i = 0; i < ptype->params->params_count;
+ i++, aa = TQ_NEXT(aa, next)) {
+ if(strcmp(ref->components[0].name,
+ ptype->params->params[i].argument) == 0)
+ return aa;
+ }
+
+ return NULL;
+}
diff --git a/libasn1fix/asn1fix_param.h b/libasn1fix/asn1fix_param.h
new file mode 100644
index 00000000..062ad8bd
--- /dev/null
+++ b/libasn1fix/asn1fix_param.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_PARAMETRIZATION_H_
+#define _ASN1FIX_PARAMETRIZATION_H_
+
+int asn1f_fix_parametrized_assignment(arg_t *arg);
+
+#endif /* _ASN1FIX_PARAMETRIZATION_H_ */
diff --git a/libasn1fix/asn1fix_retrieve.c b/libasn1fix/asn1fix_retrieve.c
new file mode 100644
index 00000000..0dfcce40
--- /dev/null
+++ b/libasn1fix/asn1fix_retrieve.c
@@ -0,0 +1,366 @@
+#include "asn1fix_internal.h"
+
+static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, asn1p_module_t **optm, int type_or_value);
+static int asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name);
+
+
+/*
+ * Lookup a child by its name.
+ */
+asn1p_expr_t *
+asn1f_lookup_child(asn1p_expr_t *tc, const char *name) {
+ asn1p_expr_t *child_tc;
+
+ TQ_FOR(child_tc, &(tc->members), next) {
+ if(child_tc->Identifier
+ && strcmp(child_tc->Identifier, name) == 0) {
+ return child_tc;
+ }
+ }
+
+ errno = ESRCH;
+ return NULL;
+}
+
+asn1p_module_t *
+asn1f_lookup_in_imports(arg_t *arg, const char *name) {
+ asn1p_module_t *mod;
+ asn1p_xports_t *xp;
+ asn1p_expr_t *tc;
+
+ /*
+ * Search in which exactly module this name is defined.
+ */
+ TQ_FOR(xp, &(arg->mod->imports), xp_next) {
+ TQ_FOR(tc, &(xp->members), next) {
+ if(strcmp(name, tc->Identifier) == 0)
+ break;
+ }
+ if(tc) break;
+ }
+ if(xp == NULL) {
+ errno = ESRCH;
+ return NULL;
+ }
+
+ /*
+ * Okay, right now we have a module name and, hopefully, an OID.
+ * Search the arg->asn for the specified module.
+ */
+ mod = asn1f_lookup_module(arg, xp->from, xp->from_oid);
+ if(mod == NULL) {
+ /* ENOENT/ETOOMANYREFS */
+ return NULL;
+ }
+
+ /*
+ * Check that the EXPORTS section of this module contains
+ * the symbol we care about, or it is EXPORTS ALL.
+ */
+ if(asn1f_compatible_with_exports(arg, mod, name)) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ return mod;
+}
+
+asn1p_module_t *
+asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
+ asn1p_module_t *mod;
+
+ assert(module_name);
+
+ /*
+ * If OID is given, the module_name is unused.
+ * If OID is not given, the module_name may mean
+ * either the real module's name, or the symbol which is the
+ * result of renaming. Check this first.
+ */
+ if(oid == 0) {
+ asn1p_xports_t *xp;
+ /*
+ * Check inside the IMPORTS section for possible renaming.
+ * Renaming practically means that a module_name is mentioned
+ * somewhere in the IMPORTS section AND OID is given.
+ */
+ TQ_FOR(xp, &(arg->mod->imports), xp_next) {
+ if(strcmp(module_name, xp->from))
+ continue;
+ if(oid) {
+ FATAL("Ambiguous reference: "
+ "%s "
+ "matches several modules",
+ module_name);
+ errno = ETOOMANYREFS;
+ return NULL;
+ }
+ /*
+ * Yes, there is a renaming.
+ * Make lookup use OID instead.
+ */
+ oid = xp->from_oid;
+ }
+ }
+
+ /*
+ * Perform lookup using OID or module_name.
+ */
+ TQ_FOR(mod, &(arg->asn->modules), mod_next) {
+ if(oid) {
+ if(mod->module_oid) {
+ if(asn1p_oid_compare(oid,
+ mod->module_oid)) {
+ continue;
+ } else {
+ /* Match! Even if name doesn't. */
+ return mod;
+ }
+ } else {
+ /* Not match, even if name is the same. */
+ continue;
+ }
+ }
+
+ if(strcmp(module_name, mod->Identifier) == 0)
+ return mod;
+ }
+
+ DEBUG("\tModule \"%s\" not found", module_name);
+
+ errno = ENOENT;
+ return NULL;
+}
+
+
+
+asn1p_expr_t *
+asn1f_lookup_symbol(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **module_r) {
+ asn1p_expr_t *ref_tc; /* Referenced tc */
+ asn1p_module_t *src_mod;
+ char *modulename;
+ char *identifier;
+
+ /*
+ * First of all, a reference to a symbol may be specified
+ * using several possible forms:
+ * a) simple identifier
+ * v INTEGER ::= value
+ * b) external reference
+ * v INTEGER ::= Module1.value
+ * c) class-related stuff (the most complex stuff)
+ * v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
+ * All other forms are not implemented at this moment.
+ */
+
+ DEBUG("%s(%s) in %s for line %d", __func__,
+ asn1f_printable_reference(ref),
+ arg->mod->Identifier,
+ ref->_lineno);
+
+ if(ref->comp_count == 1) {
+ modulename = NULL;
+ identifier = ref->components[0].name;
+ } else if(ref->comp_count == 2
+ && ref->components[1].name[0] != '&') {
+ modulename = ref->components[0].name;
+ identifier = ref->components[1].name;
+ } else if(ref->comp_count > 1
+ && isupper(ref->components[0].name[0])
+ && ref->components[1].name[0] == '&') {
+ asn1p_expr_t *extract;
+ /*
+ * This is a reference to a CLASS-related stuff.
+ * Employ a separate function for that.
+ */
+ extract = asn1f_class_access(arg, ref, module_r);
+
+ return extract;
+ } else {
+ DEBUG("\tToo many components: %d", ref->comp_count);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * If module name is specified explicitly
+ * OR the current module's IMPORTS clause contains the identifier,
+ * fetch that module.
+ */
+ if(modulename) {
+ src_mod = asn1f_lookup_module(arg, modulename, 0);
+ if(src_mod == NULL) {
+ FATAL("Module \"%s\" "
+ "mentioned at line %d is not found",
+ modulename, ref->_lineno);
+ return NULL;
+ }
+
+ /*
+ * Check that the EXPORTS section of this module contains
+ * the symbol we care about, or it is EXPORTS ALL.
+ */
+ if(asn1f_compatible_with_exports(arg, src_mod, identifier)) {
+ errno = EPERM;
+ return NULL;
+ }
+ } else {
+ src_mod = asn1f_lookup_in_imports(arg, identifier);
+ if(src_mod == NULL && errno != ESRCH) {
+ /*
+ * Return only of the name was not found.
+ * If module was not found or more serious error
+ * encountered, just return preserving the errno.
+ */
+ return NULL;
+ }
+ }
+
+ if(src_mod == 0) src_mod = arg->mod;
+
+ /*
+ * Now we know where to search for a value.
+ */
+ TQ_FOR(ref_tc, &(src_mod->members), next) {
+ if(ref_tc->Identifier)
+ if(strcmp(ref_tc->Identifier, identifier) == 0)
+ break;
+ }
+ if(ref_tc == NULL) {
+ DEBUG("Module \"%s\" does not contain \"%s\" "
+ "mentioned at line %d",
+ src_mod->Identifier,
+ identifier,
+ ref->_lineno
+ );
+ errno = ESRCH;
+ return NULL;
+ }
+
+ if(module_r)
+ *module_r = src_mod;
+
+ return ref_tc;
+}
+
+
+asn1p_expr_t *
+asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr,
+ asn1p_module_t **optm) {
+ return asn1f_find_terminal_thing(arg, expr, optm, 0);
+}
+
+asn1p_expr_t *
+asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr,
+ asn1p_module_t **optm) {
+ return asn1f_find_terminal_thing(arg, expr, optm, 1);
+}
+
+static asn1p_expr_t *
+asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr,
+ asn1p_module_t **optm, int type_or_value) {
+ asn1p_module_t *mod;
+ asn1p_ref_t *ref;
+ asn1p_expr_t *tc;
+
+ if(type_or_value) {
+ /* VALUE */
+ assert(expr->meta_type == AMT_VALUE);
+ assert(expr->value);
+ if(expr->value->type != ATV_REFERENCED) {
+ /* Expression is a terminal value itself */
+ if(optm) *optm = arg->mod;
+ return expr;
+ }
+ ref = expr->value->value.reference;
+ } else {
+ /* TYPE */
+ if(expr->expr_type != A1TC_REFERENCE) {
+ /* Expression is a terminal type itself */
+ if(optm) *optm = arg->mod;
+ return expr;
+ }
+ ref = expr->reference;
+ }
+
+ DEBUG("%s:%s(%s->%s) for line %d",
+ __func__, type_or_value?"VALUE":"TYPE",
+ expr->Identifier, asn1f_printable_reference(ref),
+ expr->_lineno);
+
+ assert(ref);
+
+ /*
+ * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
+ */
+ if(type_or_value) {
+ asn1p_expr_t *val_type_tc;
+ val_type_tc = asn1f_find_terminal_type(arg, expr, 0);
+ if(val_type_tc
+ && asn1f_look_value_in_type(arg, val_type_tc, expr))
+ return NULL;
+ if(expr->value->type != ATV_REFERENCED) {
+ if(optm) *optm = arg->mod;
+ return expr;
+ }
+ assert(ref == expr->value->value.reference);
+ ref = expr->value->value.reference;
+ }
+
+ /*
+ * Lookup inside the default module.
+ */
+ tc = asn1f_lookup_symbol(arg, ref, &mod);
+ if(tc == NULL) {
+ DEBUG("\tSymbol \"%s\" not found",
+ asn1f_printable_reference(ref));
+ return NULL;
+ }
+
+ /*
+ * Recursive loops detection.
+ */
+ if(tc->_mark & TM_RECURSION) {
+ DEBUG("Recursion loop detected for %s at line %d",
+ asn1f_printable_reference(ref), ref->_lineno);
+ errno = EPERM;
+ return NULL;
+ }
+
+ tc->_mark |= TM_RECURSION;
+ WITH_MODULE(mod,
+ expr = asn1f_find_terminal_thing(arg, tc, optm, type_or_value));
+ tc->_mark &= ~TM_RECURSION;
+
+ return expr;
+}
+
+/*
+ * Make sure that the specified name is present or otherwise does
+ * not contradict with the EXPORTS clause of the specified module.
+ */
+static int
+asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
+ asn1p_xports_t *exports;
+ asn1p_expr_t *item;
+
+ assert(mod);
+ assert(name);
+
+ exports = TQ_FIRST(&(mod->exports));
+ if(exports == NULL) {
+ /* No EXPORTS section or EXPORTS ALL; */
+ return 0;
+ }
+
+ TQ_FOR(item, &(exports->members), next) {
+ if(strcmp(item->Identifier, name) == 0)
+ return 0;
+ }
+
+ DEBUG("Symbol \"%s\" contradicts with EXPORTS of module %s",
+ name, mod->Identifier);
+
+ errno = ESRCH;
+ return -1;
+}
diff --git a/libasn1fix/asn1fix_retrieve.h b/libasn1fix/asn1fix_retrieve.h
new file mode 100644
index 00000000..47aa0a5b
--- /dev/null
+++ b/libasn1fix/asn1fix_retrieve.h
@@ -0,0 +1,73 @@
+/*
+ * Miscellaneous functions necessary for several other modules.
+ */
+#ifndef _ASN1FIX_RETRIEVE_H_
+#define _ASN1FIX_RETRIEVE_H_
+
+/*
+ * Simple search for the label in the descendants of the given node.
+ * ERRORS:
+ * NULL/ESRCH
+ */
+asn1p_expr_t *asn1f_lookup_child(asn1p_expr_t *tc, const char *name);
+
+/*
+ * Return a module which contain a specified name, as stated in appropriate
+ * IMPORTS section of the current module (arg->mod).
+ *
+ * RETURN VALUES:
+ * NULL/ESRCH: The name was not found in IMPORTS section.
+ * NULL/EPERM: The name was not found in EXPORTS section of the source module.
+ * Also, NULL with errno values defined by asn1f_lookup_module().
+ */
+asn1p_module_t *asn1f_lookup_in_imports(arg_t *arg, const char *name);
+
+/*
+ * Return a module by its name or optional OID.
+ *
+ * RETURN VALUES:
+ * NULL/ENOENT: No module was found by the specified name and oid
+ * NULL/ETOOMANYREFS: Several modules are matching the specified name and oid
+ */
+asn1p_module_t *asn1f_lookup_module(arg_t *arg,
+ const char *module_name,
+ asn1p_oid_t *module_oid);
+
+/*
+ * Return the reference to a destination of the given reference,
+ * symbol lookup. Not a recursive function.
+ * Optional module reference may be assigned a module in which the
+ * particular expr was found.
+ */
+asn1p_expr_t *asn1f_lookup_symbol(arg_t *arg, asn1p_ref_t *ref,
+ asn1p_module_t **opt_module_r);
+
+/*
+ * Recursively find the original type for the given expression.
+ * i.e.:
+ * If the original specification defines
+ * v Type1 ::= 5
+ * Type1 ::= Type2 (1..5)
+ * Type3 ::= Type4 (2..7)
+ * Type4 ::= INTEGER (1..10)
+ * Then this function, given the the first expression as an argument,
+ * would return an expression for Type4.
+ * WARNING: No attempts are made to honor constraints at this moment.
+ */
+asn1p_expr_t *asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *tc,
+ asn1p_module_t **opt_module_r);
+
+/*
+ * Recursively find the original value for the given expression.
+ * i.e.:
+ * If the original specification defines
+ * v Type1 ::= value
+ * value Type2 ::= value2
+ * value2 Type3 ::= 3
+ * Then this function will return the expression for value2 if given
+ * the v as an argment.
+ */
+asn1p_expr_t *asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *tc,
+ asn1p_module_t **opt_module_r);
+
+#endif /* _ASN1FIX_RETRIEVE_H_ */
diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c
new file mode 100644
index 00000000..ed8c19f2
--- /dev/null
+++ b/libasn1fix/asn1fix_tags.c
@@ -0,0 +1,47 @@
+#include "asn1fix_internal.h"
+
+int
+asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag) {
+ int ret;
+
+ if(expr->tag.tag_class != TC_NOCLASS) {
+ *tag = expr->tag;
+ return 0;
+ }
+
+ if(expr->expr_type == A1TC_EXTENSIBLE) {
+ memset(tag, 0, sizeof(*tag));
+ tag->tag_class = -1;
+ return 0;
+ }
+
+ if(expr->meta_type == AMT_TYPE) {
+ memset(tag, 0, sizeof(*tag));
+ tag->tag_class = TC_UNIVERSAL;
+ tag->tag_value = expr_type2uclass_value[expr->expr_type];
+ return (tag->tag_value == 0) ? -1 : 0;
+ }
+
+ if(expr->meta_type == AMT_TYPEREF) {
+ arg_t arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.asn = asn;
+ arg.mod = mod;
+ arg.expr = expr;
+
+ expr = asn1f_lookup_symbol(&arg, expr->reference, &mod);
+ if(expr == NULL) return -1;
+
+ if(expr->_mark & TM_RECURSION)
+ return -1;
+
+ expr->_mark |= TM_RECURSION;
+ ret = asn1f_fetch_tag(asn, mod, expr, tag);
+ expr->_mark &= ~TM_RECURSION;
+ return ret;
+ }
+
+ return -1;
+}
+
diff --git a/libasn1fix/asn1fix_tags.h b/libasn1fix/asn1fix_tags.h
new file mode 100644
index 00000000..9d3595b9
--- /dev/null
+++ b/libasn1fix/asn1fix_tags.h
@@ -0,0 +1,6 @@
+#ifndef _ASN1FIX_TAGS_H_
+#define _ASN1FIX_TAGS_H_
+
+int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag);
+
+#endif /* _ASN1FIX_TAGS_H_ */
diff --git a/libasn1fix/asn1fix_value.c b/libasn1fix/asn1fix_value.c
new file mode 100644
index 00000000..a22fd3dc
--- /dev/null
+++ b/libasn1fix/asn1fix_value.c
@@ -0,0 +1,159 @@
+#include "asn1fix_internal.h"
+
+static int _asn1f_copy_value(arg_t *arg, asn1p_expr_t *to,asn1p_expr_t *from);
+
+int
+asn1f_value_resolve(arg_t *arg, asn1p_expr_t *expr) {
+ asn1p_module_t *val_mod;
+ asn1p_expr_t *val_type_expr;
+ asn1p_expr_t *value_expr;
+ asn1p_expr_t *type_expr;
+ int ret;
+
+ /* Make sure this IS a value assignment */
+ assert(expr->meta_type == AMT_VALUE);
+ assert(expr->value);
+
+ DEBUG("%s(=\"%s\", %x)", __func__,
+ asn1f_printable_value(expr->value), expr->expr_type);
+
+ /*
+ * 1. Find the terminal type for this assignment.
+ */
+ type_expr = asn1f_find_terminal_type(arg, expr, 0);
+ if(type_expr == 0) {
+ DEBUG("\tTerminal type for %s not found", expr->Identifier);
+ return -1;
+ }
+
+ if(asn1f_look_value_in_type(arg, type_expr, expr) == -1)
+ return -1;
+
+ /*
+ * 2. Find the terminal value also.
+ */
+ value_expr = asn1f_find_terminal_value(arg, expr, &val_mod);
+ if(value_expr) {
+ DEBUG("\tTerminal value for %s->%s is %s at line %d",
+ expr->Identifier, asn1f_printable_value(expr->value),
+ value_expr->Identifier, value_expr->_lineno);
+ } else {
+ DEBUG("\tTerminal value for %s->%s not found",
+ expr->Identifier, asn1f_printable_value(expr->value));
+ return -1;
+ }
+
+ /*
+ * 3. Find the _type_ of a _terminal value_.
+ */
+ WITH_MODULE(val_mod,
+ val_type_expr = asn1f_find_terminal_type(arg, value_expr, 0));
+ if(val_type_expr) {
+ DEBUG("\tTerminal type of value %s->%s is %s at line %d",
+ expr->Identifier, asn1f_printable_value(expr->value),
+ val_type_expr->Identifier, val_type_expr->_lineno);
+ } else {
+ DEBUG("\tTerminal type of value %s->%s not found",
+ expr->Identifier, asn1f_printable_value(expr->value));
+ return -1;
+ }
+
+ /*
+ * 4. Check compatibility between the type of the current expression
+ * and the type of the discovered value.
+ */
+ ret = asn1f_check_type_compatibility(arg, type_expr, val_type_expr);
+ if(ret == -1) {
+ DEBUG("\tIncompatible type of %s at %d with %s at %d",
+ type_expr->Identifier, type_expr->_lineno,
+ val_type_expr->Identifier, val_type_expr->_lineno);
+ return -1;
+ }
+
+ if(asn1f_look_value_in_type(arg, val_type_expr, expr) == -1)
+ return -1;
+
+ /*
+ * 5. Copy value from the terminal value into the current expression.
+ */
+ ret = _asn1f_copy_value(arg, expr, value_expr);
+ if(ret == -1) {
+ DEBUG("\tValue %s cannot be copied from line %d to line %d",
+ asn1f_printable_value(value_expr->value),
+ value_expr->_lineno, expr->_lineno);
+ return -1;
+ }
+
+ DEBUG("\tFinal value for \"%s\" at line %d is %s",
+ expr->Identifier, expr->_lineno,
+ asn1f_printable_value(expr->value));
+
+ return 0;
+}
+
+static int
+_asn1f_copy_value(arg_t *arg, asn1p_expr_t *to, asn1p_expr_t *from) {
+ asn1p_value_t *v;
+
+ v = asn1p_value_clone(from->value);
+ if(v) {
+ asn1p_value_free(to->value);
+ to->value = v;
+ DEBUG("Copied value %s from \"%s\" on line %d "
+ "to \"%s\" on line %d",
+ asn1f_printable_value(v),
+ from->Identifier,
+ from->_lineno,
+ to->Identifier,
+ to->_lineno
+ );
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int
+asn1f_look_value_in_type(arg_t *arg,
+ asn1p_expr_t *type_expr,
+ asn1p_expr_t *value_expr) {
+ asn1p_expr_t *child_expr;
+ char *identifier;
+
+ if(value_expr->value->type != ATV_REFERENCED
+ || value_expr->value->value.reference->comp_count != 1)
+ return 0;
+ if(type_expr->expr_type != ASN_BASIC_INTEGER
+ && type_expr->expr_type != ASN_BASIC_ENUMERATED)
+ return 0;
+
+ DEBUG("%s(for %s in %s %x) for line %d", __func__,
+ asn1f_printable_value(value_expr->value),
+ type_expr->Identifier,
+ type_expr->expr_type,
+ value_expr->_lineno);
+
+ /*
+ * Look into the definitions of the type itself:
+ * Type1 ::= INTEGER { a(1), b(2) }
+ * value Type1 = b -- will assign 2
+ */
+ identifier = value_expr->value->value.reference->components[0].name;
+
+ child_expr = asn1f_lookup_child(type_expr, identifier);
+ DEBUG("\tLooking into a type %s at line %d for %s at line %d: %s",
+ type_expr->Identifier, type_expr->_lineno,
+ identifier, value_expr->_lineno,
+ child_expr
+ ? asn1f_printable_value(child_expr->value)
+ : "<not found>"
+ );
+
+ if(child_expr && child_expr->value) {
+ if(_asn1f_copy_value(arg, value_expr, child_expr))
+ return -1;
+ /* Fall through */
+ }
+
+ return 0;
+}
diff --git a/libasn1fix/asn1fix_value.h b/libasn1fix/asn1fix_value.h
new file mode 100644
index 00000000..7234035e
--- /dev/null
+++ b/libasn1fix/asn1fix_value.h
@@ -0,0 +1,28 @@
+/*
+ * Functions related with processing values.
+ */
+#ifndef _ASN1FIX_VALUE_H_
+#define _ASN1FIX_VALUE_H_
+
+/*
+ * Resolve the value given by reference.
+ * This function also takes a parameter which specifies the desired
+ * value's type.
+ *
+ * RETURN VALUES:
+ * 0: Value resolved successfully.
+ * -1/EPERM: Recursive looping detected.
+ * -1/EEXIST: Reference is not compatible with the desired type.
+ * -1/ESRCH: Cannot find the terminal reference.
+ */
+int asn1f_value_resolve(arg_t *arg, asn1p_expr_t *tc);
+
+/*
+ * Check if a value in value_expr refers to the enumeration or integer element
+ * within the type provided. If yes, it will replace referenced value with
+ * the appropriate inline value.
+ */
+int asn1f_look_value_in_type(arg_t *arg,
+ asn1p_expr_t *type_expr, asn1p_expr_t *value_expr);
+
+#endif /* _ASN1FIX_VALUE_H_ */
diff --git a/libasn1fix/check_fixer.c b/libasn1fix/check_fixer.c
new file mode 100644
index 00000000..21c5b12f
--- /dev/null
+++ b/libasn1fix/check_fixer.c
@@ -0,0 +1,313 @@
+#undef NDEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sysexits.h>
+
+#include "asn1fix.h"
+#include "asn1fix_internal.h"
+
+static int check(const char *fname,
+ enum asn1p_flags parser_flags,
+ enum asn1f_flags fixer_flags);
+static int post_fix_check(asn1p_t *asn);
+static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr);
+
+int
+main(int ac, char **av) {
+ struct dirent *dp;
+ DIR *dir;
+ int failed = 0;
+ int completed = 0;
+ enum asn1p_flags parser_flags = A1P_NOFLAGS;
+ enum asn1f_flags fixer_flags = A1F_NOFLAGS;
+ int ret;
+
+ /*
+ * Just in case when one decides that some flags better be
+ * enabled during `ASN1_FIXER_FLAGS=1 make check` or some
+ * similar usage.
+ */
+ if(getenv("ASN1_PARSER_FLAGS"))
+ parser_flags = atoi(getenv("ASN1_PARSER_FLAGS"));
+ if(getenv("ASN1_FIXER_FLAGS"))
+ fixer_flags = atoi(getenv("ASN1_FIXER_FLAGS"));
+
+ /*
+ * Go into a directory with tests.
+ */
+ if(ac <= 1) {
+ fprintf(stderr, "Testing in ./tests...\n");
+ ret = chdir("../tests");
+ assert(ret == 0);
+ dir = opendir(".");
+ assert(dir);
+ } else {
+ dir = 0;
+ }
+
+ /*
+ * Scan every *.asn1 file and try to parse and fix it.
+ */
+ if(dir) {
+ while((dp = readdir(dir))) {
+ int len = strlen(dp->d_name);
+ if(len && strcmp(dp->d_name + len - 5, ".asn1") == 0) {
+ ret = check(dp->d_name,
+ parser_flags, fixer_flags);
+ if(ret) {
+ fprintf(stderr,
+ "FAILED: %s\n",
+ dp->d_name);
+ failed++;
+ }
+ completed++;
+ }
+ }
+ closedir(dir);
+
+ fprintf(stderr,
+ "Tests COMPLETED: %d\n"
+ "Tests FAILED: %d\n"
+ ,
+ completed, failed
+ );
+ } else {
+ int i;
+ for(i = 1; i < ac; i++) {
+ ret = check(av[i], parser_flags, fixer_flags);
+ if(ret) {
+ fprintf(stderr, "FAILED: %s\n", av[i]);
+ failed++;
+ }
+ completed++;
+ }
+ }
+
+ if(completed == 0) {
+ fprintf(stderr, "No tests defined?!\n");
+ exit(EX_NOINPUT);
+ }
+
+ if(failed)
+ exit(EX_DATAERR);
+ return 0;
+}
+
+static int
+check(const char *fname,
+ enum asn1p_flags parser_flags,
+ enum asn1f_flags fixer_flags) {
+ asn1p_t *asn;
+ int expected_parseable; /* Is it expected to be parseable? */
+ int expected_fix_code; /* What code a fixer must return */
+ int r_value = 0;
+
+ /*
+ * Figure out how the processing should go by inferring
+ * expectations from the file name.
+ */
+ if(strstr(fname, "-OK.")) {
+ expected_parseable = 1;
+ expected_fix_code = 0;
+ } else if(strstr(fname, "-NP.")) {
+ expected_parseable = 0;
+ expected_fix_code = 123; /* Does not matter */
+ } else if(strstr(fname, "-SE.")) {
+ expected_parseable = 1;
+ expected_fix_code = -1; /* Semantically incorrect */
+ } else if(strstr(fname, "-SW.")) {
+ expected_parseable = 1;
+ expected_fix_code = 1; /* Semantically suspicious */
+ } else {
+ fprintf(stderr, "%s: Invalid file name format\n", fname);
+ return -1;
+ }
+
+ fprintf(stderr, "[=> %s]\n", fname);
+
+ /*
+ * Perform low-level parsing.
+ */
+ if(!expected_parseable)
+ fprintf(stderr, "Expecting error...\n");
+ asn = asn1p_parse_file(fname, parser_flags);
+ if(asn == NULL) {
+ if(expected_parseable) {
+ fprintf(stderr, "Cannot parse file \"%s\"\n", fname);
+ r_value = -1;
+ } else {
+ fprintf(stderr,
+ "Previous error is EXPECTED, no worry\n");
+ }
+ } else if(!expected_parseable) {
+ fprintf(stderr,
+ "The file \"%s\" is not expected to be parseable, "
+ "yet parsing was successfull!\n", fname);
+ r_value = -1;
+ }
+
+ /*
+ * Perform semantical checks and fixes.
+ */
+ if(asn && r_value == 0) {
+ int ret;
+
+ if(expected_fix_code)
+ fprintf(stderr, "Expecting some problems...\n");
+
+ ret = asn1f_process(asn, fixer_flags, 0);
+ if(ret) {
+ if(ret == expected_fix_code) {
+ fprintf(stderr,
+ "Previous error is EXPECTED, "
+ "no worry\n");
+ } else {
+ fprintf(stderr,
+ "Cannot process file \"%s\": %d\n",
+ fname, ret);
+ r_value = -1;
+ }
+ } else if(ret != expected_fix_code) {
+ fprintf(stderr,
+ "File \"%s\" is expected "
+ "to be semantically incorrect, "
+ "yet processing was successful!\n",
+ fname);
+ r_value = -1;
+ }
+ }
+
+ /*
+ * Check validity of some values, if grammar has special
+ * instructions for that.
+ */
+ if(asn && r_value == 0) {
+ if(post_fix_check(asn))
+ r_value = -1;
+ }
+
+ /*
+ * TODO: destroy the asn.
+ */
+
+ return r_value;
+}
+
+
+static int
+post_fix_check(asn1p_t *asn) {
+ asn1p_module_t *mod;
+ asn1p_expr_t *expr;
+ int r_value = 0;
+
+ TQ_FOR(mod, &(asn->modules), mod_next) {
+ TQ_FOR(expr, &(mod->members), next) {
+ assert(expr->Identifier);
+ if(strncmp(expr->Identifier, "check-", 6) == 0) {
+ if(post_fix_check_element(mod, expr))
+ r_value = -1;
+ }
+ }
+ }
+
+ return r_value;
+}
+
+
+static int
+post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) {
+ asn1p_expr_t *expr = NULL;
+ char *name;
+ asn1p_value_t *value;
+
+ if(check_expr->expr_type != ASN_BASIC_INTEGER
+ || check_expr->meta_type != AMT_VALUE) {
+ fprintf(stderr,
+ "CHECKER: Unsupported type of \"%s\" value: "
+ "%d at line %d of %s\n",
+ check_expr->Identifier,
+ check_expr->expr_type,
+ check_expr->_lineno,
+ mod->source_file_name
+ );
+ return -1;
+ }
+
+ assert(check_expr->meta_type == AMT_VALUE);
+
+ value = check_expr->value;
+ if(value == NULL || value->type != ATV_INTEGER) {
+ fprintf(stderr,
+ "CHECKER: Unsupported value type of \"%s\": "
+ "%d at line %d of %s\n",
+ check_expr->Identifier,
+ value?value->type:-1,
+ expr->_lineno,
+ mod->source_file_name
+ );
+ return -1;
+ }
+
+ name = check_expr->Identifier + sizeof("check-") - 1;
+
+ /*
+ * Scan in search for the original.
+ */
+ TQ_FOR(expr, &(mod->members), next) {
+ if(strcmp(expr->Identifier, name) == 0)
+ break;
+ }
+
+ if(expr == NULL) {
+ fprintf(stderr,
+ "CHECKER: Value \"%s\" requested by "
+ "\"check-%s\" at line %d of %s is not found!\n",
+ name, name, check_expr->_lineno,
+ mod->source_file_name
+ );
+ return -1;
+ }
+
+ if(0 && expr->expr_type != check_expr->expr_type) {
+ fprintf(stderr,
+ "CHECKER: Value type of \"%s\" (=%d) at line %d "
+ "does not have desired type %d as requested by "
+ "\"check-%s\" in %s\n",
+ expr->Identifier,
+ expr->expr_type,
+ expr->_lineno,
+ check_expr->expr_type,
+ name,
+ mod->source_file_name
+ );
+ return -1;
+ }
+
+ if(expr->value == NULL
+ || expr->value->type != value->type) {
+ fprintf(stderr,
+ "CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d "
+ "does not have desired type %d as requested by "
+ "\"check-%s\" in %s\n",
+ expr->Identifier,
+ asn1f_printable_value(expr->value),
+ expr->value->type,
+ expr->_lineno,
+ value->type,
+ name,
+ mod->source_file_name
+ );
+ return -1;
+ }
+
+ assert(value->type = ATV_INTEGER);
+
+ return 0;
+}
+
+