Index: server/stream.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/stream.cpp,v
retrieving revision 1.39
diff -U 2 -r1.39 stream.cpp
--- server/stream.cpp	4 Dec 2007 18:35:16 -0000	1.39
+++ server/stream.cpp	7 Dec 2007 11:46:45 -0000
@@ -29,118 +29,154 @@
 //#include <iostream> // debugging only
 
-//#define USE_TU_FILE_BYTESWAPPING 1
-
 namespace gnash {
+
+		//log_debug("FILL_CACHE_IF_NEEDED: _cacheOffset:%d, _UsedBits:%d, _cacheSize:%d", _cacheOffset, _usedBits, _cacheSize); 
+#define FILL_CACHE_IF_NEEDED { \
+		if ( _cacheOffset+(_usedBits/8) >= _cacheSize ) fillEmptyCache(); \
+	}
+
+		//log_debug("BYTEALIGN: _cacheOffset:%d, _UsedBits:%d, _cacheSize:%d", _cacheOffset, _usedBits, _cacheSize); 
+#define BYTEALIGN { \
+		if ( _usedBits ) { ++_cacheOffset; _usedBits=0; } \
+		if ( _cacheOffset >= _cacheSize ) fillEmptyCache(); \
+	}
 	
 stream::stream(tu_file* input)
 	:
 	m_input(input),
-	m_current_byte(0),
-	m_unused_bits(0)
+	_usedBits(0),
+	_cacheOffset(0),
+	_cacheSize(0),
+	_inputEOF(false)
 {
 }
 
+unsigned
+stream::readFromCache(char *buf, unsigned count)
+{
+	align();
+
+	// no data available in the cache
+	if ( _cacheOffset >= _cacheSize ) return 0;
+
+	count = std::min(_cacheSize-_cacheOffset, count);
+	memcpy(buf, _cache+_cacheOffset, count);
+	_cacheOffset += count;
+	assert(_cacheOffset <= _cacheSize);
+	//log_msg("Read %d bytes from cache, new _cacheOffset is %lu (size %lu)", count, _cacheOffset, _cacheSize);
+	return count;
+
+}
 
