1
2
3
4
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
25 HEADER_VERSION = '\x00\xbf'
26
27 HEADER_SIGNATURE = 'TCSO\x00\x04\x00\x00\x00\x00'
28
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
52 version = stream.read(2)
53
54 if version != HEADER_VERSION:
55 raise pyamf.DecodeError('Unknown SOL version in header')
56
57
58 length = stream.read_ulong()
59
60 if strict and stream.remaining() != length:
61 raise pyamf.DecodeError('Inconsistent stream header length')
62
63
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
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
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
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
113 stream.write(HEADER_VERSION)
114
115 if strict is True:
116 length_pos = stream.tell()
117
118 stream.write_ulong(0)
119
120
121 stream.write(HEADER_SIGNATURE)
122
123
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
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
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
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
206 """
207 Local Shared Object class, allows easy manipulation of the internals of a
208 C{sol} file.
209 """
212
214 save(self, name_or_file, encoding)
215
217 return '<%s %s %s at 0x%x>' % (self.__class__.__name__,
218 self.name, dict.__repr__(self), id(self))
219
220 LSO = SOL
221