util/python/alibabacloud_oss_util/verify_stream.py (89 lines of code) (raw):
import hashlib
import base64
import os
import sys
from _io import BytesIO
from Tea.stream import BaseStream
def _length(o):
if hasattr(o, 'len'):
return o.len
elif isinstance(o, BytesIO):
return o.getbuffer().nbytes
elif hasattr(o, 'fileno'):
return os.path.getsize(o.name)
return len(o)
class CRC64:
POLY = (0xC96C5795 << 32) | 0xD7870F42
def __init__(self):
self.value = 0
@property
def _table(self):
table = []
for n in range(256):
crc = n
for j in range(8):
if crc & True:
crc = (crc >> 1) & ~(0x8 << 60) ^ self.POLY
else:
crc = (crc >> 1) & ~(0x8 << 60)
table.append(crc)
return table
def get_value(self):
return str(self.value)
def update(self, bt):
for b in bt:
self.value = ~self.value
self.value = self._table[(self.value ^ b) & 0xff] ^ (self.value >> 8) & ~(0xff << 56)
self.value = ~self.value
class VerifyStream(BaseStream):
def __init__(self, file, res, size=1024):
super().__init__(size)
self.file = file
self.size = size
self.crc = CRC64()
self.ref = res
self.md5 = hashlib.md5()
self.file_size = _length(file)
self._file_size = self.file_size
def __len__(self):
return self.file_size
def __iter__(self):
return self
def __next__(self):
return self.read(size=self.size, loop=True)
def read(self, size=None, loop=False):
res = self.file.read(size)
if size is None:
size = sys.maxsize
if isinstance(res, str):
bres = res.encode('utf-8')
else:
bres = res
if size <= self._file_size:
self.crc.update(bres)
self.md5.update(bres)
else:
self.ref['md5'] = base64.b64encode(self.md5.digest()).decode('utf-8')
self.ref['crc'] = self.crc.get_value()
if not res:
self.refresh()
if loop:
raise StopIteration
else:
return res
if size == sys.maxsize or size >= self.file_size:
self.crc.update(bres)
self.md5.update(bres)
self.ref['md5'] = base64.b64encode(self.md5.digest()).decode('utf-8')
self.ref['crc'] = self.crc.get_value()
return res
self._file_size -= len(bres)
return res
def refresh(self):
self.crc = CRC64()
self.md5 = hashlib.md5()
if hasattr(self.file, 'seek'):
self.file.seek(0, 0)
self._file_size = self.file_size
def close(self):
self.file.close()