dvi_extractor.c (8783B)
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 28 29 /** 30 * Pair of a PostScipt prefix and the corresponding LE type. 31 */ 32 struct Matches 33 { 34 /** 35 * Prefix in the PS map. 36 */ 37 const char *text; 38 39 /** 40 * Corresponding LE type. 41 */ 42 enum EXTRACTOR_MetaType type; 43 }; 44 45 46 /** 47 * Map from PS names to LE types. 48 */ 49 static struct Matches tmap[] = { 50 { "/Title (", EXTRACTOR_METATYPE_TITLE }, 51 { "/Subject (", EXTRACTOR_METATYPE_SUBJECT }, 52 { "/Author (", EXTRACTOR_METATYPE_AUTHOR_NAME }, 53 { "/Keywords (", EXTRACTOR_METATYPE_KEYWORDS }, 54 { "/Creator (", EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE }, 55 { "/Producer (", EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE }, 56 { NULL, 0 } 57 }; 58 59 60 /** 61 * Parse a "ZZZ" tag. Specifically, the data may contain a 62 * postscript dictionary with metadata. 63 * 64 * @param data overall input stream 65 * @param pos where in data is the zzz data 66 * @param len how many bytes from 'pos' does the zzz data extend? 67 * @param proc function to call with meta data found 68 * @param proc_cls closure for proc 69 * @return 0 to continue to extract, 1 to stop 70 */ 71 static int 72 parseZZZ (const char *data, 73 size_t pos, size_t len, 74 EXTRACTOR_MetaDataProcessor proc, 75 void *proc_cls) 76 { 77 size_t slen; 78 size_t end; 79 unsigned int i; 80 81 end = pos + len; 82 slen = strlen ("ps:SDict begin ["); 83 if ( (len <= slen) || 84 (0 != strncmp ("ps:SDict begin [ ", &data[pos], slen)) ) 85 return 0; 86 pos += slen; 87 while (pos < end) 88 { 89 for (i = 0; NULL != tmap[i].text; i++) 90 { 91 slen = strlen (tmap[i].text); 92 if ( (pos + slen > end) || 93 (0 != strncmp (&data[pos], tmap[i].text, slen)) ) 94 continue; 95 pos += slen; 96 slen = pos; 97 while ((slen < end) && (data[slen] != ')')) 98 slen++; 99 slen = slen - pos; 100 { 101 char value[slen + 1]; 102 103 value[slen] = '\0'; 104 memcpy (value, &data[pos], slen); 105 if (0 != proc (proc_cls, 106 "dvi", 107 tmap[i].type, 108 EXTRACTOR_METAFORMAT_C_STRING, 109 "text/plain", 110 value, 111 slen + 1)) 112 return 1; 113 } 114 pos += slen + 1; 115 break; 116 } 117 pos++; 118 } 119 return 0; 120 } 121 122 123 /** 124 * Read 32-bit unsigned integer in big-endian format from 'data'. 125 * 126 * @param data pointer to integer (possibly unaligned) 127 * @return 32-bit integer in host byte order 128 */ 129 static uint32_t 130 getIntAt (const void *data) 131 { 132 uint32_t p; 133 134 memcpy (&p, data, 4); /* ensure alignment! */ 135 return ntohl (p); 136 } 137 138 139 /** 140 * Read 16-bit unsigned integer in big-endian format from 'data'. 141 * 142 * @param data pointer to integer (possibly unaligned) 143 * @return 16-bit integer in host byte order 144 */ 145 static uint16_t 146 getShortAt (const void *data) 147 { 148 uint16_t p; 149 150 memcpy (&p, data, sizeof (uint16_t)); /* ensure alignment! */ 151 return ntohs (p); 152 } 153 154 155 /** 156 * Main entry method for the 'application/x-dvi' extraction plugin. 157 * 158 * @param ec extraction context provided to the plugin 159 */ 160 void 161 EXTRACTOR_dvi_extract_method (struct EXTRACTOR_ExtractContext *ec); 162 163 void 164 EXTRACTOR_dvi_extract_method (struct EXTRACTOR_ExtractContext *ec) 165 { 166 unsigned int klen; 167 uint32_t pos; 168 uint32_t opos; 169 unsigned int len; 170 unsigned int pageCount; 171 char pages[16]; 172 void *buf; 173 unsigned char *data; 174 uint64_t size; 175 uint64_t off; 176 ssize_t iret; 177 178 if (40 >= (iret = ec->read (ec->cls, &buf, 1024))) 179 return; 180 data = buf; 181 if ( (data[0] != 247) || 182 (data[1] != 2) ) 183 return; /* cannot be DVI or unsupported version */ 184 klen = data[14]; 185 size = ec->get_size (ec->cls); 186 if (size > 16 * 1024 * 1024) 187 return; /* too large */ 188 if (klen + 15 > size) 189 return; /* malformed klen */ 190 if (NULL == (data = malloc ((size_t) size))) 191 return; /* out of memory */ 192 memcpy (data, buf, iret); 193 off = iret; 194 while (off < size) 195 { 196 if (0 >= (iret = ec->read (ec->cls, &buf, 16 * 1024))) 197 { 198 free (data); 199 return; 200 } 201 memcpy (&data[off], buf, iret); 202 off += iret; 203 } 204 pos = size - 1; 205 while ( (223 == data[pos]) && 206 (pos > 0) ) 207 pos--; 208 if ( (2 != data[pos]) || 209 (pos < 40) ) 210 goto CLEANUP; 211 pos--; 212 pos -= 4; 213 /* assert pos at 'post_post tag' */ 214 if (data[pos] != 249) 215 goto CLEANUP; 216 opos = pos; 217 pos = getIntAt (&data[opos + 1]); 218 if ( (pos + 25 > size) || 219 (pos + 25 < pos) ) 220 goto CLEANUP; 221 /* assert pos at 'post' command */ 222 if (data[pos] != 248) 223 goto CLEANUP; 224 pageCount = 0; 225 opos = pos; 226 pos = getIntAt (&data[opos + 1]); 227 while (1) 228 { 229 if (UINT32_MAX == pos) 230 break; 231 if ( (pos + 45 > size) || 232 (pos + 45 < pos) ) 233 goto CLEANUP; 234 if (data[pos] != 139) /* expect 'bop' */ 235 goto CLEANUP; 236 pageCount++; 237 opos = pos; 238 pos = getIntAt (&data[opos + 41]); 239 if (UINT32_MAX == pos) 240 break; 241 if (pos >= opos) 242 goto CLEANUP; /* invalid! */ 243 } 244 /* ok, now we believe it's a dvi... */ 245 snprintf (pages, 246 sizeof (pages), 247 "%u", 248 pageCount); 249 if (0 != ec->proc (ec->cls, 250 "dvi", 251 EXTRACTOR_METATYPE_PAGE_COUNT, 252 EXTRACTOR_METAFORMAT_UTF8, 253 "text/plain", 254 pages, 255 strlen (pages) + 1)) 256 goto CLEANUP; 257 if (0 != ec->proc (ec->cls, 258 "dvi", 259 EXTRACTOR_METATYPE_MIMETYPE, 260 EXTRACTOR_METAFORMAT_UTF8, 261 "text/plain", 262 "application/x-dvi", 263 strlen ("application/x-dvi") + 1)) 264 goto CLEANUP; 265 { 266 char comment[klen + 1]; 267 268 comment[klen] = '\0'; 269 memcpy (comment, &data[15], klen); 270 if (0 != ec->proc (ec->cls, 271 "dvi", 272 EXTRACTOR_METATYPE_COMMENT, 273 EXTRACTOR_METAFORMAT_C_STRING, 274 "text/plain", 275 comment, 276 klen + 1)) 277 goto CLEANUP; 278 } 279 /* try to find PDF/ps special */ 280 pos = opos; 281 while ( (size >= 100) && 282 (pos < size - 100) ) 283 { 284 switch (data[pos]) 285 { 286 case 139: /* begin page 'bop', we typically have to skip that one to 287 find the zzz's */ 288 pos += 45; /* skip bop */ 289 break; 290 case 239: /* zzz1 */ 291 len = data[pos + 1]; 292 if ( (pos + 2 + len < size) && 293 (0 != parseZZZ ((const char *) data, pos + 2, len, ec->proc, 294 ec->cls)) ) 295 goto CLEANUP; 296 pos += len + 2; 297 break; 298 case 240: /* zzz2 */ 299 len = getShortAt (&data[pos + 1]); 300 if ( (pos + 3 + len < size) && 301 (0 != parseZZZ ((const char *) data, pos + 3, len, ec->proc, 302 ec->cls)) ) 303 goto CLEANUP; 304 pos += len + 3; 305 break; 306 case 241: /* zzz3, who uses that? */ 307 len = (getShortAt (&data[pos + 1])) + 65536 * data[pos + 3]; 308 if ( (pos + 4 + len < size) && 309 (0 != parseZZZ ((const char *) data, pos + 4, len, ec->proc, 310 ec->cls)) ) 311 goto CLEANUP; 312 pos += len + 4; 313 break; 314 case 242: /* zzz4, hurray! */ 315 len = getIntAt (&data[pos + 1]); 316 if ( (pos + 5 + len < size) && 317 (0 != parseZZZ ((const char *) data, pos + 5, len, ec->proc, 318 ec->cls)) ) 319 goto CLEANUP; 320 pos += len + 5; 321 break; 322 default: /* unsupported opcode, abort scan */ 323 goto CLEANUP; 324 } 325 } 326 CLEANUP: 327 free (data); 328 } 329 330 331 /* end of dvi_extractor.c */