1 #include "mupdf/fitz.h"
2 
3 #include <float.h>
4 #include <math.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 
8 #ifdef _MSC_VER
9 #if _MSC_VER < 1500 /* MSVC 2008 */
snprintf(char * s,size_t n,const char * fmt,...)10 int snprintf(char *s, size_t n, const char *fmt, ...)
11 {
12 		int r;
13 		va_list ap;
14 		va_start(ap, fmt);
15 		r = vsprintf(s, fmt, ap);
16 		va_end(ap);
17 		return r;
18 }
19 #else if _MSC_VER < 1900 /* MSVC 2015 */
20 #define snprintf _snprintf
21 #endif
22 #endif
23 
24 static const char *fz_hex_digits = "0123456789abcdef";
25 
26 struct fmtbuf
27 {
28 	fz_context *ctx;
29 	void *user;
30 	void (*emit)(fz_context *ctx, void *user, int c);
31 };
32 
fmtputc(struct fmtbuf * out,int c)33 static inline void fmtputc(struct fmtbuf *out, int c)
34 {
35 	out->emit(out->ctx, out->user, c);
36 }
37 
38 /*
39  * Convert float to shortest possible string that won't lose precision, except:
40  * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX.
41  */
fmtfloat(struct fmtbuf * out,float f)42 static void fmtfloat(struct fmtbuf *out, float f)
43 {
44 	char digits[40], *s = digits;
45 	int exp, ndigits, point;
46 
47 	if (isnan(f)) f = 0;
48 	if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX;
49 
50 	if (signbit(f))
51 		fmtputc(out, '-');
52 
53 	if (f == 0)
54 	{
55 		fmtputc(out, '0');
56 		return;
57 	}
58 
59 	ndigits = fz_grisu(f, digits, &exp);
60 	point = exp + ndigits;
61 
62 	if (point <= 0)
63 	{
64 		fmtputc(out, '.');
65 		while (point++ < 0)
66 			fmtputc(out, '0');
67 		while (ndigits-- > 0)
68 			fmtputc(out, *s++);
69 	}
70 
71 	else
72 	{
73 		while (ndigits-- > 0)
74 		{
75 			fmtputc(out, *s++);
76 			if (--point == 0 && ndigits > 0)
77 				fmtputc(out, '.');
78 		}
79 		while (point-- > 0)
80 			fmtputc(out, '0');
81 	}
82 }
83 
fmtfloat_e(struct fmtbuf * out,double f,int w,int p)84 static void fmtfloat_e(struct fmtbuf *out, double f, int w, int p)
85 {
86 	char buf[100], *s = buf;
87 	snprintf(buf, sizeof buf, "%*.*e", w, p, f);
88 	while (*s)
89 		fmtputc(out, *s++);
90 }
91 
fmtfloat_f(struct fmtbuf * out,double f,int w,int p)92 static void fmtfloat_f(struct fmtbuf *out, double f, int w, int p)
93 {
94 	char buf[100], *s = buf;
95 	snprintf(buf, sizeof buf, "%*.*f", w, p, f);
96 	while (*s)
97 		fmtputc(out, *s++);
98 }
99 
fmtuint32(struct fmtbuf * out,unsigned int a,int s,int z,int w,int base)100 static void fmtuint32(struct fmtbuf *out, unsigned int a, int s, int z, int w, int base)
101 {
102 	char buf[40];
103 	int i;
104 
105 	i = 0;
106 	if (a == 0)
107 		buf[i++] = '0';
108 	while (a) {
109 		buf[i++] = fz_hex_digits[a % base];
110 		a /= base;
111 	}
112 	if (s) {
113 		if (z == '0')
114 			while (i < w - 1)
115 				buf[i++] = z;
116 		buf[i++] = s;
117 	}
118 	while (i < w)
119 		buf[i++] = z;
120 	while (i > 0)
121 		fmtputc(out, buf[--i]);
122 }
123 
fmtuint64(struct fmtbuf * out,uint64_t a,int s,int z,int w,int base)124 static void fmtuint64(struct fmtbuf *out, uint64_t a, int s, int z, int w, int base)
125 {
126 	char buf[80];
127 	int i;
128 
129 	i = 0;
130 	if (a == 0)
131 		buf[i++] = '0';
132 	while (a) {
133 		buf[i++] = fz_hex_digits[a % base];
134 		a /= base;
135 	}
136 	if (s) {
137 		if (z == '0')
138 			while (i < w - 1)
139 				buf[i++] = z;
140 		buf[i++] = s;
141 	}
142 	while (i < w)
143 		buf[i++] = z;
144 	while (i > 0)
145 		fmtputc(out, buf[--i]);
146 }
147 
fmtint32(struct fmtbuf * out,int value,int s,int z,int w,int base)148 static void fmtint32(struct fmtbuf *out, int value, int s, int z, int w, int base)
149 {
150 	unsigned int a;
151 
152 	if (value < 0)
153 	{
154 		s = '-';
155 		a = -value;
156 	}
157 	else if (s)
158 	{
159 		s = '+';
160 		a = value;
161 	}
162 	else
163 	{
164 		s = 0;
165 		a = value;
166 	}
167 	fmtuint32(out, a, s, z, w, base);
168 }
169 
fmtint64(struct fmtbuf * out,int64_t value,int s,int z,int w,int base)170 static void fmtint64(struct fmtbuf *out, int64_t value, int s, int z, int w, int base)
171 {
172 	uint64_t a;
173 
174 	if (value < 0)
175 	{
176 		s = '-';
177 		a = -value;
178 	}
179 	else if (s)
180 	{
181 		s = '+';
182 		a = value;
183 	}
184 	else
185 	{
186 		s = 0;
187 		a = value;
188 	}
189 	fmtuint64(out, a, s, z, w, base);
190 }
191 
fmtquote(struct fmtbuf * out,const char * s,int sq,int eq,int verbatim)192 static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq, int verbatim)
193 {
194 	int i, n, c;
195 	fmtputc(out, sq);
196 	while (*s != 0) {
197 		n = fz_chartorune(&c, s);
198 		switch (c) {
199 		default:
200 			if (c < 32) {
201 				fmtputc(out, '\\');
202 				fmtputc(out, 'x');
203 				fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
204 				fmtputc(out, "0123456789ABCDEF"[(c)&15]);
205 			} else if (c > 127) {
206 				if (verbatim)
207 				{
208 					for (i = 0; i < n; ++i)
209 						fmtputc(out, s[i]);
210 				}
211 				else
212 				{
213 					fmtputc(out, '\\');
214 					fmtputc(out, 'u');
215 					fmtputc(out, "0123456789ABCDEF"[(c>>12)&15]);
216 					fmtputc(out, "0123456789ABCDEF"[(c>>8)&15]);
217 					fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
218 					fmtputc(out, "0123456789ABCDEF"[(c)&15]);
219 				}
220 			} else {
221 				if (c == sq || c == eq)
222 					fmtputc(out, '\\');
223 				fmtputc(out, c);
224 			}
225 			break;
226 		case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
227 		case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
228 		case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
229 		case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
230 		case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
231 		case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
232 		}
233 		s += n;
234 	}
235 	fmtputc(out, eq);
236 }
237 
fmtquote_pdf(struct fmtbuf * out,const char * s,int sq,int eq)238 static void fmtquote_pdf(struct fmtbuf *out, const char *s, int sq, int eq)
239 {
240 	int c;
241 	fmtputc(out, sq);
242 	while ((c = (unsigned char)*s++) != 0) {
243 		switch (c) {
244 		default:
245 			if (c < 32 || c > 127) {
246 				fmtputc(out, '\\');
247 				if (sq == '(')
248 				{
249 					fmtputc(out, '0' + ((c >> 6) & 7));
250 					fmtputc(out, '0' + ((c >> 3) & 7));
251 					fmtputc(out, '0' + ((c) & 7));
252 				}
253 				else
254 				{
255 					fmtputc(out, 'x');
256 					fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
257 					fmtputc(out, "0123456789ABCDEF"[(c)&15]);
258 				}
259 			} else {
260 				if (c == sq || c == eq)
261 					fmtputc(out, '\\');
262 				fmtputc(out, c);
263 			}
264 			break;
265 		case '\\': fmtputc(out, '\\'); fmtputc(out, '\\'); break;
266 		case '\b': fmtputc(out, '\\'); fmtputc(out, 'b'); break;
267 		case '\f': fmtputc(out, '\\'); fmtputc(out, 'f'); break;
268 		case '\n': fmtputc(out, '\\'); fmtputc(out, 'n'); break;
269 		case '\r': fmtputc(out, '\\'); fmtputc(out, 'r'); break;
270 		case '\t': fmtputc(out, '\\'); fmtputc(out, 't'); break;
271 		}
272 	}
273 	fmtputc(out, eq);
274 }
275 
fmtname(struct fmtbuf * out,const char * s)276 static void fmtname(struct fmtbuf *out, const char *s)
277 {
278 	int c;
279 	fmtputc(out, '/');
280 	while ((c = *s++) != 0) {
281 		if (c <= 32 || c == '/' || c == '#') {
282 			fmtputc(out, '#');
283 			fmtputc(out, "0123456789ABCDEF"[(c>>4)&15]);
284 			fmtputc(out, "0123456789ABCDEF"[(c)&15]);
285 		} else {
286 			fmtputc(out, c);
287 		}
288 	}
289 }
290 
291 void
fz_format_string(fz_context * ctx,void * user,void (* emit)(fz_context * ctx,void * user,int c),const char * fmt,va_list args)292 fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args)
293 {
294 	struct fmtbuf out;
295 	int c, s, z, p, w;
296 	int32_t i32;
297 	int64_t i64;
298 	const char *str;
299 	size_t bits;
300 
301 	out.ctx = ctx;
302 	out.user = user;
303 	out.emit = emit;
304 
305 	while ((c = *fmt++) != 0)
306 	{
307 		if (c == '%')
308 		{
309 			s = 0;
310 			z = ' ';
311 
312 			/* flags */
313 			while ((c = *fmt++) != 0)
314 			{
315 				/* plus sign */
316 				if (c == '+')
317 					s = 1;
318 				/* space sign */
319 				else if (c == ' ')
320 					s = ' ';
321 				/* zero padding */
322 				else if (c == '0')
323 					z = '0';
324 				/* TODO: '-' to left justify */
325 				else
326 					break;
327 			}
328 			if (c == 0)
329 				break;
330 
331 			/* width */
332 			w = 0;
333 			if (c == '*') {
334 				c = *fmt++;
335 				w = va_arg(args, int);
336 			} else {
337 				while (c >= '0' && c <= '9') {
338 					w = w * 10 + c - '0';
339 					c = *fmt++;
340 				}
341 			}
342 			if (c == 0)
343 				break;
344 
345 			/* precision */
346 			p = 6;
347 			if (c == '.') {
348 				c = *fmt++;
349 				if (c == 0)
350 					break;
351 				if (c == '*') {
352 					c = *fmt++;
353 					p = va_arg(args, int);
354 				} else {
355 					if (c >= '0' && c <= '9')
356 						p = 0;
357 					while (c >= '0' && c <= '9') {
358 						p = p * 10 + c - '0';
359 						c = *fmt++;
360 					}
361 				}
362 			}
363 			if (c == 0)
364 				break;
365 
366 			/* lengths */
367 			bits = 0;
368 			if (c == 'l') {
369 				c = *fmt++;
370 				bits = sizeof(int64_t) * 8;
371 				if (c == 0)
372 					break;
373 			}
374 			if (c == 't') {
375 				c = *fmt++;
376 				bits = sizeof(ptrdiff_t) * 8;
377 				if (c == 0)
378 					break;
379 			}
380 			if (c == 'z') {
381 				c = *fmt++;
382 				bits = sizeof(size_t) * 8;
383 				if (c == 0)
384 					break;
385 			}
386 
387 			switch (c) {
388 			default:
389 				fmtputc(&out, '%');
390 				fmtputc(&out, c);
391 				break;
392 			case '%':
393 				fmtputc(&out, '%');
394 				break;
395 
396 			case 'M':
397 				{
398 					fz_matrix *matrix = va_arg(args, fz_matrix*);
399 					fmtfloat(&out, matrix->a); fmtputc(&out, ' ');
400 					fmtfloat(&out, matrix->b); fmtputc(&out, ' ');
401 					fmtfloat(&out, matrix->c); fmtputc(&out, ' ');
402 					fmtfloat(&out, matrix->d); fmtputc(&out, ' ');
403 					fmtfloat(&out, matrix->e); fmtputc(&out, ' ');
404 					fmtfloat(&out, matrix->f);
405 				}
406 				break;
407 			case 'R':
408 				{
409 					fz_rect *rect = va_arg(args, fz_rect*);
410 					fmtfloat(&out, rect->x0); fmtputc(&out, ' ');
411 					fmtfloat(&out, rect->y0); fmtputc(&out, ' ');
412 					fmtfloat(&out, rect->x1); fmtputc(&out, ' ');
413 					fmtfloat(&out, rect->y1);
414 				}
415 				break;
416 			case 'P':
417 				{
418 					fz_point *point = va_arg(args, fz_point*);
419 					fmtfloat(&out, point->x); fmtputc(&out, ' ');
420 					fmtfloat(&out, point->y);
421 				}
422 				break;
423 
424 			case 'C': /* unicode char */
425 				c = va_arg(args, int);
426 				if (c < 128)
427 					fmtputc(&out, c);
428 				else {
429 					char buf[10];
430 					int i, n = fz_runetochar(buf, c);
431 					for (i=0; i < n; ++i)
432 						fmtputc(&out, buf[i]);
433 				}
434 				break;
435 			case 'c':
436 				c = va_arg(args, int);
437 				fmtputc(&out, c);
438 				break;
439 
440 			case 'e':
441 				fmtfloat_e(&out, va_arg(args, double), w, p);
442 				break;
443 			case 'f':
444 				fmtfloat_f(&out, va_arg(args, double), w, p);
445 				break;
446 			case 'g':
447 				fmtfloat(&out, va_arg(args, double));
448 				break;
449 
450 			case 'p':
451 				bits = 8 * sizeof(void *);
452 				z = '0';
453 				fmtputc(&out, '0');
454 				fmtputc(&out, 'x');
455 				/* fallthrough */
456 			case 'x':
457 				if (bits == 64)
458 				{
459 					i64 = va_arg(args, int64_t);
460 					fmtuint64(&out, i64, 0, z, w, 16);
461 				}
462 				else
463 				{
464 					i32 = va_arg(args, int);
465 					fmtuint32(&out, i32, 0, z, w, 16);
466 				}
467 				break;
468 			case 'd':
469 			case 'i':
470 				if (bits == 64)
471 				{
472 					i64 = va_arg(args, int64_t);
473 					fmtint64(&out, i64, s, z, w, 10);
474 				}
475 				else
476 				{
477 					i32 = va_arg(args, int);
478 					fmtint32(&out, i32, s, z, w, 10);
479 				}
480 				break;
481 			case 'u':
482 				if (bits == 64)
483 				{
484 					i64 = va_arg(args, int64_t);
485 					fmtuint64(&out, i64, 0, z, w, 10);
486 				}
487 				else
488 				{
489 					i32 = va_arg(args, int);
490 					fmtuint32(&out, i32, 0, z, w, 10);
491 				}
492 				break;
493 
494 			case 's':
495 				str = va_arg(args, const char*);
496 				if (!str)
497 					str = "(null)";
498 				while ((c = *str++) != 0)
499 					fmtputc(&out, c);
500 				break;
501 			case 'Q': /* quoted string (with verbatim unicode) */
502 				str = va_arg(args, const char*);
503 				if (!str) str = "";
504 				fmtquote(&out, str, '"', '"', 1);
505 				break;
506 			case 'q': /* quoted string */
507 				str = va_arg(args, const char*);
508 				if (!str) str = "";
509 				fmtquote(&out, str, '"', '"', 0);
510 				break;
511 			case '(': /* pdf string */
512 				str = va_arg(args, const char*);
513 				if (!str) str = "";
514 				fmtquote_pdf(&out, str, '(', ')');
515 				break;
516 			case 'n': /* pdf name */
517 				str = va_arg(args, const char*);
518 				if (!str) str = "";
519 				fmtname(&out, str);
520 				break;
521 			}
522 		}
523 		else
524 		{
525 			fmtputc(&out, c);
526 		}
527 	}
528 }
529 
530 struct snprintf_buffer
531 {
532 	char *p;
533 	size_t s, n;
534 };
535 
snprintf_emit(fz_context * ctx,void * out_,int c)536 static void snprintf_emit(fz_context *ctx, void *out_, int c)
537 {
538 	struct snprintf_buffer *out = out_;
539 	if (out->n < out->s)
540 		out->p[out->n] = c;
541 	++(out->n);
542 }
543 
544 size_t
fz_vsnprintf(char * buffer,size_t space,const char * fmt,va_list args)545 fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args)
546 {
547 	struct snprintf_buffer out;
548 	out.p = buffer;
549 	out.s = space > 0 ? space - 1 : 0;
550 	out.n = 0;
551 
552 	/* Note: using a NULL context is safe here */
553 	fz_format_string(NULL, &out, snprintf_emit, fmt, args);
554 	if (space > 0)
555 		out.p[out.n < space ? out.n : space - 1] = '\0';
556 
557 	return out.n;
558 }
559 
560 size_t
fz_snprintf(char * buffer,size_t space,const char * fmt,...)561 fz_snprintf(char *buffer, size_t space, const char *fmt, ...)
562 {
563 	va_list ap;
564 	struct snprintf_buffer out;
565 	out.p = buffer;
566 	out.s = space > 0 ? space - 1 : 0;
567 	out.n = 0;
568 
569 	va_start(ap, fmt);
570 	/* Note: using a NULL context is safe here */
571 	fz_format_string(NULL, &out, snprintf_emit, fmt, ap);
572 	if (space > 0)
573 		out.p[out.n < space ? out.n : space - 1] = '\0';
574 	va_end(ap);
575 
576 	return out.n;
577 }
578 
579 char *
fz_asprintf(fz_context * ctx,const char * fmt,...)580 fz_asprintf(fz_context *ctx, const char *fmt, ...)
581 {
582 	size_t len;
583 	char *mem;
584 	va_list ap;
585 	va_start(ap, fmt);
586 	len = fz_vsnprintf(NULL, 0, fmt, ap);
587 	va_end(ap);
588 	mem = Memento_label(fz_malloc(ctx, len+1), "asprintf");
589 	va_start(ap, fmt);
590 	fz_vsnprintf(mem, len+1, fmt, ap);
591 	va_end(ap);
592 	return mem;
593 }
594