1/*	$OpenBSD: inout.c,v 1.18 2014/12/01 13:13:00 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/cdefs.h>
20#include <openssl/ssl.h>
21#include <ctype.h>
22#include <err.h>
23#include <string.h>
24
25#include "extern.h"
26
27#define MAX_CHARS_PER_LINE 68
28
29static int	 lastchar;
30static int	 charcount;
31
32static int	 src_getcharstream(struct source *);
33static void	 src_ungetcharstream(struct source *);
34static char	*src_getlinestream(struct source *);
35static int	 src_getcharstring(struct source *);
36static void	 src_ungetcharstring(struct source *);
37static char	*src_getlinestring(struct source *);
38static void	 src_freestring(struct source *);
39static void	 flushwrap(FILE *);
40static void	 putcharwrap(FILE *, int);
41static void	 printwrap(FILE *, const char *);
42static char	*get_digit(u_long, int, u_int);
43
44static struct vtable stream_vtable = {
45	src_getcharstream,
46	src_ungetcharstream,
47	src_getlinestream,
48	NULL
49};
50
51static struct vtable string_vtable = {
52	src_getcharstring,
53	src_ungetcharstring,
54	src_getlinestring,
55	src_freestring
56};
57
58void
59src_setstream(struct source *src, FILE *stream)
60{
61
62	src->u.stream = stream;
63	src->vtable = &stream_vtable;
64}
65
66void
67src_setstring(struct source *src, char *p)
68{
69
70	src->u.string.buf = (u_char *)p;
71	src->u.string.pos = 0;
72	src->vtable = &string_vtable;
73}
74
75static int
76src_getcharstream(struct source *src)
77{
78
79	return (src->lastchar = getc(src->u.stream));
80}
81
82static void
83src_ungetcharstream(struct source *src)
84{
85
86	ungetc(src->lastchar, src->u.stream);
87}
88
89static char *
90src_getlinestream(struct source *src)
91{
92	char buf[BUFSIZ];
93
94	if (fgets(buf, BUFSIZ, src->u.stream) == NULL)
95		return (bstrdup(""));
96	return bstrdup(buf);
97}
98
99static int
100src_getcharstring(struct source *src)
101{
102
103	src->lastchar = src->u.string.buf[src->u.string.pos];
104	if (src->lastchar == '\0')
105		return (EOF);
106	else {
107		src->u.string.pos++;
108		return (src->lastchar);
109	}
110}
111
112static void
113src_ungetcharstring(struct source *src)
114{
115
116	if (src->u.string.pos > 0) {
117		if (src->lastchar != '\0')
118			--src->u.string.pos;
119	}
120}
121
122static char *
123src_getlinestring(struct source *src)
124{
125	char buf[BUFSIZ];
126	int i, ch;
127
128	i = 0;
129	while (i < BUFSIZ-1) {
130		ch = src_getcharstring(src);
131		if (ch == EOF)
132			break;
133		buf[i++] = ch;
134		if (ch == '\n')
135			break;
136	}
137	buf[i] = '\0';
138	return (bstrdup(buf));
139}
140
141static void
142src_freestring(struct source *src)
143{
144
145	free(src->u.string.buf);
146}
147
148static void
149flushwrap(FILE *f)
150{
151
152	if (lastchar != -1)
153		putc(lastchar, f);
154}
155
156static void
157putcharwrap(FILE *f, int ch)
158{
159
160	if (charcount >= MAX_CHARS_PER_LINE) {
161		charcount = 0;
162		fputs("\\\n", f);
163	}
164	if (lastchar != -1) {
165		charcount++;
166		putc(lastchar, f);
167	}
168	lastchar = ch;
169}
170
171static void
172printwrap(FILE *f, const char *p)
173{
174	char *q;
175	char buf[12];
176
177	q = buf;
178	strlcpy(buf, p, sizeof(buf));
179	while (*q)
180		putcharwrap(f, *q++);
181}
182
183struct number *
184readnumber(struct source *src, u_int base, u_int bscale)
185{
186	struct number *n;
187	BN_ULONG v;
188	int ch;
189	u_int iscale = 0;
190	bool dot = false, sign = false;
191
192	n = new_number();
193	BN_zero(n->number);
194
195	while ((ch = (*src->vtable->readchar)(src)) != EOF) {
196
197		if ('0' <= ch && ch <= '9')
198			v = ch - '0';
199		else if ('A' <= ch && ch <= 'F')
200			v = ch - 'A' + 10;
201		else if (ch == '_') {
202			sign = true;
203			continue;
204		} else if (ch == '.') {
205			if (dot)
206				break;
207			dot = true;
208			continue;
209		} else {
210			(*src->vtable->unreadchar)(src);
211			break;
212		}
213		if (dot)
214			iscale++;
215
216		bn_check(BN_mul_word(n->number, base));
217		bn_check(BN_add_word(n->number, v));
218	}
219	if (base == 10) {
220		n->scale = iscale;
221	} else {
222		/* At this point, the desired result is n->number / base^iscale*/
223		struct number *quotient, *divisor, *_n;
224		BIGNUM *base_n, *exponent;
225		BN_CTX *ctx;
226
227		ctx = BN_CTX_new();
228		base_n = BN_new();
229		exponent = BN_new();
230		divisor = new_number();
231		BN_zero(base_n);
232		BN_zero(exponent);
233
234		bn_check(BN_add_word(base_n, base));
235		bn_check(BN_add_word(exponent, iscale));
236		bn_check(BN_exp(divisor->number, base_n, exponent, ctx));
237		divisor->scale = 0;
238		quotient = div_number(n, divisor, bscale);
239		_n = n;
240		n = quotient;
241
242		/*
243		 * Trim off trailing zeros to yield the smallest scale without
244		 * loss of accuracy
245		 */
246		while ( n->scale > 0 &&
247			BN_mod_word(n->number, 10) == 0) {
248			normalize(n, n->scale - 1);
249		}
250
251		free_number(_n);
252		free_number(divisor);
253		BN_CTX_free(ctx);
254		BN_free(base_n);
255		BN_free(exponent);
256	}
257	if (sign)
258		negate(n);
259	return (n);
260}
261
262char *
263read_string(struct source *src)
264{
265	char *p;
266	int count, ch, i, new_sz, sz;
267	bool escape;
268
269	escape = false;
270	count = 1;
271	i = 0;
272	sz = 15;
273	p = bmalloc(sz + 1);
274
275	while ((ch = (*src->vtable->readchar)(src)) != EOF) {
276		if (!escape) {
277			if (ch == '[')
278				count++;
279			else if (ch == ']')
280				count--;
281			if (count == 0)
282				break;
283		}
284		if (ch == '\\' && !escape)
285			escape = true;
286		else {
287			escape = false;
288			if (i == sz) {
289				new_sz = sz * 2;
290				p = breallocarray(p, 1, new_sz + 1);
291				sz = new_sz;
292			}
293			p[i++] = ch;
294		}
295	}
296	p[i] = '\0';
297	return (p);
298}
299
300static char *
301get_digit(u_long num, int digits, u_int base)
302{
303	char *p;
304
305	if (base <= 16) {
306		p = bmalloc(2);
307		p[0] = num >= 10 ? num + 'A' - 10 : num + '0';
308		p[1] = '\0';
309	} else {
310		if (asprintf(&p, "%0*lu", digits, num) == -1)
311			err(1, NULL);
312	}
313	return (p);
314}
315
316void
317printnumber(FILE *f, const struct number *b, u_int base)
318{
319	struct number *fract_part, *int_part;
320	struct stack stack;
321	char *p;
322	char buf[11];
323	size_t sz;
324	unsigned int i;
325	int digits;
326
327	charcount = 0;
328	lastchar = -1;
329	if (BN_is_zero(b->number))
330		putcharwrap(f, '0');
331
332	int_part = new_number();
333	fract_part = new_number();
334	fract_part->scale = b->scale;
335
336	if (base <= 16)
337		digits = 1;
338	else {
339		digits = snprintf(buf, sizeof(buf), "%u", base-1);
340	}
341	split_number(b, int_part->number, fract_part->number);
342
343	i = 0;
344	stack_init(&stack);
345	while (!BN_is_zero(int_part->number)) {
346		BN_ULONG rem = BN_div_word(int_part->number, base);
347		stack_pushstring(&stack, get_digit(rem, digits, base));
348		i++;
349	}
350	sz = i;
351	if (BN_is_negative(b->number))
352		putcharwrap(f, '-');
353	for (i = 0; i < sz; i++) {
354		p = stack_popstring(&stack);
355		if (base > 16)
356			putcharwrap(f, ' ');
357		printwrap(f, p);
358		free(p);
359	}
360	stack_clear(&stack);
361	if (b->scale > 0) {
362		struct number *num_base;
363		BIGNUM *mult, *stop;
364
365		putcharwrap(f, '.');
366		num_base = new_number();
367		bn_check(BN_set_word(num_base->number, base));
368		mult = BN_new();
369		bn_checkp(mult);
370		bn_check(BN_one(mult));
371		stop = BN_new();
372		bn_checkp(stop);
373		bn_check(BN_one(stop));
374		scale_number(stop, b->scale);
375
376		i = 0;
377		while (BN_cmp(mult, stop) < 0) {
378			u_long rem;
379
380			if (i && base > 16)
381				putcharwrap(f, ' ');
382			i = 1;
383
384			bmul_number(fract_part, fract_part, num_base,
385			    bmachine_scale());
386			split_number(fract_part, int_part->number, NULL);
387			rem = BN_get_word(int_part->number);
388			p = get_digit(rem, digits, base);
389			int_part->scale = 0;
390			normalize(int_part, fract_part->scale);
391			bn_check(BN_sub(fract_part->number, fract_part->number,
392			    int_part->number));
393			printwrap(f, p);
394			free(p);
395			bn_check(BN_mul_word(mult, base));
396		}
397		free_number(num_base);
398		BN_free(mult);
399		BN_free(stop);
400	}
401	flushwrap(f);
402	free_number(int_part);
403	free_number(fract_part);
404}
405
406void
407print_value(FILE *f, const struct value *value, const char *prefix, u_int base)
408{
409
410	fputs(prefix, f);
411	switch (value->type) {
412	case BCODE_NONE:
413		if (value->array != NULL)
414			fputs("<array>", f);
415		break;
416	case BCODE_NUMBER:
417		printnumber(f, value->u.num, base);
418		break;
419	case BCODE_STRING:
420		fputs(value->u.string, f);
421		break;
422	}
423}
424
425void
426print_ascii(FILE *f, const struct number *n)
427{
428	BIGNUM *v;
429	int ch, i, numbits;
430
431	v = BN_dup(n->number);
432	bn_checkp(v);
433
434	if (BN_is_negative(v))
435		BN_set_negative(v, 0);
436
437	numbits = BN_num_bytes(v) * 8;
438	while (numbits > 0) {
439		ch = 0;
440		for (i = 0; i < 8; i++)
441			ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i);
442		putc(ch, f);
443		numbits -= 8;
444	}
445	BN_free(v);
446}
447