/* [<][>][^][v][top][bottom][index][help] */
//
// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
// 2011 Free Software Foundation, Inc
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef GNASH_ACTION_BUFFER_H
#define GNASH_ACTION_BUFFER_H
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/cstdint.hpp>
#include "GnashException.h"
#include "log.h"
// Forward declarations
namespace gnash {
class as_environment;
class as_value;
class movie_definition;
class SWFStream; // for read signature
}
namespace gnash {
/// A code segment.
//
/// This currently holds the actions in a memory
/// buffer, but I'm workin toward making this unneeded
/// so to eventually use a gnash::stream directly and
/// avoid full loads. (not before profiling!).
//
/// Good, would make jumping to other tags possible.
class action_buffer : boost::noncopyable
{
public:
action_buffer(const movie_definition& md);
/// Read action bytes from input stream up to but not including endPos
//
/// @param endPos
/// One past last valid-to-read byte position.
/// Make sure it's > then in.tell() and
/// <= in.get_tag_end_position() or an assertion will
/// fail.
///
void read(SWFStream& in, unsigned long endPos);
size_t size() const { return m_buffer.size(); }
boost::uint8_t operator[] (size_t off) const
{
if (off >= m_buffer.size()) {
throw ActionParserException (_("Attempt to read outside "
"action buffer"));
}
return m_buffer[off];
}
/// Disassemble instruction at given offset and return as a string
std::string disasm(size_t pc) const;
/// Get a null-terminated string from given offset
//
/// Useful to hide complexity of underlying buffer access.
///
const char* read_string(size_t pc) const
{
assert(pc <= m_buffer.size() );
if (pc == m_buffer.size())
{
throw ActionParserException(_("Asked to read string when only "
"1 byte remains in the buffer"));
}
return reinterpret_cast<const char*>(&m_buffer[pc]);
}
/// Get a pointer to the current instruction within the code
const unsigned char* getFramePointer(size_t pc) const
{
assert (pc < m_buffer.size());
return reinterpret_cast<const unsigned char*>(&m_buffer.at(pc));
}
/// Get a signed integer value from given offset
//
/// Useful to hide complexity of underlying buffer access.
///
boost::int16_t read_int16(size_t pc) const
{
if (pc + 1 >= m_buffer.size()) {
throw ActionParserException(_("Attempt to read outside action buffer limits"));
}
boost::int16_t ret = (m_buffer[pc] | (m_buffer[pc + 1] << 8));
return ret;
}
/// Get an unsigned short integer value from given offset
/// read_int16 should check buffer boundaries.
boost::uint16_t read_uint16(size_t pc) const
{
return static_cast<boost::uint16_t>(read_int16(pc));
}
/// Read a 32-bit integer starting at given offset.
//
/// Useful to hide complexity of underlying buffer access.
///
boost::int32_t read_int32(size_t pc) const
{
if (pc + 3 >= m_buffer.size()) {
throw ActionParserException(_("Attempt to read outside action buffer limits"));
}
boost::int32_t val = m_buffer[pc]
| (m_buffer[pc + 1] << 8)
| (m_buffer[pc + 2] << 16)
| (m_buffer[pc + 3] << 24);
return val;
}
/// Read a little-endian 32-bit float starting at given offset
//
/// Useful to hide complexity of underlying buffer access.
///
float read_float_little(size_t pc) const;
/// Read a 64-bit double starting at given offset.
//
/// wacky format: 45670123
/// Useful to hide complexity of underlying buffer access.
///
double read_double_wacky(size_t pc) const;
/// Return number of entries in the constant pool
size_t dictionary_size() const
{
return m_dictionary.size();
}
/// Return a value from the constant pool
const char* dictionary_get(size_t n) const
{
assert (n < m_dictionary.size());
return m_dictionary[n];
}
/// Interpret the SWF::ACTION_CONSTANTPOOL opcode.
//
/// Don't read stop_pc or later.
///
/// A dictionary is a table of indexed strings to be
/// used in action blocks to reduce their size.
///
/// NOTE: Normally the dictionary is declared as the first
/// action in an action buffer, but I've seen what looks like
/// some form of copy protection that amounts to:
///
/// |start of action buffer|
/// push true
/// branch_if_true label
/// decl_dict [0] // this is never executed, but has lots of orphan data declared in the opcode
/// label: // (embedded inside the previous opcode; looks like an invalid jump)
/// ... "protected" code here, including the real decl_dict opcode ...
/// <end of the dummy decl_dict [0] opcode>
///
/// Note also that the dictionary may be overridden multiple times.
/// See testsuite/misc-swfmill.all/dict_override.xml
///
void process_decl_dict(size_t start_pc, size_t stop_pc) const;
/// Return url of the SWF this action block was found in
const std::string& getDefinitionURL() const;
/// Return version of the SWF this action block was found in
int getDefinitionVersion() const;
const movie_definition& getMovieDefinition() const {
return _src;
}
private:
/// the code itself, as read from the SWF
std::vector<boost::uint8_t> m_buffer;
/// The dictionary
mutable std::vector<const char*> m_dictionary;
/// FIXME: move to ActionExec
mutable int m_decl_dict_processed_at;
/// The movie_definition containing this action buffer
//
/// This pointer will be used to determine domain-based
/// permissions to grant to the action code.
///
const movie_definition& _src;
};
} // end namespace gnash
#endif // GNASH_ACTION_BUFFER_H
// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End:
/* [<][>][^][v][top][bottom][index][help] */