-stream::~stream()
+void
+stream::fillEmptyCache()
 {
+	// cache is empty
+	assert ( _cacheOffset+(_usedBits/8) >= _cacheSize );
+
+	if ( _inputEOF ) throw ParserException("Premature end of input stream");
+
+	_cacheSize = m_input->read_bytes(_cache, _cacheCapacity);
+	if ( _cacheSize < _cacheCapacity )
+	{
+		log_debug("Could only fill %d bytes out of %d of stream cache capacity", _cacheSize, _cacheCapacity);
+		_inputEOF = true;
+	}
+	else
+	{
+		//log_debug("Filled the empty cache");
+	}
+	_cacheOffset = _usedBits = 0; 
 }
 
 unsigned stream::read(char *buf, unsigned count)
 {
-	align();
-	return m_input->read_bytes(buf, count);
+	BYTEALIGN;
+
+	unsigned readSoFar = readFromCache(buf, count);
+	if ( readSoFar < count ) // cache wasn't enough
+	{
+		readSoFar += m_input->read_bytes(buf+readSoFar, count-readSoFar);
+		_cacheSize = _cacheOffset = _usedBits = 0; // discard the cache
+	}
+	return readSoFar;
 }
 
 bool stream::read_bit()
 {
-	if (!m_unused_bits)
-	{
-		m_current_byte = m_input->read_byte(); // don't want to align here
-		m_unused_bits = 7;
-		return (m_current_byte&0x80);
-	}
-	else
+#if 1
+	return read_uint(1);
+#else
+	FILL_CACHE_IF_NEEDED;
+	if ( _usedBits > 7 ) 
 	{
-		return ( m_current_byte & (1<<(--m_unused_bits)) );
+		_usedBits=0;
+		++_cacheOffset;
 	}
+
+	bool ret = ( _cache[_cacheOffset] & (128>>_usedBits) );
+	++_usedBits;
+	return ret;
+#endif
 }
 
 unsigned stream::read_uint(unsigned short bitcount)
 {
-	//assert(bitcount <= 24);
-	// should be 24, check why htf_sweet.swf fails this assertion
 	assert(bitcount <= 32);
 
-	// Optimization for multibyte read
-	if ( bitcount > m_unused_bits )
-	{
-		typedef unsigned char byte;
-
-		boost::uint32_t value = 0;
+	boost::uint32_t value = 0;
 
-		if (m_unused_bits) // Consume all the unused bits.
+	unsigned short bits_needed = bitcount;
+	do
+	{
+		FILL_CACHE_IF_NEEDED;
+		if ( _usedBits > 7 ) 
 		{
-			int unusedMask = (1 << m_unused_bits)-1;
-			bitcount -= m_unused_bits; 
-			value |= ((m_current_byte&unusedMask) << bitcount);
+			_usedBits=0;
+			++_cacheOffset;
 		}
 
-		int bytesToRead = bitcount/8;
-		int spareBits = bitcount%8; // additional bits to read
-
-		//std::cerr << "BytesToRead: " << bytesToRead << " spareBits: " << spareBits << " unusedBits: " << (int)m_unused_bits << std::endl;
+		int unusedMask = 0xFF >> _usedBits;
+		int unusedBits = 8 - _usedBits;
 
-		byte cache[4]; // at most 4 bytes in the cache
+		//log_debug("%d unused bits, %d needed", unusedBits, bits_needed);
 
-		if ( spareBits ) m_input->read_bytes(&cache, bytesToRead+1);
-		else m_input->read_bytes(&cache, bytesToRead);
-
-		for (int i=0; i<bytesToRead; ++i)
+		if (bits_needed == unusedBits)
 		{
-			bitcount -= 8;
-			value |= cache[i] << bitcount; 
-		}
+			// Consume all the unused bits.
+			value |= ( _cache[_cacheOffset] & unusedMask );
+			_usedBits += bits_needed; 
+			break;
 
-		//assert(bitcount == spareBits);
-		if ( bitcount )
+		}
+		else if (bits_needed > unusedBits)
 		{
-			m_current_byte = cache[bytesToRead];
-			m_unused_bits = 8-bitcount;
-			value |= m_current_byte >> m_unused_bits;
+			// Consume all the unused bits.
+
+			bits_needed -= unusedBits; // assert(bits_needed>0)
+
+			value |= ((_cache[_cacheOffset] & unusedMask) << bits_needed);
+			++_cacheOffset; _usedBits=0; // advance to next byte
 		}
 		else
 		{
-			m_unused_bits = 0;
-		}
+			//assert(bits_needed <= unusedBits);
 
-		return value;
-		
-	}
+			// Consume some of the unused bits.
 
-	if (!m_unused_bits)
-	{
-		m_current_byte = m_input->read_byte();
-		m_unused_bits = 8;
-	}
+			unusedBits -= bits_needed;
 
-	// TODO: optimize unusedMask creation ?
-	//       (it's 0xFF if ! m_unused_bits above)
-	int unusedMask = (1 << m_unused_bits)-1;
+			value |= ((_cache[_cacheOffset] & unusedMask) >> unusedBits);
 
-	if (bitcount == m_unused_bits)
-	{
-		// Consume all the unused bits.
-		m_unused_bits = 0;
-		return (m_current_byte&unusedMask);
-	}
-	else
-	{
-		assert(bitcount < m_unused_bits);
-		// Consume some of the unused bits.
+			_usedBits += bits_needed;
 
-		m_unused_bits -= bitcount;
-		return ((m_current_byte&unusedMask) >> m_unused_bits);
+			// We're done.
+			break;
+		}
 	}
+	while (bits_needed > 0);
 
+	//std::cerr << "Returning value: " << value << " unused bits: " << (int)m_unused_bits << std::endl;
+	return value;
 }
 
@@ -148,6 +184,4 @@
 int	stream::read_sint(unsigned short bitcount)
 {
-	//assert(bitcount <= 32); // already asserted in read_uint
-
 	boost::int32_t	value = boost::int32_t(read_uint(bitcount));
 
@@ -157,6 +191,4 @@
 	}
 
-//		IF_DEBUG(log_msg("stream::read_sint(%d) == %d\n", bitcount, value));
-
 	return value;
 }
