text: # 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.
  
  
  
  
  # no unicode literals
  
  try:
      from . import bser
  except ImportError:
      from . import pybser as bser
  
  import ctypes
  
  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(
          buf, len(header))
      read_len = _read_bytes(fp, body)
      if read_len < len(body):
          raise RuntimeError('bser data ended early')
  
      return bser.loads(
          (ctypes.c_char * total_len).from_buffer(buf, 0),
          mutable,
          value_encoding,
          value_errors)
  