Package pyamf :: Module sol
[hide private]
[frames] | no frames]

Source Code for Module pyamf.sol

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (c) 2007-2008 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  @author: U{Nick Joyce<mailto:nick@boxdesign.co.uk>} 
 19   
 20  @since: 0.1.0 
 21  """ 
 22   
 23  import pyamf 
 24  from pyamf import util 
 25   
 26  #: Magic Number - 2 bytes 
 27  HEADER_VERSION = '\x00\xbf' 
 28  #: Marker - 10 bytes 
 29  HEADER_SIGNATURE = 'TCSO\x00\x04\x00\x00\x00\x00' 
 30  #: Padding - 4 bytes 
 31  PADDING_BYTE = '\x00' 
 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 @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 DecoderError: Inconsistent stream header length. 44 @raise DecodeError: Invalid padding read. 45 @raise DecodeError: Missing padding byte. 46 """ 47 if not isinstance(stream, util.BufferedByteStream): 48 stream = util.BufferedByteStream(stream) 49 50 # read the version 51 version = stream.read(2) 52 53 if version != HEADER_VERSION: 54 raise pyamf.DecodeError, 'Unknown SOL version in header' 55 56 # read the length 57 length = stream.read_ulong() 58 59 if strict and stream.remaining() != length: 60 raise pyamf.DecodeError, 'Inconsistent stream header length' 61 62 # read the signature 63 signature = stream.read(10) 64 65 if signature != HEADER_SIGNATURE: 66 raise pyamf.DecodeError, 'Invalid signature' 67 68 length = stream.read_ushort() 69 root_name = stream.read_utf8_string(length) 70 71 # read padding 72 if stream.read(3) != PADDING_BYTE * 3: 73 raise pyamf.DecodeError, 'Invalid padding read' 74 75 decoder = pyamf.get_decoder(stream.read_uchar()) 76 decoder.stream = stream 77 78 values = {} 79 80 while 1: 81 if stream.at_eof(): 82 break 83 84 name = decoder.readString() 85 value = decoder.readElement() 86 87 # read the padding 88 if stream.read(1) != PADDING_BYTE: 89 raise pyamf.DecodeError, 'Missing padding byte' 90 91 values[name] = value 92 93 return (root_name, values)
94
95 -def encode(name, values, strict=True, encoding=pyamf.AMF0):
96 """ 97 Produces a SharedObject encoded stream based on the name and values. 98 99 @param name: The root name of the SharedObject. 100 @type name: C{basestring} 101 @param values: A C{dict} of name value pairs to be encoded in the stream. 102 @type values: C{dict} 103 @type strict: C{bool} 104 @return: A SharedObject encoded stream. 105 @rtype: L{BufferedByteStream<pyamf.util.BufferedByteStream>} 106 """ 107 encoder = pyamf.get_encoder(encoding) 108 encoder.stream = stream = util.BufferedByteStream() 109 110 # write the header 111 stream.write(HEADER_VERSION) 112 113 if strict is True: 114 length_pos = stream.tell() 115 116 stream.write_ulong(0) 117 118 # write the signature 119 stream.write(HEADER_SIGNATURE) 120 121 # write the root name 122 if not isinstance(name, unicode): 123 name = unicode(name) 124 125 stream.write_ushort(len(name)) 126 stream.write_utf8_string(name) 127 128 # write the padding 129 stream.write(PADDING_BYTE * 3) 130 stream.write_uchar(encoding) 131 132 for n, v in values.iteritems(): 133 encoder._writeString(n) 134 encoder.writeElement(v) 135 136 # write the padding 137 stream.write(PADDING_BYTE) 138 139 if strict: 140 stream.seek(length_pos) 141 stream.write_ulong(stream.remaining() - 4) 142 143 stream.seek(0) 144 145 return stream
146
147 -def load(name_or_file):
148 """ 149 Loads a sol file and returns a L{SOL} object. 150 151 @param name_or_file: 152 @type name_or_file: 153 154 @raise ValueError: Readable stream expected. 155 """ 156 f = name_or_file 157 opened = False 158 159 if isinstance(name_or_file, basestring): 160 f = open(name_or_file, 'rb') 161 opened = True 162 elif not hasattr(f, 'read'): 163 raise ValueError, 'readable stream expected' 164 165 name, values = decode(f.read()) 166 s = SOL(name) 167 168 for n, v in values.iteritems(): 169 s[n] = v 170 171 if opened is True: 172 f.close() 173 174 return s
175
176 -def save(sol, name_or_file, encoding=pyamf.AMF0):
177 """ 178 Writes a L{SOL} object to C{name_or_file}. 179 180 @param sol: 181 @type sol: 182 @param name_or_file: 183 @type name_or_file: 184 185 @raise ValueError: Writable stream expected. 186 """ 187 f = name_or_file 188 opened = False 189 190 if isinstance(name_or_file, basestring): 191 f = open(name_or_file, 'wb+') 192 opened = True 193 elif not hasattr(f, 'write'): 194 raise ValueError, 'writable stream expected' 195 196 f.write(encode(sol.name, sol, encoding=encoding).getvalue()) 197 198 if opened: 199 f.close()
200
201 -class SOL(dict):
202 """ 203 Local Shared Object class, allows easy manipulation of the internals of a 204 C{sol} file. 205 """
206 - def __init__(self, name):
207 self.name = name
208
209 - def save(self, name_or_file, encoding=pyamf.AMF0):
210 save(self, name_or_file, encoding)
211
212 - def __repr__(self):
213 return '<%s %s %s at 0x%x>' % (self.__class__.__name__, 214 self.name, dict.__repr__(self), id(self))
215 216 LSO = SOL 217