dvi_extractor.c (41973B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2002, 2003, 2004, 2012, 2017, 2019 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/dvi_extractor.c 22 * @brief plugin to support DVI files (from LaTeX) 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include "fulltext.h" 28 #include "pagelayout.h" 29 #include <math.h> 30 31 32 /** 33 * Pair of a PostScipt prefix and the corresponding LE type. 34 */ 35 struct Matches 36 { 37 /** 38 * Prefix in the PS map. 39 */ 40 const char *text; 41 42 /** 43 * Corresponding LE type. 44 */ 45 enum EXTRACTOR_MetaType type; 46 }; 47 48 49 /** 50 * Map from PS names to LE types. 51 */ 52 static struct Matches tmap[] = { 53 { "/Title (", EXTRACTOR_METATYPE_TITLE }, 54 { "/Subject (", EXTRACTOR_METATYPE_SUBJECT }, 55 { "/Author (", EXTRACTOR_METATYPE_AUTHOR_NAME }, 56 { "/Keywords (", EXTRACTOR_METATYPE_KEYWORDS }, 57 { "/Creator (", EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE }, 58 { "/Producer (", EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE }, 59 { NULL, 0 } 60 }; 61 62 63 /** 64 * Parse a "ZZZ" tag. Specifically, the data may contain a 65 * postscript dictionary with metadata. 66 * 67 * @param data overall input stream 68 * @param pos where in data is the zzz data 69 * @param len how many bytes from 'pos' does the zzz data extend? 70 * @param proc function to call with meta data found 71 * @param proc_cls closure for proc 72 * @return 0 to continue to extract, 1 to stop 73 */ 74 static int 75 parseZZZ (const char *data, 76 size_t pos, size_t len, 77 EXTRACTOR_MetaDataProcessor proc, 78 void *proc_cls) 79 { 80 size_t slen; 81 size_t end; 82 unsigned int i; 83 84 end = pos + len; 85 slen = strlen ("ps:SDict begin ["); 86 if ( (len <= slen) || 87 (0 != strncmp ("ps:SDict begin [ ", &data[pos], slen)) ) 88 return 0; 89 pos += slen; 90 while (pos < end) 91 { 92 for (i = 0; NULL != tmap[i].text; i++) 93 { 94 slen = strlen (tmap[i].text); 95 if ( (pos + slen > end) || 96 (0 != strncmp (&data[pos], tmap[i].text, slen)) ) 97 continue; 98 pos += slen; 99 slen = pos; 100 while ((slen < end) && (data[slen] != ')')) 101 slen++; 102 slen = slen - pos; 103 { 104 char value[slen + 1]; 105 106 value[slen] = '\0'; 107 memcpy (value, &data[pos], slen); 108 if (0 != proc (proc_cls, 109 "dvi", 110 tmap[i].type, 111 EXTRACTOR_METAFORMAT_C_STRING, 112 "text/plain", 113 value, 114 strlen (value) + 1)) 115 return 1; 116 } 117 pos += slen + 1; 118 break; 119 } 120 pos++; 121 } 122 return 0; 123 } 124 125 126 /** 127 * Read 32-bit unsigned integer in big-endian format from 'data'. 128 * 129 * @param data pointer to integer (possibly unaligned) 130 * @return 32-bit integer in host byte order 131 */ 132 static uint32_t 133 getIntAt (const void *data) 134 { 135 uint32_t p; 136 137 memcpy (&p, data, 4); /* ensure alignment! */ 138 return ntohl (p); 139 } 140 141 142 /** 143 * Read 16-bit unsigned integer in big-endian format from 'data'. 144 * 145 * @param data pointer to integer (possibly unaligned) 146 * @return 16-bit integer in host byte order 147 */ 148 static uint16_t 149 getShortAt (const void *data) 150 { 151 uint16_t p; 152 153 memcpy (&p, data, sizeof (uint16_t)); /* ensure alignment! */ 154 return ntohs (p); 155 } 156 157 158 /* ****************** full text extraction ********************** */ 159 160 /** 161 * Maximum number of fonts we track. 162 */ 163 #define DVI_MAX_FONTS 1024 164 165 /** 166 * Size of the font hash table (a power of two, larger than 167 * #DVI_MAX_FONTS). 168 */ 169 #define DVI_FONT_HASH 2048 170 171 /** 172 * Maximum depth of the push/pop stack. 173 */ 174 #define DVI_MAX_STACK 1024 175 176 /** 177 * Maximum number of pages we extract text from. 178 */ 179 #define DVI_MAX_PAGES 50000 180 181 /** 182 * Maximum number of lines we collect over the whole document. 183 */ 184 #define DVI_MAX_LINES 500000 185 186 /** 187 * Maximum number of bytes in one line. 188 */ 189 #define DVI_MAX_LINE_BYTES (64 * 1024) 190 191 /** 192 * Font size assumed for undefined fonts (10pt in TeX's scaled points). 193 */ 194 #define DVI_DEFAULT_SIZE 655360 195 196 /** 197 * Markers in the encoding tables for glyphs that expand to several 198 * characters. Real code points are never below 0x20. 199 */ 200 #define LIG_FF 1 201 #define LIG_FI 2 202 #define LIG_FL 3 203 #define LIG_FFI 4 204 #define LIG_FFL 5 205 #define LIG_SS 6 206 207 208 /** 209 * Font encodings we know how to map to Unicode. 210 */ 211 enum DviEncoding 212 { 213 /** 214 * TeX text (OT1), e.g. cmr10. 215 */ 216 ENC_OT1, 217 218 /** 219 * TeX typewriter text (OT1 variant), e.g. cmtt10. 220 */ 221 ENC_OT1TT, 222 223 /** 224 * Cork encoding (T1), e.g. ecrm1000, sfrm1000, ec-lmr10. 225 */ 226 ENC_T1, 227 228 /** 229 * ASCII plus ISO-8859-1 upper half (roughly TeXBase1, 8r). 230 */ 231 ENC_LATIN1, 232 233 /** 234 * TeX math italic, e.g. cmmi10. 235 */ 236 ENC_MATHIT, 237 238 /** 239 * TeX math symbols, e.g. cmsy10. 240 */ 241 ENC_SYMBOL, 242 243 /** 244 * Font whose glyphs we do not map (math extension, dingbats, ...). 245 */ 246 ENC_NONE 247 }; 248 249 250 /** 251 * A font defined in the DVI file. 252 */ 253 struct DviFont 254 { 255 /** 256 * Font number used in the DVI file. 257 */ 258 uint32_t k; 259 260 /** 261 * Scaled size in DVI units. 262 */ 263 double size; 264 265 /** 266 * Encoding guessed from the font name. 267 */ 268 enum DviEncoding enc; 269 }; 270 271 272 /** 273 * Registers of the DVI machine. 274 */ 275 struct DviRegs 276 { 277 int64_t h; 278 int64_t v; 279 int64_t w; 280 int64_t x; 281 int64_t y; 282 int64_t z; 283 }; 284 285 286 /** 287 * State of the full-text extraction. 288 */ 289 struct DviText 290 { 291 /** 292 * Extraction context, for keep-alives. 293 */ 294 struct EXTRACTOR_ExtractContext *ec; 295 296 /** 297 * The DVI file. 298 */ 299 const unsigned char *data; 300 301 /** 302 * Number of bytes in @e data. 303 */ 304 size_t size; 305 306 /** 307 * Defined fonts. 308 */ 309 struct DviFont fonts[DVI_MAX_FONTS]; 310 311 /** 312 * Number of entries in @e fonts. 313 */ 314 unsigned int num_fonts; 315 316 /** 317 * Hash table (open addressing) mapping font numbers to 1 + their 318 * index in @e fonts; 0 marks an empty slot. 319 */ 320 uint16_t font_hash[DVI_FONT_HASH]; 321 322 /** 323 * Pages collected so far. 324 */ 325 struct EXTRACTOR_FullTextPage *pages; 326 327 /** 328 * Geometry of the lines of each page. 329 */ 330 struct EXTRACTOR_PageLineGeom **geoms; 331 332 /** 333 * Number of pages in @e pages / @e geoms. 334 */ 335 unsigned int num_pages; 336 337 /** 338 * Allocated length of the geometry array of the current page. 339 */ 340 unsigned int geom_cap; 341 342 /** 343 * Text of the current line. 344 */ 345 char *lbuf; 346 347 /** 348 * Bytes in @e lbuf. 349 */ 350 size_t llen; 351 352 /** 353 * Allocated size of @e lbuf. 354 */ 355 size_t lcap; 356 357 /** 358 * 1 if a line is being collected. 359 */ 360 int in_line; 361 362 /** 363 * 1 if a space must precede the next character of the line. 364 */ 365 int pending_space; 366 367 /** 368 * Accent (combining code point) waiting for its base character, 0 369 * for none. 370 */ 371 uint32_t pending_accent; 372 373 /** 374 * 1 if @e pending_accent was placed over the preceding base character 375 * (@e last_cp), so that it may belong to it rather than to the next. 376 */ 377 int accent_post_ok; 378 379 /** 380 * Last base character appended to the line (for accents placed 381 * after their base), 0 if none. 382 */ 383 uint32_t last_cp; 384 385 /** 386 * Offset of @e last_cp in @e lbuf. 387 */ 388 size_t last_cp_off; 389 390 /** 391 * Baseline of the current line. 392 */ 393 int64_t line_v; 394 395 /** 396 * Left end of the current line. 397 */ 398 double line_x0; 399 400 /** 401 * (Estimated) right end of the current line. 402 */ 403 double line_x1; 404 405 /** 406 * Font size at the start of the current line. 407 */ 408 double line_size; 409 410 /** 411 * (Estimated) horizontal position after the last glyph. 412 */ 413 double last_end; 414 415 /** 416 * Total number of lines collected. 417 */ 418 unsigned int total_lines; 419 420 /** 421 * Total number of text bytes collected. 422 */ 423 size_t total_bytes; 424 425 /** 426 * Smallest and largest baseline seen. 427 */ 428 int64_t vmin; 429 int64_t vmax; 430 431 /** 432 * 1 if @e vmin and @e vmax are set. 433 */ 434 int have_v; 435 436 /** 437 * Remaining number of opcodes we are willing to interpret. 438 */ 439 uint64_t budget; 440 441 /** 442 * 1 if we ran out of memory or into a limit: stop collecting. 443 */ 444 int full; 445 }; 446 447 448 /** 449 * Approximate widths (in 1/1000 em) of the glyphs of cmr10, used to 450 * estimate where a glyph ends (DVI does not record glyph widths). 451 */ 452 static const uint16_t cmr_widths[128] = { 453 /* 0x00 Greek capitals */ 454 625, 833, 778, 694, 667, 750, 722, 778, 722, 778, 722, 455 /* 0x0B ff fi fl ffi ffl */ 456 583, 556, 556, 833, 833, 457 /* 0x10 dotless i/j, accents */ 458 278, 306, 500, 500, 500, 500, 500, 750, 444, 459 /* 0x19 ss ae oe o/ AE OE O/ */ 460 500, 722, 778, 500, 903, 1014, 778, 461 /* 0x20 */ 462 278, 278, 500, 833, 500, 833, 778, 278, 389, 389, 500, 778, 278, 333, 463 278, 500, 464 /* 0x30 digits */ 465 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 466 /* 0x3A */ 467 278, 278, 278, 778, 472, 472, 468 /* 0x40 @ A-O */ 469 778, 750, 708, 722, 764, 681, 653, 785, 750, 361, 514, 778, 625, 917, 470 750, 778, 471 /* 0x50 P-Z [ " ] ^ . */ 472 681, 778, 736, 556, 722, 750, 750, 1028, 750, 750, 611, 278, 500, 278, 473 500, 278, 474 /* 0x60 ` a-o */ 475 278, 500, 556, 444, 556, 444, 306, 500, 556, 278, 306, 528, 278, 833, 476 556, 500, 477 /* 0x70 p-z -- --- accents */ 478 556, 528, 392, 394, 389, 556, 528, 722, 528, 528, 444, 500, 1000, 500, 479 500, 500 480 }; 481 482 483 /** 484 * Greek capitals at 0x00-0x0A of OT1 and math italic fonts. 485 */ 486 static const uint16_t greek_caps[11] = { 487 0x0393, 0x0394, 0x0398, 0x039B, 0x039E, 0x03A0, 0x03A3, 0x03A5, 488 0x03A6, 0x03A8, 0x03A9 489 }; 490 491 /** 492 * Glyphs 0x10-0x1F of OT1 fonts. 493 */ 494 static const uint16_t ot1_10[16] = { 495 0x0131, 0x0237, 0x0300, 0x0301, 0x030C, 0x0306, 0x0304, 0x030A, 496 0x0327, 0x00DF, 0x00E6, 0x0153, 0x00F8, 0x00C6, 0x0152, 0x00D8 497 }; 498 499 /** 500 * Glyphs 0x00-0x1F of T1 fonts. 501 */ 502 static const uint16_t t1_00[32] = { 503 0x0300, 0x0301, 0x0302, 0x0303, 0x0308, 0x030B, 0x030A, 0x030C, 504 0x0306, 0x0304, 0x0307, 0x0327, 0x0328, 0x201A, 0x2039, 0x203A, 505 0x201C, 0x201D, 0x201E, 0x00AB, 0x00BB, 0x2013, 0x2014, 0, 506 0, 0x0131, 0x0237, LIG_FF, LIG_FI, LIG_FL, LIG_FFI, LIG_FFL 507 }; 508 509 /** 510 * Glyphs 0x80-0xBF of T1 fonts. 511 */ 512 static const uint16_t t1_80[64] = { 513 0x0102, 0x0104, 0x0106, 0x010C, 0x010E, 0x011A, 0x0118, 0x011E, 514 0x0139, 0x013D, 0x0141, 0x0143, 0x0147, 0x014A, 0x0150, 0x0154, 515 0x0158, 0x015A, 0x0160, 0x015E, 0x0164, 0x0162, 0x0170, 0x016E, 516 0x0178, 0x0179, 0x017D, 0x017B, 0x0132, 0x0130, 0x0111, 0x00A7, 517 0x0103, 0x0105, 0x0107, 0x010D, 0x010F, 0x011B, 0x0119, 0x011F, 518 0x013A, 0x013E, 0x0142, 0x0144, 0x0148, 0x014B, 0x0151, 0x0155, 519 0x0159, 0x015B, 0x0161, 0x015F, 0x0165, 0x0163, 0x0171, 0x016F, 520 0x00FF, 0x017A, 0x017E, 0x017C, 0x0133, 0x00A1, 0x00BF, 0x00A3 521 }; 522 523 /** 524 * Glyphs 0x0B-0x27 of math italic fonts (lower-case Greek). 525 */ 526 static const uint16_t mathit_0b[29] = { 527 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03F5, 0x03B6, 0x03B7, 0x03B8, 528 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03C0, 0x03C1, 529 0x03C3, 0x03C4, 0x03C5, 0x03D5, 0x03C7, 0x03C8, 0x03C9, 0x03B5, 530 0x03D1, 0x03D6, 0x03F1, 0x03C2, 0x03C6 531 }; 532 533 /** 534 * Glyphs 0x00-0x7F of math symbol fonts (0: not mapped). 535 */ 536 static const uint16_t symbol_map[128] = { 537 0x2212, 0x22C5, 0x00D7, 0x2217, 0x00F7, 0x22C4, 0x00B1, 0x2213, 538 0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x25EF, 0x2218, 0x2022, 539 0x224D, 0x2261, 0x2286, 0x2287, 0x2264, 0x2265, 0x2AAF, 0x2AB0, 540 0x223C, 0x2248, 0x2282, 0x2283, 0x226A, 0x226B, 0x227A, 0x227B, 541 0x2190, 0x2192, 0x2191, 0x2193, 0x2194, 0x2197, 0x2198, 0x2243, 542 0x21D0, 0x21D2, 0x21D1, 0x21D3, 0x21D4, 0x2196, 0x2199, 0x221D, 543 0x2032, 0x221E, 0x2208, 0x220B, 0x25B3, 0x25BD, 0, 0, 544 0x2200, 0x2203, 0x00AC, 0x2205, 0x211C, 0x2111, 0x22A4, 0x22A5, 545 0x2135, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 546 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 547 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 548 'X', 'Y', 'Z', 0x222A, 0x2229, 0x228E, 0x2227, 0x2228, 549 0x22A2, 0x22A3, 0x230A, 0x230B, 0x2308, 0x2309, '{', '}', 550 0x27E8, 0x27E9, '|', 0x2016, 0x2195, 0x21D5, '\\', 0x2240, 551 0x221A, 0x2A3F, 0x2207, 0x222B, 0x2294, 0x2293, 0x2291, 0x2292, 552 0x00A7, 0x2020, 0x2021, 0x00B6, 0x2663, 0x2662, 0x2661, 0x2660 553 }; 554 555 556 /** 557 * Map glyph @a c of a font with encoding @a enc to Unicode. 558 * 559 * @param enc font encoding 560 * @param c glyph code 561 * @return code point, a LIG_* marker, or 0 if the glyph has no text 562 */ 563 static uint32_t 564 dvi_map_glyph (enum DviEncoding enc, 565 uint32_t c) 566 { 567 if (c > 255) 568 return 0; 569 switch (enc) 570 { 571 case ENC_OT1: 572 case ENC_OT1TT: 573 if (c >= 128) 574 return 0; 575 if (c < 0x0B) 576 return greek_caps[c]; 577 if (ENC_OT1TT == enc) 578 { 579 switch (c) 580 { 581 case 0x0B: return 0x2191; 582 case 0x0C: return 0x2193; 583 case 0x0D: return '\''; 584 case 0x0E: return 0x00A1; 585 case 0x0F: return 0x00BF; 586 case 0x7F: return 0x0308; 587 default: 588 break; 589 } 590 if (c >= 0x20) 591 return c; 592 } 593 if (c < 0x10) 594 return LIG_FF + (c - 0x0B); 595 if (c < 0x20) 596 return ot1_10[c - 0x10]; 597 switch (c) 598 { 599 case 0x20: return 0x0337; /* stroke of \l and \L */ 600 case 0x22: return 0x201D; 601 case 0x27: return 0x2019; 602 case 0x3C: return 0x00A1; 603 case 0x3E: return 0x00BF; 604 case 0x5C: return 0x201C; 605 case 0x5E: return 0x0302; 606 case 0x5F: return 0x0307; 607 case 0x60: return 0x2018; 608 case 0x7B: return 0x2013; 609 case 0x7C: return 0x2014; 610 case 0x7D: return 0x030B; 611 case 0x7E: return 0x0303; 612 case 0x7F: return 0x0308; 613 default: 614 return c; 615 } 616 case ENC_T1: 617 if (c < 0x20) 618 return t1_00[c]; 619 if (c == 0x7F) 620 return '-'; 621 if (c < 0x80) 622 return c; 623 if (c < 0xC0) 624 return t1_80[c - 0x80]; 625 switch (c) 626 { 627 case 0xD7: return 0x0152; 628 case 0xDF: return LIG_SS; 629 case 0xF7: return 0x0153; 630 case 0xFF: return 0x00DF; 631 default: 632 return c; 633 } 634 case ENC_LATIN1: 635 if ( ( (c >= 0x20) && (c < 0x7F) ) || 636 (c >= 0xA0) ) 637 return c; 638 return 0; 639 case ENC_MATHIT: 640 if (c < 0x0B) 641 return greek_caps[c]; 642 if (c < 0x28) 643 return mathit_0b[c - 0x0B]; 644 if ( (c >= 0x30) && (c <= 0x3E) && (c != 0x3D) ) 645 return c; 646 if (0x3D == c) 647 return '/'; 648 if (0x40 == c) 649 return 0x2202; 650 if ( ( (c >= 'A') && (c <= 'Z') ) || 651 ( (c >= 'a') && (c <= 'z') ) ) 652 return c; 653 if (0x60 == c) 654 return 0x2113; 655 if (0x7B == c) 656 return 0x0131; 657 if (0x7C == c) 658 return 0x0237; 659 return 0; 660 case ENC_SYMBOL: 661 if (c >= 128) 662 return 0; 663 return symbol_map[c]; 664 case ENC_NONE: 665 default: 666 return 0; 667 } 668 } 669 670 671 /** 672 * Estimate the width of glyph @a c, in 1/1000 em. 673 * 674 * @param enc font encoding 675 * @param c glyph code 676 * @return estimated width 677 */ 678 static unsigned int 679 dvi_glyph_width (enum DviEncoding enc, 680 uint32_t c) 681 { 682 switch (enc) 683 { 684 case ENC_OT1: 685 return (c < 128) ? cmr_widths[c] : 500; 686 case ENC_OT1TT: 687 return 525; 688 case ENC_T1: 689 case ENC_LATIN1: 690 if ( (c >= 0x21) && (c < 0x7F) && 691 (c != '"') && (c != '<') && (c != '>') && (c != '\\') && 692 (c != '_') && (c < '{') ) 693 return cmr_widths[c]; 694 if (c >= 0x80) 695 return ( (c & 0x3F) < 0x20) ? 720 : 500; 696 return 500; 697 default: 698 return 600; 699 } 700 } 701 702 703 /** 704 * Guess the encoding of a font from its name. 705 * 706 * @param name font name (not 0-terminated) 707 * @param len length of @a name 708 * @return guessed encoding 709 */ 710 static enum DviEncoding 711 dvi_font_encoding (const char *name, 712 size_t len) 713 { 714 static const char *const none[] = { 715 "cmex", "lmex", "msam", "msbm", "lasy", "wasy", "line", "lcircle", 716 "tc", "ts1-", "eufm", "eusm", "eurm", "rsfs", "stmary", "bbm", "dsrom", 717 "pzd", "psy", "wncy", "manfnt", "logo", "esint", "cmbsy10x", 718 NULL 719 }; 720 static const char *const tt[] = { 721 "cmtt", "cmsltt", "cmitt", "cmtcsc", "lmtt", "rm-lmtt", NULL 722 }; 723 static const char *const sf[] = { 724 "rm", "ti", "bx", "sl", "ss", "tt", "cc", "bi", "bl", "si", "sx", 725 "so", "sq", "xc", "tl", "st", "oc", "ci", "ui", "vi", "bo", 726 NULL 727 }; 728 char lc[64]; 729 size_t i; 730 size_t end; 731 732 if (len >= sizeof (lc)) 733 len = sizeof (lc) - 1; 734 for (i = 0; i < len; i++) 735 lc[i] = (char) tolower ((unsigned char) name[i]); 736 lc[len] = '\0'; 737 for (i = 0; NULL != none[i]; i++) 738 if (0 == strncmp (lc, none[i], strlen (none[i]))) 739 return ENC_NONE; 740 if ( (0 == strncmp (lc, "cmmi", 4)) || 741 (0 == strncmp (lc, "lmmi", 4)) || 742 (0 == strncmp (lc, "rm-lmmi", 7)) ) 743 return ENC_MATHIT; 744 if ( (0 == strncmp (lc, "cmsy", 4)) || 745 (0 == strncmp (lc, "cmbsy", 5)) || 746 (0 == strncmp (lc, "lmsy", 4)) || 747 (0 == strncmp (lc, "lmbsy", 5)) ) 748 return ENC_SYMBOL; 749 for (i = 0; NULL != tt[i]; i++) 750 if (0 == strncmp (lc, tt[i], strlen (tt[i]))) 751 return ENC_OT1TT; 752 if ( (0 == strncmp (lc, "ec-", 3)) || 753 (0 == strncmp (lc, "t1-", 3)) || 754 (0 == strncmp (lc, "cs-", 3)) || 755 (0 == strncmp (lc, "qx-", 3)) || 756 (0 == strncmp (lc, "l7x-", 4)) || 757 (0 == strncmp (lc, "t5-", 3)) || 758 (0 == strncmp (lc, "texnansi-", 9)) ) 759 return ENC_T1; 760 if ( (len > 2) && 761 (0 == strncmp (lc, "ec", 2)) && 762 isalpha ((unsigned char) lc[2]) ) 763 return ENC_T1; 764 if ( (len > 4) && 765 (0 == strncmp (lc, "sf", 2)) ) 766 for (i = 0; NULL != sf[i]; i++) 767 if (0 == strncmp (&lc[2], sf[i], 2)) 768 return ENC_T1; 769 /* Karl Berry's font names: <supplier><family><variant><encoding> */ 770 end = len; 771 while ( (end > 0) && 772 isdigit ((unsigned char) lc[end - 1]) ) 773 end--; 774 for (i = (end > 4) ? end - 4 : 0; i + 1 < end; i++) 775 { 776 if ('8' == lc[i]) 777 { 778 if ('t' == lc[i + 1]) 779 return ENC_T1; 780 if ('r' == lc[i + 1]) 781 return ENC_LATIN1; 782 if ( ('c' == lc[i + 1]) || 783 ('y' == lc[i + 1]) ) 784 return ENC_NONE; 785 } 786 } 787 return ENC_OT1; 788 } 789 790 791 /** 792 * Check whether @a cp is a combining accent. 793 * 794 * @param cp code point 795 * @return 1 if combining 796 */ 797 static int 798 is_accent (uint32_t cp) 799 { 800 return ( (cp >= 0x0300) && (cp < 0x0370) ) ? 1 : 0; 801 } 802 803 804 /** 805 * Append raw bytes to the current line. 806 * 807 * @param t state 808 * @param s bytes to append 809 * @param len number of bytes 810 */ 811 static void 812 line_bytes (struct DviText *t, 813 const char *s, 814 size_t len) 815 { 816 if (t->llen + len > DVI_MAX_LINE_BYTES) 817 return; 818 if (t->llen + len > t->lcap) 819 { 820 size_t ncap = (0 == t->lcap) ? 256 : t->lcap; 821 char *n; 822 823 while (ncap < t->llen + len) 824 ncap *= 2; 825 n = realloc (t->lbuf, 826 ncap); 827 if (NULL == n) 828 { 829 t->full = 1; 830 return; 831 } 832 t->lbuf = n; 833 t->lcap = ncap; 834 } 835 memcpy (&t->lbuf[t->llen], 836 s, 837 len); 838 t->llen += len; 839 } 840 841 842 /** 843 * Append a code point to the current line, preceded by a space if one 844 * is pending. 845 * 846 * @param t state 847 * @param cp code point (not a LIG_* marker) 848 */ 849 static void 850 line_cp (struct DviText *t, 851 uint32_t cp) 852 { 853 char enc[4]; 854 size_t n; 855 856 if ( (t->pending_space) && 857 (t->llen > 0) ) 858 line_bytes (t, " ", 1); 859 t->pending_space = 0; 860 if (cp < 0x80) 861 { 862 enc[0] = (char) cp; 863 n = 1; 864 } 865 else if (cp < 0x800) 866 { 867 enc[0] = (char) (0xC0 | (cp >> 6)); 868 enc[1] = (char) (0x80 | (cp & 0x3F)); 869 n = 2; 870 } 871 else 872 { 873 enc[0] = (char) (0xE0 | (cp >> 12)); 874 enc[1] = (char) (0x80 | ((cp >> 6) & 0x3F)); 875 enc[2] = (char) (0x80 | (cp & 0x3F)); 876 n = 3; 877 } 878 line_bytes (t, enc, n); 879 } 880 881 882 static void 883 resolve_accent (struct DviText *t); 884 885 886 /** 887 * Finish the current line (if any) and add it to the current page. 888 * 889 * @param t state 890 */ 891 static void 892 flush_line (struct DviText *t) 893 { 894 struct EXTRACTOR_FullTextPage *page; 895 struct EXTRACTOR_PageLineGeom *g; 896 897 if (! t->in_line) 898 return; 899 resolve_accent (t); 900 t->in_line = 0; 901 t->pending_space = 0; 902 t->last_cp = 0; 903 if ( (0 == t->llen) || 904 (t->full) || 905 (0 == t->num_pages) ) 906 { 907 t->llen = 0; 908 return; 909 } 910 if ( (t->total_lines >= DVI_MAX_LINES) || 911 (t->total_bytes + t->llen >= EXTRACTOR_FULLTEXT_MAX) ) 912 { 913 t->full = 1; 914 t->llen = 0; 915 return; 916 } 917 page = &t->pages[t->num_pages - 1]; 918 if (page->num_lines >= t->geom_cap) 919 { 920 unsigned int ncap = (0 == t->geom_cap) ? 32 : 2 * t->geom_cap; 921 922 g = realloc (t->geoms[t->num_pages - 1], 923 ncap * sizeof (*g)); 924 if (NULL == g) 925 { 926 t->full = 1; 927 t->llen = 0; 928 return; 929 } 930 t->geoms[t->num_pages - 1] = g; 931 t->geom_cap = ncap; 932 } 933 g = &t->geoms[t->num_pages - 1][page->num_lines]; 934 if (0 != EXTRACTOR_fulltext_page_add_ (page, 935 t->lbuf, 936 t->llen, 937 -1.0, 938 0)) 939 { 940 t->full = 1; 941 t->llen = 0; 942 return; 943 } 944 g->x0 = t->line_x0; 945 g->x1 = t->line_x1; 946 g->y = (double) t->line_v; 947 g->size = t->line_size; 948 if ( (! t->have_v) || 949 (t->line_v < t->vmin) ) 950 t->vmin = t->line_v; 951 if ( (! t->have_v) || 952 (t->line_v > t->vmax) ) 953 t->vmax = t->line_v; 954 t->have_v = 1; 955 t->total_lines++; 956 t->total_bytes += t->llen; 957 t->llen = 0; 958 } 959 960 961 /** 962 * Attach a pending accent to the preceding base character if it was 963 * placed over it; otherwise drop it. 964 * 965 * @param t state 966 */ 967 static void 968 resolve_accent (struct DviText *t) 969 { 970 uint32_t comp; 971 int pending_space; 972 973 if (0 == t->pending_accent) 974 return; 975 if ( (t->accent_post_ok) && 976 (0 != t->last_cp) && 977 (t->last_cp_off <= t->llen) ) 978 { 979 comp = EXTRACTOR_pagelayout_compose_ (t->last_cp, 980 t->pending_accent); 981 pending_space = t->pending_space; 982 t->pending_space = 0; 983 if (0 != comp) 984 { 985 t->llen = t->last_cp_off; 986 line_cp (t, comp); 987 } 988 else 989 { 990 line_cp (t, t->pending_accent); 991 } 992 t->pending_space = pending_space; 993 t->last_cp = 0; 994 } 995 t->pending_accent = 0; 996 t->accent_post_ok = 0; 997 } 998 999 1000 /** 1001 * Typeset glyph @a c of @a font at (@a h, @a v). 1002 * 1003 * @param t state 1004 * @param font the font, NULL if undefined 1005 * @param c glyph code 1006 * @param h horizontal position 1007 * @param v vertical position 1008 * @return estimated width of the glyph 1009 */ 1010 static double 1011 put_glyph (struct DviText *t, 1012 const struct DviFont *font, 1013 uint32_t c, 1014 int64_t h, 1015 int64_t v) 1016 { 1017 enum DviEncoding enc = (NULL == font) ? ENC_OT1 : font->enc; 1018 double size = (NULL == font) ? DVI_DEFAULT_SIZE : font->size; 1019 double width = size * dvi_glyph_width (enc, c) / 1000.0; 1020 double hd = (double) h; 1021 uint32_t cp; 1022 double gap; 1023 1024 cp = dvi_map_glyph (enc, c); 1025 if (0 == cp) 1026 return width; 1027 if (t->in_line) 1028 { 1029 double big = (size > t->line_size) ? size : t->line_size; 1030 double dv = (double) v - (double) t->line_v; 1031 1032 if (fabs (dv) > 0.7 * big) 1033 flush_line (t); 1034 } 1035 if (! t->in_line) 1036 { 1037 t->in_line = 1; 1038 t->line_v = v; 1039 t->line_x0 = hd; 1040 t->line_x1 = hd; 1041 t->line_size = size; 1042 t->last_end = hd; 1043 t->pending_space = 0; 1044 t->pending_accent = 0; 1045 t->accent_post_ok = 0; 1046 t->last_cp = 0; 1047 } 1048 gap = hd - t->last_end; 1049 if (gap > 0.17 * size) 1050 t->pending_space = 1; 1051 if (hd + width > t->line_x1) 1052 t->line_x1 = hd + width; 1053 t->last_end = hd + width; 1054 if (is_accent (cp)) 1055 { 1056 resolve_accent (t); 1057 t->pending_accent = cp; 1058 /* the accent overlaps the preceding base character: it belongs to 1059 that one unless the next glyph is set under it, too */ 1060 t->accent_post_ok = ( (0 != t->last_cp) && 1061 (gap < -0.1 * size) && 1062 (! t->pending_space) ) ? 1 : 0; 1063 return width; 1064 } 1065 if ( (0 != t->pending_accent) && 1066 (gap >= 0) ) 1067 resolve_accent (t); 1068 if (cp < 0x20) 1069 { 1070 static const char *const ligs[] = { 1071 "", "ff", "fi", "fl", "ffi", "ffl", "SS" 1072 }; 1073 const char *l = ligs[cp]; 1074 1075 t->pending_accent = 0; 1076 t->accent_post_ok = 0; 1077 while ('\0' != *l) 1078 { 1079 line_cp (t, (unsigned char) *l); 1080 l++; 1081 } 1082 t->last_cp = 0; 1083 return width; 1084 } 1085 if (0 != t->pending_accent) 1086 { 1087 uint32_t comp = EXTRACTOR_pagelayout_compose_ (cp, 1088 t->pending_accent); 1089 1090 if (0 != comp) 1091 { 1092 line_cp (t, comp); 1093 } 1094 else 1095 { 1096 line_cp (t, cp); 1097 line_cp (t, t->pending_accent); 1098 } 1099 t->pending_accent = 0; 1100 t->accent_post_ok = 0; 1101 t->last_cp = 0; 1102 return width; 1103 } 1104 { 1105 size_t before = t->llen; 1106 1107 line_cp (t, cp); 1108 if (t->llen > before) 1109 { 1110 t->last_cp_off = t->llen - ( (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : 3); 1111 t->last_cp = cp; 1112 } 1113 else 1114 { 1115 t->last_cp = 0; 1116 } 1117 } 1118 return width; 1119 } 1120 1121 1122 /** 1123 * Read an unsigned big-endian integer of @a n bytes. 1124 * 1125 * @param t state 1126 * @param pos position to read at, updated 1127 * @param n number of bytes (1-4) 1128 * @param[out] ret value read 1129 * @return 0 on success, -1 if out of bounds 1130 */ 1131 static int 1132 read_u (const struct DviText *t, 1133 size_t *pos, 1134 unsigned int n, 1135 uint32_t *ret) 1136 { 1137 uint32_t r = 0; 1138 unsigned int i; 1139 1140 if ( (*pos > t->size) || 1141 (t->size - *pos < n) ) 1142 return -1; 1143 for (i = 0; i < n; i++) 1144 r = (r << 8) | t->data[*pos + i]; 1145 *pos += n; 1146 *ret = r; 1147 return 0; 1148 } 1149 1150 1151 /** 1152 * Read a signed big-endian integer of @a n bytes. 1153 * 1154 * @param t state 1155 * @param pos position to read at, updated 1156 * @param n number of bytes (1-4) 1157 * @param[out] ret value read 1158 * @return 0 on success, -1 if out of bounds 1159 */ 1160 static int 1161 read_s (const struct DviText *t, 1162 size_t *pos, 1163 unsigned int n, 1164 int64_t *ret) 1165 { 1166 uint32_t u; 1167 1168 if (0 != read_u (t, pos, n, &u)) 1169 return -1; 1170 if ( (n < 4) && 1171 (u & (1U << (8 * n - 1))) ) 1172 *ret = (int64_t) u - ((int64_t) 1 << (8 * n)); 1173 else if (4 == n) 1174 *ret = (int64_t) (int32_t) u; 1175 else 1176 *ret = (int64_t) u; 1177 return 0; 1178 } 1179 1180 1181 /** 1182 * Hash a font number. 1183 * 1184 * @param k font number 1185 * @return initial slot in the font hash table 1186 */ 1187 static unsigned int 1188 font_slot (uint32_t k) 1189 { 1190 return (unsigned int) ((k * 2654435761U) >> 21) & (DVI_FONT_HASH - 1); 1191 } 1192 1193 1194 /** 1195 * Look up font @a k. 1196 * 1197 * @param t state 1198 * @param k font number 1199 * @return the font, NULL if undefined 1200 */ 1201 static const struct DviFont * 1202 find_font (const struct DviText *t, 1203 uint32_t k) 1204 { 1205 unsigned int h = font_slot (k); 1206 1207 while (0 != t->font_hash[h]) 1208 { 1209 const struct DviFont *f = &t->fonts[t->font_hash[h] - 1]; 1210 1211 if (f->k == k) 1212 return f; 1213 h = (h + 1) & (DVI_FONT_HASH - 1); 1214 } 1215 return NULL; 1216 } 1217 1218 1219 /** 1220 * Parse a fnt_def command (opcode already consumed) and register the 1221 * font. 1222 * 1223 * @param t state 1224 * @param pos position after the opcode, updated 1225 * @param n number of bytes of the font number (1-4) 1226 * @return 0 on success, -1 on malformed input 1227 */ 1228 static int 1229 parse_fnt_def (struct DviText *t, 1230 size_t *pos, 1231 unsigned int n) 1232 { 1233 uint32_t k; 1234 uint32_t csum; 1235 int64_t s; 1236 uint32_t d; 1237 uint32_t a; 1238 uint32_t l; 1239 unsigned int i; 1240 1241 if ( (0 != read_u (t, pos, n, &k)) || 1242 (0 != read_u (t, pos, 4, &csum)) || 1243 (0 != read_s (t, pos, 4, &s)) || 1244 (0 != read_u (t, pos, 4, &d)) || 1245 (0 != read_u (t, pos, 1, &a)) || 1246 (0 != read_u (t, pos, 1, &l)) ) 1247 return -1; 1248 if (t->size - *pos < a + l) 1249 return -1; 1250 if ( (NULL == find_font (t, k)) && 1251 (t->num_fonts < DVI_MAX_FONTS) ) 1252 { 1253 unsigned int h = font_slot (k); 1254 1255 while (0 != t->font_hash[h]) 1256 h = (h + 1) & (DVI_FONT_HASH - 1); 1257 t->font_hash[h] = (uint16_t) (t->num_fonts + 1); 1258 struct DviFont *f = &t->fonts[t->num_fonts++]; 1259 1260 f->k = k; 1261 if (s < 0) 1262 s = -s; 1263 if ( (0 == s) || 1264 (s > (1 << 30)) ) 1265 s = DVI_DEFAULT_SIZE; 1266 f->size = (double) s; 1267 f->enc = dvi_font_encoding ((const char *) &t->data[*pos + a], 1268 l); 1269 } 1270 *pos += a + l; 1271 (void) csum; 1272 (void) d; 1273 return 0; 1274 } 1275 1276 1277 /** 1278 * Interpret the page starting with the bop at @a bop and collect its 1279 * text into a new page. 1280 * 1281 * @param t state 1282 * @param bop offset of the page's bop command 1283 */ 1284 static void 1285 interpret_page (struct DviText *t, 1286 size_t bop) 1287 { 1288 struct DviRegs r; 1289 struct DviRegs *stack; 1290 unsigned int depth; 1291 const struct DviFont *font; 1292 size_t pos; 1293 struct EXTRACTOR_FullTextPage *np; 1294 struct EXTRACTOR_PageLineGeom **ng; 1295 1296 np = realloc (t->pages, 1297 (t->num_pages + 1) * sizeof (*np)); 1298 if (NULL == np) 1299 { 1300 t->full = 1; 1301 return; 1302 } 1303 t->pages = np; 1304 ng = realloc (t->geoms, 1305 (t->num_pages + 1) * sizeof (*ng)); 1306 if (NULL == ng) 1307 { 1308 t->full = 1; 1309 return; 1310 } 1311 t->geoms = ng; 1312 memset (&t->pages[t->num_pages], 0, sizeof (*np)); 1313 t->geoms[t->num_pages] = NULL; 1314 t->num_pages++; 1315 t->geom_cap = 0; 1316 stack = malloc (DVI_MAX_STACK * sizeof (*stack)); 1317 if (NULL == stack) 1318 { 1319 t->full = 1; 1320 return; 1321 } 1322 memset (&r, 0, sizeof (r)); 1323 depth = 0; 1324 font = NULL; 1325 pos = bop + 45; 1326 while ( (pos < t->size) && 1327 (! t->full) ) 1328 { 1329 unsigned char op = t->data[pos++]; 1330 uint32_t u; 1331 int64_t s; 1332 int64_t s2; 1333 1334 if (0 == t->budget) 1335 { 1336 t->full = 1; 1337 break; 1338 } 1339 t->budget--; 1340 if (0 == (t->budget & 0xFFFF)) 1341 (void) t->ec->seek (t->ec->cls, 1342 0, 1343 SEEK_CUR); /* keep the host from giving up */ 1344 if (op < 128) 1345 { 1346 r.h += (int64_t) put_glyph (t, font, op, r.h, r.v); 1347 continue; 1348 } 1349 if ( (op >= 171) && 1350 (op <= 234) ) 1351 { 1352 font = find_font (t, op - 171); 1353 continue; 1354 } 1355 switch (op) 1356 { 1357 case 128: case 129: case 130: case 131: /* set1..4 */ 1358 if (0 != read_u (t, &pos, op - 127, &u)) 1359 goto DONE; 1360 r.h += (int64_t) put_glyph (t, font, u, r.h, r.v); 1361 break; 1362 case 133: case 134: case 135: case 136: /* put1..4 */ 1363 if (0 != read_u (t, &pos, op - 132, &u)) 1364 goto DONE; 1365 (void) put_glyph (t, font, u, r.h, r.v); 1366 break; 1367 case 132: /* set_rule */ 1368 if ( (0 != read_s (t, &pos, 4, &s)) || 1369 (0 != read_s (t, &pos, 4, &s2)) ) 1370 goto DONE; 1371 r.h += s2; 1372 break; 1373 case 137: /* put_rule */ 1374 if ( (0 != read_s (t, &pos, 4, &s)) || 1375 (0 != read_s (t, &pos, 4, &s2)) ) 1376 goto DONE; 1377 break; 1378 case 138: /* nop */ 1379 break; 1380 case 141: /* push */ 1381 if (depth >= DVI_MAX_STACK) 1382 goto DONE; 1383 stack[depth++] = r; 1384 break; 1385 case 142: /* pop */ 1386 if (0 == depth) 1387 goto DONE; 1388 r = stack[--depth]; 1389 break; 1390 case 143: case 144: case 145: case 146: /* right1..4 */ 1391 if (0 != read_s (t, &pos, op - 142, &s)) 1392 goto DONE; 1393 r.h += s; 1394 break; 1395 case 147: /* w0 */ 1396 r.h += r.w; 1397 break; 1398 case 148: case 149: case 150: case 151: /* w1..4 */ 1399 if (0 != read_s (t, &pos, op - 147, &s)) 1400 goto DONE; 1401 r.w = s; 1402 r.h += s; 1403 break; 1404 case 152: /* x0 */ 1405 r.h += r.x; 1406 break; 1407 case 153: case 154: case 155: case 156: /* x1..4 */ 1408 if (0 != read_s (t, &pos, op - 152, &s)) 1409 goto DONE; 1410 r.x = s; 1411 r.h += s; 1412 break; 1413 case 157: case 158: case 159: case 160: /* down1..4 */ 1414 if (0 != read_s (t, &pos, op - 156, &s)) 1415 goto DONE; 1416 r.v += s; 1417 break; 1418 case 161: /* y0 */ 1419 r.v += r.y; 1420 break; 1421 case 162: case 163: case 164: case 165: /* y1..4 */ 1422 if (0 != read_s (t, &pos, op - 161, &s)) 1423 goto DONE; 1424 r.y = s; 1425 r.v += s; 1426 break; 1427 case 166: /* z0 */ 1428 r.v += r.z; 1429 break; 1430 case 167: case 168: case 169: case 170: /* z1..4 */ 1431 if (0 != read_s (t, &pos, op - 166, &s)) 1432 goto DONE; 1433 r.z = s; 1434 r.v += s; 1435 break; 1436 case 235: case 236: case 237: case 238: /* fnt1..4 */ 1437 if (0 != read_u (t, &pos, op - 234, &u)) 1438 goto DONE; 1439 font = find_font (t, u); 1440 break; 1441 case 239: case 240: case 241: case 242: /* xxx1..4 */ 1442 if (0 != read_u (t, &pos, op - 238, &u)) 1443 goto DONE; 1444 if (t->size - pos < u) 1445 goto DONE; 1446 pos += u; 1447 break; 1448 case 243: case 244: case 245: case 246: /* fnt_def1..4 */ 1449 if (0 != parse_fnt_def (t, &pos, op - 242)) 1450 goto DONE; 1451 break; 1452 case 140: /* eop */ 1453 default: /* bop, pre, post, post_post, undefined */ 1454 goto DONE; 1455 } 1456 /* keep the registers far away from overflowing */ 1457 if ( (r.h > INT64_C (1) << 50) || (r.h < -(INT64_C (1) << 50)) || 1458 (r.v > INT64_C (1) << 50) || (r.v < -(INT64_C (1) << 50)) ) 1459 goto DONE; 1460 } 1461 DONE: 1462 flush_line (t); 1463 free (stack); 1464 } 1465 1466 1467 /** 1468 * Extract the full text of the DVI file and emit it. 1469 * 1470 * @param ec extraction context 1471 * @param data the DVI file 1472 * @param size number of bytes in @a data 1473 * @param post offset of the postamble 1474 * @param page_count number of pages 1475 * @return 0 to continue, 1 if the callback asked us to stop 1476 */ 1477 static int 1478 dvi_fulltext (struct EXTRACTOR_ExtractContext *ec, 1479 const unsigned char *data, 1480 size_t size, 1481 size_t post, 1482 unsigned int page_count) 1483 { 1484 struct DviText *t; 1485 size_t *bops; 1486 size_t pos; 1487 unsigned int n; 1488 unsigned int i; 1489 int64_t l = 0; 1490 double top; 1491 double bottom; 1492 int ret = 0; 1493 1494 if ( (0 == page_count) || 1495 (post > size) || 1496 (size - post < 29) ) 1497 return 0; 1498 t = calloc (1, sizeof (*t)); 1499 if (NULL == t) 1500 return 0; 1501 t->ec = ec; 1502 t->data = data; 1503 t->size = size; 1504 t->budget = 4 * (uint64_t) size + 1000000; 1505 /* fonts from the postamble */ 1506 pos = post + 29; 1507 while (pos < size) 1508 { 1509 unsigned char op = data[pos++]; 1510 1511 if (138 == op) 1512 continue; 1513 if ( (op < 243) || 1514 (op > 246) || 1515 (0 != parse_fnt_def (t, &pos, op - 242)) ) 1516 break; 1517 } 1518 pos = post + 17; 1519 (void) read_s (t, &pos, 4, &l); 1520 /* list of pages, in order */ 1521 if (page_count > DVI_MAX_PAGES) 1522 page_count = DVI_MAX_PAGES; 1523 bops = malloc (page_count * sizeof (size_t)); 1524 if (NULL == bops) 1525 { 1526 free (t); 1527 return 0; 1528 } 1529 { 1530 uint32_t p; 1531 uint32_t prev; 1532 unsigned int total; 1533 1534 total = 0; 1535 p = getIntAt (&data[post + 1]); 1536 prev = UINT32_MAX; 1537 while ( (UINT32_MAX != p) && 1538 ((size_t) p + 45 <= size) && 1539 (p < prev) && 1540 (139 == data[p]) ) 1541 { 1542 total++; 1543 prev = p; 1544 p = getIntAt (&data[p + 41]); 1545 } 1546 n = (total < page_count) ? total : page_count; 1547 p = getIntAt (&data[post + 1]); 1548 prev = UINT32_MAX; 1549 while ( (total > 0) && 1550 (UINT32_MAX != p) && 1551 ((size_t) p + 45 <= size) && 1552 (p < prev) && 1553 (139 == data[p]) ) 1554 { 1555 total--; 1556 if (total < n) 1557 bops[total] = p; 1558 prev = p; 1559 p = getIntAt (&data[p + 41]); 1560 } 1561 } 1562 for (i = 0; (i < n) && (! t->full); i++) 1563 interpret_page (t, bops[i]); 1564 free (bops); 1565 /* relative vertical positions */ 1566 top = 0; 1567 bottom = (l > 0) ? (double) l : 0; 1568 if (t->have_v) 1569 { 1570 if ((double) t->vmin < top) 1571 top = (double) t->vmin; 1572 if ((double) t->vmax > bottom) 1573 bottom = (double) t->vmax; 1574 } 1575 for (i = 0; i < t->num_pages; i++) 1576 { 1577 unsigned int j; 1578 1579 for (j = 0; j < t->pages[i].num_lines; j++) 1580 { 1581 double y = -1; 1582 1583 if (bottom > top) 1584 y = (t->geoms[i][j].y - top) / (bottom - top); 1585 if (y > 1) 1586 y = 1; 1587 t->pages[i].lines[j].y = y; 1588 } 1589 } 1590 if (t->num_pages > 0) 1591 { 1592 struct EXTRACTOR_FullText ft; 1593 1594 EXTRACTOR_fulltext_filter_margins_ (t->pages, 1595 t->num_pages); 1596 EXTRACTOR_pagelayout_paragraphs_ (t->pages, 1597 t->geoms, 1598 t->num_pages, 1599 0.06); 1600 EXTRACTOR_fulltext_init_ (&ft); 1601 EXTRACTOR_fulltext_append_pages_ (&ft, 1602 t->pages, 1603 t->num_pages); 1604 ret = EXTRACTOR_fulltext_emit_ (&ft, 1605 ec, 1606 "dvi"); 1607 EXTRACTOR_fulltext_clear_ (&ft); 1608 } 1609 for (i = 0; i < t->num_pages; i++) 1610 { 1611 EXTRACTOR_fulltext_page_clear_ (&t->pages[i]); 1612 free (t->geoms[i]); 1613 } 1614 free (t->pages); 1615 free (t->geoms); 1616 free (t->lbuf); 1617 free (t); 1618 return (0 != ret) ? 1 : 0; 1619 } 1620 1621 1622 /** 1623 * Main entry method for the 'application/x-dvi' extraction plugin. 1624 * 1625 * @param ec extraction context provided to the plugin 1626 */ 1627 void 1628 EXTRACTOR_dvi_extract_method (struct EXTRACTOR_ExtractContext *ec); 1629 1630 void 1631 EXTRACTOR_dvi_extract_method (struct EXTRACTOR_ExtractContext *ec) 1632 { 1633 unsigned int klen; 1634 uint32_t pos; 1635 uint32_t opos; 1636 unsigned int len; 1637 unsigned int pageCount; 1638 char pages[16]; 1639 void *buf; 1640 unsigned char *data; 1641 uint64_t size; 1642 uint64_t off; 1643 ssize_t iret; 1644 uint32_t post; 1645 1646 if (40 >= (iret = ec->read (ec->cls, &buf, 1024))) 1647 return; 1648 data = buf; 1649 if ( (data[0] != 247) || 1650 (data[1] != 2) ) 1651 return; /* cannot be DVI or unsupported version */ 1652 klen = data[14]; 1653 size = ec->get_size (ec->cls); 1654 if (size > 16 * 1024 * 1024) 1655 return; /* too large */ 1656 if (klen + 15 > size) 1657 return; /* malformed klen */ 1658 if (NULL == (data = malloc ((size_t) size))) 1659 return; /* out of memory */ 1660 memcpy (data, buf, iret); 1661 off = iret; 1662 while (off < size) 1663 { 1664 if (0 >= (iret = ec->read (ec->cls, &buf, 16 * 1024))) 1665 { 1666 free (data); 1667 return; 1668 } 1669 memcpy (&data[off], buf, iret); 1670 off += iret; 1671 } 1672 pos = size - 1; 1673 while ( (223 == data[pos]) && 1674 (pos > 0) ) 1675 pos--; 1676 if ( (2 != data[pos]) || 1677 (pos < 40) ) 1678 goto CLEANUP; 1679 pos--; 1680 pos -= 4; 1681 /* assert pos at 'post_post tag' */ 1682 if (data[pos] != 249) 1683 goto CLEANUP; 1684 opos = pos; 1685 pos = getIntAt (&data[opos + 1]); 1686 if ( (pos + 25 > size) || 1687 (pos + 25 < pos) ) 1688 goto CLEANUP; 1689 /* assert pos at 'post' command */ 1690 if (data[pos] != 248) 1691 goto CLEANUP; 1692 post = pos; 1693 pageCount = 0; 1694 opos = pos; 1695 pos = getIntAt (&data[opos + 1]); 1696 while (1) 1697 { 1698 if (UINT32_MAX == pos) 1699 break; 1700 if ( (pos + 45 > size) || 1701 (pos + 45 < pos) ) 1702 goto CLEANUP; 1703 if (data[pos] != 139) /* expect 'bop' */ 1704 goto CLEANUP; 1705 pageCount++; 1706 opos = pos; 1707 pos = getIntAt (&data[opos + 41]); 1708 if (UINT32_MAX == pos) 1709 break; 1710 if (pos >= opos) 1711 goto CLEANUP; /* invalid! */ 1712 } 1713 /* ok, now we believe it's a dvi... */ 1714 snprintf (pages, 1715 sizeof (pages), 1716 "%u", 1717 pageCount); 1718 if (0 != ec->proc (ec->cls, 1719 "dvi", 1720 EXTRACTOR_METATYPE_PAGE_COUNT, 1721 EXTRACTOR_METAFORMAT_UTF8, 1722 "text/plain", 1723 pages, 1724 strlen (pages) + 1)) 1725 goto CLEANUP; 1726 if (0 != ec->proc (ec->cls, 1727 "dvi", 1728 EXTRACTOR_METATYPE_MIMETYPE, 1729 EXTRACTOR_METAFORMAT_UTF8, 1730 "text/plain", 1731 "application/x-dvi", 1732 strlen ("application/x-dvi") + 1)) 1733 goto CLEANUP; 1734 { 1735 char comment[klen + 1]; 1736 1737 comment[klen] = '\0'; 1738 memcpy (comment, &data[15], klen); 1739 if (0 != ec->proc (ec->cls, 1740 "dvi", 1741 EXTRACTOR_METATYPE_COMMENT, 1742 EXTRACTOR_METAFORMAT_C_STRING, 1743 "text/plain", 1744 comment, 1745 strlen (comment) + 1)) 1746 goto CLEANUP; 1747 } 1748 /* try to find PDF/ps special */ 1749 pos = opos; 1750 while ( (size >= 100) && 1751 (pos < size - 100) ) 1752 { 1753 switch (data[pos]) 1754 { 1755 case 139: /* begin page 'bop', we typically have to skip that one to 1756 find the zzz's */ 1757 pos += 45; /* skip bop */ 1758 break; 1759 case 239: /* zzz1 */ 1760 len = data[pos + 1]; 1761 if ( (pos + 2 + len < size) && 1762 (0 != parseZZZ ((const char *) data, pos + 2, len, ec->proc, 1763 ec->cls)) ) 1764 goto CLEANUP; 1765 pos += len + 2; 1766 break; 1767 case 240: /* zzz2 */ 1768 len = getShortAt (&data[pos + 1]); 1769 if ( (pos + 3 + len < size) && 1770 (0 != parseZZZ ((const char *) data, pos + 3, len, ec->proc, 1771 ec->cls)) ) 1772 goto CLEANUP; 1773 pos += len + 3; 1774 break; 1775 case 241: /* zzz3, who uses that? */ 1776 len = (getShortAt (&data[pos + 1])) + 65536 * data[pos + 3]; 1777 if ( (pos + 4 + len < size) && 1778 (0 != parseZZZ ((const char *) data, pos + 4, len, ec->proc, 1779 ec->cls)) ) 1780 goto CLEANUP; 1781 pos += len + 4; 1782 break; 1783 case 242: /* zzz4, hurray! */ 1784 len = getIntAt (&data[pos + 1]); 1785 if ( (pos + 5 + len < size) && 1786 (0 != parseZZZ ((const char *) data, pos + 5, len, ec->proc, 1787 ec->cls)) ) 1788 goto CLEANUP; 1789 pos += len + 5; 1790 break; 1791 default: /* unsupported opcode, abort scan */ 1792 goto FULLTEXT; 1793 } 1794 } 1795 FULLTEXT: 1796 if (EXTRACTOR_fulltext_requested_ (ec->config)) 1797 (void) dvi_fulltext (ec, 1798 data, 1799 (size_t) size, 1800 post, 1801 pageCount); 1802 CLEANUP: 1803 free (data); 1804 } 1805 1806 1807 /* end of dvi_extractor.c */