introduce generic encoder
diff --git a/skeletons/Makefile.am b/skeletons/Makefile.am
index d61c66c..4427360 100644
--- a/skeletons/Makefile.am
+++ b/skeletons/Makefile.am
@@ -59,7 +59,8 @@
 	VisibleString.c VisibleString.h			\
 	asn_SEQUENCE_OF.c asn_SEQUENCE_OF.h		\
 	asn_SET_OF.c asn_SET_OF.h			\
-	asn_application.h asn_codecs.h			\
+	asn_application.c asn_application.h			\
+	asn_codecs.h			\
 	asn_codecs_prim.c asn_codecs_prim.h		\
 	asn_internal.h asn_system.h			\
 	asn_bit_data.c asn_bit_data.h			\
@@ -88,3 +89,9 @@
 	xer_encoder.c xer_encoder.h			\
 	xer_support.c xer_support.h
 
+check_PROGRAMS = check-converter_sample
+LDADD = -lm
+
+check_converter_sample_CFLAGS = $(SKELETONS_CFLAGS) -DNO_ASN_PDU
+check_converter_sample_SOURCES = converter-sample.c
+check_converter_sample_LDADD = libasn1cskeletons.la
diff --git a/skeletons/asn_application.c b/skeletons/asn_application.c
new file mode 100644
index 0000000..60c8e78
--- /dev/null
+++ b/skeletons/asn_application.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <asn_application.h>
+#include <errno.h>
+
+static asn_enc_rval_t asn_encode_internal(
+    const asn_codec_ctx_t *opt_codec_parameters,
+    enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
+    void *sptr, asn_app_consume_bytes_f *callback, void *callback_key);
+
+
+struct callback_count_bytes_key {
+    asn_app_consume_bytes_f *callback;
+    void *callback_key;
+    size_t computed_size;
+};
+
+/*
+ * Encoder which just counts bytes that come through it.
+ */
+static int
+callback_count_bytes_cb(const void *data, size_t size, void *keyp) {
+    struct callback_count_bytes_key *key = keyp;
+    int ret;
+
+    ret = key->callback(data, size, key->callback_key);
+    if(ret >= 0) {
+        key->computed_size += size;
+    }
+
+    return ret;
+}
+
+struct overrun_encoder_key {
+    void *buffer;
+    size_t buffer_size;
+    size_t computed_size;
+};
+
+struct callback_failure_catch_key {
+    asn_app_consume_bytes_f *callback;
+    void *callback_key;
+    int callback_failed;
+};
+
+/*
+ * Encoder which doesn't stop counting bytes
+ * even if it reaches the end of the buffer.
+ */
+static int
+overrun_encoder_cb(const void *data, size_t size, void *keyp) {
+    struct overrun_encoder_key *key = keyp;
+
+    if(key->computed_size + size > key->buffer_size) {
+        /*
+         * Avoid accident on the next call:
+         * stop adding bytes to the buffer.
+         */
+        key->buffer_size = 0;
+    } else {
+        memcpy((char *)key->buffer + key->computed_size, data, size);
+        key->computed_size += size;
+    }
+
+    return 0;
+}
+
+/*
+ * Encoder which help convert the application level encoder failure into EIO.
+ */
+static int
+callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
+    struct callback_failure_catch_key *key = keyp;
+    int ret;
+
+    ret = key->callback(data, size, key->callback_key);
+    if(ret < 0) {
+        key->callback_failed = 1;
+    }
+
+    return ret;
+}
+
+asn_enc_rval_t
+asn_encode(const asn_codec_ctx_t *opt_codec_parameters,
+           enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
+           void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
+    struct callback_failure_catch_key cb_key;
+    asn_enc_rval_t er;
+
+    if(!callback) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    cb_key.callback = callback;
+    cb_key.callback_key = callback_key;
+    cb_key.callback_failed = 0;
+
+    er = asn_encode_internal(opt_codec_parameters, syntax, td, sptr,
+                             callback_failure_catch_cb, &cb_key);
+    if(cb_key.callback_failed) {
+        assert(er.encoded == -1);
+        assert(errno == EBADF);
+        errno = EIO;
+    }
+
+    return er;
+}
+
+asn_enc_rval_t
+asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_parameters,
+                     enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
+                     void *sptr, void *buffer, size_t buffer_size) {
+    struct overrun_encoder_key buf_key;
+    asn_enc_rval_t er;
+
+    if(buffer_size > 0 && !buffer) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    buf_key.buffer = buffer;
+    buf_key.buffer_size = buffer_size;
+    buf_key.computed_size = 0;
+
+    er = asn_encode_internal(opt_codec_parameters, syntax, td, sptr,
+                             overrun_encoder_cb, &buf_key);
+
+    assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
+
+    return er;
+}
+
+static asn_enc_rval_t
+asn_encode_internal(const asn_codec_ctx_t *opt_codec_parameters,
+                    enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
+                    void *sptr, asn_app_consume_bytes_f *callback,
+                    void *callback_key) {
+    asn_enc_rval_t er;
+    enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
+
+    (void)opt_codec_parameters; /* Parameters are not checked on encode yet. */
+
+    if(!td || !sptr) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    switch(syntax) {
+    case ATS_BER:
+        /* BER is a superset of DER. */
+        /* Fall through. */
+    case ATS_DER:
+        if(td->op->der_encoder) {
+            er = der_encode(td, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->der_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* DER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+    case ATS_CER:
+        errno = ENOENT; /* Transfer syntax is not defined for any type. */
+        ASN__ENCODE_FAILED;
+
+#ifdef  ASN_DISABLE_OER_SUPPORT
+    case ATS_BASIC_OER:
+    case ATS_CANONICAL_OER:
+        errno = ENOENT; /* PER is not defined. */
+        ASN__ENCODE_FAILED;
+        break;
+#else /* ASN_DISABLE_OER_SUPPORT */
+    case ATS_BASIC_OER:
+        /* CANONICAL-OER is a superset of BASIC-OER. */
+        /* Fall through. */
+    case ATS_CANONICAL_OER:
+        if(td->op->oer_encoder) {
+            er = oer_encode(td, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->oer_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* OER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+#endif /* ASN_DISABLE_OER_SUPPORT */
+
+#ifdef  ASN_DISABLE_PER_SUPPORT
+    case ATS_UNALIGNED_BASIC_PER:
+    case ATS_UNALIGNED_CANONICAL_PER:
+        errno = ENOENT; /* PER is not defined. */
+        ASN__ENCODE_FAILED;
+        break;
+#else /* ASN_DISABLE_PER_SUPPORT */
+    case ATS_UNALIGNED_BASIC_PER:
+        /* CANONICAL-UPER is a superset of BASIC-UPER. */
+        /* Fall through. */
+    case ATS_UNALIGNED_CANONICAL_PER:
+        if(td->op->uper_encoder) {
+            er = uper_encode(td, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->uper_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* UPER is not defined for this type. */
+                }
+            } else {
+                ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
+                if(er.encoded == 0) {
+                    /* Enforce "Complete Encoding" of X.691 #11.1 */
+                    if(callback("\0", 1, callback_key) < 0) {
+                        errno = EBADF;
+                        ASN__ENCODE_FAILED;
+                    }
+                    er.encoded = 8; /* Exactly 8 zero bits is added. */
+                }
+                /* Convert bits into bytes */
+                er.encoded = (er.encoded + 7) >> 3;
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+    case ATS_BASIC_XER:
+        /* CANONICAL-XER is a superset of BASIC-XER. */
+        xer_flags &= ~XER_F_CANONICAL;
+        xer_flags |= XER_F_BASIC;
+        /* Fall through. */
+    case ATS_CANONICAL_XER:
+        if(td->op->xer_encoder) {
+            er = xer_encode(td, sptr, xer_flags, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->xer_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* XER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+
+    case ATS_NONSTANDARD_PLAINTEXT:
+        if(td->op->print_struct) {
+            struct callback_count_bytes_key cb_key;
+            cb_key.callback = callback;
+            cb_key.callback_key = callback_key;
+            cb_key.computed_size = 0;
+            if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
+                                    &cb_key)
+                   < 0
+               || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
+                errno = EBADF; /* Structure has incorrect form. */
+                er.encoded = -1;
+                er.failed_type = td;
+                er.structure_ptr = sptr;
+            } else {
+                er.encoded = cb_key.computed_size;
+                er.failed_type = 0;
+                er.structure_ptr = 0;
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+
+    default:
+        errno = ENOENT;
+        ASN__ENCODE_FAILED;
+    }
+
+    return er;
+}
diff --git a/skeletons/asn_application.h b/skeletons/asn_application.h
index 71e9ba6..0a24018 100644
--- a/skeletons/asn_application.h
+++ b/skeletons/asn_application.h
@@ -16,14 +16,101 @@
 #endif
 
 /*
+ * A selection of ASN.1 Transfer Syntaxes to use with generalized
+ * encoder and decoders declared further in this .h file.
+ */
+enum asn_transfer_syntax {
+    /* Avoid appearance of a default transfer syntax. */
+    ATS_INVALID = 0,
+    /* Plaintext output, useful for debugging. */
+    ATS_NONSTANDARD_PLAINTEXT,
+    /*
+     * X.690:
+     * BER: Basic Encoding Rules.
+     * DER: Distinguished Encoding Rules.
+     * CER: Canonical Encoding Rules.
+     * DER and CER are more strict variants of BER.
+     */
+    ATS_BER,
+    ATS_DER,
+    ATS_CER, /* Only decoding is supported */
+    /*
+     * X.696:
+     * OER: Octet Encoding Rules.
+     * CANONICAL-OER is a more strict variant of BASIC-OER.
+     */
+    ATS_BASIC_OER,
+    ATS_CANONICAL_OER,
+    /*
+     * X.691:
+     * PER: Packed Encoding Rules.
+     * CANONICAL-PER is a more strict variant of BASIC-PER.
+     * NOTE: Produces or consumes a complete encoding (X.691 (08/2015) #11.1).
+     */
+    ATS_UNALIGNED_BASIC_PER,
+    ATS_UNALIGNED_CANONICAL_PER,
+    /*
+     * X.693:
+     * XER: XML Encoding Rules.
+     * CANONICAL-XER is a more strict variant of BASIC-XER.
+     */
+    ATS_BASIC_XER,
+    ATS_CANONICAL_XER,
+};
+
+/*
+ * A generic encoder for any supported transfer syntax.
+ * RETURN VALUES:
+ * The (.encoded) field of the return value is REDEFINED to mean the following:
+ * >=0: The computed size of the encoded data. Can exceed the (buffer_size).
+ *  -1: Error encoding the structure. See the error code in (errno):
+ *      EINVAL: Incorrect parameters to the function, such as NULLs.
+ *      ENOENT: Encoding transfer syntax is not defined (for this type).
+ *      EBADF:  The structure has invalid form or content constraint failed.
+ *      The (.failed_type) and (.structure_ptr) MIGHT be set to the appropriate
+ *      values at the place of failure, if at all possible.
+ * WARNING: The (.encoded) field of the return value can exceed the buffer_size.
+ * This is similar to snprintf(3) contract which might return values
+ * greater than the buffer size.
+ */
+asn_enc_rval_t asn_encode_to_buffer(
+    const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */
+    enum asn_transfer_syntax,
+    struct asn_TYPE_descriptor_s *type_to_encode,
+    void *structure_to_encode,
+    void *buffer, size_t buffer_size);
+
+
+/*
  * Generic type of an application-defined callback to return various
  * types of data to the application.
  * EXPECTED RETURN VALUES:
  *  -1: Failed to consume bytes. Abort the mission.
  * Non-negative return values indicate success, and ignored.
  */
-typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size,
-	void *application_specific_key);
+typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size,
+                                     void *application_specific_key);
+
+
+/*
+ * A generic encoder for any supported transfer syntax.
+ * Returns the comprehensive encoding result descriptor (see asn_codecs.h).
+ * RETURN VALUES:
+ * The negative (.encoded) field of the return values is accompanied with the
+ * following error codes (errno):
+ *      EINVAL: Incorrect parameters to the function, such as NULLs.
+ *      ENOENT: Encoding transfer syntax is not defined (for this type).
+ *      EBADF:  The structure has invalid form or content constraint failed.
+ *      EIO:    The (callback) has returned negative value during encoding.
+ */
+asn_enc_rval_t asn_encode(
+    const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */
+    enum asn_transfer_syntax,
+    struct asn_TYPE_descriptor_s *type_to_encode,
+    void *structure_to_encode,
+    asn_app_consume_bytes_f *callback, void *callback_key);
+
+
 
 /*
  * A callback of this type is called whenever constraint validation fails
@@ -38,6 +125,7 @@
 	const void *structure_which_failed_ptr,
 	const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5);
 
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/skeletons/converter-sample.c b/skeletons/converter-sample.c
index 8ec45f2..bbf276c 100644
--- a/skeletons/converter-sample.c
+++ b/skeletons/converter-sample.c
@@ -22,20 +22,31 @@
 #include <asn_internal.h>    /* for ASN__DEFAULT_STACK_MAX */
 
 /* Convert "Type" defined by -DPDU into "asn_DEF_Type" */
+
+#ifndef NO_ASN_PDU
+#ifndef PDU
+#error Define -DPDU to compile this sample converter.
+#endif
+#ifdef    ASN_PDU_COLLECTION        /* Generated by asn1c: -pdu=... */
+extern asn_TYPE_descriptor_t *asn_pdu_collection[];
+#endif
 #define    ASN_DEF_PDU(t)    asn_DEF_ ## t
 #define    DEF_PDU_Type(t)    ASN_DEF_PDU(t)
 #define    PDU_Type    DEF_PDU_Type(PDU)
 
 extern asn_TYPE_descriptor_t PDU_Type;    /* ASN.1 type to be decoded */
-#ifdef    ASN_PDU_COLLECTION        /* Generated by asn1c: -pdu=... */
-extern asn_TYPE_descriptor_t *asn_pdu_collection[];
-#endif
+#define PDU_Type_Ptr (&PDU_Type)
+#else   /* NO_ASN_PDU */
+#define PDU_Type_Ptr    NULL
+#endif  /* NO_ASN_PDU */
 
 /*
  * Open file and parse its contens.
  */
-static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
-    FILE *file, const char *name, ssize_t suggested_bufsize, int first_pdu);
+static void *data_decode_from_file(enum asn_transfer_syntax,
+                                   asn_TYPE_descriptor_t *asnTypeOfPDU,
+                                   FILE *file, const char *name,
+                                   ssize_t suggested_bufsize, int first_pdu);
 static int write_out(const void *buffer, size_t size, void *key);
 static FILE *argument_to_file(char *av[], int idx);
 static char *argument_to_name(char *av[], int idx);
@@ -46,24 +57,6 @@
 static int opt_nopad;    /* -per-nopad (PER input is not padded) */
 static int opt_onepdu;    /* -1 (decode single PDU) */
 
-/* Input data format selector */
-static enum input_format {
-    INP_BER,    /* -iber: BER input */
-    INP_XER,    /* -ixer: XER input */
-    INP_OER,    /* -ioer: OER input */
-    INP_PER        /* -iper: Unaligned PER input */
-} iform;    /* -i<format> */
-
-/* Output data format selector */
-static enum output_format {
-    OUT_XER,    /* -oxer: XER (XML) output */
-    OUT_DER,    /* -oder: DER (BER) output */
-    OUT_OER,    /* -ooer: Canonical OER output */
-    OUT_PER,    /* -oper: Unaligned PER output */
-    OUT_TEXT,    /* -otext: semi-structured text */
-    OUT_NULL    /* -onull: No pretty-printing */
-} oform;    /* -o<format> */
-
 #ifdef    JUNKTEST        /* Enable -J <probability> */
 #define    JUNKOPT    "J:"
 static double opt_jprob;    /* Junk bit probability */
@@ -85,20 +78,60 @@
     fprintf(stderr, "\n");
 }
 
+static const char *
+ats_simple_name(enum asn_transfer_syntax syntax) {
+    switch(syntax) {
+    case ATS_INVALID:
+        return "/dev/null";
+    case ATS_NONSTANDARD_PLAINTEXT:
+        return "plaintext";
+    case ATS_BER:
+        return "BER";
+    case ATS_DER:
+        return "DER";
+    case ATS_CER:
+        return "CER";
+    case ATS_BASIC_OER:
+    case ATS_CANONICAL_OER:
+        return "OER";
+    case ATS_BASIC_XER:
+    case ATS_CANONICAL_XER:
+        return "XER";
+    case ATS_UNALIGNED_BASIC_PER:
+    case ATS_UNALIGNED_CANONICAL_PER:
+        return "PER";
+    default:
+        return "<?>";
+    }
+}
+
 int
 main(int ac, char *av[]) {
     FILE *binary_out;
-    static asn_TYPE_descriptor_t *pduType = &PDU_Type;
+    static asn_TYPE_descriptor_t *pduType = PDU_Type_Ptr;
     ssize_t suggested_bufsize = 8192;  /* close or equal to stdio buffer */
     int number_of_iterations = 1;
     int num;
     int ch;
+    enum asn_transfer_syntax isyntax = ATS_INVALID;
+    enum asn_transfer_syntax osyntax = ATS_INVALID;
+
+#ifndef  PDU
+    if(!pduType) {
+        fprintf(stderr, "No -DPDU defined during compilation.\n");
+#ifdef  NO_ASN_PDU
+        exit(0);
+#else
+        exit(EX_SOFTWARE);
+#endif
+    }
+#endif
 
     /* Figure out if specialty decoder needs to be default */
     if(pduType->op->oer_decoder)
-        iform = INP_OER;
+        isyntax = ATS_BASIC_OER;
     else if(pduType->op->uper_decoder)
-        iform = INP_PER;
+        isyntax = ATS_UNALIGNED_BASIC_PER;
 
     /*
      * Pocess the command-line argments.
@@ -106,24 +139,24 @@
     while((ch = getopt(ac, av, "i:o:1b:cdn:p:hs:" JUNKOPT)) != -1)
     switch(ch) {
     case 'i':
-        if(optarg[0] == 'b') { iform = INP_BER; break; }
-        if(optarg[0] == 'x') { iform = INP_XER; break; }
+        if(optarg[0] == 'b') { isyntax = ATS_BER; break; }
+        if(optarg[0] == 'x') { isyntax = ATS_BASIC_XER; break; }
         if(pduType->op->oer_decoder
-        && optarg[0] == 'o') { iform = INP_OER; break; }
+        && optarg[0] == 'o') { isyntax = ATS_BASIC_OER; break; }
         if(pduType->op->uper_decoder
-        && optarg[0] == 'p') { iform = INP_PER; break; }
+        && optarg[0] == 'p') { isyntax = ATS_UNALIGNED_BASIC_PER; break; }
         fprintf(stderr, "-i<format>: '%s': improper format selector\n",
             optarg);
         exit(EX_UNAVAILABLE);
     case 'o':
-        if(optarg[0] == 'd') { oform = OUT_DER; break; }
+        if(optarg[0] == 'd') { osyntax = ATS_DER; break; }
         if(pduType->op->oer_encoder
-        && optarg[0] == 'o') { oform = OUT_OER; break; }
+        && optarg[0] == 'o') { osyntax = ATS_CANONICAL_OER; break; }
         if(pduType->op->uper_encoder
-        && optarg[0] == 'p') { oform = OUT_PER; break; }
-        if(optarg[0] == 'x') { oform = OUT_XER; break; }
-        if(optarg[0] == 't') { oform = OUT_TEXT; break; }
-        if(optarg[0] == 'n') { oform = OUT_NULL; break; }
+        && optarg[0] == 'p') { osyntax = ATS_UNALIGNED_CANONICAL_PER; break; }
+        if(optarg[0] == 'x') { osyntax = ATS_BASIC_XER; break; }
+        if(optarg[0] == 't') { osyntax = ATS_NONSTANDARD_PLAINTEXT; break; }
+        if(optarg[0] == 'n') { osyntax = ATS_INVALID; break; }
         fprintf(stderr, "-o<format>: '%s': improper format selector\n",
             optarg);
         exit(EX_UNAVAILABLE);
@@ -219,14 +252,14 @@
         if(pduType->op->oer_decoder)
         fprintf(stderr,
         "  -ioer        Input is in OER (Octet Encoding Rules)%s\n",
-            iform == INP_OER ? " (DEFAULT)" : "");
+            isyntax == ATS_BASIC_OER ? " (DEFAULT)" : "");
         if(pduType->op->uper_decoder)
         fprintf(stderr,
         "  -iper        Input is in Unaligned PER (Packed Encoding Rules)%s\n",
-            iform == INP_PER ? " (DEFAULT)" : "");
+            isyntax == ATS_UNALIGNED_BASIC_PER ? " (DEFAULT)" : "");
         fprintf(stderr,
         "  -iber        Input is in BER (Basic Encoding Rules)%s\n",
-            iform == INP_BER ? " (DEFAULT)" : "");
+            isyntax == ATS_BER ? " (DEFAULT)" : "");
         fprintf(stderr,
         "  -ixer        Input is in XER (XML Encoding Rules)\n");
         if(pduType->op->oer_encoder)
@@ -273,7 +306,7 @@
     }
 
     if(isatty(1)) {
-        const int is_text_output = oform == OUT_TEXT || oform == OUT_XER;
+        const int is_text_output = osyntax == ATS_NONSTANDARD_PLAINTEXT || osyntax == ATS_CANONICAL_XER || osyntax == ATS_BASIC_XER;
         if(is_text_output) {
             binary_out = stdout;
         } else {
@@ -301,11 +334,11 @@
         char *name = argument_to_name(av, ac_i);
         int first_pdu;
 
-        for(first_pdu = 1; first_pdu || !opt_onepdu; first_pdu = 0) {
+        for(first_pdu = 1; file && (first_pdu || !opt_onepdu); first_pdu = 0) {
             /*
              * Decode the encoded structure from file.
              */
-            structure = data_decode_from_file(pduType, file, name,
+            structure = data_decode_from_file(isyntax, pduType, file, name,
                                               suggested_bufsize, first_pdu);
             if(!structure) {
                 if(errno) {
@@ -330,59 +363,24 @@
                 }
             }
 
-            switch(oform) {
-            case OUT_NULL:
+            if(osyntax == ATS_INVALID) {
 #ifdef JUNKTEST
-                if(opt_jprob == 0.0)
-#endif
+                if(opt_jprob == 0.0) {
                     fprintf(stderr, "%s: decoded successfully\n", name);
-                break;
-            case OUT_TEXT: /* -otext */
-                asn_fprint(stdout, pduType, structure);
-                break;
-            case OUT_XER: /* -oxer */
-                if(xer_fprint(stdout, pduType, structure)) {
-                    fprintf(stderr, "%s: Cannot convert %s into XML\n", name,
-                            pduType->name);
-                    exit(EX_UNAVAILABLE);
                 }
-                break;
-            case OUT_DER:
-                erv = der_encode(pduType, structure, write_out, binary_out);
-                if(erv.encoded < 0) {
-                    fprintf(stderr, "%s: Cannot convert %s into DER\n", name,
-                            pduType->name);
-                    exit(EX_UNAVAILABLE);
-                }
-                DEBUG("Encoded in %ld bytes of DER", (long)erv.encoded);
-                break;
-            case OUT_OER:
-#ifdef  ASN_DISABLE_OER_SUPPORT
-                erv.encoded = -1;
 #else
-                erv = oer_encode(pduType, structure, write_out, binary_out);
+                fprintf(stderr, "%s: decoded successfully\n", name);
 #endif
-                if(erv.encoded < 0) {
-                    fprintf(stderr, "%s: Cannot convert %s into OER\n", name,
-                            pduType->name);
+            } else {
+                erv = asn_encode(NULL, osyntax, pduType, structure, write_out, binary_out);
+
+                if(erv.encoded == -1) {
+                    fprintf(stderr, "%s: Cannot convert %s into %s\n", name,
+                            pduType->name, ats_simple_name(osyntax));
                     exit(EX_UNAVAILABLE);
                 }
-                DEBUG("Encoded in %ld bytes of OER", (long)erv.encoded);
-                break;
-            case OUT_PER:
-#ifdef  ASN_DISABLE_PER_SUPPORT
-                erv.encoded = -1;
-#else
-                erv = uper_encode(pduType, structure, write_out, binary_out);
-#endif
-                if(erv.encoded < 0) {
-                    fprintf(stderr,
-                            "%s: Cannot convert %s into Unaligned PER\n", name,
-                            pduType->name);
-                    exit(EX_UNAVAILABLE);
-                }
-                DEBUG("Encoded in %ld bits of UPER", (long)erv.encoded);
-                break;
+                DEBUG("Encoded in %zd bytes of %s", erv.encoded,
+                      ats_simple_name(osyntax));
             }
 
             ASN_STRUCT_FREE(*pduType, structure);
@@ -610,7 +608,7 @@
 }
 
 static void *
-data_decode_from_file(asn_TYPE_descriptor_t *pduType, FILE *file, const char *name, ssize_t suggested_bufsize, int on_first_pdu) {
+data_decode_from_file(enum asn_transfer_syntax isyntax, asn_TYPE_descriptor_t *pduType, FILE *file, const char *name, ssize_t suggested_bufsize, int on_first_pdu) {
     static uint8_t *fbuf;
     static ssize_t fbuf_size;
     static asn_codec_ctx_t s_codec_ctx;
@@ -688,12 +686,12 @@
         junk_bytes_with_probability(i_bptr, i_size, opt_jprob);
 #endif
 
-        switch(iform) {
-        case INP_BER:
+        switch(isyntax) {
+        case ATS_BER:
             rval = ber_decode(opt_codec_ctx, pduType,
                 (void **)&structure, i_bptr, i_size);
             break;
-        case INP_OER:
+        case ATS_BASIC_OER:
 #ifdef ASN_DISABLE_OER_SUPPORT
             rval.code = RC_FAIL;
             rval.consumed = 0;
@@ -702,11 +700,11 @@
                 (void **)&structure, i_bptr, i_size);
 #endif
             break;
-        case INP_XER:
+        case ATS_BASIC_XER:
             rval = xer_decode(opt_codec_ctx, pduType,
                 (void **)&structure, i_bptr, i_size);
             break;
-        case INP_PER:
+        case ATS_UNALIGNED_BASIC_PER:
 #ifdef ASN_DISABLE_PER_SUPPORT
             rval.code = RC_FAIL;
             rval.consumed = 0;
@@ -740,6 +738,9 @@
                 break;
             }
             break;
+        default:
+            rval.consumed = 0;
+            /* Fall through */
         }
         DEBUG("decode(%ld) consumed %ld+%db (%ld), code %d",
             (long)DynamicBuffer.length,
@@ -804,7 +805,7 @@
      */
     if(on_first_pdu
     || DynamicBuffer.length
-    || new_offset - old_offset > ((iform == INP_XER)?sizeof("\r\n")-1:0)
+    || new_offset - old_offset > ((isyntax == ATS_BASIC_XER)?sizeof("\r\n")-1:0)
     ) {
 
 #ifdef    JUNKTEST
diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies
index 8814d68..e13e7d1 100644
--- a/skeletons/file-dependencies
+++ b/skeletons/file-dependencies
@@ -41,7 +41,7 @@
 constr_SET_OF.h constr_SET_OF.c asn_SET_OF.h
 
 COMMON-FILES:			# THIS IS A SPECIAL SECTION
-asn_application.h		# Applications should include this file
+asn_application.h asn_application.c		# Applications should include this file
 asn_ioc.h			# Information Object Classes, runtime support
 asn_system.h			# Platform-dependent types
 asn_codecs.h			# Return types of encoders and decoders
diff --git a/skeletons/per_decoder.h b/skeletons/per_decoder.h
index 803341a..0a50705 100644
--- a/skeletons/per_decoder.h
+++ b/skeletons/per_decoder.h
@@ -15,8 +15,8 @@
 struct asn_TYPE_descriptor_s;	/* Forward declaration */
 
 /*
- * Unaligned PER decoder of a "complete encoding" as per X.691#10.1.
- * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3.
+ * Unaligned PER decoder of a "complete encoding" as per X.691 (08/2015) #11.1.
+ * On success, this call always returns (.consumed >= 1), as per #11.1.3.
  */
 asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx,
 	struct asn_TYPE_descriptor_s *type_descriptor,	/* Type to decode */