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