Package pyamf :: Module sol

[hide private]
[frames] | no frames]

# Source Code for Module pyamf.sol

      1  # -*- coding: utf-8 -*-
      2  #
      3  # Copyright (c) 2007-2009 The PyAMF Project.
      4  # See LICENSE.txt for details.
      5
      6  """
      7  Local Shared Object implementation.
      8
      9  Local Shared Object (LSO), sometimes known as Adobe Flash cookies, is a
     10  cookie-like data entity used by the Adobe Flash Player and Gnash. The players
     11  allow web content to read and write LSO data to the computer's local drive on
     12  a per-domain basis.
     13
     14  @see: U{Local Shared Object on WikiPedia (external)
     15  <http://en.wikipedia.org/wiki/Local_Shared_Object>}
     16  @see: U{Local Shared Object envelope (external)
     17  <http://osflash.org/documentation/amf/envelopes/sharedobject>}
     18
     19  @since: 0.1.0
     20  """
     21
     22  import pyamf
     23  from pyamf import util
     24
     25  #: Magic Number - 2 bytes
     26  HEADER_VERSION = '\x00\xbf'
     27  #: Marker - 10 bytes
     28  HEADER_SIGNATURE = 'TCSO\x00\x04\x00\x00\x00\x00'
     29  #: Padding - 4 bytes
     30  PADDING_BYTE = '\x00'
     31
     32
     33 -def decode(stream, strict=True):
     34      """
     35      Decodes a SOL stream. C{strict} mode ensures that the sol stream is as spec
     36      compatible as possible.
     37
     38      @param strict: Ensure that the SOL stream is as spec compatible as possible.
     39      @type strict: C{bool}
     40      @return: A C{tuple} containing the C{root_name} and a C{dict} of name,
     41          value pairs.
     42      @rtype: C{tuple}
     43
     44      @raise DecodeError: Unknown SOL version in header.
     45      @raise DecodeError: Inconsistent stream header length.
     46      @raise DecodeError: Invalid signature.
     47      @raise DecodeError: Invalid padding read.
     48      @raise DecodeError: Missing padding byte.
     49      """
     50      if not isinstance(stream, util.BufferedByteStream):
     51          stream = util.BufferedByteStream(stream)
     52
     53      # read the version
     54      version = stream.read(2)
     55
     56      if version != HEADER_VERSION:
     57          raise pyamf.DecodeError('Unknown SOL version in header')
     58
     59      # read the length
     60      length = stream.read_ulong()
     61
     62      if strict and stream.remaining() != length:
     63          raise pyamf.DecodeError('Inconsistent stream header length')
     64
     65      # read the signature
     66      signature = stream.read(10)
     67
     68      if signature != HEADER_SIGNATURE:
     69          raise pyamf.DecodeError('Invalid signature')
     70
     71      length = stream.read_ushort()
     72      root_name = stream.read_utf8_string(length)
     73
     74      # read padding
     75      if stream.read(3) != PADDING_BYTE * 3:
     76          raise pyamf.DecodeError('Invalid padding read')
     77
     78      decoder = pyamf.get_decoder(stream.read_uchar())
     79      decoder.stream = stream
     80
     81      values = {}
     82
     83      while 1:
     84          if stream.at_eof():
     85              break
     86
     87          name = decoder.readString()
     88          value = decoder.readElement()
     89
     90          # read the padding
     91          if stream.read(1) != PADDING_BYTE:
     92              raise pyamf.DecodeError('Missing padding byte')
     93
     94          values[name] = value
     95
     96      return (root_name, values)
     97
     98
     99 -def encode(name, values, strict=True, encoding=pyamf.AMF0):
    100      """
    101      Produces a SharedObject encoded stream based on the name and values.
    102
    103      @param name: The root name of the SharedObject.
    104      @type name: C{basestring}
    105      @param values: A C{dict} of name value pairs to be encoded in the stream.
    106      @type values: C{dict}
    107      @param strict: Ensure that the SOL stream is as spec compatible as possible.
    108      @type strict: C{bool}
    109      @return: A SharedObject encoded stream.
    110      @rtype: L{BufferedByteStream<pyamf.util.BufferedByteStream>}
    111      """
    112      encoder = pyamf.get_encoder(encoding)
    113      encoder.stream = stream = util.BufferedByteStream()
    114
    115      # write the header
    116      stream.write(HEADER_VERSION)
    117
    118      if strict is True:
    119          length_pos = stream.tell()
    120
    121      stream.write_ulong(0)
    122
    123      # write the signature
    124      stream.write(HEADER_SIGNATURE)
    125
    126      # write the root name
    127      if not isinstance(name, unicode):
    128          name = unicode(name)
    129
    130      stream.write_ushort(len(name))
    131      stream.write_utf8_string(name)
    132
    133      # write the padding
    134      stream.write(PADDING_BYTE * 3)
    135      stream.write_uchar(encoding)
    136
    137      for n, v in values.iteritems():
    138          encoder.writeString(n, writeType=False)
    139          encoder.writeElement(v)
    140
    141          # write the padding
    142          stream.write(PADDING_BYTE)
    143
    144      if strict:
    145          stream.seek(length_pos)
    146          stream.write_ulong(stream.remaining() - 4)
    147
    148      stream.seek(0)
    149
    150      return stream
    151
    152
    153 -def load(name_or_file):
    154      """
    155      Loads a sol file and returns a L{SOL} object.
    156
    157      @param name_or_file: Name of file, or file-object.
    158      @type name_or_file: C{str} or C{StringIO}
    159
    160      @raise ValueError: Readable stream expected.
    161      """
    162      f = name_or_file
    163      opened = False
    164
    165      if isinstance(name_or_file, basestring):
    166          f = open(name_or_file, 'rb')
    167          opened = True
    168      elif not hasattr(f, 'read'):
    169          raise ValueError('Readable stream expected')
    170
    171      name, values = decode(f.read())
    172      s = SOL(name)
    173
    174      for n, v in values.iteritems():
    175          s[n] = v
    176
    177      if opened is True:
    178          f.close()
    179
    180      return s
    181
    182
    183 -def save(sol, name_or_file, encoding=pyamf.AMF0):
    184      """
    185      Writes a L{SOL} object to C{name_or_file}.
    186
    187      @param sol:
    188      @type sol:
    189      @param name_or_file: Name of file, or file-object.
    190      @type name_or_file: C{str} or C{StringIO}
    191      @param encoding: AMF encoding type.
    192      @type encoding: C{int}
    193
    194      @raise ValueError: Writable stream expected.
    195      """
    196      f = name_or_file
    197      opened = False
    198
    199      if isinstance(name_or_file, basestring):
    200          f = open(name_or_file, 'wb+')
    201          opened = True
    202      elif not hasattr(f, 'write'):
    203          raise ValueError('Writable stream expected')
    204
    205      f.write(encode(sol.name, sol, encoding=encoding).getvalue())
    206
    207      if opened:
    208          f.close()
    209
    210
    211 -class SOL(dict):
    212      """
    213      Local Shared Object class, allows easy manipulation of the internals of a
    214      C{sol} file.
    215      """
    216 -    def __init__(self, name):
    217          self.name = name
    218
    219 -    def save(self, name_or_file, encoding=pyamf.AMF0):
    220          save(self, name_or_file, encoding)
    221
    222 -    def __repr__(self):
    223          return '<%s %s %s at 0x%x>' % (self.__class__.__name__,
    224              self.name, dict.__repr__(self), id(self))
    225
    226  LSO = SOL
    227