1*99acaf1eSschwarze /* $OpenBSD: preconv.c,v 1.9 2018/12/13 11:55:14 schwarze Exp $ */
27232fc26Sschwarze /*
37232fc26Sschwarze * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
47232fc26Sschwarze * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
57232fc26Sschwarze *
67232fc26Sschwarze * Permission to use, copy, modify, and distribute this software for any
77232fc26Sschwarze * purpose with or without fee is hereby granted, provided that the above
87232fc26Sschwarze * copyright notice and this permission notice appear in all copies.
97232fc26Sschwarze *
107232fc26Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117232fc26Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127232fc26Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137232fc26Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147232fc26Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157232fc26Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167232fc26Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177232fc26Sschwarze */
187232fc26Sschwarze #include <sys/types.h>
197232fc26Sschwarze
2052a7f466Sschwarze #include <assert.h>
217232fc26Sschwarze #include <stdio.h>
227232fc26Sschwarze #include <string.h>
23*99acaf1eSschwarze
247232fc26Sschwarze #include "mandoc.h"
25*99acaf1eSschwarze #include "roff.h"
26*99acaf1eSschwarze #include "mandoc_parse.h"
277232fc26Sschwarze #include "libmandoc.h"
287232fc26Sschwarze
297232fc26Sschwarze int
preconv_encode(const struct buf * ib,size_t * ii,struct buf * ob,size_t * oi,int * filenc)304d57ce78Sschwarze preconv_encode(const struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
31cdea9283Sschwarze int *filenc)
327232fc26Sschwarze {
334d57ce78Sschwarze const unsigned char *cu;
3452a7f466Sschwarze int nby;
357232fc26Sschwarze unsigned int accum;
3652a7f466Sschwarze
374d57ce78Sschwarze cu = (const unsigned char *)ib->buf + *ii;
3852a7f466Sschwarze assert(*cu & 0x80);
397232fc26Sschwarze
407232fc26Sschwarze if ( ! (*filenc & MPARSE_UTF8))
417232fc26Sschwarze goto latin;
427232fc26Sschwarze
4352a7f466Sschwarze nby = 1;
4452a7f466Sschwarze while (nby < 5 && *cu & (1 << (7 - nby)))
4552a7f466Sschwarze nby++;
467232fc26Sschwarze
4752a7f466Sschwarze switch (nby) {
4852a7f466Sschwarze case 2:
4952a7f466Sschwarze accum = *cu & 0x1f;
5052a7f466Sschwarze if (accum < 0x02) /* Obfuscated ASCII. */
5152a7f466Sschwarze goto latin;
527232fc26Sschwarze break;
5352a7f466Sschwarze case 3:
5452a7f466Sschwarze accum = *cu & 0x0f;
5552a7f466Sschwarze break;
5652a7f466Sschwarze case 4:
5752a7f466Sschwarze accum = *cu & 0x07;
5852a7f466Sschwarze if (accum > 0x04) /* Beyond Unicode. */
5952a7f466Sschwarze goto latin;
6052a7f466Sschwarze break;
6152a7f466Sschwarze default: /* Bad sequence header. */
6252a7f466Sschwarze goto latin;
637232fc26Sschwarze }
647232fc26Sschwarze
6552a7f466Sschwarze cu++;
6652a7f466Sschwarze switch (nby) {
6752a7f466Sschwarze case 3:
6852a7f466Sschwarze if ((accum == 0x00 && ! (*cu & 0x20)) || /* Use 2-byte. */
6952a7f466Sschwarze (accum == 0x0d && *cu & 0x20)) /* Surrogates. */
7052a7f466Sschwarze goto latin;
717232fc26Sschwarze break;
7252a7f466Sschwarze case 4:
7352a7f466Sschwarze if ((accum == 0x00 && ! (*cu & 0x30)) || /* Use 3-byte. */
7452a7f466Sschwarze (accum == 0x04 && *cu & 0x30)) /* Beyond Unicode. */
7552a7f466Sschwarze goto latin;
767232fc26Sschwarze break;
777232fc26Sschwarze default:
787232fc26Sschwarze break;
797232fc26Sschwarze }
807232fc26Sschwarze
8152a7f466Sschwarze while (--nby) {
8252a7f466Sschwarze if ((*cu & 0xc0) != 0x80) /* Invalid continuation. */
8352a7f466Sschwarze goto latin;
8452a7f466Sschwarze accum <<= 6;
8552a7f466Sschwarze accum += *cu & 0x3f;
8652a7f466Sschwarze cu++;
8752a7f466Sschwarze }
8852a7f466Sschwarze
8952a7f466Sschwarze assert(accum > 0x7f);
9052a7f466Sschwarze assert(accum < 0x110000);
9152a7f466Sschwarze assert(accum < 0xd800 || accum > 0xdfff);
9252a7f466Sschwarze
9352a7f466Sschwarze *oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
944d57ce78Sschwarze *ii = (const char *)cu - ib->buf;
9552a7f466Sschwarze *filenc &= ~MPARSE_LATIN1;
96526e306bSschwarze return 1;
977232fc26Sschwarze
987232fc26Sschwarze latin:
997232fc26Sschwarze if ( ! (*filenc & MPARSE_LATIN1))
100526e306bSschwarze return 0;
1017232fc26Sschwarze
102cdea9283Sschwarze *oi += snprintf(ob->buf + *oi, 11,
103cdea9283Sschwarze "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
1047232fc26Sschwarze
1057232fc26Sschwarze *filenc &= ~MPARSE_UTF8;
106526e306bSschwarze return 1;
1077232fc26Sschwarze }
1087232fc26Sschwarze
1097232fc26Sschwarze int
preconv_cue(const struct buf * b,size_t offset)110cdea9283Sschwarze preconv_cue(const struct buf *b, size_t offset)
1117232fc26Sschwarze {
1127232fc26Sschwarze const char *ln, *eoln, *eoph;
1137232fc26Sschwarze size_t sz, phsz;
1147232fc26Sschwarze
115cdea9283Sschwarze ln = b->buf + offset;
116cdea9283Sschwarze sz = b->sz - offset;
1177232fc26Sschwarze
1187232fc26Sschwarze /* Look for the end-of-line. */
1197232fc26Sschwarze
1207232fc26Sschwarze if (NULL == (eoln = memchr(ln, '\n', sz)))
1217232fc26Sschwarze eoln = ln + sz;
1227232fc26Sschwarze
1237232fc26Sschwarze /* Check if we have the correct header/trailer. */
1247232fc26Sschwarze
1257232fc26Sschwarze if ((sz = (size_t)(eoln - ln)) < 10 ||
1267232fc26Sschwarze memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
127526e306bSschwarze return MPARSE_UTF8 | MPARSE_LATIN1;
1287232fc26Sschwarze
1297232fc26Sschwarze /* Move after the header and adjust for the trailer. */
1307232fc26Sschwarze
1317232fc26Sschwarze ln += 7;
1327232fc26Sschwarze sz -= 10;
1337232fc26Sschwarze
1347232fc26Sschwarze while (sz > 0) {
1357232fc26Sschwarze while (sz > 0 && ' ' == *ln) {
1367232fc26Sschwarze ln++;
1377232fc26Sschwarze sz--;
1387232fc26Sschwarze }
1397232fc26Sschwarze if (0 == sz)
1407232fc26Sschwarze break;
1417232fc26Sschwarze
1427232fc26Sschwarze /* Find the end-of-phrase marker (or eoln). */
1437232fc26Sschwarze
1447232fc26Sschwarze if (NULL == (eoph = memchr(ln, ';', sz)))
1457232fc26Sschwarze eoph = eoln - 3;
1467232fc26Sschwarze else
1477232fc26Sschwarze eoph++;
1487232fc26Sschwarze
1497232fc26Sschwarze /* Only account for the "coding" phrase. */
1507232fc26Sschwarze
1517232fc26Sschwarze if ((phsz = eoph - ln) < 7 ||
1527232fc26Sschwarze strncasecmp(ln, "coding:", 7)) {
1537232fc26Sschwarze sz -= phsz;
1547232fc26Sschwarze ln += phsz;
1557232fc26Sschwarze continue;
1567232fc26Sschwarze }
1577232fc26Sschwarze
1587232fc26Sschwarze sz -= 7;
1597232fc26Sschwarze ln += 7;
1607232fc26Sschwarze
1617232fc26Sschwarze while (sz > 0 && ' ' == *ln) {
1627232fc26Sschwarze ln++;
1637232fc26Sschwarze sz--;
1647232fc26Sschwarze }
1657232fc26Sschwarze if (0 == sz)
166526e306bSschwarze return 0;
1677232fc26Sschwarze
1687232fc26Sschwarze /* Check us against known encodings. */
1697232fc26Sschwarze
1707232fc26Sschwarze if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
171526e306bSschwarze return MPARSE_UTF8;
1727232fc26Sschwarze if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
173526e306bSschwarze return MPARSE_LATIN1;
174526e306bSschwarze return 0;
1757232fc26Sschwarze }
176526e306bSschwarze return MPARSE_UTF8 | MPARSE_LATIN1;
1777232fc26Sschwarze }
178