You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

152 lines
5.6 KiB

  1. # Copyright (c) 2011, SmartFile <btimby@smartfile.com>
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are met:
  6. # * Redistributions of source code must retain the above copyright
  7. # notice, this list of conditions and the following disclaimer.
  8. # * Redistributions in binary form must reproduce the above copyright
  9. # notice, this list of conditions and the following disclaimer in the
  10. # documentation and/or other materials provided with the distribution.
  11. # * Neither the name of the organization nor the
  12. # names of its contributors may be used to endorse or promote products
  13. # derived from this software without specific prior written permission.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  16. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
  19. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. import os, time
  26. from libarchive import is_archive, Entry, SeekableArchive
  27. from zipfile import ZIP_STORED, ZIP_DEFLATED
  28. def is_zipfile(filename):
  29. return is_archive(filename, formats=('zip', ))
  30. class ZipEntry(Entry):
  31. def __init__(self, *args, **kwargs):
  32. super(ZipEntry, self).__init__(*args, **kwargs)
  33. def get_filename(self):
  34. return self.pathname
  35. def set_filename(self, value):
  36. self.pathname = value
  37. filename = property(get_filename, set_filename)
  38. def get_file_size(self):
  39. return self.size
  40. def set_file_size(self, value):
  41. assert isinstance(size, (int, long)), 'Please provide size as int or long.'
  42. self.size = value
  43. file_size = property(get_file_size, set_file_size)
  44. def get_date_time(self):
  45. return time.localtime(self.mtime)[0:6]
  46. def set_date_time(self, value):
  47. assert isinstance(value, tuple), 'mtime should be tuple (year, month, day, hour, minute, second).'
  48. assert len(value) == 6, 'mtime should be tuple (year, month, day, hour, minute, second).'
  49. self.mtime = time.mktime(value + (0, 0, 0))
  50. date_time = property(get_date_time, set_date_time)
  51. header_offset = Entry.header_position
  52. def _get_missing(self):
  53. raise NotImplemented()
  54. def _set_missing(self, value):
  55. raise NotImplemented()
  56. compress_type = property(_get_missing, _set_missing)
  57. comment = property(_get_missing, _set_missing)
  58. extra = property(_get_missing, _set_missing)
  59. create_system = property(_get_missing, _set_missing)
  60. create_version = property(_get_missing, _set_missing)
  61. extract_version = property(_get_missing, _set_missing)
  62. reserved = property(_get_missing, _set_missing)
  63. flag_bits = property(_get_missing, _set_missing)
  64. volume = property(_get_missing, _set_missing)
  65. internal_attr = property(_get_missing, _set_missing)
  66. external_attr = property(_get_missing, _set_missing)
  67. CRC = property(_get_missing, _set_missing)
  68. compress_size = property(_get_missing, _set_missing)
  69. class ZipFile(SeekableArchive):
  70. def __init__(self, f, mode='r', compression=ZIP_DEFLATED, allowZip64=False):
  71. super(ZipFile, self).__init__(f, mode=mode, format='zip', entry_class=ZipEntry, encoding='CP437')
  72. if mode == 'w' and compression == ZIP_STORED:
  73. # Disable compression for writing.
  74. _libarchive.archive_write_set_format_option(self.archive._a, "zip", "compression", "store")
  75. self.compression = compression
  76. getinfo = SeekableArchive.getentry
  77. def namelist(self):
  78. return list(self.iterpaths)
  79. def infolist(self):
  80. return list(self)
  81. def open(self, name, mode, pwd=None):
  82. if pwd:
  83. raise NotImplemented('Encryption not supported.')
  84. if mode == 'r':
  85. return self.readstream(name)
  86. else:
  87. return self.writestream(name)
  88. def extract(self, name, path=None, pwd=None):
  89. if pwd:
  90. raise NotImplemented('Encryption not supported.')
  91. if not path:
  92. path = os.getcwd()
  93. return self.readpath(name, os.path.join(path, name))
  94. def extractall(self, path, names=None, pwd=None):
  95. if pwd:
  96. raise NotImplemented('Encryption not supported.')
  97. if not names:
  98. names = self.namelist()
  99. if names:
  100. for name in names:
  101. self.extract(name, path)
  102. def read(self, name, pwd=None):
  103. if pwd:
  104. raise NotImplemented('Encryption not supported.')
  105. return self.read(name)
  106. def writestr(self, member, data, compress_type=None):
  107. if compress_type != self.compression:
  108. raise Exception('Cannot change compression type for individual entries.')
  109. return self.write(member, data)
  110. def setpassword(self, pwd):
  111. raise NotImplemented('Encryption not supported.')
  112. def testzip(self):
  113. raise NotImplemented()
  114. def _get_missing(self):
  115. raise NotImplemented()
  116. def _set_missing(self, value):
  117. raise NotImplemented()
  118. comment = property(_get_missing, _set_missing)