generic asn_decoder
diff --git a/skeletons/asn_application.c b/skeletons/asn_application.c
index 60c8e78..d7a2bcb 100644
--- a/skeletons/asn_application.c
+++ b/skeletons/asn_application.c
@@ -292,3 +292,51 @@
 
     return er;
 }
+
+asn_dec_rval_t
+asn_decode(const asn_codec_ctx_t *opt_codec_parameters,
+           enum asn_transfer_syntax syntax, struct asn_TYPE_descriptor_s *td,
+           void **sptr, const void *buffer, size_t size) {
+
+    (void)opt_codec_parameters;
+    asn_codec_ctx_t *opt_ctx = 0;
+
+    if(!td || !sptr || (size && !buffer)) {
+        ASN__DECODE_FAILED;
+    }
+
+    switch(syntax) {
+    case ATS_CER:
+    case ATS_NONSTANDARD_PLAINTEXT:
+    default:
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+
+    case ATS_DER:
+    case ATS_BER:
+        return ber_decode(opt_ctx, td, sptr, buffer, size);
+
+    case ATS_BASIC_OER:
+    case ATS_CANONICAL_OER:
+#ifdef  ASN_DISABLE_OER_SUPPORT
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+#else
+        return oer_decode(opt_ctx, td, sptr, buffer, size);
+#endif
+
+    case ATS_UNALIGNED_BASIC_PER:
+    case ATS_UNALIGNED_CANONICAL_PER:
+#ifdef  ASN_DISABLE_PER_SUPPORT
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+#else
+        return uper_decode_complete(opt_ctx, td, sptr, buffer, size);
+#endif
+
+    case ATS_BASIC_XER:
+    case ATS_CANONICAL_XER:
+        return xer_decode(opt_ctx, td, sptr, buffer, size);
+    }
+}
+
diff --git a/skeletons/asn_application.h b/skeletons/asn_application.h
index 0a24018..5fea20c 100644
--- a/skeletons/asn_application.h
+++ b/skeletons/asn_application.h
@@ -111,6 +111,17 @@
     asn_app_consume_bytes_f *callback, void *callback_key);
 
 
+/*
+ * A generic decoder for any supported transfer syntax.
+ */
+asn_dec_rval_t asn_decode(
+    const asn_codec_ctx_t *opt_codec_parameters, enum asn_transfer_syntax,
+    struct asn_TYPE_descriptor_s *type_to_decode,
+    void **structure_ptr, /* Pointer to a target structure's pointer */
+    const void *buffer,   /* Data to be decoded */
+    size_t size           /* Size of that buffer */
+    );
+
 
 /*
  * A callback of this type is called whenever constraint validation fails
diff --git a/skeletons/converter-sample.c b/skeletons/converter-sample.c
index 81200aa..c95b0d0 100644
--- a/skeletons/converter-sample.c
+++ b/skeletons/converter-sample.c
@@ -54,7 +54,6 @@
        int opt_debug;    /* -d (or -dd) */
 static int opt_check;    /* -c (constraints checking) */
 static int opt_stack;    /* -s (maximum stack size) */
-static int opt_nopad;    /* -per-nopad (PER input is not padded) */
 static int opt_onepdu;    /* -1 (decode single PDU) */
 
 #ifdef    JUNKTEST        /* Enable -J <probability> */
@@ -242,10 +241,6 @@
         }
         break;
     case 'p':
-        if(strcmp(optarg, "er-nopad") == 0) {
-            opt_nopad = 1;
-            break;
-        }
 #ifdef    ASN_PDU_COLLECTION
         if(strcmp(optarg, "list") == 0) {
             asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
@@ -318,9 +313,6 @@
                         (sel->syntax == osyntax) ? " (DEFAULT)" : "");
             }
         }
-        if(pduType->op->uper_decoder)
-        fprintf(stderr,
-        "  -per-nopad   Assume PER PDUs are not padded (-iper)\n");
 #ifdef    ASN_PDU_COLLECTION
         fprintf(stderr,
         "  -p <PDU>     Specify PDU type to decode\n"
@@ -655,6 +647,12 @@
         (long)DynamicBuffer.allocated);
 }
 
+static int
+restartability_supported(enum asn_transfer_syntax syntax) {
+    return (syntax != ATS_UNALIGNED_BASIC_PER
+            && syntax != ATS_UNALIGNED_CANONICAL_PER);
+}
+
 static void *
 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;
@@ -734,66 +732,16 @@
         junk_bytes_with_probability(i_bptr, i_size, opt_jprob);
 #endif
 
-        switch(isyntax) {
-        case ATS_BER:
-        case ATS_DER:
-            rval = ber_decode(opt_codec_ctx, pduType,
-                (void **)&structure, i_bptr, i_size);
-            break;
-        case ATS_BASIC_OER:
-        case ATS_CANONICAL_OER:
-#ifdef ASN_DISABLE_OER_SUPPORT
-            rval.code = RC_FAIL;
+        rval = asn_decode(opt_codec_ctx, isyntax, pduType, (void **)&structure,
+                          i_bptr, i_size);
+        if(rval.code == RC_WMORE && !restartability_supported(isyntax)) {
+            /* PER does not support restartability */
+            ASN_STRUCT_FREE(*pduType, structure);
+            structure = 0;
             rval.consumed = 0;
-#else
-            rval = oer_decode(opt_codec_ctx, pduType,
-                (void **)&structure, i_bptr, i_size);
-#endif
-            break;
-        case ATS_BASIC_XER:
-        case ATS_CANONICAL_XER:
-            rval = xer_decode(opt_codec_ctx, pduType,
-                (void **)&structure, i_bptr, i_size);
-            break;
-        case ATS_UNALIGNED_BASIC_PER:
-        case ATS_UNALIGNED_CANONICAL_PER:
-#ifdef ASN_DISABLE_PER_SUPPORT
-            rval.code = RC_FAIL;
-            rval.consumed = 0;
-#else
-            if(opt_nopad)
-            rval = uper_decode(opt_codec_ctx, pduType,
-                (void **)&structure, i_bptr, i_size, 0,
-                DynamicBuffer.unbits);
-            else
-            rval = uper_decode_complete(opt_codec_ctx, pduType,
-                (void **)&structure, i_bptr, i_size);
-#endif
-            switch(rval.code) {
-            case RC_OK:
-                /* Fall through */
-            case RC_FAIL:
-                if(opt_nopad) {
-                    /* uper_decode() returns bits! */
-                    /* Extra bits */
-                    ecbits = rval.consumed % 8;
-                    /* Convert into bytes! */
-                    rval.consumed /= 8;
-                }
-                break;
-            case RC_WMORE:
-                /* PER does not support restartability */
-                ASN_STRUCT_FREE(*pduType, structure);
-                structure = 0;
-                rval.consumed = 0;
-                /* Continue accumulating data */
-                break;
-            }
-            break;
-        default:
-            rval.consumed = 0;
-            /* Fall through */
+            /* Continue accumulating data */
         }
+
         DEBUG("decode(%ld) consumed %ld+%db (%ld), code %d",
             (long)DynamicBuffer.length,
             (long)rval.consumed, ecbits, (long)i_size,