zipmanager.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. # Purpose: read DXF files from zip archive
  2. # Created: 02.05.2014
  3. # Copyright (c) 2014-2018, Manfred Moitzi
  4. # License: MIT License
  5. from typing import BinaryIO, cast, TextIO, List
  6. import zipfile
  7. from contextlib import contextmanager
  8. from ezdxf.lldxf.tags import dxf_info
  9. from ezdxf.lldxf.validator import is_dxf_stream
  10. WIN_NEW_LINE = b'\r\n'
  11. NEW_LINE = b'\n'
  12. class ZipReader:
  13. def __init__(self, zip_archive_name: str):
  14. if not zipfile.is_zipfile(zip_archive_name):
  15. raise IOError("'{}' is not a zip archive.".format(zip_archive_name))
  16. self.zip_archive_name = zip_archive_name
  17. self.zip_archive = None # type: zipfile.ZipFile
  18. self.dxf_file_name = None # type: str
  19. self.dxf_file = None # type: BinaryIO
  20. self.encoding = 'cp1252'
  21. self.dxfversion = 'AC1009'
  22. def open(self, dxf_file_name: str = None) -> None:
  23. def open_dxf_file() -> BinaryIO:
  24. return self.zip_archive.open(self.dxf_file_name) # open always in binary mode
  25. self.zip_archive = zipfile.ZipFile(self.zip_archive_name)
  26. self.dxf_file_name = dxf_file_name if dxf_file_name is not None else self.get_first_dxf_file_name()
  27. self.dxf_file = open_dxf_file()
  28. # reading with standard encoding 'cp1252' - readline() fails if leading comments contain none ascii characters
  29. if not is_dxf_stream(cast(TextIO, self)):
  30. raise IOError("'{}' is not a DXF file.".format(self.dxf_file_name))
  31. self.dxf_file = open_dxf_file() # restart
  32. self.get_dxf_info()
  33. self.dxf_file = open_dxf_file() # restart
  34. def get_first_dxf_file_name(self) -> str:
  35. dxf_file_names = self.get_dxf_file_names()
  36. if len(dxf_file_names) > 0:
  37. return dxf_file_names[0]
  38. else:
  39. raise IOError("'{}' has no DXF files.")
  40. def get_dxf_file_names(self) -> List[str]:
  41. return [name for name in self.zip_archive.namelist() if name.lower().endswith('.dxf')]
  42. def get_dxf_info(self) -> None:
  43. info = dxf_info(cast(TextIO, self))
  44. # since DXF R2007 (AC1021) file encoding is always 'utf-8'
  45. self.encoding = info.encoding if info.version < 'AC1021' else 'utf-8'
  46. self.dxfversion = info.version
  47. # required TextIO interface
  48. def readline(self) -> str:
  49. next_line = self.dxf_file.readline().replace(WIN_NEW_LINE, NEW_LINE)
  50. return str(next_line, self.encoding)
  51. def close(self) -> None:
  52. self.zip_archive.close()
  53. @contextmanager
  54. def ctxZipReader(zipfilename: str, filename: str = None) -> ZipReader:
  55. zip_reader = ZipReader(zipfilename)
  56. zip_reader.open(filename)
  57. yield zip_reader
  58. zip_reader.close()