1# Copyright 2019 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 15 16"""Module providing conversion functions like long to bytes or bytes to long.""" 17 18import operator 19import struct 20 21import six 22 23 24def _PadZeroBytes(byte_str, blocksize): 25 """Pads the front of byte_str with binary zeros. 26 27 Args: 28 byte_str: byte string to pad the binary zeros. 29 blocksize: the byte_str will be padded so that the length of the output will 30 be a multiple of blocksize. 31 32 Returns: 33 a new byte string padded with binary zeros if necessary. 34 """ 35 if len(byte_str) % blocksize: 36 return (blocksize - len(byte_str) % blocksize) * b'\000' + byte_str 37 return byte_str 38 39 40def LongToBytes(number: int, blocksize: int = 0) -> bytes: 41 """Converts an arbitrary length number to a byte string. 42 43 Args: 44 number: number to convert to bytes. 45 blocksize: if specified, the output bytes length will be a multiple of 46 blocksize. 47 48 Returns: 49 byte string for the number. 50 51 Raises: 52 ValueError: when the number is negative. 53 """ 54 if number < 0: 55 raise ValueError('number needs to be >=0, given: {}'.format(number)) 56 number_32bitunit_components = [] 57 while number != 0: 58 number_32bitunit_components.insert(0, number & 0xFFFFFFFF) 59 number >>= 32 60 converter = struct.Struct('>' + str(len(number_32bitunit_components)) + 'I') 61 n_bytes = six.ensure_binary(converter.pack(*number_32bitunit_components)) 62 for idx in range(len(n_bytes)): 63 if operator.getitem(n_bytes, idx) != 0: 64 break 65 else: 66 n_bytes = b'\000' 67 idx = 0 68 n_bytes = n_bytes[idx:] 69 if blocksize > 0: 70 n_bytes = _PadZeroBytes(n_bytes, blocksize) 71 return six.ensure_binary(n_bytes) 72 73 74def BytesToLong(byte_string: bytes) -> int: 75 """Converts given byte string to a long.""" 76 result = 0 77 padded_byte_str = _PadZeroBytes(byte_string, 4) 78 component_length = len(padded_byte_str) // 4 79 converter = struct.Struct('>' + str(component_length) + 'I') 80 unpacked_data = converter.unpack(padded_byte_str) 81 for i in range(0, component_length): 82 result += unpacked_data[i] << (32 * (component_length - i - 1)) 83 return result 84