blob: a1dc8f43d6aba0d7187fae8cdfe62348d998d563 [file] [log] [blame]
Lev Walkin22b54552004-10-28 13:22:54 +00001/*
Lev Walkind0625682006-08-25 02:35:08 +00002 * Generic converter template for a selected ASN.1 type.
Lev Walkind19216f2017-08-04 03:02:57 -07003 * Copyright (c) 2005-2017 Lev Walkin <vlm@lionet.info>.
Lev Walkin8a4a06c2007-06-29 12:44:01 +00004 * All rights reserved.
Lev Walkin22b54552004-10-28 13:22:54 +00005 *
Lev Walkin478819d2017-09-26 22:48:30 -07006 * To compile with your own ASN.1 type, redefine the PDU as shown:
Lev Walkin22b54552004-10-28 13:22:54 +00007 *
Lev Walkin478819d2017-09-26 22:48:30 -07008 * cc -DPDU=MyCustomType -o myDecoder.o -c converter-example.c
Lev Walkin22b54552004-10-28 13:22:54 +00009 */
Lev Walkinfb35e082017-08-04 03:06:51 -070010#ifdef HAVE_CONFIG_H
Lev Walkin22b54552004-10-28 13:22:54 +000011#include <config.h>
12#endif
13#include <stdio.h>
14#include <sys/types.h>
Lev Walkinfb35e082017-08-04 03:06:51 -070015#include <stdlib.h> /* for atoi(3) */
16#include <unistd.h> /* for getopt(3) */
17#include <string.h> /* for strerror(3) */
18#include <sysexits.h> /* for EX_* exit codes */
19#include <errno.h> /* for errno */
Lev Walkin22b54552004-10-28 13:22:54 +000020
Lev Walkin00949562005-03-10 13:39:03 +000021#include <asn_application.h>
Lev Walkinfb35e082017-08-04 03:06:51 -070022#include <asn_internal.h> /* for ASN__DEFAULT_STACK_MAX */
Lev Walkin22b54552004-10-28 13:22:54 +000023
Lev Walkind0625682006-08-25 02:35:08 +000024/* Convert "Type" defined by -DPDU into "asn_DEF_Type" */
Lev Walkin6d46bc32017-09-12 21:34:00 -070025
26#ifndef NO_ASN_PDU
27#ifndef PDU
28#error Define -DPDU to compile this sample converter.
29#endif
30#ifdef ASN_PDU_COLLECTION /* Generated by asn1c: -pdu=... */
31extern asn_TYPE_descriptor_t *asn_pdu_collection[];
32#endif
Lev Walkinfb35e082017-08-04 03:06:51 -070033#define ASN_DEF_PDU(t) asn_DEF_ ## t
34#define DEF_PDU_Type(t) ASN_DEF_PDU(t)
35#define PDU_Type DEF_PDU_Type(PDU)
Lev Walkind0625682006-08-25 02:35:08 +000036
Lev Walkinfb35e082017-08-04 03:06:51 -070037extern asn_TYPE_descriptor_t PDU_Type; /* ASN.1 type to be decoded */
Lev Walkin6d46bc32017-09-12 21:34:00 -070038#define PDU_Type_Ptr (&PDU_Type)
39#else /* NO_ASN_PDU */
40#define PDU_Type_Ptr NULL
41#endif /* NO_ASN_PDU */
Lev Walkin22b54552004-10-28 13:22:54 +000042
43/*
Lev Walkin00949562005-03-10 13:39:03 +000044 * Open file and parse its contens.
Lev Walkin22b54552004-10-28 13:22:54 +000045 */
Lev Walkin6d46bc32017-09-12 21:34:00 -070046static void *data_decode_from_file(enum asn_transfer_syntax,
47 asn_TYPE_descriptor_t *asnTypeOfPDU,
48 FILE *file, const char *name,
49 ssize_t suggested_bufsize, int first_pdu);
Lev Walkind1bfea62005-11-08 03:06:16 +000050static int write_out(const void *buffer, size_t size, void *key);
Lev Walkinc744a022006-09-15 18:33:25 +000051static FILE *argument_to_file(char *av[], int idx);
52static char *argument_to_name(char *av[], int idx);
Lev Walkin22b54552004-10-28 13:22:54 +000053
Lev Walkin0f77cea2017-09-13 00:28:20 -070054 int opt_debug; /* -d (or -dd) */
55static int opt_check; /* -c (constraints checking) */
56static int opt_stack; /* -s (maximum stack size) */
57static int opt_nopad; /* -per-nopad (PER input is not padded between msgs) */
58static int opt_onepdu; /* -1 (decode single PDU) */
Lev Walkind1bfea62005-11-08 03:06:16 +000059
Lev Walkinfb35e082017-08-04 03:06:51 -070060#ifdef JUNKTEST /* Enable -J <probability> */
61#define JUNKOPT "J:"
62static double opt_jprob; /* Junk bit probability */
Lev Walkin1f12da42006-09-24 19:47:07 +000063static int junk_failures;
64static void junk_bytes_with_probability(uint8_t *, size_t, double prob);
65#else
Lev Walkinfb35e082017-08-04 03:06:51 -070066#define JUNKOPT
Lev Walkin1f12da42006-09-24 19:47:07 +000067#endif
68
Lev Walkin1d9e8dd2005-12-07 05:46:03 +000069/* Debug output function */
Lev Walkineff98a52017-09-13 22:24:35 +000070static void
Lev Walkin1d9e8dd2005-12-07 05:46:03 +000071DEBUG(const char *fmt, ...) {
Lev Walkinfb35e082017-08-04 03:06:51 -070072 va_list ap;
73 if(!opt_debug) return;
74 fprintf(stderr, "AD: ");
75 va_start(ap, fmt);
76 vfprintf(stderr, fmt, ap);
77 va_end(ap);
78 fprintf(stderr, "\n");
Lev Walkin1d9e8dd2005-12-07 05:46:03 +000079}
Lev Walkin22b54552004-10-28 13:22:54 +000080
Lev Walkin6d46bc32017-09-12 21:34:00 -070081static const char *
82ats_simple_name(enum asn_transfer_syntax syntax) {
83 switch(syntax) {
84 case ATS_INVALID:
85 return "/dev/null";
86 case ATS_NONSTANDARD_PLAINTEXT:
87 return "plaintext";
88 case ATS_BER:
89 return "BER";
90 case ATS_DER:
91 return "DER";
92 case ATS_CER:
93 return "CER";
94 case ATS_BASIC_OER:
95 case ATS_CANONICAL_OER:
96 return "OER";
97 case ATS_BASIC_XER:
98 case ATS_CANONICAL_XER:
99 return "XER";
100 case ATS_UNALIGNED_BASIC_PER:
101 case ATS_UNALIGNED_CANONICAL_PER:
102 return "PER";
103 default:
104 return "<?>";
105 }
106}
107
Lev Walkin3b327a82017-09-18 22:19:03 -0700108#define CODEC_OFFSET(fname) ((ptrdiff_t)&(((asn_TYPE_operation_t *)0)->fname))
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700109typedef struct {
110 const char *name;
111 enum asn_transfer_syntax syntax;
Lev Walkin3b327a82017-09-18 22:19:03 -0700112 ptrdiff_t codec_offset;
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700113 const char *full_name;
114} syntax_selector;
115
116static syntax_selector input_encodings[] = {
Lev Walkin3b327a82017-09-18 22:19:03 -0700117 {"ber", ATS_BER, CODEC_OFFSET(ber_decoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700118 "Input is in BER (Basic Encoding Rules) or DER"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700119 {"oer", ATS_BASIC_OER, CODEC_OFFSET(oer_decoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700120 "Input is in OER (Octet Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700121 {"per", ATS_UNALIGNED_BASIC_PER, CODEC_OFFSET(uper_decoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700122 "Input is in Unaligned PER (Packed Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700123 {"xer", ATS_BASIC_XER, CODEC_OFFSET(xer_decoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700124 "Input is in XER (XML Encoding Rules)"},
125 {0, ATS_INVALID, 0, 0}};
126
127static syntax_selector output_encodings[] = {
Lev Walkin3b327a82017-09-18 22:19:03 -0700128 {"der", ATS_DER, CODEC_OFFSET(der_encoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700129 "Output as DER (Distinguished Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700130 {"oer", ATS_CANONICAL_OER, CODEC_OFFSET(oer_encoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700131 "Output as Canonical OER (Octet Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700132 {"per", ATS_UNALIGNED_CANONICAL_PER, CODEC_OFFSET(uper_encoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700133 "Output as Unaligned PER (Packed Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700134 {"xer", ATS_BASIC_XER, CODEC_OFFSET(xer_encoder),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700135 "Output as XER (XML Encoding Rules)"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700136 {"text", ATS_NONSTANDARD_PLAINTEXT, CODEC_OFFSET(print_struct),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700137 "Output as plain semi-structured text"},
Lev Walkin3b327a82017-09-18 22:19:03 -0700138 {"null", ATS_INVALID, CODEC_OFFSET(print_struct),
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700139 "Verify (decode) input, but do not output"},
140 {0, ATS_INVALID, 0, 0}};
141
Lev Walkin3b327a82017-09-18 22:19:03 -0700142static int
143has_codec_defined(const asn_TYPE_descriptor_t *td,
144 const syntax_selector *element) {
145 return *(const void *const *)(const void *)((const char *)td->op
146 + element->codec_offset) != 0;
147}
148
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700149/*
150 * Select ASN.1 Transfer Enocoding Syntax by command line name.
151 */
152static const syntax_selector *
153ats_by_name(const char *name, const asn_TYPE_descriptor_t *td,
154 const syntax_selector *first_element) {
155 const syntax_selector *element;
156 for(element = first_element; element->name; element++) {
157 if(strcmp(element->name, name) == 0) {
Lev Walkin3b327a82017-09-18 22:19:03 -0700158 if(td && td->op && has_codec_defined(td, element)) {
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700159 return element;
160 }
161 }
162 }
163 return NULL;
164}
165
Lev Walkin22b54552004-10-28 13:22:54 +0000166int
Lev Walkinc744a022006-09-15 18:33:25 +0000167main(int ac, char *av[]) {
Lev Walkin7bb9d5b2017-08-26 23:31:58 -0700168 FILE *binary_out;
Lev Walkin6d46bc32017-09-12 21:34:00 -0700169 static asn_TYPE_descriptor_t *pduType = PDU_Type_Ptr;
Lev Walkinfb35e082017-08-04 03:06:51 -0700170 ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */
171 int number_of_iterations = 1;
172 int num;
173 int ch;
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700174 const syntax_selector *sel;
Lev Walkin6d46bc32017-09-12 21:34:00 -0700175 enum asn_transfer_syntax isyntax = ATS_INVALID;
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700176 enum asn_transfer_syntax osyntax = ATS_BASIC_XER;
Lev Walkin6d46bc32017-09-12 21:34:00 -0700177
178#ifndef PDU
179 if(!pduType) {
180 fprintf(stderr, "No -DPDU defined during compilation.\n");
181#ifdef NO_ASN_PDU
182 exit(0);
183#else
184 exit(EX_SOFTWARE);
185#endif
186 }
187#endif
Lev Walkin22b54552004-10-28 13:22:54 +0000188
Lev Walkinfb35e082017-08-04 03:06:51 -0700189 /* Figure out if specialty decoder needs to be default */
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700190 if(ats_by_name("oer", pduType, input_encodings))
Lev Walkin6d46bc32017-09-12 21:34:00 -0700191 isyntax = ATS_BASIC_OER;
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700192 if(ats_by_name("per", pduType, input_encodings))
Lev Walkin6d46bc32017-09-12 21:34:00 -0700193 isyntax = ATS_UNALIGNED_BASIC_PER;
Lev Walkin59b176e2005-11-26 11:25:14 +0000194
Lev Walkinfb35e082017-08-04 03:06:51 -0700195 /*
196 * Pocess the command-line argments.
197 */
198 while((ch = getopt(ac, av, "i:o:1b:cdn:p:hs:" JUNKOPT)) != -1)
199 switch(ch) {
200 case 'i':
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700201 sel = ats_by_name(optarg, pduType, input_encodings);
202 if(sel) {
203 isyntax = sel->syntax;
204 } else {
205 fprintf(stderr, "-i<format>: '%s': improper format selector\n",
206 optarg);
207 exit(EX_UNAVAILABLE);
208 }
209 break;
Lev Walkinfb35e082017-08-04 03:06:51 -0700210 case 'o':
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700211 sel = ats_by_name(optarg, pduType, output_encodings);
212 if(sel) {
213 osyntax = sel->syntax;
214 } else {
215 fprintf(stderr, "-o<format>: '%s': improper format selector\n",
216 optarg);
217 exit(EX_UNAVAILABLE);
218 }
219 break;
Lev Walkinfb35e082017-08-04 03:06:51 -0700220 case '1':
221 opt_onepdu = 1;
222 break;
223 case 'b':
224 suggested_bufsize = atoi(optarg);
225 if(suggested_bufsize < 1
226 || suggested_bufsize > 16 * 1024 * 1024) {
227 fprintf(stderr,
228 "-b %s: Improper buffer size (1..16M)\n",
229 optarg);
230 exit(EX_UNAVAILABLE);
231 }
232 break;
233 case 'c':
234 opt_check = 1;
235 break;
236 case 'd':
237 opt_debug++; /* Double -dd means ASN.1 debug */
238 break;
239 case 'n':
240 number_of_iterations = atoi(optarg);
241 if(number_of_iterations < 1) {
242 fprintf(stderr,
243 "-n %s: Improper iterations count\n", optarg);
244 exit(EX_UNAVAILABLE);
245 }
246 break;
247 case 'p':
Lev Walkin0f77cea2017-09-13 00:28:20 -0700248 if(strcmp(optarg, "er-nopad") == 0) {
249 opt_nopad = 1;
250 break;
251 }
Lev Walkinfb35e082017-08-04 03:06:51 -0700252#ifdef ASN_PDU_COLLECTION
253 if(strcmp(optarg, "list") == 0) {
254 asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
255 fprintf(stderr, "Available PDU types:\n");
256 for(; *pdu; pdu++) printf("%s\n", (*pdu)->name);
257 exit(0);
258 } else if(optarg[0] >= 'A' && optarg[0] <= 'Z') {
259 asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
260 while(*pdu && strcmp((*pdu)->name, optarg)) pdu++;
261 if(*pdu) { pduType = *pdu; break; }
262 fprintf(stderr, "-p %s: Unrecognized PDU\n", optarg);
Lev Walkin7e5ea1d2017-08-06 00:59:28 -0700263 exit(EX_USAGE);
264 }
265#else /* Without -pdu=auto there's just a single type */
266 if(strcmp(optarg, "list") == 0) {
267 fprintf(stderr, "Available PDU types:\n");
268 printf("%s\n", pduType->name);
269 exit(0);
270 } else if(optarg[0] >= 'A' && optarg[0] <= 'Z') {
271 if(strcmp(optarg, pduType->name) == 0) {
272 break;
273 }
274 fprintf(stderr, "-p %s: Unrecognized PDU\n", optarg);
275 exit(EX_USAGE);
Lev Walkinfb35e082017-08-04 03:06:51 -0700276 }
277#endif /* ASN_PDU_COLLECTION */
278 fprintf(stderr, "-p %s: Unrecognized option\n", optarg);
279 exit(EX_UNAVAILABLE);
280 case 's':
281 opt_stack = atoi(optarg);
282 if(opt_stack < 0) {
283 fprintf(stderr,
284 "-s %s: Non-negative value expected\n",
285 optarg);
286 exit(EX_UNAVAILABLE);
287 }
288 break;
289#ifdef JUNKTEST
290 case 'J':
291 opt_jprob = strtod(optarg, 0);
292 if(opt_jprob <= 0.0 || opt_jprob > 1.0) {
293 fprintf(stderr,
294 "-J %s: Probability range 0..1 expected \n",
295 optarg);
296 exit(EX_UNAVAILABLE);
297 }
298 break;
299#endif /* JUNKTEST */
300 case 'h':
301 default:
302#ifdef ASN_CONVERTER_TITLE
303#define _AXS(x) #x
304#define _ASX(x) _AXS(x)
305 fprintf(stderr, "%s\n", _ASX(ASN_CONVERTER_TITLE));
Lev Walkin8a4a06c2007-06-29 12:44:01 +0000306#endif
Lev Walkinae0c3c22017-08-26 17:20:32 -0700307 fprintf(stderr, "Usage: %s [options] <datafile> ...\n", av[0]);
Lev Walkinfb35e082017-08-04 03:06:51 -0700308 fprintf(stderr, "Where options are:\n");
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700309 for(sel = input_encodings; sel->name; sel++) {
310 if(ats_by_name(sel->name, pduType, sel)) {
311 fprintf(stderr, " -i%s %s%s\n", sel->name,
312 sel->full_name,
313 (sel->syntax == isyntax) ? " (DEFAULT)" : "");
314 }
315 }
316 for(sel = output_encodings; sel->name; sel++) {
317 if(ats_by_name(sel->name, pduType, sel)) {
318 fprintf(stderr, " -o%s%s %s%s\n", sel->name,
319 strlen(sel->name) > 3 ? "" : " ",
320 sel->full_name,
321 (sel->syntax == osyntax) ? " (DEFAULT)" : "");
322 }
323 }
Lev Walkin0f77cea2017-09-13 00:28:20 -0700324 if(pduType->op->uper_decoder) {
325 fprintf(stderr,
326 " -per-nopad Assume PER PDUs are not padded (-iper)\n");
327 }
Lev Walkinfb35e082017-08-04 03:06:51 -0700328#ifdef ASN_PDU_COLLECTION
329 fprintf(stderr,
330 " -p <PDU> Specify PDU type to decode\n"
331 " -p list List available PDUs\n");
332#endif /* ASN_PDU_COLLECTION */
333 fprintf(stderr,
334 " -1 Decode only the first PDU in file\n"
335 " -b <size> Set the i/o buffer size (default is %ld)\n"
336 " -c Check ASN.1 constraints after decoding\n"
337 " -d Enable debugging (-dd is even better)\n"
338 " -n <num> Process files <num> times\n"
339 " -s <size> Set the stack usage limit (default is %d)\n"
340#ifdef JUNKTEST
341 " -J <prob> Set random junk test bit garbaging probability\n"
Lev Walkin1f12da42006-09-24 19:47:07 +0000342#endif
Lev Walkinfb35e082017-08-04 03:06:51 -0700343 , (long)suggested_bufsize, ASN__DEFAULT_STACK_MAX);
344 exit(EX_USAGE);
345 }
Lev Walkin22b54552004-10-28 13:22:54 +0000346
Lev Walkinfb35e082017-08-04 03:06:51 -0700347 ac -= optind;
348 av += optind;
Lev Walkin22b54552004-10-28 13:22:54 +0000349
Lev Walkinfb35e082017-08-04 03:06:51 -0700350 if(ac < 1) {
351 fprintf(stderr, "%s: No input files specified. "
352 "Try '-h' for more information\n",
353 av[-optind]);
354 exit(EX_USAGE);
355 }
Lev Walkin22b54552004-10-28 13:22:54 +0000356
Lev Walkin7bb9d5b2017-08-26 23:31:58 -0700357 if(isatty(1)) {
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700358 const int is_text_output = osyntax == ATS_NONSTANDARD_PLAINTEXT
359 || osyntax == ATS_BASIC_XER
360 || osyntax == ATS_CANONICAL_XER;
Lev Walkin7bb9d5b2017-08-26 23:31:58 -0700361 if(is_text_output) {
362 binary_out = stdout;
363 } else {
364 fprintf(stderr, "(Suppressing binary output to a terminal.)\n");
365 binary_out = fopen("/dev/null", "wb");
366 if(!binary_out) {
367 fprintf(stderr, "Can't open /dev/null: %s\n", strerror(errno));
368 exit(EX_OSERR);
369 }
370 }
371 } else {
372 binary_out = stdout;
373 }
Lev Walkinfb35e082017-08-04 03:06:51 -0700374 setvbuf(stdout, 0, _IOLBF, 0);
Lev Walkin22b54552004-10-28 13:22:54 +0000375
Lev Walkinfb35e082017-08-04 03:06:51 -0700376 for(num = 0; num < number_of_iterations; num++) {
377 int ac_i;
378 /*
379 * Process all files in turn.
380 */
381 for(ac_i = 0; ac_i < ac; ac_i++) {
382 asn_enc_rval_t erv;
383 void *structure; /* Decoded structure */
384 FILE *file = argument_to_file(av, ac_i);
385 char *name = argument_to_name(av, ac_i);
386 int first_pdu;
Lev Walkin22b54552004-10-28 13:22:54 +0000387
Lev Walkin3eeafe12017-09-18 22:20:41 -0700388 for(first_pdu = 1; (first_pdu || !opt_onepdu); first_pdu = 0) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700389 /*
390 * Decode the encoded structure from file.
391 */
Lev Walkin6d46bc32017-09-12 21:34:00 -0700392 structure = data_decode_from_file(isyntax, pduType, file, name,
Lev Walkinfb35e082017-08-04 03:06:51 -0700393 suggested_bufsize, first_pdu);
394 if(!structure) {
395 if(errno) {
396 /* Error message is already printed */
397 exit(EX_DATAERR);
398 } else {
399 /* EOF */
400 break;
401 }
402 }
Lev Walkin22b54552004-10-28 13:22:54 +0000403
Lev Walkinfb35e082017-08-04 03:06:51 -0700404 /* Check ASN.1 constraints */
405 if(opt_check) {
406 char errbuf[128];
407 size_t errlen = sizeof(errbuf);
408 if(asn_check_constraints(pduType, structure, errbuf, &errlen)) {
409 fprintf(stderr,
410 "%s: ASN.1 constraint "
411 "check failed: %s\n",
412 name, errbuf);
413 exit(EX_DATAERR);
414 }
415 }
Lev Walkin22b54552004-10-28 13:22:54 +0000416
Lev Walkin6d46bc32017-09-12 21:34:00 -0700417 if(osyntax == ATS_INVALID) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700418#ifdef JUNKTEST
Lev Walkin6d46bc32017-09-12 21:34:00 -0700419 if(opt_jprob == 0.0) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700420 fprintf(stderr, "%s: decoded successfully\n", name);
Lev Walkinfb35e082017-08-04 03:06:51 -0700421 }
Lev Walkin69033802017-08-25 12:15:58 -0700422#else
Lev Walkin6d46bc32017-09-12 21:34:00 -0700423 fprintf(stderr, "%s: decoded successfully\n", name);
Lev Walkin69033802017-08-25 12:15:58 -0700424#endif
Lev Walkin6d46bc32017-09-12 21:34:00 -0700425 } else {
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700426 erv = asn_encode(NULL, osyntax, pduType, structure, write_out,
427 binary_out);
Lev Walkin6d46bc32017-09-12 21:34:00 -0700428
429 if(erv.encoded == -1) {
430 fprintf(stderr, "%s: Cannot convert %s into %s\n", name,
431 pduType->name, ats_simple_name(osyntax));
Lev Walkinfb35e082017-08-04 03:06:51 -0700432 exit(EX_UNAVAILABLE);
433 }
Lev Walkin6d46bc32017-09-12 21:34:00 -0700434 DEBUG("Encoded in %zd bytes of %s", erv.encoded,
435 ats_simple_name(osyntax));
Lev Walkin7bb9d5b2017-08-26 23:31:58 -0700436 }
Lev Walkind1bfea62005-11-08 03:06:16 +0000437
Lev Walkin7bb9d5b2017-08-26 23:31:58 -0700438 ASN_STRUCT_FREE(*pduType, structure);
Lev Walkinfb35e082017-08-04 03:06:51 -0700439 }
Lev Walkinbc691772006-09-17 11:02:53 +0000440
Lev Walkinfb35e082017-08-04 03:06:51 -0700441 if(file && file != stdin) {
442 fclose(file);
443 }
444 }
445 }
Lev Walkin22b54552004-10-28 13:22:54 +0000446
Lev Walkinfb35e082017-08-04 03:06:51 -0700447#ifdef JUNKTEST
448 if(opt_jprob > 0.0) {
449 fprintf(stderr, "Junked %f OK (%d/%d)\n",
450 opt_jprob, junk_failures, number_of_iterations);
451 }
452#endif /* JUNKTEST */
Lev Walkin1f12da42006-09-24 19:47:07 +0000453
Lev Walkinfb35e082017-08-04 03:06:51 -0700454 return 0;
Lev Walkin22b54552004-10-28 13:22:54 +0000455}
456
Lev Walkin419f6752006-09-13 04:02:00 +0000457static struct dynamic_buffer {
Lev Walkinfb35e082017-08-04 03:06:51 -0700458 uint8_t *data; /* Pointer to the data bytes */
459 size_t offset; /* Offset from the start */
460 size_t length; /* Length of meaningful contents */
461 size_t unbits; /* Unused bits in the last byte */
462 size_t allocated; /* Allocated memory for data */
463 int nreallocs; /* Number of data reallocations */
464 off_t bytes_shifted; /* Number of bytes ever shifted */
Lev Walkin419f6752006-09-13 04:02:00 +0000465} DynamicBuffer;
Lev Walkin22b54552004-10-28 13:22:54 +0000466
Lev Walkin5a621d62006-09-18 20:05:34 +0000467static void
468buffer_dump() {
Lev Walkinfb35e082017-08-04 03:06:51 -0700469 uint8_t *p = DynamicBuffer.data + DynamicBuffer.offset;
470 uint8_t *e = p + DynamicBuffer.length - (DynamicBuffer.unbits ? 1 : 0);
471 if(!opt_debug) return;
472 DEBUG("Buffer: { d=%p, o=%ld, l=%ld, u=%ld, a=%ld, s=%ld }",
473 DynamicBuffer.data,
474 (long)DynamicBuffer.offset,
475 (long)DynamicBuffer.length,
476 (long)DynamicBuffer.unbits,
477 (long)DynamicBuffer.allocated,
478 (long)DynamicBuffer.bytes_shifted);
479 for(; p < e; p++) {
480 fprintf(stderr, " %c%c%c%c%c%c%c%c",
481 ((*p >> 7) & 1) ? '1' : '0',
482 ((*p >> 6) & 1) ? '1' : '0',
483 ((*p >> 5) & 1) ? '1' : '0',
484 ((*p >> 4) & 1) ? '1' : '0',
485 ((*p >> 3) & 1) ? '1' : '0',
486 ((*p >> 2) & 1) ? '1' : '0',
487 ((*p >> 1) & 1) ? '1' : '0',
488 ((*p >> 0) & 1) ? '1' : '0');
489 }
490 if(DynamicBuffer.unbits) {
491 unsigned int shift;
492 fprintf(stderr, " ");
493 for(shift = 7; shift >= DynamicBuffer.unbits; shift--)
494 fprintf(stderr, "%c", ((*p >> shift) & 1) ? '1' : '0');
495 fprintf(stderr, " %ld:%ld\n",
496 (long)DynamicBuffer.length - 1,
497 (long)8 - DynamicBuffer.unbits);
498 } else {
499 fprintf(stderr, " %ld\n", (long)DynamicBuffer.length);
500 }
Lev Walkin5a621d62006-09-18 20:05:34 +0000501}
502
503/*
504 * Move the buffer content left N bits, possibly joining it with
505 * preceeding content.
506 */
507static void
508buffer_shift_left(size_t offset, int bits) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700509 uint8_t *ptr = DynamicBuffer.data + DynamicBuffer.offset + offset;
510 uint8_t *end = DynamicBuffer.data + DynamicBuffer.offset
511 + DynamicBuffer.length - 1;
512
513 if(!bits) return;
Lev Walkin5a621d62006-09-18 20:05:34 +0000514
Lev Walkinfb35e082017-08-04 03:06:51 -0700515 DEBUG("Shifting left %d bits off %ld (o=%ld, u=%ld, l=%ld)",
516 bits, (long)offset,
517 (long)DynamicBuffer.offset,
518 (long)DynamicBuffer.unbits,
519 (long)DynamicBuffer.length);
Lev Walkin5a621d62006-09-18 20:05:34 +0000520
Lev Walkinfb35e082017-08-04 03:06:51 -0700521 if(offset) {
522 int right;
523 right = ptr[0] >> (8 - bits);
Lev Walkin5a621d62006-09-18 20:05:34 +0000524
Lev Walkinfb35e082017-08-04 03:06:51 -0700525 DEBUG("oleft: %c%c%c%c%c%c%c%c",
526 ((ptr[-1] >> 7) & 1) ? '1' : '0',
527 ((ptr[-1] >> 6) & 1) ? '1' : '0',
528 ((ptr[-1] >> 5) & 1) ? '1' : '0',
529 ((ptr[-1] >> 4) & 1) ? '1' : '0',
530 ((ptr[-1] >> 3) & 1) ? '1' : '0',
531 ((ptr[-1] >> 2) & 1) ? '1' : '0',
532 ((ptr[-1] >> 1) & 1) ? '1' : '0',
533 ((ptr[-1] >> 0) & 1) ? '1' : '0');
Lev Walkin5a621d62006-09-18 20:05:34 +0000534
Lev Walkinfb35e082017-08-04 03:06:51 -0700535 DEBUG("oriht: %c%c%c%c%c%c%c%c",
536 ((ptr[0] >> 7) & 1) ? '1' : '0',
537 ((ptr[0] >> 6) & 1) ? '1' : '0',
538 ((ptr[0] >> 5) & 1) ? '1' : '0',
539 ((ptr[0] >> 4) & 1) ? '1' : '0',
540 ((ptr[0] >> 3) & 1) ? '1' : '0',
541 ((ptr[0] >> 2) & 1) ? '1' : '0',
542 ((ptr[0] >> 1) & 1) ? '1' : '0',
543 ((ptr[0] >> 0) & 1) ? '1' : '0');
Lev Walkin5a621d62006-09-18 20:05:34 +0000544
Lev Walkinfb35e082017-08-04 03:06:51 -0700545 DEBUG("mriht: %c%c%c%c%c%c%c%c",
546 ((right >> 7) & 1) ? '1' : '0',
547 ((right >> 6) & 1) ? '1' : '0',
548 ((right >> 5) & 1) ? '1' : '0',
549 ((right >> 4) & 1) ? '1' : '0',
550 ((right >> 3) & 1) ? '1' : '0',
551 ((right >> 2) & 1) ? '1' : '0',
552 ((right >> 1) & 1) ? '1' : '0',
553 ((right >> 0) & 1) ? '1' : '0');
Lev Walkin5a621d62006-09-18 20:05:34 +0000554
Lev Walkinfb35e082017-08-04 03:06:51 -0700555 ptr[-1] = (ptr[-1] & (0xff << bits)) | right;
Lev Walkin5a621d62006-09-18 20:05:34 +0000556
Lev Walkinfb35e082017-08-04 03:06:51 -0700557 DEBUG("after: %c%c%c%c%c%c%c%c",
558 ((ptr[-1] >> 7) & 1) ? '1' : '0',
559 ((ptr[-1] >> 6) & 1) ? '1' : '0',
560 ((ptr[-1] >> 5) & 1) ? '1' : '0',
561 ((ptr[-1] >> 4) & 1) ? '1' : '0',
562 ((ptr[-1] >> 3) & 1) ? '1' : '0',
563 ((ptr[-1] >> 2) & 1) ? '1' : '0',
564 ((ptr[-1] >> 1) & 1) ? '1' : '0',
565 ((ptr[-1] >> 0) & 1) ? '1' : '0');
566 }
Lev Walkin5a621d62006-09-18 20:05:34 +0000567
Lev Walkinfb35e082017-08-04 03:06:51 -0700568 buffer_dump();
Lev Walkin5a621d62006-09-18 20:05:34 +0000569
Lev Walkinfb35e082017-08-04 03:06:51 -0700570 for(; ptr < end; ptr++) {
571 int right = ptr[1] >> (8 - bits);
572 *ptr = (*ptr << bits) | right;
573 }
574 *ptr <<= bits;
Lev Walkin5a621d62006-09-18 20:05:34 +0000575
Lev Walkinfb35e082017-08-04 03:06:51 -0700576 DEBUG("Unbits [%d=>", (int)DynamicBuffer.unbits);
577 if(DynamicBuffer.unbits == 0) {
578 DynamicBuffer.unbits += bits;
579 } else {
580 DynamicBuffer.unbits += bits;
581 if(DynamicBuffer.unbits > 7) {
582 DynamicBuffer.unbits -= 8;
583 DynamicBuffer.length--;
584 DynamicBuffer.bytes_shifted++;
585 }
586 }
587 DEBUG("Unbits =>%d]", (int)DynamicBuffer.unbits);
Lev Walkin5a621d62006-09-18 20:05:34 +0000588
Lev Walkinfb35e082017-08-04 03:06:51 -0700589 buffer_dump();
Lev Walkin5a621d62006-09-18 20:05:34 +0000590
Lev Walkinfb35e082017-08-04 03:06:51 -0700591 DEBUG("Shifted. Now (o=%ld, u=%ld l=%ld)",
592 (long)DynamicBuffer.offset,
593 (long)DynamicBuffer.unbits,
594 (long)DynamicBuffer.length);
595
Lev Walkin5a621d62006-09-18 20:05:34 +0000596
597}
598
Lev Walkin22b54552004-10-28 13:22:54 +0000599/*
Lev Walkind1bfea62005-11-08 03:06:16 +0000600 * Ensure that the buffer contains at least this amount of free space.
Lev Walkin22b54552004-10-28 13:22:54 +0000601 */
Lev Walkin5a621d62006-09-18 20:05:34 +0000602static void add_bytes_to_buffer(const void *data2add, size_t bytes) {
Lev Walkin22b54552004-10-28 13:22:54 +0000603
Lev Walkinfb35e082017-08-04 03:06:51 -0700604 if(bytes == 0) return;
Lev Walkin5a621d62006-09-18 20:05:34 +0000605
Lev Walkinfb35e082017-08-04 03:06:51 -0700606 DEBUG("=> add_bytes(%ld) { o=%ld l=%ld u=%ld, s=%ld }",
607 (long)bytes,
608 (long)DynamicBuffer.offset,
609 (long)DynamicBuffer.length,
610 (long)DynamicBuffer.unbits,
611 (long)DynamicBuffer.allocated);
Lev Walkin22b54552004-10-28 13:22:54 +0000612
Lev Walkinfb35e082017-08-04 03:06:51 -0700613 if(DynamicBuffer.allocated
614 >= (DynamicBuffer.offset + DynamicBuffer.length + bytes)) {
615 DEBUG("\tNo buffer reallocation is necessary");
616 } else if(bytes <= DynamicBuffer.offset) {
617 DEBUG("\tContents shifted by %ld", DynamicBuffer.offset);
Lev Walkin22b54552004-10-28 13:22:54 +0000618
Lev Walkinfb35e082017-08-04 03:06:51 -0700619 /* Shift the buffer contents */
620 memmove(DynamicBuffer.data,
621 DynamicBuffer.data + DynamicBuffer.offset,
622 DynamicBuffer.length);
623 DynamicBuffer.bytes_shifted += DynamicBuffer.offset;
624 DynamicBuffer.offset = 0;
625 } else {
626 size_t newsize = (DynamicBuffer.allocated << 2) + bytes;
627 void *p = MALLOC(newsize);
628 if(!p) {
629 perror("malloc()");
630 exit(EX_OSERR);
631 }
632 memcpy(p,
633 DynamicBuffer.data + DynamicBuffer.offset,
634 DynamicBuffer.length);
635 FREEMEM(DynamicBuffer.data);
636 DynamicBuffer.data = (uint8_t *)p;
637 DynamicBuffer.offset = 0;
638 DynamicBuffer.allocated = newsize;
639 DynamicBuffer.nreallocs++;
640 DEBUG("\tBuffer reallocated to %ld (%d time)",
641 newsize, DynamicBuffer.nreallocs);
642 }
Lev Walkin1d9e8dd2005-12-07 05:46:03 +0000643
Lev Walkinfb35e082017-08-04 03:06:51 -0700644 memcpy(DynamicBuffer.data
645 + DynamicBuffer.offset + DynamicBuffer.length,
646 data2add, bytes);
647 DynamicBuffer.length += bytes;
648 if(DynamicBuffer.unbits) {
649 int bits = DynamicBuffer.unbits;
650 DynamicBuffer.unbits = 0;
651 buffer_shift_left(DynamicBuffer.length - bytes, bits);
652 }
Lev Walkin5a621d62006-09-18 20:05:34 +0000653
Lev Walkinfb35e082017-08-04 03:06:51 -0700654 DEBUG("<= add_bytes(%ld) { o=%ld l=%ld u=%ld, s=%ld }",
655 (long)bytes,
656 (long)DynamicBuffer.offset,
657 (long)DynamicBuffer.length,
658 (long)DynamicBuffer.unbits,
659 (long)DynamicBuffer.allocated);
Lev Walkin22b54552004-10-28 13:22:54 +0000660}
661
Lev Walkine8bbe932017-09-12 23:06:52 -0700662static int
Lev Walkin0f77cea2017-09-13 00:28:20 -0700663is_syntax_PER(enum asn_transfer_syntax syntax) {
Lev Walkine8bbe932017-09-12 23:06:52 -0700664 return (syntax != ATS_UNALIGNED_BASIC_PER
665 && syntax != ATS_UNALIGNED_CANONICAL_PER);
666}
667
Lev Walkin0f77cea2017-09-13 00:28:20 -0700668static int
669restartability_supported(enum asn_transfer_syntax syntax) {
670 return is_syntax_PER(syntax);
671}
672
Lev Walkinc744a022006-09-15 18:33:25 +0000673static void *
Lev Walkin6d46bc32017-09-12 21:34:00 -0700674data_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) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700675 static uint8_t *fbuf;
676 static ssize_t fbuf_size;
677 static asn_codec_ctx_t s_codec_ctx;
678 asn_codec_ctx_t *opt_codec_ctx = 0;
679 void *structure = 0;
680 asn_dec_rval_t rval;
681 size_t old_offset;
682 size_t new_offset;
683 int tolerate_eof;
684 size_t rd;
Lev Walkinc744a022006-09-15 18:33:25 +0000685
Lev Walkinfb35e082017-08-04 03:06:51 -0700686 if(!file) {
687 fprintf(stderr, "%s: %s\n", name, strerror(errno));
688 errno = EINVAL;
689 return 0;
690 }
Lev Walkin22b54552004-10-28 13:22:54 +0000691
Lev Walkinfb35e082017-08-04 03:06:51 -0700692 if(opt_stack) {
693 s_codec_ctx.max_stack_size = opt_stack;
694 opt_codec_ctx = &s_codec_ctx;
695 }
Lev Walkin22b54552004-10-28 13:22:54 +0000696
Lev Walkinfb35e082017-08-04 03:06:51 -0700697 DEBUG("Processing %s", name);
Lev Walkin22b54552004-10-28 13:22:54 +0000698
Lev Walkinfb35e082017-08-04 03:06:51 -0700699 /* prepare the file buffer */
700 if(fbuf_size != suggested_bufsize) {
701 fbuf = (uint8_t *)REALLOC(fbuf, suggested_bufsize);
702 if(!fbuf) {
703 perror("realloc()");
704 exit(EX_OSERR);
705 }
706 fbuf_size = suggested_bufsize;
707 }
Lev Walkin22b54552004-10-28 13:22:54 +0000708
Lev Walkinfb35e082017-08-04 03:06:51 -0700709 if(on_first_pdu) {
710 DynamicBuffer.offset = 0;
711 DynamicBuffer.length = 0;
712 DynamicBuffer.unbits = 0;
713 DynamicBuffer.allocated = 0;
714 DynamicBuffer.bytes_shifted = 0;
715 DynamicBuffer.nreallocs = 0;
716 }
Lev Walkinbc691772006-09-17 11:02:53 +0000717
Lev Walkinfb35e082017-08-04 03:06:51 -0700718 old_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset;
Lev Walkin22b54552004-10-28 13:22:54 +0000719
Lev Walkinfb35e082017-08-04 03:06:51 -0700720 /* Pretend immediate EOF */
721 rval.code = RC_WMORE;
722 rval.consumed = 0;
Lev Walkind1bfea62005-11-08 03:06:16 +0000723
Lev Walkinfb35e082017-08-04 03:06:51 -0700724 for(tolerate_eof = 1; /* Allow EOF first time buffer is non-empty */
725 (rd = fread(fbuf, 1, fbuf_size, file))
726 || feof(file) == 0
727 || (tolerate_eof && DynamicBuffer.length)
728 ;) {
729 int ecbits = 0; /* Extra consumed bits in case of PER */
730 uint8_t *i_bptr;
731 size_t i_size;
Lev Walkin22b54552004-10-28 13:22:54 +0000732
Lev Walkinfb35e082017-08-04 03:06:51 -0700733 /*
734 * Copy the data over, or use the original buffer.
735 */
736 if(DynamicBuffer.allocated) {
737 /* Append new data into the existing dynamic buffer */
738 add_bytes_to_buffer(fbuf, rd);
739 i_bptr = DynamicBuffer.data + DynamicBuffer.offset;
740 i_size = DynamicBuffer.length;
741 } else {
742 i_bptr = fbuf;
743 i_size = rd;
744 }
Lev Walkin22b54552004-10-28 13:22:54 +0000745
Lev Walkinfb35e082017-08-04 03:06:51 -0700746 DEBUG("Decoding %ld bytes", (long)i_size);
Lev Walkinbc691772006-09-17 11:02:53 +0000747
Lev Walkinfb35e082017-08-04 03:06:51 -0700748#ifdef JUNKTEST
749 junk_bytes_with_probability(i_bptr, i_size, opt_jprob);
Lev Walkin1f12da42006-09-24 19:47:07 +0000750#endif
751
Lev Walkin0f77cea2017-09-13 00:28:20 -0700752 if(is_syntax_PER(isyntax) && opt_nopad) {
753#ifdef ASN_DISABLE_PER_SUPPORT
754 rval.code = RC_FAIL;
755 rval.consumed = 0;
756#else
757 rval = uper_decode(opt_codec_ctx, pduType, (void **)&structure,
758 i_bptr, i_size, 0, DynamicBuffer.unbits);
759 /* uper_decode() returns bits! */
760 ecbits = rval.consumed % 8; /* Bits consumed from the last byte */
761 rval.consumed >>= 3; /* Convert bits into bytes. */
762#endif
763 /* Non-padded PER decoder */
764 } else {
765 rval = asn_decode(opt_codec_ctx, isyntax, pduType,
766 (void **)&structure, i_bptr, i_size);
767 }
Lev Walkine8bbe932017-09-12 23:06:52 -0700768 if(rval.code == RC_WMORE && !restartability_supported(isyntax)) {
769 /* PER does not support restartability */
770 ASN_STRUCT_FREE(*pduType, structure);
771 structure = 0;
Lev Walkin69033802017-08-25 12:15:58 -0700772 rval.consumed = 0;
Lev Walkine8bbe932017-09-12 23:06:52 -0700773 /* Continue accumulating data */
Lev Walkinfb35e082017-08-04 03:06:51 -0700774 }
Lev Walkine8bbe932017-09-12 23:06:52 -0700775
Lev Walkinfb35e082017-08-04 03:06:51 -0700776 DEBUG("decode(%ld) consumed %ld+%db (%ld), code %d",
777 (long)DynamicBuffer.length,
778 (long)rval.consumed, ecbits, (long)i_size,
779 rval.code);
Lev Walkin22b54552004-10-28 13:22:54 +0000780
Lev Walkinfb35e082017-08-04 03:06:51 -0700781 if(DynamicBuffer.allocated == 0) {
782 /*
783 * Flush remainder into the intermediate buffer.
784 */
785 if(rval.code != RC_FAIL && rval.consumed < rd) {
786 add_bytes_to_buffer(fbuf + rval.consumed,
787 rd - rval.consumed);
788 buffer_shift_left(0, ecbits);
789 DynamicBuffer.bytes_shifted = rval.consumed;
790 rval.consumed = 0;
791 ecbits = 0;
792 }
793 }
Lev Walkin22b54552004-10-28 13:22:54 +0000794
Lev Walkinfb35e082017-08-04 03:06:51 -0700795 /*
796 * Adjust position inside the source buffer.
797 */
798 if(DynamicBuffer.allocated) {
799 DynamicBuffer.offset += rval.consumed;
800 DynamicBuffer.length -= rval.consumed;
801 } else {
802 DynamicBuffer.bytes_shifted += rval.consumed;
803 }
Lev Walkinbc691772006-09-17 11:02:53 +0000804
Lev Walkinfb35e082017-08-04 03:06:51 -0700805 switch(rval.code) {
806 case RC_OK:
807 if(ecbits) buffer_shift_left(0, ecbits);
808 DEBUG("RC_OK, finishing up with %ld+%d",
809 (long)rval.consumed, ecbits);
810 return structure;
811 case RC_WMORE:
812 DEBUG("RC_WMORE, continuing read=%ld, cons=%ld "
813 " with %ld..%ld-%ld..%ld",
814 (long)rd,
815 (long)rval.consumed,
816 (long)DynamicBuffer.offset,
817 (long)DynamicBuffer.length,
818 (long)DynamicBuffer.unbits,
819 (long)DynamicBuffer.allocated);
820 if(!rd) tolerate_eof--;
821 continue;
822 case RC_FAIL:
823 break;
824 }
825 break;
826 }
Lev Walkin22b54552004-10-28 13:22:54 +0000827
Lev Walkinb48bc2f2017-09-12 22:39:47 -0700828 DEBUG("Clean up partially decoded %s", pduType->name);
Lev Walkinfb35e082017-08-04 03:06:51 -0700829 ASN_STRUCT_FREE(*pduType, structure);
Lev Walkin22b54552004-10-28 13:22:54 +0000830
Lev Walkinfb35e082017-08-04 03:06:51 -0700831 new_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset;
Lev Walkinbc691772006-09-17 11:02:53 +0000832
Lev Walkinfb35e082017-08-04 03:06:51 -0700833 /*
834 * Print a message and return failure only if not EOF,
835 * unless this is our first PDU (empty file).
836 */
837 if(on_first_pdu
838 || DynamicBuffer.length
Lev Walkin6d46bc32017-09-12 21:34:00 -0700839 || new_offset - old_offset > ((isyntax == ATS_BASIC_XER)?sizeof("\r\n")-1:0)
Lev Walkinfb35e082017-08-04 03:06:51 -0700840 ) {
Lev Walkin1f12da42006-09-24 19:47:07 +0000841
Lev Walkinfb35e082017-08-04 03:06:51 -0700842#ifdef JUNKTEST
843 /*
844 * Nothing's wrong with being unable to decode junk.
845 * Simulate EOF.
846 */
847 if(opt_jprob != 0.0) {
848 junk_failures++;
849 errno = 0;
850 return 0;
851 }
Lev Walkin1f12da42006-09-24 19:47:07 +0000852#endif
853
Lev Walkinfb35e082017-08-04 03:06:51 -0700854 DEBUG("ofp %d, no=%ld, oo=%ld, dbl=%ld",
855 on_first_pdu, (long)new_offset, (long)old_offset,
856 (long)DynamicBuffer.length);
857 fprintf(stderr, "%s: "
858 "Decode failed past byte %ld: %s\n",
859 name, (long)new_offset,
860 (rval.code == RC_WMORE)
861 ? "Unexpected end of input"
862 : "Input processing error");
863#ifndef ENOMSG
864#define ENOMSG EINVAL
Lev Walkin4bf96b92006-09-18 21:46:50 +0000865#endif
Lev Walkinfb35e082017-08-04 03:06:51 -0700866#ifndef EBADMSG
867#define EBADMSG EINVAL
Lev Walkin4bf96b92006-09-18 21:46:50 +0000868#endif
Lev Walkinfb35e082017-08-04 03:06:51 -0700869 errno = (rval.code == RC_WMORE) ? ENOMSG : EBADMSG;
870 } else {
871 /* Got EOF after a few successful PDUs */
872 errno = 0;
873 }
Lev Walkin22b54552004-10-28 13:22:54 +0000874
Lev Walkinfb35e082017-08-04 03:06:51 -0700875 return 0;
Lev Walkin22b54552004-10-28 13:22:54 +0000876}
877
Lev Walkin419f6752006-09-13 04:02:00 +0000878/* Dump the buffer out to the specified FILE */
879static int write_out(const void *buffer, size_t size, void *key) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700880 FILE *fp = (FILE *)key;
881 return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1;
Lev Walkin419f6752006-09-13 04:02:00 +0000882}
Lev Walkinc744a022006-09-15 18:33:25 +0000883
884static int argument_is_stdin(char *av[], int idx) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700885 if(strcmp(av[idx], "-")) {
886 return 0; /* Certainly not <stdin> */
887 } else {
888 /* This might be <stdin>, unless `./program -- -` */
889 if(strcmp(av[-1], "--"))
890 return 1;
891 else
892 return 0;
893 }
Lev Walkinc744a022006-09-15 18:33:25 +0000894}
895
896static FILE *argument_to_file(char *av[], int idx) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700897 return argument_is_stdin(av, idx) ? stdin : fopen(av[idx], "rb");
Lev Walkinc744a022006-09-15 18:33:25 +0000898}
899
900static char *argument_to_name(char *av[], int idx) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700901 return argument_is_stdin(av, idx) ? "standard input" : av[idx];
Lev Walkinc744a022006-09-15 18:33:25 +0000902}
Lev Walkin1f12da42006-09-24 19:47:07 +0000903
Lev Walkinfb35e082017-08-04 03:06:51 -0700904#ifdef JUNKTEST
Lev Walkin1f12da42006-09-24 19:47:07 +0000905/*
906 * Fill bytes with some garbage with specified probability (more or less).
907 */
908static void
909junk_bytes_with_probability(uint8_t *buf, size_t size, double prob) {
Lev Walkinfb35e082017-08-04 03:06:51 -0700910 static int junkmode;
911 uint8_t *ptr;
912 uint8_t *end;
913 if(opt_jprob <= 0.0) return;
914 for(ptr = buf, end = ptr + size; ptr < end; ptr++) {
915 int byte = *ptr;
916 if(junkmode++ & 1) {
917 if((((double)random() / RAND_MAX) < prob))
918 byte = random() & 0xff;
919 } else {
920#define BPROB(b) ((((double)random() / RAND_MAX) < prob) ? b : 0)
921 byte ^= BPROB(0x80);
922 byte ^= BPROB(0x40);
923 byte ^= BPROB(0x20);
924 byte ^= BPROB(0x10);
925 byte ^= BPROB(0x08);
926 byte ^= BPROB(0x04);
927 byte ^= BPROB(0x02);
928 byte ^= BPROB(0x01);
929 }
930 if(byte != *ptr) {
931 DEBUG("Junk buf[%d] %02x -> %02x", ptr - buf, *ptr, byte);
932 *ptr = byte;
933 }
934 }
Lev Walkin1f12da42006-09-24 19:47:07 +0000935}
Lev Walkinfb35e082017-08-04 03:06:51 -0700936#endif /* JUNKTEST */
Lev Walkin1f12da42006-09-24 19:47:07 +0000937