1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 // This file is for the low level support for encoding and decoding AMF objects.
20 // As this class has no data associated with it, all the methods are static as
21 // they are for convenience only.
22 // All the encoding methods return a Buffer class, which is simply an array on
23 // of unsigned bytes, and a byte count.
24 // The only extraction classes parse either a raw AMF object or the larger
25 // "variable"
26 
27 #ifndef _AMF_H_
28 #define _AMF_H_
29 
30 #include <string>
31 #include <cstring>
32 #include <cstdint>
33 
34 #include "element.h"
35 #include "dsodefs.h"
36 
37 /// Action Message Format specific classes of libamf.
38 namespace cygnal
39 {
40 
41 // forward declaration
42 class Buffer;
43 
44 /// All numbers in AMF format are 8 byte doubles.
45 const size_t AMF0_NUMBER_SIZE = 0x08;
46 
47 /// \brief The header size in bytes of an common AMF object.
48 ///	The size of an AMF header is a type field (1 byte), followed by a
49 ///	length field. (short)
50 const std::uint8_t AMF_HEADER_SIZE = 3;
51 
52 /// \brief  The header size of a property.
53 ///	A property is a little different. It always assumes the the
54 ///	first field is a string that's the property name, then the
55 ///	type byte like a regular AMF object and length is used for the
56 ///	data. So a property object header is then only 5 bytes instead
57 ///	of the 6 that one assumes would be used.
58 const std::uint8_t AMF_PROP_HEADER_SIZE = 5;
59 
60 /// AMF version 0 is supported by default
61 const std::uint8_t AMF_VERSION = 0;
62 
63 /// For terminating sequences, a byte with value 0x09 is used.
64 const std::uint8_t TERMINATOR = 0x09;
65 
66 /// \brief The maximum size for a string.
67 /// As if there is a parsing error, we'll often see the symptom of the length
68 /// for the following value is bogus. Although the length field is a short, it
69 /// seems silly to assume we'll ever see a string 65,000 characters long. Still,
70 /// it makes sense to make this an adjustable thing.
71 const std::uint16_t SANE_STR_SIZE = 65535;
72 
73 /// Binary representation of an ActionScript object.
74 //
75 /// AMF is used to send objects, whether to a SharedObject .sol file,
76 /// a memory based LocalConnection segment, or over an RTMP connection
77 /// for streaming.
78 ///
79 class DSOEXPORT AMF {
80 public:
81 
82     ///	Types of SharedObjects that can be serialized or deserialized.
83     typedef enum {
84         CONNECT = 0x01,
85         DISCONNECT = 0x02,
86         SET_ATTRIBUTE = 0x03,
87         UPDATE_DATA = 0x04,
88         UPDATE_ATTRIBUTE = 0x05,
89         SEND_MESSAGE = 0x06,
90         STATUS = 0x07,
91         CLEAR_DATA = 0x08,
92         DELETE_DATA = 0x09,
93         DELETE_ATTRIBYTE = 0x0a,
94         INITIAL_DATA = 0x0b
95     } shared_obj_types_e;
96 
97     ///	Type of file being streamed.
98     typedef enum {
99 	FILETYPE_ERROR = -1,
100 	FILETYPE_NONE = 0,
101 	FILETYPE_HTML,
102 	FILETYPE_SWF,
103 	FILETYPE_VIDEO,
104 	FILETYPE_AUDIO,
105 	FILETYPE_MP3,
106 	FILETYPE_FCS,
107 	FILETYPE_OSCP
108     } filetype_e;
109 
110     /// Create a new AMF object.
111     //
112     ///	As most of the methods in the AMF class a static, this
113     ///	is primarily only used when encoding complex objects
114     ///	where the byte count is accumulated.
115     ///
116     AMF();
117 
118     /// Delete the allocated AMF object
119     ~AMF();
120 
121     /// @name Encoding methods
122     ///
123     ///		Methods for encoding data into big endian formatted
124     ///		raw AMF data. Note that while we could have had a
125     ///		single overloaded encode method, this is more
126     ///		explicit, which when it comes to manipulating binary
127     ///		protocols make the code much more readable.
128     ///
129     /// @{
130 
131     /// Encode a string object to its serialized representation.
132     //
133     /// @param str a string value
134     ///
135     /// @return a binary AMF packet in big endian format
136     ///
137     static std::shared_ptr<Buffer> encodeString(const std::string &str);
138 
139     /// Encode an array of ASCII bytes to its serialized representation.
140     //
141     /// @param data The data to serialize into big endian format
142     ///
143     /// @param size The size of the data in bytes
144     ///
145     /// @return a binary AMF packet in big endian format
146     ///
147     static std::shared_ptr<Buffer> encodeString(std::uint8_t *data,
148 						  size_t size);
149 
150     /// Encode a String object to its serialized representation.
151     //
152     ///	A NULL String is a string with no associated data.
153     ///
154     /// @return a binary AMF packet in big endian format
155     ///
156     static std::shared_ptr<Buffer> encodeNullString();
157 
158     /// Encode a Boolean object to its serialized representation.
159     //
160     /// @param flag The boolean value to serialize.
161     ///
162     /// @return a binary AMF packet in big endian format
163     ///
164     static std::shared_ptr<Buffer> encodeBoolean(bool flag);
165 
166     /// Encode an "Undefined" object to its serialized representation.
167     //
168     /// @return a binary AMF packet in big endian format
169     ///
170     static std::shared_ptr<Buffer> encodeUndefined();
171 
172     /// Encode a NULL object to its serialized representation.
173     //
174     ///	A NULL object is often used as a placeholder in RTMP.
175     ///
176     /// @return a binary AMF packet in big endian format
177     ///
178     static std::shared_ptr<Buffer> encodeNull();
179 
180     /// Encode a "Unsupported" object to its serialized representation.
181     //
182     /// @return a binary AMF packet in big endian format
183     ///
184     static  std::shared_ptr<Buffer> encodeUnsupported();
185 
186     /// Encode an XML object to its serialized representation.
187     //
188     /// @param data A pointer to the raw bytes that becomes the XML data.
189     ///
190     /// @param nbytes The number of bytes to serialize.
191     ///
192     /// @return a binary AMF packet in big endian format
193     ///
194     static std::shared_ptr<Buffer> encodeXMLObject(const std::uint8_t *data,
195 						     size_t nbytes);
196 
197     /// Encode a Typed Object to its serialized representation.
198     //
199     /// @param data A pointer to the raw bytes that becomes the data.
200     ///
201     /// @param size The number of bytes to serialize.
202     ///
203     /// @return a binary AMF packet in big endian format
204     ///
205     static std::shared_ptr<Buffer> encodeTypedObject(const cygnal::Element &data);
206 
207     /// Encode a Reference to an object to its serialized representation.
208     //
209     /// @param data A pointer to the raw bytes that becomes the data.
210     ///
211     /// @param size The number of bytes to serialize.
212     ///
213     /// @return a binary AMF packet in big endian format (header,data)
214     ///
215     static std::shared_ptr<Buffer> encodeReference(std::uint16_t index);
216 
217     /// Encode a Movie Clip (swf data) to its serialized representation.
218     //
219     /// @param data A pointer to the raw bytes that becomes the data.
220     ///
221     /// @param size The number of bytes to serialize.
222     ///
223     /// @return a binary AMF packet in big endian format (header,data)
224     ///
225     static std::shared_ptr<Buffer> encodeMovieClip(const std::uint8_t *data,
226 						     size_t size);
227 
228     /// Encode an ECMA Array to its serialized representation.
229     //
230     ///	An ECMA Array, also called a Mixed Array, contains any
231     ///	AMF data type as an item in the array.
232     ///
233     /// @param data A pointer to the raw bytes that becomes the data.
234     ///
235     /// @param size The number of bytes to serialize.
236     ///
237     /// @return a binary AMF packet in big endian format
238     ///
239     static std::shared_ptr<Buffer> encodeECMAArray(const cygnal::Element &data);
240 
241     /// Encode a Long String to its serialized representation.
242     //
243     /// @param data A pointer to the raw bytes that becomes the data.
244     ///
245     /// @param size The number of bytes to serialize.
246     ///
247     /// @return a binary AMF packet in big endian format
248     ///
249     static std::shared_ptr<Buffer> encodeLongString(const std::uint8_t *data,
250 						      size_t size);
251 
252     /// Encode a Record Set to its serialized representation.
253     //
254     /// @param data A pointer to the raw bytes that becomes the data.
255     ///
256     /// @param size The number of bytes to serialize.
257     ///
258     /// @return a binary AMF packet in big endian format
259     ///
260     static std::shared_ptr<Buffer> encodeRecordSet(const std::uint8_t *data,
261 						     size_t size);
262 
263     /// Encode a Date to its serialized representation.
264     //
265     /// @param data A pointer to the raw bytes that becomes the data.
266     ///
267     /// @return a binary AMF packet in big endian format
268     ///
269     static std::shared_ptr<Buffer> encodeDate(const std::uint8_t *data);
270 
271     /// Encode a Strict Array to its serialized representation.
272     //
273     ///	A Strict Array is one where all the items are the same
274     ///	data type, commonly either a number or a string.
275     ///
276     /// @param data A pointer to the raw bytes that becomes the data.
277     ///
278     /// @param size The number of bytes to serialize.
279     ///
280     /// @return a binary AMF packet in big endian format (header,data)
281     ///
282     static std::shared_ptr<Buffer> encodeStrictArray(const cygnal::Element &data);
283 
284     /// Encode an object to its serialized representation.
285     //
286     /// @param el A smart pointer to an Element class.
287     ///
288     /// @return a binary AMF packet in big endian format
289     ///
290     static std::shared_ptr<Buffer> encodeObject(const cygnal::Element &data);
291 
292     /// Encode the end of an object to its serialized representation.
293     //
294     /// @return a binary AMF packet in big endian format
295     ///
296     static std::shared_ptr<Buffer> encodeObjectEnd();
297 
298     /// Encode a 64 bit number to its serialized representation.
299     //
300     /// @param num A double value to serialize.
301     ///
302     /// @return a binary AMF packet in big endian format
303     ///
304     static std::shared_ptr<Buffer> encodeNumber(double num);
305 
306     /// Encode an Element to its serialized representation.
307     //
308     /// @param el A smart pointer to the Element to encode.
309     ///
310     /// @return a binary AMF packet in big endian format
311     ///
312     static std::shared_ptr<Buffer> encodeElement(std::shared_ptr<cygnal::Element> el);
313 
314     /// Encode an Element to its serialized representation.
315     //
316     /// @param el the Element to encode.
317     ///
318     /// @return a binary AMF packet in big endian format
319     ///
320     static std::shared_ptr<Buffer> encodeElement(const cygnal::Element& el);
321 
322     /// Encode a variable to its serialized representation.
323     //
324     /// @param el A smart pointer to the Element to encode.
325     ///
326     /// @return a binary AMF packet in big endian format
327     ///
328     std::shared_ptr<Buffer> encodeProperty(std::shared_ptr<cygnal::Element> el);
329 
330     /// @} end of encoding methods
331 
332     /// @name Decoding methods
333     ///
334     ///		Methods for extracting data from big endian formatted raw AMF data.
335     ///
336     /// @{
337 
338     /// Extract the AMF0 object type from the header.
339     //
340     /// @param in The raw data to extract values from.
341     ///
342     /// @return The data type from the header
343     ///
extractElementHeader(std::uint8_t * in)344     static Element::amf0_type_e extractElementHeader(std::uint8_t *in)
345                          { return *(reinterpret_cast<Element::amf0_type_e *>(in)); };
346 
347     /// Extract an AMF object from an array of raw bytes.
348     //
349     ///	An AMF object is one of the support data types.
350     ///
351     /// @param in A real pointer to the raw data to start parsing from.
352     ///
353     /// @param tooFar A pointer to one-byte-past the last valid memory
354     ///		address within the buffer.
355     ///
356     /// @return A smart ptr to an Element.
357     ///
358     /// @remarks May throw a ParserException
359     ///
360     std::shared_ptr<cygnal::Element> extractAMF(std::uint8_t *in, std::uint8_t* tooFar);
361 
362     /// Extract an AMF object from an array of raw bytes.
363     //
364     /// @param buf A smart pointer to a Buffer to parse the data from.
365     ///
366     /// @return A smart ptr to an Element.
367     ///
368     /// @remarks May throw a ParserException
369     ///
370     std::shared_ptr<cygnal::Element> extractAMF(std::shared_ptr<Buffer> buf);
371 
372     /// Extract a Property.
373     //
374     ///		A Property is a standard AMF object preceeded by a
375     ///		length and an ASCII name field. These are only used
376     ///		with higher level ActionScript objects.
377     ///
378     /// @param in A real pointer to the raw data to start parsing from.
379     ///
380     /// @param tooFar A pointer to one-byte-past the last valid memory
381     ///		address within the buffer.
382     ///
383     /// @return A smart ptr to an Element.
384     ///
385     /// @remarks May throw a ParserException
386     ///
387     std::shared_ptr<cygnal::Element> extractProperty(std::uint8_t *in, std::uint8_t* tooFar);
388 
389     /// Extract a Property.
390     //
391     ///		A Property is a standard AMF object preceeded by a
392     ///		length and an ASCII name field. These are only used
393     ///		with higher level ActionScript objects.
394     ///
395     /// @param buf A smart pointer to an Buffer to parse the data from.
396     ///
397     /// @return A smart ptr to an Element.
398     ///
399     /// @remarks May throw a ParserException
400     ///
401     std::shared_ptr<cygnal::Element> extractProperty(std::shared_ptr<Buffer> buf);
402 
403     /// @} end of decoding methods
404 
405     /// Get the total number of allocated bytes used when serializing.
406     //
407     /// @return The total allocated bytes.
408     ///
totalsize()409     size_t totalsize() { return _totalsize; }
410 
411 private:
412 
413     /// The total number of bytes in serialized ActionScript object.
414     size_t _totalsize;
415 
416 };
417 
418 /// Swap bytes in raw data.
419 //
420 ///	This only swaps bytes if the host byte order is little endian.
421 ///
422 /// @param word The address of the data to byte swap.
423 ///
424 /// @param size The number of bytes in the data.
425 ///
426 /// @return A pointer to the raw data.
427 ///
428 DSOEXPORT void *swapBytes(void *word, size_t size);
429 
430 
431 } // end of amf namespace
432 
433 // end of _AMF_H_
434 #endif
435 
436 // local Variables:
437 // mode: C++
438 // indent-tabs-mode: t
439 // End:
440