Coverage for /pythoncovmergedfiles/medio/medio/src/pdfminer.six/pdfminer/ccitt.py: 61%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# CCITT Fax decoder
2#
3# Bugs: uncompressed mode untested.
4#
5# cf.
6# ITU-T Recommendation T.4
7# "Standardization of Group 3 facsimile terminals
8# for document transmission"
9# ITU-T Recommendation T.6
10# "FACSIMILE CODING SCHEMES AND CODING CONTROL FUNCTIONS
11# FOR GROUP 4 FACSIMILE APPARATUS"
14import array
15from typing import (
16 Any,
17 Callable,
18 Dict,
19 Iterator,
20 List,
21 MutableSequence,
22 Optional,
23 Sequence,
24 Union,
25 cast,
26)
28from pdfminer.pdfexceptions import PDFException, PDFValueError
31def get_bytes(data: bytes) -> Iterator[int]:
32 yield from data
35# Workaround https://github.com/python/mypy/issues/731
36BitParserState = MutableSequence[Any]
37# A better definition (not supported by mypy) would be:
38# BitParserState = MutableSequence[Union["BitParserState", int, str, None]]
41class BitParser:
42 _state: BitParserState
44 # _accept is declared Optional solely as a workaround for
45 # https://github.com/python/mypy/issues/708
46 _accept: Optional[Callable[[Any], BitParserState]]
48 def __init__(self) -> None:
49 self._pos = 0
51 @classmethod
52 def add(cls, root: BitParserState, v: Union[int, str], bits: str) -> None:
53 p: BitParserState = root
54 b = None
55 for i in range(len(bits)):
56 if i > 0:
57 assert b is not None
58 if p[b] is None:
59 p[b] = [None, None]
60 p = p[b]
61 if bits[i] == "1":
62 b = 1
63 else:
64 b = 0
65 assert b is not None
66 p[b] = v
68 def feedbytes(self, data: bytes) -> None:
69 for byte in get_bytes(data):
70 for m in (128, 64, 32, 16, 8, 4, 2, 1):
71 self._parse_bit(byte & m)
73 def _parse_bit(self, x: object) -> None:
74 if x:
75 v = self._state[1]
76 else:
77 v = self._state[0]
78 self._pos += 1
79 if isinstance(v, list):
80 self._state = v
81 else:
82 assert self._accept is not None
83 self._state = self._accept(v)
86class CCITTG4Parser(BitParser):
87 MODE = [None, None]
88 BitParser.add(MODE, 0, "1")
89 BitParser.add(MODE, +1, "011")
90 BitParser.add(MODE, -1, "010")
91 BitParser.add(MODE, "h", "001")
92 BitParser.add(MODE, "p", "0001")
93 BitParser.add(MODE, +2, "000011")
94 BitParser.add(MODE, -2, "000010")
95 BitParser.add(MODE, +3, "0000011")
96 BitParser.add(MODE, -3, "0000010")
97 BitParser.add(MODE, "u", "0000001111")
98 BitParser.add(MODE, "x1", "0000001000")
99 BitParser.add(MODE, "x2", "0000001001")
100 BitParser.add(MODE, "x3", "0000001010")
101 BitParser.add(MODE, "x4", "0000001011")
102 BitParser.add(MODE, "x5", "0000001100")
103 BitParser.add(MODE, "x6", "0000001101")
104 BitParser.add(MODE, "x7", "0000001110")
105 BitParser.add(MODE, "e", "000000000001000000000001")
107 WHITE = [None, None]
108 BitParser.add(WHITE, 0, "00110101")
109 BitParser.add(WHITE, 1, "000111")
110 BitParser.add(WHITE, 2, "0111")
111 BitParser.add(WHITE, 3, "1000")
112 BitParser.add(WHITE, 4, "1011")
113 BitParser.add(WHITE, 5, "1100")
114 BitParser.add(WHITE, 6, "1110")
115 BitParser.add(WHITE, 7, "1111")
116 BitParser.add(WHITE, 8, "10011")
117 BitParser.add(WHITE, 9, "10100")
118 BitParser.add(WHITE, 10, "00111")
119 BitParser.add(WHITE, 11, "01000")
120 BitParser.add(WHITE, 12, "001000")
121 BitParser.add(WHITE, 13, "000011")
122 BitParser.add(WHITE, 14, "110100")
123 BitParser.add(WHITE, 15, "110101")
124 BitParser.add(WHITE, 16, "101010")
125 BitParser.add(WHITE, 17, "101011")
126 BitParser.add(WHITE, 18, "0100111")
127 BitParser.add(WHITE, 19, "0001100")
128 BitParser.add(WHITE, 20, "0001000")
129 BitParser.add(WHITE, 21, "0010111")
130 BitParser.add(WHITE, 22, "0000011")
131 BitParser.add(WHITE, 23, "0000100")
132 BitParser.add(WHITE, 24, "0101000")
133 BitParser.add(WHITE, 25, "0101011")
134 BitParser.add(WHITE, 26, "0010011")
135 BitParser.add(WHITE, 27, "0100100")
136 BitParser.add(WHITE, 28, "0011000")
137 BitParser.add(WHITE, 29, "00000010")
138 BitParser.add(WHITE, 30, "00000011")
139 BitParser.add(WHITE, 31, "00011010")
140 BitParser.add(WHITE, 32, "00011011")
141 BitParser.add(WHITE, 33, "00010010")
142 BitParser.add(WHITE, 34, "00010011")
143 BitParser.add(WHITE, 35, "00010100")
144 BitParser.add(WHITE, 36, "00010101")
145 BitParser.add(WHITE, 37, "00010110")
146 BitParser.add(WHITE, 38, "00010111")
147 BitParser.add(WHITE, 39, "00101000")
148 BitParser.add(WHITE, 40, "00101001")
149 BitParser.add(WHITE, 41, "00101010")
150 BitParser.add(WHITE, 42, "00101011")
151 BitParser.add(WHITE, 43, "00101100")
152 BitParser.add(WHITE, 44, "00101101")
153 BitParser.add(WHITE, 45, "00000100")
154 BitParser.add(WHITE, 46, "00000101")
155 BitParser.add(WHITE, 47, "00001010")
156 BitParser.add(WHITE, 48, "00001011")
157 BitParser.add(WHITE, 49, "01010010")
158 BitParser.add(WHITE, 50, "01010011")
159 BitParser.add(WHITE, 51, "01010100")
160 BitParser.add(WHITE, 52, "01010101")
161 BitParser.add(WHITE, 53, "00100100")
162 BitParser.add(WHITE, 54, "00100101")
163 BitParser.add(WHITE, 55, "01011000")
164 BitParser.add(WHITE, 56, "01011001")
165 BitParser.add(WHITE, 57, "01011010")
166 BitParser.add(WHITE, 58, "01011011")
167 BitParser.add(WHITE, 59, "01001010")
168 BitParser.add(WHITE, 60, "01001011")
169 BitParser.add(WHITE, 61, "00110010")
170 BitParser.add(WHITE, 62, "00110011")
171 BitParser.add(WHITE, 63, "00110100")
172 BitParser.add(WHITE, 64, "11011")
173 BitParser.add(WHITE, 128, "10010")
174 BitParser.add(WHITE, 192, "010111")
175 BitParser.add(WHITE, 256, "0110111")
176 BitParser.add(WHITE, 320, "00110110")
177 BitParser.add(WHITE, 384, "00110111")
178 BitParser.add(WHITE, 448, "01100100")
179 BitParser.add(WHITE, 512, "01100101")
180 BitParser.add(WHITE, 576, "01101000")
181 BitParser.add(WHITE, 640, "01100111")
182 BitParser.add(WHITE, 704, "011001100")
183 BitParser.add(WHITE, 768, "011001101")
184 BitParser.add(WHITE, 832, "011010010")
185 BitParser.add(WHITE, 896, "011010011")
186 BitParser.add(WHITE, 960, "011010100")
187 BitParser.add(WHITE, 1024, "011010101")
188 BitParser.add(WHITE, 1088, "011010110")
189 BitParser.add(WHITE, 1152, "011010111")
190 BitParser.add(WHITE, 1216, "011011000")
191 BitParser.add(WHITE, 1280, "011011001")
192 BitParser.add(WHITE, 1344, "011011010")
193 BitParser.add(WHITE, 1408, "011011011")
194 BitParser.add(WHITE, 1472, "010011000")
195 BitParser.add(WHITE, 1536, "010011001")
196 BitParser.add(WHITE, 1600, "010011010")
197 BitParser.add(WHITE, 1664, "011000")
198 BitParser.add(WHITE, 1728, "010011011")
199 BitParser.add(WHITE, 1792, "00000001000")
200 BitParser.add(WHITE, 1856, "00000001100")
201 BitParser.add(WHITE, 1920, "00000001101")
202 BitParser.add(WHITE, 1984, "000000010010")
203 BitParser.add(WHITE, 2048, "000000010011")
204 BitParser.add(WHITE, 2112, "000000010100")
205 BitParser.add(WHITE, 2176, "000000010101")
206 BitParser.add(WHITE, 2240, "000000010110")
207 BitParser.add(WHITE, 2304, "000000010111")
208 BitParser.add(WHITE, 2368, "000000011100")
209 BitParser.add(WHITE, 2432, "000000011101")
210 BitParser.add(WHITE, 2496, "000000011110")
211 BitParser.add(WHITE, 2560, "000000011111")
213 BLACK = [None, None]
214 BitParser.add(BLACK, 0, "0000110111")
215 BitParser.add(BLACK, 1, "010")
216 BitParser.add(BLACK, 2, "11")
217 BitParser.add(BLACK, 3, "10")
218 BitParser.add(BLACK, 4, "011")
219 BitParser.add(BLACK, 5, "0011")
220 BitParser.add(BLACK, 6, "0010")
221 BitParser.add(BLACK, 7, "00011")
222 BitParser.add(BLACK, 8, "000101")
223 BitParser.add(BLACK, 9, "000100")
224 BitParser.add(BLACK, 10, "0000100")
225 BitParser.add(BLACK, 11, "0000101")
226 BitParser.add(BLACK, 12, "0000111")
227 BitParser.add(BLACK, 13, "00000100")
228 BitParser.add(BLACK, 14, "00000111")
229 BitParser.add(BLACK, 15, "000011000")
230 BitParser.add(BLACK, 16, "0000010111")
231 BitParser.add(BLACK, 17, "0000011000")
232 BitParser.add(BLACK, 18, "0000001000")
233 BitParser.add(BLACK, 19, "00001100111")
234 BitParser.add(BLACK, 20, "00001101000")
235 BitParser.add(BLACK, 21, "00001101100")
236 BitParser.add(BLACK, 22, "00000110111")
237 BitParser.add(BLACK, 23, "00000101000")
238 BitParser.add(BLACK, 24, "00000010111")
239 BitParser.add(BLACK, 25, "00000011000")
240 BitParser.add(BLACK, 26, "000011001010")
241 BitParser.add(BLACK, 27, "000011001011")
242 BitParser.add(BLACK, 28, "000011001100")
243 BitParser.add(BLACK, 29, "000011001101")
244 BitParser.add(BLACK, 30, "000001101000")
245 BitParser.add(BLACK, 31, "000001101001")
246 BitParser.add(BLACK, 32, "000001101010")
247 BitParser.add(BLACK, 33, "000001101011")
248 BitParser.add(BLACK, 34, "000011010010")
249 BitParser.add(BLACK, 35, "000011010011")
250 BitParser.add(BLACK, 36, "000011010100")
251 BitParser.add(BLACK, 37, "000011010101")
252 BitParser.add(BLACK, 38, "000011010110")
253 BitParser.add(BLACK, 39, "000011010111")
254 BitParser.add(BLACK, 40, "000001101100")
255 BitParser.add(BLACK, 41, "000001101101")
256 BitParser.add(BLACK, 42, "000011011010")
257 BitParser.add(BLACK, 43, "000011011011")
258 BitParser.add(BLACK, 44, "000001010100")
259 BitParser.add(BLACK, 45, "000001010101")
260 BitParser.add(BLACK, 46, "000001010110")
261 BitParser.add(BLACK, 47, "000001010111")
262 BitParser.add(BLACK, 48, "000001100100")
263 BitParser.add(BLACK, 49, "000001100101")
264 BitParser.add(BLACK, 50, "000001010010")
265 BitParser.add(BLACK, 51, "000001010011")
266 BitParser.add(BLACK, 52, "000000100100")
267 BitParser.add(BLACK, 53, "000000110111")
268 BitParser.add(BLACK, 54, "000000111000")
269 BitParser.add(BLACK, 55, "000000100111")
270 BitParser.add(BLACK, 56, "000000101000")
271 BitParser.add(BLACK, 57, "000001011000")
272 BitParser.add(BLACK, 58, "000001011001")
273 BitParser.add(BLACK, 59, "000000101011")
274 BitParser.add(BLACK, 60, "000000101100")
275 BitParser.add(BLACK, 61, "000001011010")
276 BitParser.add(BLACK, 62, "000001100110")
277 BitParser.add(BLACK, 63, "000001100111")
278 BitParser.add(BLACK, 64, "0000001111")
279 BitParser.add(BLACK, 128, "000011001000")
280 BitParser.add(BLACK, 192, "000011001001")
281 BitParser.add(BLACK, 256, "000001011011")
282 BitParser.add(BLACK, 320, "000000110011")
283 BitParser.add(BLACK, 384, "000000110100")
284 BitParser.add(BLACK, 448, "000000110101")
285 BitParser.add(BLACK, 512, "0000001101100")
286 BitParser.add(BLACK, 576, "0000001101101")
287 BitParser.add(BLACK, 640, "0000001001010")
288 BitParser.add(BLACK, 704, "0000001001011")
289 BitParser.add(BLACK, 768, "0000001001100")
290 BitParser.add(BLACK, 832, "0000001001101")
291 BitParser.add(BLACK, 896, "0000001110010")
292 BitParser.add(BLACK, 960, "0000001110011")
293 BitParser.add(BLACK, 1024, "0000001110100")
294 BitParser.add(BLACK, 1088, "0000001110101")
295 BitParser.add(BLACK, 1152, "0000001110110")
296 BitParser.add(BLACK, 1216, "0000001110111")
297 BitParser.add(BLACK, 1280, "0000001010010")
298 BitParser.add(BLACK, 1344, "0000001010011")
299 BitParser.add(BLACK, 1408, "0000001010100")
300 BitParser.add(BLACK, 1472, "0000001010101")
301 BitParser.add(BLACK, 1536, "0000001011010")
302 BitParser.add(BLACK, 1600, "0000001011011")
303 BitParser.add(BLACK, 1664, "0000001100100")
304 BitParser.add(BLACK, 1728, "0000001100101")
305 BitParser.add(BLACK, 1792, "00000001000")
306 BitParser.add(BLACK, 1856, "00000001100")
307 BitParser.add(BLACK, 1920, "00000001101")
308 BitParser.add(BLACK, 1984, "000000010010")
309 BitParser.add(BLACK, 2048, "000000010011")
310 BitParser.add(BLACK, 2112, "000000010100")
311 BitParser.add(BLACK, 2176, "000000010101")
312 BitParser.add(BLACK, 2240, "000000010110")
313 BitParser.add(BLACK, 2304, "000000010111")
314 BitParser.add(BLACK, 2368, "000000011100")
315 BitParser.add(BLACK, 2432, "000000011101")
316 BitParser.add(BLACK, 2496, "000000011110")
317 BitParser.add(BLACK, 2560, "000000011111")
319 UNCOMPRESSED = [None, None]
320 BitParser.add(UNCOMPRESSED, "1", "1")
321 BitParser.add(UNCOMPRESSED, "01", "01")
322 BitParser.add(UNCOMPRESSED, "001", "001")
323 BitParser.add(UNCOMPRESSED, "0001", "0001")
324 BitParser.add(UNCOMPRESSED, "00001", "00001")
325 BitParser.add(UNCOMPRESSED, "00000", "000001")
326 BitParser.add(UNCOMPRESSED, "T00", "00000011")
327 BitParser.add(UNCOMPRESSED, "T10", "00000010")
328 BitParser.add(UNCOMPRESSED, "T000", "000000011")
329 BitParser.add(UNCOMPRESSED, "T100", "000000010")
330 BitParser.add(UNCOMPRESSED, "T0000", "0000000011")
331 BitParser.add(UNCOMPRESSED, "T1000", "0000000010")
332 BitParser.add(UNCOMPRESSED, "T00000", "00000000011")
333 BitParser.add(UNCOMPRESSED, "T10000", "00000000010")
335 class CCITTException(PDFException):
336 pass
338 class EOFB(CCITTException):
339 pass
341 class InvalidData(CCITTException):
342 pass
344 class ByteSkip(CCITTException):
345 pass
347 _color: int
349 def __init__(self, width: int, bytealign: bool = False) -> None:
350 BitParser.__init__(self)
351 self.width = width
352 self.bytealign = bytealign
353 self.reset()
355 def feedbytes(self, data: bytes) -> None:
356 for byte in get_bytes(data):
357 try:
358 for m in (128, 64, 32, 16, 8, 4, 2, 1):
359 self._parse_bit(byte & m)
360 except self.ByteSkip:
361 self._accept = self._parse_mode
362 self._state = self.MODE
363 except self.EOFB:
364 break
366 def _parse_mode(self, mode: object) -> BitParserState:
367 if mode == "p":
368 self._do_pass()
369 self._flush_line()
370 return self.MODE
371 elif mode == "h":
372 self._n1 = 0
373 self._accept = self._parse_horiz1
374 if self._color:
375 return self.WHITE
376 else:
377 return self.BLACK
378 elif mode == "u":
379 self._accept = self._parse_uncompressed
380 return self.UNCOMPRESSED
381 elif mode == "e":
382 raise self.EOFB
383 elif isinstance(mode, int):
384 self._do_vertical(mode)
385 self._flush_line()
386 return self.MODE
387 else:
388 raise self.InvalidData(mode)
390 def _parse_horiz1(self, n: Any) -> BitParserState:
391 if n is None:
392 raise self.InvalidData
393 self._n1 += n
394 if n < 64:
395 self._n2 = 0
396 self._color = 1 - self._color
397 self._accept = self._parse_horiz2
398 if self._color:
399 return self.WHITE
400 else:
401 return self.BLACK
403 def _parse_horiz2(self, n: Any) -> BitParserState:
404 if n is None:
405 raise self.InvalidData
406 self._n2 += n
407 if n < 64:
408 self._color = 1 - self._color
409 self._accept = self._parse_mode
410 self._do_horizontal(self._n1, self._n2)
411 self._flush_line()
412 return self.MODE
413 elif self._color:
414 return self.WHITE
415 else:
416 return self.BLACK
418 def _parse_uncompressed(self, bits: Optional[str]) -> BitParserState:
419 if not bits:
420 raise self.InvalidData
421 if bits.startswith("T"):
422 self._accept = self._parse_mode
423 self._color = int(bits[1])
424 self._do_uncompressed(bits[2:])
425 return self.MODE
426 else:
427 self._do_uncompressed(bits)
428 return self.UNCOMPRESSED
430 def _get_bits(self) -> str:
431 return "".join(str(b) for b in self._curline[: self._curpos])
433 def _get_refline(self, i: int) -> str:
434 if i < 0:
435 return "[]" + "".join(str(b) for b in self._refline)
436 elif len(self._refline) <= i:
437 return "".join(str(b) for b in self._refline) + "[]"
438 else:
439 return (
440 "".join(str(b) for b in self._refline[:i])
441 + "["
442 + str(self._refline[i])
443 + "]"
444 + "".join(str(b) for b in self._refline[i + 1 :])
445 )
447 def reset(self) -> None:
448 self._y = 0
449 self._curline = array.array("b", [1] * self.width)
450 self._reset_line()
451 self._accept = self._parse_mode
452 self._state = self.MODE
454 def output_line(self, y: int, bits: Sequence[int]) -> None:
455 print(y, "".join(str(b) for b in bits))
457 def _reset_line(self) -> None:
458 self._refline = self._curline
459 self._curline = array.array("b", [1] * self.width)
460 self._curpos = -1
461 self._color = 1
463 def _flush_line(self) -> None:
464 if self.width <= self._curpos:
465 self.output_line(self._y, self._curline)
466 self._y += 1
467 self._reset_line()
468 if self.bytealign:
469 raise self.ByteSkip
471 def _do_vertical(self, dx: int) -> None:
472 x1 = self._curpos + 1
473 while 1:
474 if x1 == 0:
475 if self._color == 1 and self._refline[x1] != self._color:
476 break
477 elif x1 == len(self._refline) or (
478 self._refline[x1 - 1] == self._color
479 and self._refline[x1] != self._color
480 ):
481 break
482 x1 += 1
483 x1 += dx
484 x0 = max(0, self._curpos)
485 x1 = max(0, min(self.width, x1))
486 if x1 < x0:
487 for x in range(x1, x0):
488 self._curline[x] = self._color
489 elif x0 < x1:
490 for x in range(x0, x1):
491 self._curline[x] = self._color
492 self._curpos = x1
493 self._color = 1 - self._color
495 def _do_pass(self) -> None:
496 x1 = self._curpos + 1
497 while 1:
498 if x1 == 0:
499 if self._color == 1 and self._refline[x1] != self._color:
500 break
501 elif x1 == len(self._refline) or (
502 self._refline[x1 - 1] == self._color
503 and self._refline[x1] != self._color
504 ):
505 break
506 x1 += 1
507 while 1:
508 if x1 == 0:
509 if self._color == 0 and self._refline[x1] == self._color:
510 break
511 elif x1 == len(self._refline) or (
512 self._refline[x1 - 1] != self._color
513 and self._refline[x1] == self._color
514 ):
515 break
516 x1 += 1
517 for x in range(self._curpos, x1):
518 self._curline[x] = self._color
519 self._curpos = x1
521 def _do_horizontal(self, n1: int, n2: int) -> None:
522 if self._curpos < 0:
523 self._curpos = 0
524 x = self._curpos
525 for _ in range(n1):
526 if len(self._curline) <= x:
527 break
528 self._curline[x] = self._color
529 x += 1
530 for _ in range(n2):
531 if len(self._curline) <= x:
532 break
533 self._curline[x] = 1 - self._color
534 x += 1
535 self._curpos = x
537 def _do_uncompressed(self, bits: str) -> None:
538 for c in bits:
539 self._curline[self._curpos] = int(c)
540 self._curpos += 1
541 self._flush_line()
544class CCITTFaxDecoder(CCITTG4Parser):
545 def __init__(
546 self,
547 width: int,
548 bytealign: bool = False,
549 reversed: bool = False,
550 ) -> None:
551 CCITTG4Parser.__init__(self, width, bytealign=bytealign)
552 self.reversed = reversed
553 self._buf = b""
555 def close(self) -> bytes:
556 return self._buf
558 def output_line(self, y: int, bits: Sequence[int]) -> None:
559 arr = array.array("B", [0] * ((len(bits) + 7) // 8))
560 if self.reversed:
561 bits = [1 - b for b in bits]
562 for i, b in enumerate(bits):
563 if b:
564 arr[i // 8] += (128, 64, 32, 16, 8, 4, 2, 1)[i % 8]
565 self._buf += arr.tobytes()
568def ccittfaxdecode(data: bytes, params: Dict[str, object]) -> bytes:
569 K = params.get("K")
570 if K == -1:
571 cols = cast(int, params.get("Columns"))
572 bytealign = cast(bool, params.get("EncodedByteAlign"))
573 reversed = cast(bool, params.get("BlackIs1"))
574 parser = CCITTFaxDecoder(cols, bytealign=bytealign, reversed=reversed)
575 else:
576 raise PDFValueError(K)
577 parser.feedbytes(data)
578 return parser.close()
581# test
582def main(argv: List[str]) -> None:
583 if not argv[1:]:
584 import unittest
586 unittest.main()
587 return
589 class Parser(CCITTG4Parser):
590 def __init__(self, width: int, bytealign: bool = False) -> None:
591 import pygame # type: ignore[import]
593 CCITTG4Parser.__init__(self, width, bytealign=bytealign)
594 self.img = pygame.Surface((self.width, 1000))
596 def output_line(self, y: int, bits: Sequence[int]) -> None:
597 for x, b in enumerate(bits):
598 if b:
599 self.img.set_at((x, y), (255, 255, 255))
600 else:
601 self.img.set_at((x, y), (0, 0, 0))
603 def close(self) -> None:
604 import pygame
606 pygame.image.save(self.img, "out.bmp")
608 for path in argv[1:]:
609 fp = open(path, "rb")
610 (_, _, k, w, h, _) = path.split(".")
611 parser = Parser(int(w))
612 parser.feedbytes(fp.read())
613 parser.close()
614 fp.close()