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