def _float_adjust(v, encode): if encode and six.indexbytes(v, 0) & 0x80 != 0x00: return b''.join(map(lambda x: six.int2byte(x ^ 0xff), six.iterbytes(v))) elif not encode and six.indexbytes(v, 0) & 0x80 != 0x80: return b''.join(map(lambda x: six.int2byte(x ^ 0xff), six.iterbytes(v))) else: return six.int2byte(six.indexbytes(v, 0) ^ 0x80) + v[1:]
def from_bytes(cls, v, start=0): if not isinstance(v, bytes): raise TypeError("Cannot parse versionstamp from non-byte string") elif len(v) - start < cls.LENGTH: raise ValueError("Versionstamp byte string is too short (only " + str(len(v) - start) + " bytes to read from") else: tr_version = v[start:start + cls._TR_VERSION_LEN] if tr_version == cls._UNSET_TR_VERSION: tr_version = None user_version = six.indexbytes(v, start + cls._TR_VERSION_LEN) * ( 1 << 8) + six.indexbytes(v, start + cls._TR_VERSION_LEN + 1) return Versionstamp(tr_version, user_version)
def _decode(v, pos): code = six.indexbytes(v, pos) if code == NULL_CODE: return None, pos + 1 elif code == BYTES_CODE: end = _find_terminator(v, pos + 1) return v[pos + 1:end].replace(b"\x00\xFF", b"\x00"), end + 1 elif code == STRING_CODE: end = _find_terminator(v, pos + 1) return v[pos + 1:end].replace(b"\x00\xFF", b"\x00").decode("utf-8"), end + 1 elif code >= INT_ZERO_CODE and code < POS_INT_END: n = code - 20 end = pos + 1 + n return struct.unpack(">Q", b'\x00' * (8 - n) + v[pos + 1:end])[0], end elif code > NEG_INT_START and code < INT_ZERO_CODE: n = 20 - code end = pos + 1 + n return struct.unpack( ">Q", b'\x00' * (8 - n) + v[pos + 1:end])[0] - _size_limits[n], end elif code == POS_INT_END: # 0x1d; Positive 9-255 byte integer length = six.indexbytes(v, pos + 1) val = 0 for i in _range(length): val = val << 8 val += six.indexbytes(v, pos + 2 + i) return val, pos + 2 + length elif code == NEG_INT_START: # 0x0b; Negative 9-255 byte integer length = six.indexbytes(v, pos + 1) ^ 0xff val = 0 for i in _range(length): val = val << 8 val += six.indexbytes(v, pos + 2 + i) return val - (1 << (length * 8)) + 1, pos + 2 + length elif code == FLOAT_CODE: return SingleFloat( struct.unpack(">f", _float_adjust(v[pos + 1:pos + 5], False))[0]), pos + 5 elif code == DOUBLE_CODE: return struct.unpack(">d", _float_adjust(v[pos + 1:pos + 9], False))[0], pos + 9 elif code == UUID_CODE: return uuid.UUID(bytes=v[pos + 1:pos + 17]), pos + 17 elif code == FALSE_CODE: if fdb.is_api_version_selected() and fdb.get_api_version() < 500: raise ValueError("Invalid API version " + str(fdb._version) + " for boolean types") return False, pos + 1 elif code == TRUE_CODE: if fdb.is_api_version_selected() and fdb.get_api_version() < 500: raise ValueError("Invalid API version " + str(fdb._version) + " for boolean types") return True, pos + 1 elif code == VERSIONSTAMP_CODE: return Versionstamp.from_bytes(v, pos + 1), pos + 1 + Versionstamp.LENGTH elif code == NESTED_CODE: ret = [] end_pos = pos + 1 while end_pos < len(v): if six.indexbytes(v, end_pos) == 0x00: if end_pos + 1 < len(v) and six.indexbytes( v, end_pos + 1) == 0xff: ret.append(None) end_pos += 2 else: break else: val, end_pos = _decode(v, end_pos) ret.append(val) return tuple(ret), end_pos + 1 else: raise ValueError("Unknown data type in DB: " + repr(v))