@@ -165,5 +197,4 @@
 float	stream::read_fixed()
 {
-	// align(); // read_u32 will align 
 	return static_cast<float> (
 		static_cast<double>(read_s32()) / 65536.0f
@@ -176,5 +207,4 @@
 float	stream::read_ufixed()
 {
-	// align(); // read_u32 will align 
 	return static_cast<float> (
 		static_cast<double>(read_u32()) / 65536.0f
@@ -185,5 +215,4 @@
 float   stream::read_short_ufixed()
 {
-	// align(); // read_u16 will align 
 	return static_cast<float> ( read_u16() / 256.0f );
 }
@@ -192,5 +221,4 @@
 float	stream::read_short_sfixed()
 {
-	// align(); // read_s16 will align 
 	return static_cast<float> ( read_s16() / 256.0f );
 }
@@ -199,5 +227,4 @@
 float	stream::read_float()
 {
-	// align(); // read_s16 will align
 	return static_cast<float> ( read_s16() );
 }
@@ -206,11 +233,7 @@
 long double stream::read_d64()
 {
-#ifdef USE_TU_FILE_BYTESWAPPING 
-	align();
-	return m_input->read_le_double64();
-#else
 	using boost::uint32_t;
 
-	unsigned char _buf[8]; read((char*)_buf, 8); // would align
+	unsigned char _buf[8]; read((char*)_buf, 8); 
 	uint64_t low = _buf[0];
 		 low |= _buf[1] << 8;
@@ -224,16 +247,15 @@
 
 	return static_cast<long double> ( low | (hi<<32) );
-#endif
 }
 
 uint8_t	stream::read_u8()
 {
-	align();
-	return m_input->read_byte();
+	BYTEALIGN;
+
+	return _cache[_cacheOffset++];
 }
 
 int8_t	stream::read_s8()
 {
-	// read_u8 will align
 	return read_u8();
 }
@@ -241,21 +263,15 @@
 boost::uint16_t	stream::read_u16()
 {
-#ifdef USE_TU_FILE_BYTESWAPPING 
-	align();
-	return m_input->read_le16();
-#else
 	using boost::uint32_t;
 
-	unsigned char _buf[2]; read((char*)_buf, 2); // would align
+	unsigned char _buf[2]; read((char*)_buf, 2); 
 	uint32_t result = _buf[0];
 		 result |= (_buf[1] << 8);
 
 	return result;
-#endif
 }
 
 boost::int16_t stream::read_s16()
 {
-	// read_u16 will align
 	return read_u16();
 }
@@ -263,11 +279,7 @@
 boost::uint32_t	stream::read_u32()
 {
-#ifdef USE_TU_FILE_BYTESWAPPING 
-	align();
-	return m_input->read_le32();
-#else
 	using boost::uint32_t;
 
-	unsigned char _buf[4]; read((char*)_buf, 4); // would align
+	unsigned char _buf[4]; read((char*)_buf, 4); 
 	uint32_t result = _buf[0];
 		 result |= _buf[1] << 8;
@@ -276,10 +288,8 @@
 
 	return result;
-#endif
 }
 
 boost::int32_t	stream::read_s32()
 {
-	// read_u32 will align
 	return read_u32();
 }
@@ -288,5 +298,5 @@
 char*	stream::read_string()
 {
-	align();
+	BYTEALIGN;
 
 	std::vector<char>	buffer;
@@ -312,5 +322,5 @@
 stream::read_string(std::string& to)
 {
-	align();
+	BYTEALIGN;
 
 	to.clear();
@@ -327,5 +337,5 @@
 char*	stream::read_string_with_length()
 {
-	align();
+	BYTEALIGN;
 
 	int	len = read_u8();
@@ -351,5 +361,5 @@
 void stream::read_string_with_length(std::string& to)
 {
-	align();
+	BYTEALIGN;
 
 	unsigned int	len = read_u8();
@@ -359,5 +369,5 @@
 void stream::read_string_with_length(unsigned len, std::string& to)
 {
-	align();
+	BYTEALIGN;
 
 	to.resize(len);
@@ -370,8 +380,28 @@
 }
 
+void
+stream::align()
+{
+	if ( _usedBits ) _usedBits=8;
+}
+
 
 unsigned long stream::get_position()
 {
-	return m_input->get_position();
+	// This is the position of underlying stream
+	unsigned long pos = m_input->get_position();
+
+	// This is the amount of bytes in the cache
+	unsigned inCache = (_cacheSize-_cacheOffset);
+
+	//log_debug("get_position called, stream pos %lu, in cache %lu, usedBits %u", pos, inCache, _usedBits);
+
+	unsigned long userPos =  pos - inCache;
+
+	// If we started reading something let's assume we read one more byte
+	if ( _usedBits ) ++userPos;
+
+	return userPos;
+	
 }
 
@@ -379,4 +409,5 @@
 bool	stream::set_position(unsigned long pos)
 {
+	// first of all discard pending bits
 	align();
 
@@ -403,5 +434,37 @@
 	}
 
-	// Do the seek.
+	//
+	// Seek in cache if possible !
+	//
+
+	// In case we have a cache let's see if it contains the target pos
+	if ( _cacheSize )
+	{
+		// This is position of last byte in the cache
+		unsigned long lastCachePos = m_input->get_position();
+		assert(lastCachePos >= _cacheSize); // or we wouldn't have a cache
+
+		// And this is position of first one
+		unsigned long firstCachePos = lastCachePos-_cacheSize;
+
+		// is target position is within the range seek in cache
+		if ( pos <= lastCachePos && pos >= firstCachePos )
+		{
+#ifdef DEBUG_CACHE_SEEKS
+			log_debug("Full in-cache seek. Cache goes from %lu to %lu, we seeked from %lu to %lu (offset %d)",
+				firstCachePos, lastCachePos, firstCachePos+_cacheOffset, pos, (firstCachePos+_cacheOffset-pos));
+#endif
+			_cacheOffset = (pos-firstCachePos);
+			_usedBits=0; // re-align
+
+			assert(get_position() == pos);
+
+			return true;
+		}
+
+	}
+
+	// Reset the cache and do the seek.
+	_cacheSize = _cacheOffset = _usedBits = 0;
 	if ( m_input->set_position(pos) == TU_FILE_SEEK_ERROR )
 	{
@@ -413,4 +476,5 @@
 	}
 
+	assert(get_position() == pos);
 	return true;
 }
@@ -427,5 +491,5 @@
 SWF::tag_type stream::open_tag()
 {
-	align();
+	BYTEALIGN;
 
 	unsigned long tagStart=get_position();
@@ -434,5 +498,5 @@
 	int	tag_type = tag_header >> 6;
 	int	tag_length = tag_header & 0x3F;
-	assert(m_unused_bits == 0);
+	assert(!(_usedBits%8));
 	if (tag_length == 0x3F) {
 		tag_length = read_u32();
@@ -487,10 +551,9 @@
 	_tagBoundsStack.pop_back();
 
-	if ( m_input->set_position(end_pos) == TU_FILE_SEEK_ERROR )
+	if ( ! set_position(end_pos) )
 	{
 		log_error("Could not seek to end position");
 	}
 
-	m_unused_bits = 0;
 }
 
Index: server/stream.h
===================================================================
RCS file: /sources/gnash/gnash/server/stream.h,v
retrieving revision 1.37
diff -U 2 -r1.37 stream.h
--- server/stream.h	5 Dec 2007 11:31:52 -0000	1.37
+++ server/stream.h	7 Dec 2007 11:46:45 -0000
@@ -57,5 +57,6 @@
 public:
 	stream(tu_file* input);
-	~stream();
+
+	~stream() {}
 
 	/// \brief
@@ -130,9 +131,5 @@
 	/// will start on next byte. See get_position() for more info.
 	///
-	void	align()
-	{
-		m_unused_bits=0;
-		// m_current_byte = 0; // this is not needed
-	}
+	void	align();
 
 	/// Read <count> bytes from the source stream and copy that data to <buf>.
@@ -313,4 +310,6 @@
 	/// the end or before start of it.
 	///
+	/// Discard any pending bit in current read.
+	///
 	/// @return true on success, false on failure
 	/// 	Possible failures:
@@ -392,6 +391,21 @@
 
 	tu_file*	m_input;
-	uint8_t	m_current_byte;
-	uint8_t	m_unused_bits;
+
+	// Used bits from current _cache[_cacheOffset]
+	uint8_t	_usedBits;
+
+	// Read 'count' bytes from the cache and return number
+	// of bytes actually read.
+	// Aligns...
+	unsigned readFromCache(char* buf, unsigned count);
+
+	// Fill the cache if empty
+	void fillEmptyCache();
+
+	static const size_t _cacheCapacity = 8;
+	size_t _cacheOffset;
+	size_t _cacheSize; // actual size of the current cache
+	unsigned char _cache[_cacheCapacity];
+	bool _inputEOF; // underlying stream is at end of file
 
 	typedef std::pair<unsigned long,unsigned long> TagBoundaries;
