/* * Copyright (C) 2012-2022 Jiro Senju * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this package. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_ARPA_INET_H #include #elif defined(HAVE_NETINET_IN_H) #include #else /* What can I do? */ #endif #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #else /* What can I do? */ #endif #ifdef HAVE_LIMITS_H #include #else /* What can I do? */ #endif #include #ifdef HAVE_STDLIB_H #include #else /* What can I do? */ #endif #ifdef HAVE_STRING_H #include #else /* What can I do? */ #endif #ifdef HAVE_UNISTD_H #include #else /* What can I do? */ #endif #if HAVE_MALLOC != 1 || HAVE_MEMSET != 1 || HAVE_MMAP != 1 || HAVE_REALLOC != 1 #error malloc/memset/mmap/realloc unimplemented? #endif #include "dvi.h" /* ---------------------------------------------------------------------- */ #if 0 #define Dpri(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #else #define Dpri(fmt, ...) do {} while (0) #endif #define Errx(cond, fmt, args...) \ if (cond) \ errx(errno, "%s:%d: " fmt, __func__, __LINE__, ##args) #define Err(cond, str) Errx(cond, "%s %m", str) #define ExpandStep 25 struct dvifile { int fd; unsigned char *p; } src, dst; /* ---------------------------------------------------------------------- */ /* single SETRULE/PUTRULE with its color and coordinate */ union path { unsigned char a[64]; struct { int n, color; unsigned char p[]; }; }; #define PathCk(path) \ Errx(path->n >= sizeof(*path) - sizeof(path->n), "%d >= %lu", \ path->n, (unsigned long)sizeof(*path) - sizeof(path->n)); static void p_push(union path *path) { unsigned char *p; p = path->p + path->n; *p = PUSH; path->n++; PathCk(path); } static void p_pop(union path *path) { unsigned char *p; p = path->p + path->n; *p = POP; path->n++; PathCk(path); } static int dvi_move(unsigned char *p, unsigned char op, int v) { int n; union { int v; unsigned char a[sizeof(int)]; } u; Dpri("%p, 0x%x, %d\n", p, op, v); if (!v) return 0; u.v = htonl(v); n = 5; *p++ = op + 3; memcpy(p, u.a + 0, 4); return n; } static void p_moveto(union path *path, int h, int v) { int n; n = dvi_move(path->p + path->n, RIGHT1, h); path->n += n; PathCk(path); n = dvi_move(path->p + path->n, DOWN1, v); path->n += n; PathCk(path); } static void p_pushcolor(union path *path, unsigned int offset) { //XXX1 static unsigned char cmd[] = "\xef\x11" "color push gray 0"; unsigned char *p, *s; unsigned int len; path->color = path->n; p = path->p + path->n; if (offset) { s = src.p + offset; len = 1 + 1 + src.p[offset + 1]; } else { s = cmd; len = sizeof(cmd) - 1; } path->n += len; PathCk(path); memcpy(p, s, len); } static void p_rule(union path *path, unsigned int offset) { unsigned char *p; const unsigned int len = 1 + 4 + 4; p = path->p + path->n; path->n += len; PathCk(path); /* no setrule since it moves the current-point */ *p++ = PUTRULE; memcpy(p, src.p + offset + 1, len - 1); } static void p_popcolor(union path *path) { //XXX1 static char cmd[] = "\xef\x09" "color pop"; const unsigned int len = sizeof(cmd) - 1; unsigned char *p; p = path->p + path->n; path->n += len; PathCk(path); memcpy(p, cmd, len); } /* ---------------------------------------------------------------------- */ /* all SETRULE/PUTRULE in a page */ struct page { unsigned int total, cur; int h, v; /* to be qsort-able, use array instead of list */ union path **path; }; static int page_init(struct page *page) { page->total = ExpandStep; page->cur = 0; page->path = malloc(sizeof(page->path) * page->total); return !!page->path; } static void page_reinit(struct page *page) { page->cur = 0; } static int path_append(struct page *page, union path *path) { union path **p; if (page->cur + 1 >= page->total) { /* expand */ page->total += ExpandStep; p = realloc(page->path, sizeof(page->path) * page->total); Err(!p, "realloc"); page->path = p; } page->path[page->cur++] = path; return 0; } static int color_sort(const void *__a, const void *__b) { const union path **_a = (const union path **)__a, **_b = (const union path **)__b; const union path *a = *_a, *b = *_b; char ca[32], cb[32]; int l; l = a->p[a->color + 1]; memcpy(ca, a->p + a->color + 2, l); ca[l] = 0; l = b->p[b->color + 1]; memcpy(cb, b->p + b->color + 2, l); cb[l] = 0; l = strcmp(ca, cb); if (l > 0) l = -1; else if (l < 0) l = 1; return l; } static void page_write(int fd, struct page *page) { int i, n; union path *path, origin; ssize_t ssz; origin.n = 0; p_push(&origin); p_moveto(&origin, -page->h, -page->v); ssz = write(fd, origin.p, origin.n); Err(ssz != origin.n, "write"); n = page->cur; qsort(page->path, n, sizeof(*page->path), color_sort); for (i = 0; i < n; i++) { path = page->path[i]; ssz = write(fd, path->p, path->n); Err(ssz != path->n, "write"); } origin.n = 0; p_pop(&origin); ssz = write(fd, origin.p, origin.n); Err(ssz != origin.n, "write"); } /* ---------------------------------------------------------------------- */ static void postamble(unsigned int last, unsigned int ofbop, unsigned int srcsz) { unsigned int post, prev; ssize_t ssz; int n; Errx(src.p[last] != POST, "last %u, 0x%x expects 0x%x", last, src.p[last], POST); Dpri("last %u, 0x%x\n", last, last); post = lseek(dst.fd, 0, SEEK_CUR); ssz = write(dst.fd, src.p + last, 1); Err(ssz != 1, "write"); last++; ofbop = htonl(ofbop); ssz = write(dst.fd, &ofbop, 4); Err(ssz != 4, "write"); last += 4; ssz = write(dst.fd, src.p + last, 4 * 6); Err(ssz != 4 * 6, "write"); last += 4 * 6; prev = last; while (src.p[last] != POSTPOST) { n = 0; switch (src.p[last]) { case FNTDEF4: n++; case FNTDEF3: n++; case FNTDEF2: n++; case FNTDEF1: n++; break; default: Errx(src.p[last], "0x%x at %u(0x%x)", src.p[last], last, last); } Dpri("last %u(0x%x), n %d\n", last, last, n); n += 4 * 3 + 1 + 1; n += src.p[last + n] + 1; Dpri("n %d\n", n); last += n; } ssz = write(dst.fd, src.p + prev, last - prev); Err(ssz != last - prev, "write"); /* post_post */ Dpri("last %u, 0x%x\n", last, last); Errx(src.p[last] != POSTPOST, "last %u, 0x%x expects 0x%x", last, src.p[last], POSTPOST); ssz = write(dst.fd, src.p + last, 1); Err(ssz != 1, "write"); last++; post = htonl(post); ssz = write(dst.fd, &post, 4); Err(ssz != 4, "write"); last += 4; ssz = write(dst.fd, src.p + last, srcsz - last); Err(ssz != srcsz - last, "write"); } /* * in dvi, all offsets are represented in 32 bits. * it means no 'long', 'long long', or 'loff_t' are necessary. */ int main(int argc, char *argv[]) { int e, n, h, v; unsigned int height, width, hpx, wpx, last; /* offsets */ unsigned int ofbop, ofcolor, ofrule, ofeop, ofline; float gray; char cmd[BUFSIZ], op[BUFSIZ], colorpush[64], *cmdp, c; struct stat st; union path *path; struct page page; ssize_t ssz; src.fd = open(argv[1], O_RDWR); Err(src.fd < 0, argv[1]); last = 0; e = fstat(src.fd, &st); Err(e, argv[1]); src.p = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, src.fd, 0); Err(src.p == MAP_FAILED, argv[1]); dst.fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); Err(dst.fd < 0, argv[2]); page_init(&page); while (1) { /* read the output of marker.awk */ cmdp = fgets(cmd, sizeof(cmd), stdin); if (!cmdp) break; if (*cmdp == 'h') { /* * depends on the TeX version or variant? * h=-31 v=176 :color_push_gray_0 * : putrule height 26214, width 2290850 * (2x146 pixels) */ n = sscanf(cmdp, "h=%d v=%d " "%u:color_push_%s " "%u: %s height %u, width %u " "(%ux%u pixels)", &h, &v, &ofcolor, colorpush, &ofrule, op, &height, &width, &hpx, &wpx); if (n != 10) { n = sscanf(cmdp, "h=%d v=%d " "%u:pdf:bcolor [%f] " "%u: %s height %u, width %u " "(%ux%u pixels)", &h, &v, &ofcolor, &gray, &ofrule, op, &height, &width, &hpx, &wpx); Errx(n != 10, "n %d, %s", n, cmdp); } path = malloc(sizeof(*path)); Err(!path, "malloc"); path->n = 0; p_push(path); p_moveto(path, h, v); p_pushcolor(path, ofcolor); p_rule(path, ofrule); p_popcolor(path); p_pop(path); path_append(&page, path); } else if (!strncmp(cmdp, "bop", 3)) { /* bop : beginning of page 1 */ n = sscanf(cmdp, "bop %u: beginning %s", &ofbop, op); Errx(n != 2, "n %d, %s", n, cmdp); } else if (!strncmp(cmdp, "bol", 3) || !strncmp(cmdp, "eol", 3)) { /* bol : xxx ' sirule BOL' */ /* eol : xxx ' sirule EOL' */ n = sscanf(cmdp, "%col %u: %s", &c, &ofline, op); Errx(n != 3, "n %d, %s", n, cmdp); memset(src.p + ofline, NOP, src.p[ofline + 1] + 2); } else { /* : eop h=0 v=2206 */ n = sscanf(cmdp, "%u: eop h=%d v=%d", &ofeop, &page.h, &page.v); Errx(n != 3, "n %d, %s", n, cmdp); Dpri("last %u\n", last); ssz = write(dst.fd, src.p + last, ofeop); Errx(ssz != ofeop, "write, %p, %u, %u", src.p, last, ofeop); last = ofeop; Dpri("last %u, 0x%x\n", last, last); page_write(dst.fd, &page); ssz = write(dst.fd, src.p + last, 1); Err(ssz != 1, "write"); last++; page_reinit(&page); } } postamble(last, ofbop, st.st_size); return 0; }