1 // stream.h - SWF stream reading class, for Gnash 2 // 3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 4 // Free Software Foundation, Inc 5 // 6 // This program is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 3 of the License, or 9 // (at your option) any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program; if not, write to the Free Software 18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 20 #ifndef GNASH_STREAM_H 21 #define GNASH_STREAM_H 22 23 #include "SWF.h" 24 #include "dsodefs.h" // still neded ? 25 #include "GnashException.h" 26 27 #include <string> 28 #include <sstream> 29 #include <vector> // for composition 30 #include <cstdint> // for boost::?int??_t 31 32 // Define the following macro if you want to want Gnash parser 33 // to assume the underlying SWF is well-formed. It would make 34 // parsing faster, but might result in horrible behaviour with 35 // malformed SWFs (like taking up all system memory, keeping 36 // CPU busy for a long long time, or simply corrupting memory) 37 // 38 // This might be eventually set by a --disable-swf-checks or similar 39 // configure switch... 40 // 41 //#define GNASH_TRUST_SWF_INPUT 42 43 namespace gnash { 44 class IOChannel; 45 } 46 47 namespace gnash { 48 49 /// SWF stream wrapper class 50 // 51 /// This class is used for loading variable-length data 52 /// from a stream, and keeping track of SWF tag boundaries. 53 /// 54 /// Provides 'aligned' and 'bitwise' read functions: 55 /// - aligned reads always start on a byte boundary 56 /// - bitwise reads can cross byte boundaries 57 /// 58 class DSOEXPORT SWFStream 59 { 60 public: 61 SWFStream(IOChannel* input); 62 ~SWFStream(); 63 64 /// \brief 65 /// Reads a bit-packed unsigned integer from the stream 66 /// and returns it. The given bitcount determines the 67 /// number of bits to read. 68 // 69 /// bitwise read 70 /// 71 unsigned read_uint(unsigned short bitcount); 72 73 /// \brief 74 /// Reads a single bit off the stream 75 /// and returns it. 76 // 77 /// bitwise read 78 /// 79 bool read_bit(); 80 81 /// \brief 82 /// Reads a bit-packed little-endian signed integer 83 /// from the stream. The given bitcount determines the 84 /// number of bits to read. 85 // 86 /// bitwise read 87 /// 88 int read_sint(unsigned short bitcount); 89 90 /// Read a 16.16 fixed point signed value 91 // 92 /// aligned read 93 /// 94 float read_fixed(); 95 96 /// Read a 16.16 fixed point unsigned value 97 // 98 /// aligned read 99 /// 100 float read_ufixed(); 101 102 /// Read a 8.8 fixed point unsigned value 103 // 104 /// aligned read 105 /// 106 float read_short_ufixed(); 107 108 /// Read a 8.8 fixed point signed value 109 // 110 /// aligned read 111 /// 112 float read_short_sfixed(); 113 114 /// Read a 32bit (1:sign 8:exp 23:mantissa) floating point value 115 // 116 /// aligned read 117 /// 118 float read_long_float(); 119 120 /// Read a 64-bit double value 121 // 122 /// aligned read 123 /// 124 double read_d64(); 125 126 /// Consume all bits of current byte 127 // 128 /// This method is implicitly called by all 'aligned' reads. 129 /// 130 /// NOTE: 131 /// The position returned by tell() won't be changed 132 /// by calls to this function, altought any subsequent reads 133 /// will start on next byte. See tell() for more info. 134 /// align()135 void align() 136 { 137 m_unused_bits=0; 138 // m_current_byte = 0; // this is not needed 139 } 140 141 /// Read <count> bytes from the source stream and copy that data to <buf>. 142 // 143 /// aligned read 144 /// 145 unsigned read(char *buf, unsigned count); 146 147 /// Read a aligned unsigned 8-bit value from the stream. 148 // 149 /// aligned read 150 /// 151 std::uint8_t read_u8(); 152 153 /// Read a aligned signed 8-bit value from the stream. 154 // 155 /// aligned read 156 /// 157 std::int8_t read_s8(); 158 159 /// Read a aligned unsigned 16-bit value from the stream. 160 // 161 /// aligned read 162 /// 163 std::uint16_t read_u16(); 164 165 /// Read a aligned signed 16-bit value from the stream. 166 // 167 /// aligned read 168 /// 169 std::int16_t read_s16(); 170 171 /// Read a aligned unsigned 32-bit value from the stream. 172 // 173 /// aligned read 174 /// 175 std::uint32_t read_u32(); 176 177 /// \brief 178 /// Read a aligned signed 32-bit value from the stream. 179 // 180 /// aligned read 181 /// 182 std::int32_t read_s32(); 183 184 /// \brief 185 /// Read a variable length unsigned 32-bit value from the stream. 186 /// These values continue until either the high bit is not set or 187 /// until 5 bytes have been read. 188 // 189 /// aligned read 190 /// read_V32()191 std::uint32_t read_V32() 192 { 193 ensureBytes(1); 194 std::uint32_t res = read_u8(); 195 if (!(res & 0x00000080)) return res; 196 197 ensureBytes(1); 198 res = (res & 0x0000007F) | read_u8() << 7; 199 if (!(res & 0x00004000)) return res; 200 201 ensureBytes(1); 202 res = (res & 0x00003FFF) | read_u8() << 14; 203 if (!(res & 0x00200000)) return res; 204 205 ensureBytes(1); 206 res = (res & 0x001FFFFF) | read_u8() << 21; 207 if (!(res & 0x10000000)) return res; 208 209 ensureBytes(1); 210 res = (res & 0x0FFFFFFF) | read_u8() << 28; 211 return res; 212 } 213 214 /// \brief 215 /// Skip a variable length unsigned 32-bit value in the stream. 216 /// This is faster than doing the bitwise arithmetic of full reading. 217 /// 218 /// aligned read 219 /// skip_V32()220 void skip_V32() 221 { 222 ensureBytes(1); 223 if (!(read_u8() & 0x80)) return; 224 ensureBytes(1); 225 if (!(read_u8() & 0x80)) return; 226 ensureBytes(1); 227 if (!(read_u8() & 0x80)) return; 228 ensureBytes(1); 229 if (!(read_u8() & 0x80)) return; 230 ensureBytes(1); 231 static_cast<void> (read_u8()); 232 } 233 234 /// \brief 235 /// Read a length in a byte or three. 236 // 237 /// If the byte == 0xff, read the lenght in 238 /// next two bytes. 239 /// 240 /// Takes care of integrity check (ensureByte) 241 /// 242 /// aligned read 243 /// read_variable_count()244 unsigned read_variable_count() 245 { 246 ensureBytes(1); 247 unsigned count = read_u8(); 248 if (count == 0xFF) 249 { 250 ensureBytes(2); 251 count = read_u16(); 252 } 253 return count; 254 }; 255 256 /// \brief 257 /// Reads a null-terminated string from the given file and 258 /// assigns it to the given std::string, overriding any 259 /// previous value of it. 260 /// 261 /// aligned read 262 /// 263 /// Will throw ParserException if no terminating null is found within 264 /// tag boundaries 265 void read_string(std::string& to); 266 267 /// Reads a sized string into a provided std::string. 268 // 269 /// Length of string is read from the first byte. 270 /// 271 /// @param to 272 /// Output argument. Any previous value will be overriden. 273 /// 274 /// aligned read 275 /// 276 /// Will throw ParserException if advertised length crosses tag boundaries 277 /// 278 void read_string_with_length(std::string& to); 279 280 /// Reads a sized string into a provided std::string. 281 // 282 /// 283 /// @param len 284 /// Length of string to read. 285 /// 286 /// @param to 287 /// Output argument. Any previous value will be overriden. 288 /// 289 /// aligned read 290 /// 291 /// Will throw ParserException if len crosses tag boundaries 292 /// 293 void read_string_with_length(unsigned len, std::string& to); 294 295 /// Return our current (byte) position in the input stream. 296 // 297 /// NOTE: 298 /// This is not necessarely the byte you'll read on next read. 299 /// - For bitwise reads the currenty byte will be used only if not 300 /// completely consumed. See align(). 301 /// - For aligned reads the current byte will not be used 302 /// (already used) 303 /// 304 unsigned long tell(); 305 306 /// Set the file position to the given value (byte aligned) 307 // 308 /// If we're scanning a tag, don't allow seeking past 309 /// the end or before start of it. 310 /// 311 /// @return true on success, false on failure 312 /// Possible failures: 313 /// - given position is after end of stream. 314 /// - given position is after end of current tag, if any. 315 /// - given position is before start of current tag, if any. 316 /// 317 bool seek(unsigned long pos); 318 319 /// Return the file position of the end of the current tag. 320 unsigned long get_tag_end_position(); 321 322 /// Open an SWF tag and return it's type. 323 // 324 /// aligned read 325 /// 326 SWF::TagType open_tag(); 327 328 /// Seek to the end of the most-recently-opened tag. 329 void close_tag(); 330 331 /// Discard given number of bytes 332 // 333 /// 334 /// @return true on success, false on failure 335 /// Possible failures: 336 /// - skipping given number of bytes reaches end of stream. 337 /// - skipping given number of bytes reaches end of 338 /// current tag, if any. 339 /// 340 /// WARNING: alignment is not specified here, the method uses 341 /// tell() which is known NOT to consider 342 /// a fully-read byte as already "skipped" 343 /// TODO: force alignment and see what happens !! 344 /// skip_bytes(unsigned num)345 bool skip_bytes(unsigned num) 346 { 347 // there's probably a better way, but 348 // it's the interface that counts atm 349 size_t curpos = tell(); 350 return seek(curpos+num); 351 } 352 353 /// Discard all bytes up to end of tag skip_to_tag_end()354 void skip_to_tag_end() 355 { 356 // seek will call align... 357 seek(get_tag_end_position()); 358 } 359 360 /// \brief 361 /// Ensure the requested number of bytes are available for an aligned read 362 /// in the currently opened tag. 363 // 364 /// Throws a ParserException on a short count. 365 /// This method should be called before any attempt to read 366 /// fields from the SWF. 367 /// 368 /// NOTE: if GNASH_TRUST_SWF_INPUT is defined this function is a no-op 369 /// 370 void ensureBytes(unsigned long needed); 371 372 /// \brief 373 /// Ensure the requested number of bits are available for a bitwise read 374 /// in currently opened tag. 375 // 376 /// Throws a ParserException on a short count. 377 /// This method should be called before any attempt to read 378 /// bits from the SWF. 379 /// 380 /// NOTE: if GNASH_TRUST_SWF_INPUT is defined this function is a no-op 381 /// ensureBits(unsigned long needed)382 void ensureBits(unsigned long needed) 383 { 384 #ifndef GNASH_TRUST_SWF_INPUT 385 if ( _tagBoundsStack.empty() ) return; // not in a tag (should we check file length ?) 386 unsigned long int bytesLeft = get_tag_end_position() - tell(); 387 unsigned long int bitsLeft = (bytesLeft*8)+m_unused_bits; 388 if ( bitsLeft < needed ) 389 { 390 std::stringstream ss; 391 ss << "premature end of tag: need to read " << needed << " bytes, but only " << bitsLeft << " left in this tag"; 392 throw ParserException(ss.str()); 393 } 394 #endif 395 } 396 397 /// Consume any pending input 398 // 399 /// This method is useful to force full consumption 400 /// of the SWFStream's underlying IOChannel for the 401 /// cases in which it is a pipe and a writer would 402 /// hang on it unless someone is reading. 403 /// 404 /// This method will NOT be called automatically 405 /// on SWFStream destruction as in the current 406 /// design SWFStream does NOT own the underlying 407 /// IOChannel. TODO: rethink about ownership. 408 /// 409 /// NOTE: the stream position will be updated by 410 /// this call, so that ::tell will basically 411 /// return the full input size. 412 /// 413 void consumeInput(); 414 415 private: 416 417 IOChannel* m_input; 418 std::uint8_t m_current_byte; 419 std::uint8_t m_unused_bits; 420 421 typedef std::pair<unsigned long,unsigned long> TagBoundaries; 422 // position of start and end of tag 423 std::vector<TagBoundaries> _tagBoundsStack; 424 }; 425 426 427 } // namespace gnash 428 429 430 #endif // GNASH_STREAM_H 431 432 433 // Local Variables: 434 // mode: C++ 435 // c-basic-offset: 8 436 // tab-width: 8 437 // indent-tabs-mode: t 438 // End: 439