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