1# Copyright 2020 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import struct
16
17
18class CommonChecksum(object):
19 """Hashlib-alike helper for CRC32C operations.
20
21 This class should not be used directly and requires an update implementation.
22
23 Args:
24 initial_value (Optional[bytes]): the initial chunk of data from
25 which the CRC32C checksum is computed. Defaults to b''.
26 """
27
28 __slots__ = ()
29
30 def __init__(self, initial_value=b""):
31 self._crc = 0
32 if initial_value != b"":
33 self.update(initial_value)
34
35 def update(self, data):
36 """Update the checksum with a new chunk of data.
37
38 Args:
39 chunk (Optional[bytes]): a chunk of data used to extend
40 the CRC32C checksum.
41 """
42 raise NotImplementedError
43
44 def digest(self):
45 """Big-endian order, per RFC 4960.
46
47 See: https://cloud.google.com/storage/docs/json_api/v1/objects#crc32c
48
49 Returns:
50 bytes: An eight-byte digest string.
51 """
52 return struct.pack(">L", self._crc)
53
54 def hexdigest(self):
55 """Like :meth:`digest` except returns as a bytestring of double length.
56
57 Returns
58 bytes: A sixteen byte digest string, contaiing only hex digits.
59 """
60 return "{:08x}".format(self._crc).encode("ascii")
61
62 def copy(self):
63 """Create another checksum with the same CRC32C value.
64
65 Returns:
66 Checksum: the new instance.
67 """
68 clone = self.__class__()
69 clone._crc = self._crc
70 return clone
71
72 def consume(self, stream, chunksize):
73 """Consume chunks from a stream, extending our CRC32 checksum.
74
75 Args:
76 stream (BinaryIO): the stream to consume.
77 chunksize (int): the size of the read to perform
78
79 Returns:
80 Generator[bytes, None, None]: Iterable of the chunks read from the
81 stream.
82 """
83 while True:
84 chunk = stream.read(chunksize)
85 if not chunk:
86 break
87 self.update(chunk)
88 yield chunk