load.py
106 lines
| 3.6 KiB
| text/x-python
|
PythonLexer
Zack Hricz
|
r30656 | # Copyright 2016 Facebook, Inc. | ||
# All rights reserved. | ||||
# | ||||
# Redistribution and use in source and binary forms, with or without | ||||
# modification, are permitted provided that the following conditions are met: | ||||
# | ||||
# * Redistributions of source code must retain the above copyright notice, | ||||
# this list of conditions and the following disclaimer. | ||||
# | ||||
# * Redistributions in binary form must reproduce the above copyright notice, | ||||
# this list of conditions and the following disclaimer in the documentation | ||||
# and/or other materials provided with the distribution. | ||||
# | ||||
# * Neither the name Facebook nor the names of its contributors may be used to | ||||
# endorse or promote products derived from this software without specific | ||||
# prior written permission. | ||||
# | ||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
Gregory Szorc
|
r43703 | import ctypes | ||
Zack Hricz
|
r30656 | |||
try: | ||||
from . import bser | ||||
except ImportError: | ||||
from . import pybser as bser | ||||
EMPTY_HEADER = b"\x00\x01\x05\x00\x00\x00\x00" | ||||
def _read_bytes(fp, buf): | ||||
"""Read bytes from a file-like object | ||||
@param fp: File-like object that implements read(int) | ||||
@type fp: file | ||||
@param buf: Buffer to read into | ||||
@type buf: bytes | ||||
@return: buf | ||||
""" | ||||
# Do the first read without resizing the input buffer | ||||
offset = 0 | ||||
remaining = len(buf) | ||||
while remaining > 0: | ||||
l = fp.readinto((ctypes.c_char * remaining).from_buffer(buf, offset)) | ||||
if l is None or l == 0: | ||||
return offset | ||||
offset += l | ||||
remaining -= l | ||||
return offset | ||||
def load(fp, mutable=True, value_encoding=None, value_errors=None): | ||||
"""Deserialize a BSER-encoded blob. | ||||
@param fp: The file-object to deserialize. | ||||
@type file: | ||||
@param mutable: Whether to return mutable results. | ||||
@type mutable: bool | ||||
@param value_encoding: Optional codec to use to decode values. If | ||||
unspecified or None, return values as bytestrings. | ||||
@type value_encoding: str | ||||
@param value_errors: Optional error handler for codec. 'strict' by default. | ||||
The other most common argument is 'surrogateescape' on | ||||
Python 3. If value_encoding is None, this is ignored. | ||||
@type value_errors: str | ||||
""" | ||||
buf = ctypes.create_string_buffer(8192) | ||||
SNIFF_BUFFER_SIZE = len(EMPTY_HEADER) | ||||
header = (ctypes.c_char * SNIFF_BUFFER_SIZE).from_buffer(buf) | ||||
read_len = _read_bytes(fp, header) | ||||
if read_len < len(header): | ||||
return None | ||||
total_len = bser.pdu_len(buf) | ||||
if total_len > len(buf): | ||||
ctypes.resize(buf, total_len) | ||||
body = (ctypes.c_char * (total_len - len(header))).from_buffer( | ||||
Gregory Szorc
|
r43703 | buf, len(header) | ||
) | ||||
Zack Hricz
|
r30656 | read_len = _read_bytes(fp, body) | ||
if read_len < len(body): | ||||
Gregory Szorc
|
r43703 | raise RuntimeError("bser data ended early") | ||
Zack Hricz
|
r30656 | |||
return bser.loads( | ||||
(ctypes.c_char * total_len).from_buffer(buf, 0), | ||||
mutable, | ||||
value_encoding, | ||||
Gregory Szorc
|
r43703 | value_errors, | ||
) | ||||