<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "rdf++/reader/trix.h"

#include "rdf++/quad.h"
#include "rdf++/term.h"
#include "rdf++/triple.h"

#include "xml_reader.h"

#include <memory>  /* for std::unique_ptr */
#include <cstring> /* for std::strcmp() */

namespace {
  enum class trix_element {
    unknown = 0,
    trix,
    graph,
    triple,
    id,
    uri,
    plain_literal,
    typed_literal,
  };

  enum class trix_state {start, document, graph, triple, eof, abort};

  struct trix_context {
    trix_state state = trix_state::start;
    trix_element element = trix_element::unknown;
    unsigned int term_pos = 0;
    std::unique_ptr<rdf::term> terms[3] = {nullptr, nullptr, nullptr};
    std::unique_ptr<rdf::uri_reference> graph = nullptr;
    std::function<void (rdf::triple*)> triple_callback = nullptr;
    std::function<void (rdf::quad*)> quad_callback = nullptr;
  };

  struct implementation : public rdf::reader::implementation {
    implementation(FILE* stream,
      const char* content_type,
      const char* charset,
      const char* base_uri);
    virtual ~implementation() noexcept override;
    virtual void read_triples(std::function<void (rdf::triple*)> callback) override;
    virtual void read_quads(std::function<void (rdf::quad*)> callback) override;
    virtual void abort() override;
  protected:
    void read_with_context(trix_context& context);
    void ensure_state(trix_context& context, trix_state state);
    void assert_state(trix_context& context, trix_state state);
    void enter_state(trix_context& context, trix_state state);
    void leave_state(trix_context& context, trix_state state);
    void change_state(trix_context& context, trix_state state);
    void ensure_depth(trix_context& context, unsigned int depth);
    void record_term(trix_context& context);
    void begin_element(trix_context& context);
    void finish_element(trix_context& context);
    rdf::term* construct_term(trix_context& context);
    void throw_error(trix_context& context, const char* what);
  private:
    xml_reader _reader;
  };
}

rdf::reader::implementation*
rdf_reader_for_trix(FILE* const stream,
                    const char* const content_type,
                    const char* const charset,
                    const char* const base_uri) {
  return new implementation(stream, content_type, charset, base_uri);
}

implementation::implementation(FILE* const stream,
                               const char* const content_type,
                               const char* const charset,
                               const char* const base_uri)
  : _reader(stream, base_uri, charset) {
  assert(stream != nullptr);
  (void)content_type;
}

implementation::~implementation() noexcept = default;

static trix_element
intern_trix_element(const char* const element_name) {
  switch (*element_name) {
    case 'T':
      if (std::strcmp(element_name, "TriX") == 0 ||
          std::strcmp(element_name, "trix") == 0) {
        return trix_element::trix;
      }
      break;
    case 'g':
      if (std::strcmp(element_name, "graph") == 0) {
        return trix_element::graph;
      }
      break;
    case 't':
      if (std::strcmp(element_name, "triple") == 0) {
        return trix_element::triple;
      }
      if (std::strcmp(element_name, "typedLiteral") == 0) {
        return trix_element::typed_literal;
      }
      break;
    case 'i':
      if (std::strcmp(element_name, "id") == 0) {
        return trix_element::id;
      }
      break;
    case 'u':
      if (std::strcmp(element_name, "uri") == 0) {
        return trix_element::uri;
      }
      break;
    case 'p':
      if (std::strcmp(element_name, "plainLiteral") == 0) {
        return trix_element::plain_literal;
      }
      break;
    default:
      break;
  }
  return trix_element::unknown;
}

void
implementation::read_triples(std::function<void (rdf::triple*)> callback) {
  trix_context context;
  context.triple_callback = callback;
  read_with_context(context);
}

void
implementation::read_quads(std::function<void (rdf::quad*)> callback) {
  trix_context context;
  context.quad_callback = callback;
  read_with_context(context);
}

void
implementation::abort() {
  // TODO
}

void
implementation::read_with_context(trix_context& context) {
  while (_reader.read()) {
    switch (_reader.node_type()) {
      case xml_node_type::element:
        begin_element(context);
        break;

      case xml_node_type::end_element:
        finish_element(context);
        break;

      default: /* ignored */
        break;
    }
  }
}

void
implementation::ensure_state(trix_context& context, const trix_state state) {
  if (context.state != state) {
    throw_error(context, "mismatched nesting of elements in TriX input");
  }
}

void
implementation::assert_state(trix_context& context, const trix_state state) {
  (void)state, (void)context;
  assert(context.state == state);
}

void
implementation::enter_state(trix_context& context, const trix_state state) {
  switch (state) {
    case trix_state::graph:
      context.graph.reset();
      break;

    case trix_state::triple:
      context.term_pos = 0;
      break;

    default:
      break;
  }
}

void
implementation::leave_state(trix_context& context, const trix_state state) {
  switch (state) {
    case trix_state::triple:
      if (context.quad_callback) {
        auto quad = new rdf::quad(
          context.terms[0].get(),
          context.terms[1].get(),
          context.terms[2].get(),
          context.graph ? (context.graph)->clone() : nullptr);
        context.quad_callback(quad);
      }
      else if (context.triple_callback) {
        auto triple = new rdf::triple(
          context.terms[0].get(),
          context.terms[1].get(),
          context.terms[2].get());
        context.triple_callback(triple);
      }
      for (auto i = 0U; i < 3; i++) {
        if (context.quad_callback || context.triple_callback) {
          /* The callback took ownership of the terms: */
          context.terms[i].release();
        }
        else {
          context.terms[i].reset();
        }
      }
      context.term_pos = 0;
      break;

    default:
      break;
  }
}

void
implementation::change_state(trix_context& context, const trix_state state) {
  leave_state(context, context.state);
  context.state = state;
  enter_state(context, context.state);
}

void
implementation::ensure_depth(trix_context& context, const unsigned int depth) {
  if (_reader.depth() != depth) {
    throw_error(context, "incorrect nesting of elements in TriX input");
  }
}

void
implementation::record_term(trix_context& context) {
  if (context.term_pos >= 3) {
    throw_error(context, "too many elements inside <triple> element");
  }

  context.terms[context.term_pos].reset(construct_term(context));
  context.term_pos++;
}

void
implementation::begin_element(trix_context& context) {
  context.element = intern_trix_element(_reader.name());

  switch (context.element) {
    case trix_element::trix:
      ensure_state(context, trix_state::start);
      ensure_depth(context, 0);
      change_state(context, trix_state::document);
      break;

    case trix_element::graph:
      ensure_state(context, trix_state::document);
      ensure_depth(context, 1);
      change_state(context, trix_state::graph);
      break;

    case trix_element::triple:
      ensure_state(context, trix_state::graph);
      ensure_depth(context, 2);
      change_state(context, trix_state::triple);
      break;

    case trix_element::uri:
      if (context.state == trix_state::graph) {
        ensure_depth(context, 2);
        if (context.graph) {
          throw_error(context, "repeated <uri> element inside <graph> element");
        }
        context.graph.reset(new rdf::uri_reference(_reader.read_string()));
        break;
      }
      ensure_state(context, trix_state::triple);
      ensure_depth(context, 3);
      record_term(context);
      break;

    case trix_element::id:
    case trix_element::plain_literal:
    case trix_element::typed_literal:
      ensure_state(context, trix_state::triple);
      ensure_depth(context, 3);
      record_term(context);
      break;

    default:
      throw_error(context, "unknown XML element in TriX input");
  }
}

void
implementation::finish_element(trix_context& context) {
  context.element = intern_trix_element(_reader.name());

  switch (context.element) {
    case trix_element::trix:
      assert_state(context, trix_state::document);
      change_state(context, trix_state::eof);
      break;

    case trix_element::graph:
      assert_state(context, trix_state::graph);
      change_state(context, trix_state::document);
      break;

    case trix_element::triple:
      assert_state(context, trix_state::triple);
      change_state(context, trix_state::graph);
      break;

    case trix_element::uri:
      //assert_state(trix_state::triple, context); // FIXME: triple | graph
      break;

    case trix_element::id:
    case trix_element::plain_literal:
    case trix_element::typed_literal:
      assert_state(context, trix_state::triple);
      break;

    default: abort(); /* never reached */
  }
}

rdf::term*
implementation::construct_term(trix_context& context) {
  rdf::term* term = nullptr;

  const auto text = _reader.read_string();

  switch (context.element) {
    case trix_element::id: {
      term = new rdf::blank_node(text);
      break;
    }

    case trix_element::uri: {
      term = new rdf::uri_reference(text);
      break;
    }

    case trix_element::plain_literal: {
      term = new rdf::plain_literal(text, _reader.xml_lang());
      break;
    }

    case trix_element::typed_literal: {
      const auto datatype_uri = _reader.get_attribute("datatype");
      if (!datatype_uri) {
        throw_error(context, "missing 'datatype' attribute for <typedLiteral> element");
      }
      term = new rdf::typed_literal(text, datatype_uri);
      break;
    }

    default: abort(); /* never reached */
  }

  return term;
}

void
implementation::throw_error(trix_context& context,
                            const char* const what) {
  (void)context;
  throw rdf::reader_error(what, _reader.line_number(), _reader.column_number());
}
<commit_msg>Fixed a bug in TriX element name interning.<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "rdf++/reader/trix.h"

#include "rdf++/quad.h"
#include "rdf++/term.h"
#include "rdf++/triple.h"

#include "xml_reader.h"

#include <memory>  /* for std::unique_ptr */
#include <cstring> /* for std::strcmp() */

namespace {
  enum class trix_element {
    unknown = 0,
    trix,
    graph,
    triple,
    id,
    uri,
    plain_literal,
    typed_literal,
  };

  enum class trix_state {start, document, graph, triple, eof, abort};

  struct trix_context {
    trix_state state = trix_state::start;
    trix_element element = trix_element::unknown;
    unsigned int term_pos = 0;
    std::unique_ptr<rdf::term> terms[3] = {nullptr, nullptr, nullptr};
    std::unique_ptr<rdf::uri_reference> graph = nullptr;
    std::function<void (rdf::triple*)> triple_callback = nullptr;
    std::function<void (rdf::quad*)> quad_callback = nullptr;
  };

  struct implementation : public rdf::reader::implementation {
    implementation(FILE* stream,
      const char* content_type,
      const char* charset,
      const char* base_uri);
    virtual ~implementation() noexcept override;
    virtual void read_triples(std::function<void (rdf::triple*)> callback) override;
    virtual void read_quads(std::function<void (rdf::quad*)> callback) override;
    virtual void abort() override;
  protected:
    void read_with_context(trix_context& context);
    void ensure_state(trix_context& context, trix_state state);
    void assert_state(trix_context& context, trix_state state);
    void enter_state(trix_context& context, trix_state state);
    void leave_state(trix_context& context, trix_state state);
    void change_state(trix_context& context, trix_state state);
    void ensure_depth(trix_context& context, unsigned int depth);
    void record_term(trix_context& context);
    void begin_element(trix_context& context);
    void finish_element(trix_context& context);
    rdf::term* construct_term(trix_context& context);
    void throw_error(trix_context& context, const char* what);
  private:
    xml_reader _reader;
  };
}

rdf::reader::implementation*
rdf_reader_for_trix(FILE* const stream,
                    const char* const content_type,
                    const char* const charset,
                    const char* const base_uri) {
  return new implementation(stream, content_type, charset, base_uri);
}

implementation::implementation(FILE* const stream,
                               const char* const content_type,
                               const char* const charset,
                               const char* const base_uri)
  : _reader(stream, base_uri, charset) {
  assert(stream != nullptr);
  (void)content_type;
}

implementation::~implementation() noexcept = default;

static trix_element
intern_trix_element(const char* const element_name) {
  switch (*element_name) {
    case 'T':
      if (std::strcmp(element_name, "TriX") == 0) {
        return trix_element::trix;
      }
      break;
    case 'g':
      if (std::strcmp(element_name, "graph") == 0) {
        return trix_element::graph;
      }
      break;
    case 'i':
      if (std::strcmp(element_name, "id") == 0) {
        return trix_element::id;
      }
      break;
    case 'p':
      if (std::strcmp(element_name, "plainLiteral") == 0) {
        return trix_element::plain_literal;
      }
      break;
    case 't':
      if (std::strcmp(element_name, "trix") == 0) {
        return trix_element::trix;
      }
      if (std::strcmp(element_name, "triple") == 0) {
        return trix_element::triple;
      }
      if (std::strcmp(element_name, "typedLiteral") == 0) {
        return trix_element::typed_literal;
      }
      break;
    case 'u':
      if (std::strcmp(element_name, "uri") == 0) {
        return trix_element::uri;
      }
      break;
    default:
      break;
  }
  return trix_element::unknown;
}

void
implementation::read_triples(std::function<void (rdf::triple*)> callback) {
  trix_context context;
  context.triple_callback = callback;
  read_with_context(context);
}

void
implementation::read_quads(std::function<void (rdf::quad*)> callback) {
  trix_context context;
  context.quad_callback = callback;
  read_with_context(context);
}

void
implementation::abort() {
  // TODO
}

void
implementation::read_with_context(trix_context& context) {
  while (_reader.read()) {
    switch (_reader.node_type()) {
      case xml_node_type::element:
        begin_element(context);
        break;

      case xml_node_type::end_element:
        finish_element(context);
        break;

      default: /* ignored */
        break;
    }
  }
}

void
implementation::ensure_state(trix_context& context, const trix_state state) {
  if (context.state != state) {
    throw_error(context, "mismatched nesting of elements in TriX input");
  }
}

void
implementation::assert_state(trix_context& context, const trix_state state) {
  (void)state, (void)context;
  assert(context.state == state);
}

void
implementation::enter_state(trix_context& context, const trix_state state) {
  switch (state) {
    case trix_state::graph:
      context.graph.reset();
      break;

    case trix_state::triple:
      context.term_pos = 0;
      break;

    default:
      break;
  }
}

void
implementation::leave_state(trix_context& context, const trix_state state) {
  switch (state) {
    case trix_state::triple:
      if (context.quad_callback) {
        auto quad = new rdf::quad(
          context.terms[0].get(),
          context.terms[1].get(),
          context.terms[2].get(),
          context.graph ? (context.graph)->clone() : nullptr);
        context.quad_callback(quad);
      }
      else if (context.triple_callback) {
        auto triple = new rdf::triple(
          context.terms[0].get(),
          context.terms[1].get(),
          context.terms[2].get());
        context.triple_callback(triple);
      }
      for (auto i = 0U; i < 3; i++) {
        if (context.quad_callback || context.triple_callback) {
          /* The callback took ownership of the terms: */
          context.terms[i].release();
        }
        else {
          context.terms[i].reset();
        }
      }
      context.term_pos = 0;
      break;

    default:
      break;
  }
}

void
implementation::change_state(trix_context& context, const trix_state state) {
  leave_state(context, context.state);
  context.state = state;
  enter_state(context, context.state);
}

void
implementation::ensure_depth(trix_context& context, const unsigned int depth) {
  if (_reader.depth() != depth) {
    throw_error(context, "incorrect nesting of elements in TriX input");
  }
}

void
implementation::record_term(trix_context& context) {
  if (context.term_pos >= 3) {
    throw_error(context, "too many elements inside <triple> element");
  }

  context.terms[context.term_pos].reset(construct_term(context));
  context.term_pos++;
}

void
implementation::begin_element(trix_context& context) {
  context.element = intern_trix_element(_reader.name());

  switch (context.element) {
    case trix_element::trix:
      ensure_state(context, trix_state::start);
      ensure_depth(context, 0);
      change_state(context, trix_state::document);
      break;

    case trix_element::graph:
      ensure_state(context, trix_state::document);
      ensure_depth(context, 1);
      change_state(context, trix_state::graph);
      break;

    case trix_element::triple:
      ensure_state(context, trix_state::graph);
      ensure_depth(context, 2);
      change_state(context, trix_state::triple);
      break;

    case trix_element::uri:
      if (context.state == trix_state::graph) {
        ensure_depth(context, 2);
        if (context.graph) {
          throw_error(context, "repeated <uri> element inside <graph> element");
        }
        context.graph.reset(new rdf::uri_reference(_reader.read_string()));
        break;
      }
      ensure_state(context, trix_state::triple);
      ensure_depth(context, 3);
      record_term(context);
      break;

    case trix_element::id:
    case trix_element::plain_literal:
    case trix_element::typed_literal:
      ensure_state(context, trix_state::triple);
      ensure_depth(context, 3);
      record_term(context);
      break;

    default:
      throw_error(context, "unknown XML element in TriX input");
  }
}

void
implementation::finish_element(trix_context& context) {
  context.element = intern_trix_element(_reader.name());

  switch (context.element) {
    case trix_element::trix:
      assert_state(context, trix_state::document);
      change_state(context, trix_state::eof);
      break;

    case trix_element::graph:
      assert_state(context, trix_state::graph);
      change_state(context, trix_state::document);
      break;

    case trix_element::triple:
      assert_state(context, trix_state::triple);
      change_state(context, trix_state::graph);
      break;

    case trix_element::uri:
      //assert_state(trix_state::triple, context); // FIXME: triple | graph
      break;

    case trix_element::id:
    case trix_element::plain_literal:
    case trix_element::typed_literal:
      assert_state(context, trix_state::triple);
      break;

    default: abort(); /* never reached */
  }
}

rdf::term*
implementation::construct_term(trix_context& context) {
  rdf::term* term = nullptr;

  const auto text = _reader.read_string();

  switch (context.element) {
    case trix_element::id: {
      term = new rdf::blank_node(text);
      break;
    }

    case trix_element::uri: {
      term = new rdf::uri_reference(text);
      break;
    }

    case trix_element::plain_literal: {
      term = new rdf::plain_literal(text, _reader.xml_lang());
      break;
    }

    case trix_element::typed_literal: {
      const auto datatype_uri = _reader.get_attribute("datatype");
      if (!datatype_uri) {
        throw_error(context, "missing 'datatype' attribute for <typedLiteral> element");
      }
      term = new rdf::typed_literal(text, datatype_uri);
      break;
    }

    default: abort(); /* never reached */
  }

  return term;
}

void
implementation::throw_error(trix_context& context,
                            const char* const what) {
  (void)context;
  throw rdf::reader_error(what, _reader.line_number(), _reader.column_number());
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"

#include <boost/utility.hpp>

#include <stdlib.h>

using namespace libtorrent;

int main(int argc, char* argv[])
{
	if (argc != 3 && argc != 2)
	{
		fprintf(stderr, "Usage: fragmentation_test torrent-file file-storage-path\n"
			"       fragmentation_test file\n\n");
		return 1;
	}

	if (argc == 2)
	{
		error_code ec;
		file f(argv[1], file::read_only, ec);
		if (ec)
		{
			fprintf(stderr, "Error opening file %s: %s\n", argv[1], ec.message().c_str());
			return 1;
		}
		size_type off = f.phys_offset(0);
		printf("physical offset of file %s: %" PRId64 "\n", argv[1], off);
		return 0;
	}

	error_code ec;
	boost::intrusive_ptr<torrent_info> ti(new torrent_info(argv[1], ec));

	if (ec)
	{
		fprintf(stderr, "Error while loading torrent file: %s\n", ec.message().c_str());
		return 1;
	}

	file_pool fp;
	boost::shared_ptr<storage_interface> st(default_storage_constructor(ti->files(), 0, argv[2], fp, std::vector<boost::uint8_t>()));

	// the first field is the piece index, the second
	// one is the physical location of the piece on disk
	std::vector<std::pair<int, size_type> > pieces;

	// make sure all the files are there
	std::vector<std::pair<size_type, std::time_t> > files = get_filesizes(ti->files(), argv[2]);
	for (int i = 0; i < ti->num_files(); ++i)
	{
		if (ti->file_at(i).size == files[i].first) continue;
		fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
			, ti->files().file_path(ti->file_at(i)).c_str(), files[i].first, ti->file_at(i).size);
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		pieces.push_back(std::make_pair(i, st->physical_offset(i, 0)));
		if (pieces.back().second == size_type(i) * ti->piece_length())
		{
			// this suggests that the OS doesn't support physical offset
			// or that the file doesn't exist, or some other file error
			fprintf(stderr, "Your operating system or filesystem "
				"does not appear to support querying physical disk offset\n");
			return 1;
		}
	}

	FILE* f = fopen("fragmentation.log", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening log file: %s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		fprintf(f, "%d %"PRId64"\n", pieces[i].first, pieces[i].second);
	}

	fclose(f);

	f = fopen("fragmentation.gnuplot", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening gnuplot file: %s\n", strerror(errno));
		return 1;
	}

	fprintf(f,
		"set term png size 1200,800\n"
		"set output \"fragmentation.png\"\n"
		"set xrange [*:*]\n"
		"set xlabel \"piece\"\n"
		"set ylabel \"drive offset\"\n"
		"set key box\n"
		"set title \"fragmentation for '%s'\"\n"
		"set tics nomirror\n"
		"plot \"fragmentation.log\" using 1:2 with dots lt rgb \"#e07070\" notitle axis x1y1, x=0\n"
		, ti->name().c_str());

	fclose(f);

	system("gnuplot fragmentation.gnuplot");
}

<commit_msg>fix gnuplot syntax error in fragmentation test<commit_after>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"

#include <boost/utility.hpp>

#include <stdlib.h>

using namespace libtorrent;

int main(int argc, char* argv[])
{
	if (argc != 3 && argc != 2)
	{
		fprintf(stderr, "Usage: fragmentation_test torrent-file file-storage-path\n"
			"       fragmentation_test file\n\n");
		return 1;
	}

	if (argc == 2)
	{
		error_code ec;
		file f(argv[1], file::read_only, ec);
		if (ec)
		{
			fprintf(stderr, "Error opening file %s: %s\n", argv[1], ec.message().c_str());
			return 1;
		}
		size_type off = f.phys_offset(0);
		printf("physical offset of file %s: %" PRId64 "\n", argv[1], off);
		return 0;
	}

	error_code ec;
	boost::intrusive_ptr<torrent_info> ti(new torrent_info(argv[1], ec));

	if (ec)
	{
		fprintf(stderr, "Error while loading torrent file: %s\n", ec.message().c_str());
		return 1;
	}

	file_pool fp;
	boost::shared_ptr<storage_interface> st(default_storage_constructor(ti->files(), 0, argv[2], fp, std::vector<boost::uint8_t>()));

	// the first field is the piece index, the second
	// one is the physical location of the piece on disk
	std::vector<std::pair<int, size_type> > pieces;

	// make sure all the files are there
	std::vector<std::pair<size_type, std::time_t> > files = get_filesizes(ti->files(), argv[2]);
	for (int i = 0; i < ti->num_files(); ++i)
	{
		if (ti->file_at(i).size == files[i].first) continue;
		fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
			, ti->files().file_path(ti->file_at(i)).c_str(), files[i].first, ti->file_at(i).size);
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		pieces.push_back(std::make_pair(i, st->physical_offset(i, 0)));
		if (pieces.back().second == size_type(i) * ti->piece_length())
		{
			// this suggests that the OS doesn't support physical offset
			// or that the file doesn't exist, or some other file error
			fprintf(stderr, "Your operating system or filesystem "
				"does not appear to support querying physical disk offset\n");
			return 1;
		}
	}

	FILE* f = fopen("fragmentation.log", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening log file: %s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < ti->num_pieces(); ++i)
	{
		fprintf(f, "%d %"PRId64"\n", pieces[i].first, pieces[i].second);
	}

	fclose(f);

	f = fopen("fragmentation.gnuplot", "w+");
	if (f == 0)
	{
		fprintf(stderr, "error while opening gnuplot file: %s\n", strerror(errno));
		return 1;
	}

	fprintf(f,
		"set term png size 1200,800\n"
		"set output \"fragmentation.png\"\n"
		"set xrange [*:*]\n"
		"set xlabel \"piece\"\n"
		"set ylabel \"drive offset\"\n"
		"set key box\n"
		"set title \"fragmentation for '%s'\"\n"
		"set tics nomirror\n"
		"plot \"fragmentation.log\" using 1:2 with dots lt rgb \"#e07070\" notitle axis x1y1\n"
		, ti->name().c_str());

	fclose(f);

	system("gnuplot fragmentation.gnuplot");
}

<|endoftext|>


<commit_before>#include "tree_sitter/compiler.h"
#include "helpers.h"

namespace tree_sitter_examples {
    using tree_sitter::Grammar;
    using namespace tree_sitter::rules;

    extern const Grammar javascript({
        { "program", repeat(sym("statement")) },

        // Statements
        { "statement", choice({
            sym("statement_block"),
            sym("if_statement"),
            sym("try_statement"),
            sym("switch_statement"),
            sym("while_statement"),
            sym("for_statement"),
            sym("break_statement"),
            sym("var_declaration"),
            sym("return_statement"),
            sym("delete_statement"),
            sym("expression_statement") }) },
        { "statement_block", in_braces(err(repeat(sym("statement")))) },
        { "for_statement", seq({
            keyword("for"),
            in_parens(seq({
                choice({
                    sym("var_declaration"),
                    sym("expression_statement") }),
                sym("expression_statement"),
                err(sym("expression")) })),
            sym("statement") }) },
        { "if_statement", seq({
            keyword("if"),
            in_parens(err(sym("expression"))),
            sym("statement"),
            optional(prec(1, seq({
                keyword("else"),
                sym("statement") }))) }) },
        { "while_statement", seq({
            keyword("while"),
            in_parens(err(sym("expression"))),
            sym("statement") }) },
        { "try_statement", seq({
            keyword("try"),
            sym("statement"),
            keyword("catch"),
            in_parens(err(sym("identifier"))),
            sym("statement") }) },
        { "switch_statement", seq({
            keyword("switch"),
            in_parens(err(sym("expression"))),
            in_braces(repeat(sym("switch_case"))) }) },
        { "switch_case", seq({
            choice({
                seq({
                    keyword("case"),
                    sym("expression") }),
                keyword("default") }),
            str(":"),
            repeat(sym("statement")) }) },
        { "break_statement", seq({
            keyword("break"),
            sym("_terminator") }) },
        { "var_declaration", seq({
            keyword("var"),
            comma_sep(seq({
                optional(sym("comment")),
                choice({
                    sym("assignment"),
                    sym("identifier") }) })),
            sym("_terminator") }) },
        { "expression_statement", seq({
            err(sym("expression")),
            sym("_terminator") }) },
        { "return_statement", seq({
            keyword("return"),
            optional(sym("expression")),
            sym("_terminator") }) },
        { "delete_statement", seq({
            keyword("delete"),
            sym("property_access"),
            sym("_terminator") }) },

        // Expressions
        { "expression", choice({
            sym("function_expression"),
            sym("function_call"),
            sym("constructor_call"),
            sym("property_access"),
            sym("assignment"),
            sym("ternary"),
            sym("math_op"),
            sym("bool_op"),
            sym("object"),
            sym("array"),
            sym("regex"),
            sym("string"),
            sym("number"),
            sym("true"),
            sym("false"),
            sym("null"),
            sym("identifier"),
            in_parens(sym("expression")) }) },
        { "math_op", choice({
            prefix_op("++", "expression", 3),
            prefix_op("--", "expression", 3),
            postfix_op("++", "expression", 3),
            postfix_op("--", "expression", 3),
            prefix_op("+", "expression", 3),
            prefix_op("-", "expression", 3),
            infix_op("*", "expression", 2),
            infix_op("/", "expression", 2),
            infix_op("&", "expression", 2),
            infix_op("|", "expression", 2),
            infix_op("^", "expression", 2),
            infix_op("+", "expression", 1),
            infix_op("-", "expression", 1) }) },
        { "bool_op", choice({
            infix_op("||", "expression", 1),
            infix_op("&&", "expression", 2),
            infix_op("===", "expression", 3),
            infix_op("==", "expression", 3),
            infix_op("!==", "expression", 3),
            infix_op("!=", "expression", 3),
            infix_op("<=", "expression", 3),
            infix_op("<", "expression", 3),
            infix_op(">=", "expression", 3),
            infix_op(">", "expression", 3),
            prefix_op("!", "expression", 4) }) },
        { "ternary", seq({
            sym("expression"),
            str("?"),
            sym("expression"),
            str(":"),
            sym("expression") }) },
        { "assignment", prec(-1, seq({
            choice({
                sym("identifier"),
                sym("property_access") }),
            str("="),
            sym("expression") })) },
        { "function_expression", seq({
            keyword("function"),
            optional(sym("identifier")),
            sym("formal_parameters"),
            sym("statement_block") }) },
        { "function_call", seq({
            sym("expression"),
            in_parens(comma_sep(err(sym("expression")))) }) },
        { "constructor_call", seq({
            keyword("new"),
            sym("function_call") }) },
        { "property_access", seq({
            sym("expression"),
            choice({
                seq({
                    str("."),
                    sym("identifier") }),
                in_brackets(sym("expression")) }) }) },
        { "formal_parameters", in_parens(comma_sep(sym("identifier"))) },

        // Literals
        { "comment", token(choice({
            seq({
                str("/*"),
                repeat(pattern("[^*]|(*[^/])")),
                str("*/") }),
            pattern("//[^\n]*") })) },
        { "object", in_braces(comma_sep(err(seq({
            choice({ sym("string"), sym("identifier") }),
            str(":"),
            sym("expression") })))) },
        { "array", in_brackets(comma_sep(err(sym("expression")))) },
        { "_terminator", pattern("[;\n]") },
        { "regex", token(delimited("/")) },
        { "string", token(choice({
            delimited("\""),
            delimited("'") })) },
        { "identifier", pattern("[\\a_$][\\w_$]*") },
        { "number", pattern("\\d+(\\.\\d+)?") },
        { "null", keyword("null") },
        { "true", keyword("true") },
        { "false", keyword("false") },
    }, {
        // ubiquitous_tokens
        { "comment" }
    });
}
<commit_msg>Remove unnecessary comment rule from JS grammar<commit_after>#include "tree_sitter/compiler.h"
#include "helpers.h"

namespace tree_sitter_examples {
    using tree_sitter::Grammar;
    using namespace tree_sitter::rules;

    extern const Grammar javascript({
        { "program", repeat(sym("statement")) },

        // Statements
        { "statement", choice({
            sym("statement_block"),
            sym("if_statement"),
            sym("try_statement"),
            sym("switch_statement"),
            sym("while_statement"),
            sym("for_statement"),
            sym("break_statement"),
            sym("var_declaration"),
            sym("return_statement"),
            sym("delete_statement"),
            sym("expression_statement") }) },
        { "statement_block", in_braces(err(repeat(sym("statement")))) },
        { "for_statement", seq({
            keyword("for"),
            in_parens(seq({
                choice({
                    sym("var_declaration"),
                    sym("expression_statement") }),
                sym("expression_statement"),
                err(sym("expression")) })),
            sym("statement") }) },
        { "if_statement", seq({
            keyword("if"),
            in_parens(err(sym("expression"))),
            sym("statement"),
            optional(prec(1, seq({
                keyword("else"),
                sym("statement") }))) }) },
        { "while_statement", seq({
            keyword("while"),
            in_parens(err(sym("expression"))),
            sym("statement") }) },
        { "try_statement", seq({
            keyword("try"),
            sym("statement"),
            keyword("catch"),
            in_parens(err(sym("identifier"))),
            sym("statement") }) },
        { "switch_statement", seq({
            keyword("switch"),
            in_parens(err(sym("expression"))),
            in_braces(repeat(sym("switch_case"))) }) },
        { "switch_case", seq({
            choice({
                seq({
                    keyword("case"),
                    sym("expression") }),
                keyword("default") }),
            str(":"),
            repeat(sym("statement")) }) },
        { "break_statement", seq({
            keyword("break"),
            sym("_terminator") }) },
        { "var_declaration", seq({
            keyword("var"),
            comma_sep(err(choice({
                sym("assignment"),
                sym("identifier") }))),
            sym("_terminator") }) },
        { "expression_statement", seq({
            err(sym("expression")),
            sym("_terminator") }) },
        { "return_statement", seq({
            keyword("return"),
            optional(sym("expression")),
            sym("_terminator") }) },
        { "delete_statement", seq({
            keyword("delete"),
            sym("property_access"),
            sym("_terminator") }) },

        // Expressions
        { "expression", choice({
            sym("function_expression"),
            sym("function_call"),
            sym("constructor_call"),
            sym("property_access"),
            sym("assignment"),
            sym("ternary"),
            sym("math_op"),
            sym("bool_op"),
            sym("object"),
            sym("array"),
            sym("regex"),
            sym("string"),
            sym("number"),
            sym("true"),
            sym("false"),
            sym("null"),
            sym("identifier"),
            in_parens(sym("expression")) }) },
        { "math_op", choice({
            prefix_op("++", "expression", 3),
            prefix_op("--", "expression", 3),
            postfix_op("++", "expression", 3),
            postfix_op("--", "expression", 3),
            prefix_op("+", "expression", 3),
            prefix_op("-", "expression", 3),
            infix_op("*", "expression", 2),
            infix_op("/", "expression", 2),
            infix_op("&", "expression", 2),
            infix_op("|", "expression", 2),
            infix_op("^", "expression", 2),
            infix_op("+", "expression", 1),
            infix_op("-", "expression", 1) }) },
        { "bool_op", choice({
            infix_op("||", "expression", 1),
            infix_op("&&", "expression", 2),
            infix_op("===", "expression", 3),
            infix_op("==", "expression", 3),
            infix_op("!==", "expression", 3),
            infix_op("!=", "expression", 3),
            infix_op("<=", "expression", 3),
            infix_op("<", "expression", 3),
            infix_op(">=", "expression", 3),
            infix_op(">", "expression", 3),
            prefix_op("!", "expression", 4) }) },
        { "ternary", seq({
            sym("expression"),
            str("?"),
            sym("expression"),
            str(":"),
            sym("expression") }) },
        { "assignment", prec(-1, seq({
            choice({
                sym("identifier"),
                sym("property_access") }),
            str("="),
            sym("expression") })) },
        { "function_expression", seq({
            keyword("function"),
            optional(sym("identifier")),
            sym("formal_parameters"),
            sym("statement_block") }) },
        { "function_call", seq({
            sym("expression"),
            in_parens(comma_sep(err(sym("expression")))) }) },
        { "constructor_call", seq({
            keyword("new"),
            sym("function_call") }) },
        { "property_access", seq({
            sym("expression"),
            choice({
                seq({
                    str("."),
                    sym("identifier") }),
                in_brackets(sym("expression")) }) }) },
        { "formal_parameters", in_parens(comma_sep(sym("identifier"))) },

        // Literals
        { "comment", token(choice({
            seq({
                str("/*"),
                repeat(pattern("[^*]|(*[^/])")),
                str("*/") }),
            pattern("//[^\n]*") })) },
        { "object", in_braces(comma_sep(err(seq({
            choice({ sym("string"), sym("identifier") }),
            str(":"),
            sym("expression") })))) },
        { "array", in_brackets(comma_sep(err(sym("expression")))) },
        { "_terminator", pattern("[;\n]") },
        { "regex", token(delimited("/")) },
        { "string", token(choice({
            delimited("\""),
            delimited("'") })) },
        { "identifier", pattern("[\\a_$][\\w_$]*") },
        { "number", pattern("\\d+(\\.\\d+)?") },
        { "null", keyword("null") },
        { "true", keyword("true") },
        { "false", keyword("false") },
    }, {
        // ubiquitous_tokens
        { "comment" }
    });
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
//  Base class for the clusterization algorithm (pure abstract)
//*--
//*-- Author: Yves Schutz  SUBATECH
//////////////////////////////////////////////////////////////////////////////

// --- ROOT system ---

// --- Standard library ---

// --- AliRoot header files ---
#include "AliPHOSClusterizer.h"
#include "AliPHOSGetter.h"

ClassImp(AliPHOSClusterizer)

//____________________________________________________________________________
  AliPHOSClusterizer::AliPHOSClusterizer():TTask("","")
{
  // ctor

  fEventFolderName = "" ;
  fFirstEvent = 0 ;
  fLastEvent  = -1 ;
}

//____________________________________________________________________________
AliPHOSClusterizer::AliPHOSClusterizer(const TString alirunFileName,
				       const TString eventFolderName):
  TTask("PHOS"+AliConfig::Instance()->GetReconstructionerTaskName(),
	alirunFileName), fEventFolderName(eventFolderName)
{
  // ctor

  fFirstEvent = 0 ;
  fLastEvent  = -1 ;
}

//____________________________________________________________________________
AliPHOSClusterizer::~AliPHOSClusterizer()
{
  // dtor

 //Remove this from the parental task before destroying
  AliPHOSGetter::Instance()->PhosLoader()->CleanReconstructioner();
}

<commit_msg>Test on PHOSloader existence added to destr.<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

//_________________________________________________________________________
//  Base class for the clusterization algorithm (pure abstract)
//*--
//*-- Author: Yves Schutz  SUBATECH
//////////////////////////////////////////////////////////////////////////////

// --- ROOT system ---

// --- Standard library ---

// --- AliRoot header files ---
#include "AliPHOSClusterizer.h"
#include "AliPHOSGetter.h"

ClassImp(AliPHOSClusterizer)

//____________________________________________________________________________
  AliPHOSClusterizer::AliPHOSClusterizer():TTask("","")
{
  // ctor

  fEventFolderName = "" ;
  fFirstEvent = 0 ;
  fLastEvent  = -1 ;
}

//____________________________________________________________________________
AliPHOSClusterizer::AliPHOSClusterizer(const TString alirunFileName,
				       const TString eventFolderName):
  TTask("PHOS"+AliConfig::Instance()->GetReconstructionerTaskName(),
	alirunFileName), fEventFolderName(eventFolderName)
{
  // ctor

  fFirstEvent = 0 ;
  fLastEvent  = -1 ;
}

//____________________________________________________________________________
AliPHOSClusterizer::~AliPHOSClusterizer()
{
  // dtor

 //Remove this from the parental task before destroying
  if(AliPHOSGetter::Instance()->PhosLoader())
    AliPHOSGetter::Instance()->PhosLoader()->CleanReconstructioner();
}

<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <memory>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/program_options.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <windows.h>

#include <hadesmem/error.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/region.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/module_list.hpp>
#include <hadesmem/region_list.hpp>
#include <hadesmem/pelib/export.hpp>
#include <hadesmem/process_list.hpp>
#include <hadesmem/process_entry.hpp>
#include <hadesmem/pelib/pe_file.hpp>
#include <hadesmem/pelib/import_dir.hpp>
#include <hadesmem/detail/initialize.hpp>
#include <hadesmem/pelib/export_list.hpp>
#include <hadesmem/pelib/import_thunk.hpp>
#include <hadesmem/pelib/import_dir_list.hpp>
#include <hadesmem/pelib/import_thunk_list.hpp>

namespace
{

std::wstring PtrToString(void const* const ptr)
{
  std::wostringstream str;
  str.imbue(std::locale::classic());
  str << std::hex << reinterpret_cast<DWORD_PTR>(ptr);
  return str.str();
}

void DumpRegions(hadesmem::Process const& process)
{
  std::wcout << "\nRegions:\n";

  hadesmem::RegionList const regions(process);
  for (auto const& region : regions)
  {
    std::wcout << "\n";
    std::wcout << "\tBase: " << PtrToString(region.GetBase()) << "\n";
    std::wcout << "\tAllocation Base: "
      << PtrToString(region.GetAllocBase()) << "\n";
    std::wcout << "\tAllocation Protect: " << std::hex
      << region.GetAllocProtect() << std::dec << "\n";
    std::wcout << "\tSize: " << std::hex << region.GetSize() << std::dec
      << "\n";
    std::wcout << "\tState: " << std::hex << region.GetState() << std::dec
      << "\n";
    std::wcout << "\tProtect: " << std::hex << region.GetProtect()
      << std::dec << "\n";
    std::wcout << "\tType: " << std::hex << region.GetType() << std::dec
      << "\n";
  }
}

void DumpExports(hadesmem::Process const& process,
  hadesmem::Module const& module)
{
  std::wcout << "\n\tExports:\n";

  hadesmem::PeFile pe_file(process, module.GetHandle(),
    hadesmem::PeFileType::Image);
  hadesmem::ExportList exports(process, pe_file);
  for (auto const& e : exports)
  {
    std::wcout << std::boolalpha;
    std::wcout << "\n";
    std::wcout << "\t\tRVA: " << std::hex << e.GetRva() << std::dec << "\n";
    std::wcout << "\t\tVA: " << PtrToString(e.GetVa()) << "\n";
    std::wcout << "\t\tName: " << e.GetName().c_str() << "\n";
    std::wcout << "\t\tOrdinal: " << e.GetOrdinal() << "\n";
    std::wcout << "\t\tByName: " << e.ByName() << "\n";
    std::wcout << "\t\tByOrdinal: " << e.ByOrdinal() << "\n";
    std::wcout << "\t\tIsForwarded: " << e.IsForwarded() << "\n";
    if (e.IsForwarded())
    {
      std::wcout << "\t\tForwarder: " << e.GetForwarder().c_str() << "\n";
      std::wcout << "\t\tForwarderModule: " << e.GetForwarderModule().c_str()
        << "\n";
      std::wcout << "\t\tForwarderFunction: " <<
        e.GetForwarderFunction().c_str() << "\n";
      std::wcout << "\t\tIsForwardedByOrdinal: " << e.IsForwardedByOrdinal() <<
        "\n";
      if (e.IsForwardedByOrdinal())
      {
        try
        {
          std::wcout << "\t\tForwarderOrdinal: " << e.GetForwarderOrdinal() <<
            "\n";
        }
        catch (std::exception const& /*e*/)
        {
          std::wcout << "\t\tForwarderOrdinal Invalid.\n";
        }
      }
    }
    std::wcout << std::noboolalpha;
  }
}

void DumpImports(hadesmem::Process const& process,
  hadesmem::Module const& module)
{
  std::wcout << "\n\tImport Dirs:\n";

  hadesmem::PeFile pe_file(process, module.GetHandle(),
    hadesmem::PeFileType::Image);
  hadesmem::ImportDirList import_dirs(process, pe_file);
  for (auto const& dir : import_dirs)
  {
    std::wcout << std::boolalpha;

    std::wcout << "\n";
    std::wcout << "\t\tOriginalFirstThunk: " << std::hex <<
      dir.GetOriginalFirstThunk() << std::dec << "\n";
    std::wcout << "\t\tTimeDateStamp: " << dir.GetTimeDateStamp() << "\n";
    std::wcout << "\t\tForwarderChain: " << dir.GetForwarderChain() << "\n";
    std::wcout << "\t\tName (Raw): " << std::hex << dir.GetNameRaw() <<
      std::dec << "\n";
    std::wcout << "\t\tName: " << dir.GetName().c_str() << "\n";
    std::wcout << "\t\tFirstThunk: " << std::hex << dir.GetFirstThunk() <<
      std::dec << "\n";

    std::wcout << "\n\t\tImport Thunks:\n";

    // Images without an INT are valid, but after an image like this is loaded
    // it is impossible to recover the name table.
    if (!dir.GetOriginalFirstThunk())
    {
      std::wcout << "\n\t\t\tWARNING! No INT for this module.\n";
      continue;
    }

    // Some modules (packed modules are the only ones I've found so far) have
    // import directories where the IAT RVA is the same as the INT RVA which
    // effectively means there is no INT once the module is loaded.
    if (dir.GetOriginalFirstThunk() == dir.GetFirstThunk())
    {
      std::wcout << "\n\t\t\tWARNING! IAT is same as INT for this module.\n";
      continue;
    }

    hadesmem::ImportThunkList import_thunks(process, pe_file,
      dir.GetOriginalFirstThunk());
    for (auto const& thunk : import_thunks)
    {
      std::wcout << "\n";
      std::wcout << "\t\t\tAddressOfData: " << std::hex <<
        thunk.GetAddressOfData() << std::dec << "\n";
      std::wcout << "\t\t\tOrdinalRaw: " << thunk.GetOrdinalRaw() << "\n";
      std::wcout << "\t\t\tByOrdinal: " << thunk.ByOrdinal() << "\n";
      if (thunk.ByOrdinal())
      {
        std::wcout << "\t\t\tOrdinal: " << thunk.GetOrdinal() << "\n";
      }
      else
      {
        std::wcout << "\t\t\tHint: " << thunk.GetHint() << "\n";
        std::wcout << "\t\t\tName: " << thunk.GetName().c_str() << "\n";
      }
      std::wcout << "\t\t\tFunction: " << std::hex << thunk.GetFunction() <<
        std::dec << "\n";
    }

    std::wcout << std::noboolalpha;
  }
}

void DumpModules(hadesmem::Process const& process)
{
  std::wcout << "\nModules:\n";

  hadesmem::ModuleList const modules(process);
  for (auto const& module : modules)
  {
    std::wcout << "\n";
    std::wcout << "\tHandle: " << PtrToString(module.GetHandle()) << "\n";
    std::wcout << "\tSize: " << std::hex << module.GetSize() << std::dec
      << "\n";
    std::wcout << "\tName: " << module.GetName() << "\n";
    std::wcout << "\tPath: " << module.GetPath() << "\n";

    DumpExports(process, module);

    DumpImports(process, module);
  }
}

void DumpProcessEntry(hadesmem::ProcessEntry const& process_entry)
{
  std::wcout << "\n";
  std::wcout << "ID: " << process_entry.GetId() << "\n";
  std::wcout << "Threads: " << process_entry.GetThreads() << "\n";
  std::wcout << "Parent: " << process_entry.GetParentId() << "\n";
  std::wcout << "Priority: " << process_entry.GetPriority() << "\n";
  std::wcout << "Name: " << process_entry.GetName() << "\n";

  std::unique_ptr<hadesmem::Process> process;
  try
  {
    process.reset(new hadesmem::Process(process_entry.GetId()));
  }
  catch (std::exception const& /*e*/)
  {
    std::wcout << "\nCould not open process for further inspection.\n\n";
    return;
  }

  std::wcout << "Path: " << hadesmem::GetPath(*process) << "\n";
  std::wcout << "WoW64: " << (hadesmem::IsWoW64(*process) ? "Yes" : "No")
    << "\n";

  DumpModules(*process);

  DumpRegions(*process);
}

}

int main(int /*argc*/, char* /*argv*/[])
{
  try
  {
    hadesmem::detail::DisableUserModeCallbackExceptionFilter();
    hadesmem::detail::EnableCrtDebugFlags();
    hadesmem::detail::EnableTerminationOnHeapCorruption();
    hadesmem::detail::EnableBottomUpRand();
    hadesmem::detail::ImbueAllDefault();

    std::cout << "HadesMem Dumper\n";

    boost::program_options::options_description opts_desc(
      "General options");
    opts_desc.add_options()
      ("help", "produce help message")
      ("pid", boost::program_options::value<DWORD>(), "process id")
      ;

    std::vector<std::wstring> const args = boost::program_options::
      split_winmain(GetCommandLine());
    boost::program_options::variables_map var_map;
    boost::program_options::store(boost::program_options::wcommand_line_parser(
      args).options(opts_desc).run(), var_map);
    boost::program_options::notify(var_map);

    if (var_map.count("help"))
    {
      std::cout << '\n' << opts_desc << '\n';
      return 1;
    }

    DWORD pid = 0;
    if (var_map.count("pid"))
    {
      pid = var_map["pid"].as<DWORD>();
    }

    try
    {
      hadesmem::GetSeDebugPrivilege();

      std::wcout << "\nAcquired SeDebugPrivilege.\n";
    }
    catch (std::exception const& /*e*/)
    {
      std::wcout << "\nFailed to acquire SeDebugPrivilege.\n";
    }

    if (pid)
    {
      hadesmem::ProcessList const processes;
      auto iter = std::find_if(std::begin(processes), std::end(processes),
        [pid] (hadesmem::ProcessEntry const& process_entry)
        {
          return process_entry.GetId() == pid;
        });
      if (iter != std::end(processes))
      {
        DumpProcessEntry(*iter);
      }
      else
      {
        HADESMEM_THROW_EXCEPTION(hadesmem::Error() <<
          hadesmem::ErrorString("Failed to find requested process."));
      }
    }
    else
    {
      std::wcout << "\nProcesses:\n";

      hadesmem::ProcessList const processes;
      for (auto const& process_entry : processes)
      {
        DumpProcessEntry(process_entry);
      }
    }

    return 0;
  }
  catch (std::exception const& e)
  {
    std::cerr << "\nError!\n";
    std::cerr << boost::diagnostic_information(e) << '\n';

    return 1;
  }
}
<commit_msg>* Add file dumping support. * Cleanup output a bit.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <memory>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <windows.h>

#include <hadesmem/error.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/region.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/module_list.hpp>
#include <hadesmem/region_list.hpp>
#include <hadesmem/pelib/export.hpp>
#include <hadesmem/process_list.hpp>
#include <hadesmem/process_entry.hpp>
#include <hadesmem/pelib/pe_file.hpp>
#include <hadesmem/pelib/dos_header.hpp>
#include <hadesmem/pelib/import_dir.hpp>
#include <hadesmem/pelib/nt_headers.hpp>
#include <hadesmem/detail/self_path.hpp>
#include <hadesmem/detail/initialize.hpp>
#include <hadesmem/pelib/export_list.hpp>
#include <hadesmem/pelib/import_thunk.hpp>
#include <hadesmem/pelib/import_dir_list.hpp>
#include <hadesmem/pelib/import_thunk_list.hpp>

namespace
{

std::wstring PtrToString(void const* const ptr)
{
  std::wostringstream str;
  str.imbue(std::locale::classic());
  str << std::hex << reinterpret_cast<DWORD_PTR>(ptr);
  return str.str();
}

void DumpRegions(hadesmem::Process const& process)
{
  std::wcout << "\nRegions:\n";

  hadesmem::RegionList const regions(process);
  for (auto const& region : regions)
  {
    std::wcout << "\n";
    std::wcout << "\tBase: " << PtrToString(region.GetBase()) << "\n";
    std::wcout << "\tAllocation Base: "
      << PtrToString(region.GetAllocBase()) << "\n";
    std::wcout << "\tAllocation Protect: " << std::hex
      << region.GetAllocProtect() << std::dec << "\n";
    std::wcout << "\tSize: " << std::hex << region.GetSize() << std::dec
      << "\n";
    std::wcout << "\tState: " << std::hex << region.GetState() << std::dec
      << "\n";
    std::wcout << "\tProtect: " << std::hex << region.GetProtect()
      << std::dec << "\n";
    std::wcout << "\tType: " << std::hex << region.GetType() << std::dec
      << "\n";
  }
}

void DumpExports(hadesmem::Process const& process, PVOID module,
  hadesmem::PeFileType type)
{
  std::wcout << "\n\tExports:\n";

  hadesmem::PeFile pe_file(process, module, type);
  hadesmem::ExportList exports(process, pe_file);
  for (auto const& e : exports)
  {
    std::wcout << std::boolalpha;
    std::wcout << "\n";
    std::wcout << "\t\tRVA: " << std::hex << e.GetRva() << std::dec << "\n";
    std::wcout << "\t\tVA: " << PtrToString(e.GetVa()) << "\n";
    if (e.ByName())
    {
      std::wcout << "\t\tName: " << e.GetName().c_str() << "\n";
    }
    else if (e.ByOrdinal())
    {
      std::wcout << "\t\tOrdinal: " << e.GetOrdinal() << "\n";
    }
    else
    {
      std::wcout << "\t\tWARNING! Entry not exported by name or ordinal.\n";
    }
    if (e.IsForwarded())
    {
      std::wcout << "\t\tForwarder: " << e.GetForwarder().c_str() << "\n";
      std::wcout << "\t\tForwarderModule: " << e.GetForwarderModule().c_str()
        << "\n";
      std::wcout << "\t\tForwarderFunction: " <<
        e.GetForwarderFunction().c_str() << "\n";
      std::wcout << "\t\tIsForwardedByOrdinal: " << e.IsForwardedByOrdinal() <<
        "\n";
      if (e.IsForwardedByOrdinal())
      {
        try
        {
          std::wcout << "\t\tForwarderOrdinal: " << e.GetForwarderOrdinal() <<
            "\n";
        }
        catch (std::exception const& /*e*/)
        {
          std::wcout << "\t\tForwarderOrdinal Invalid.\n";
        }
      }
    }
    std::wcout << std::noboolalpha;
  }
}

void DumpImports(hadesmem::Process const& process, PVOID module,
  hadesmem::PeFileType type)
{
  std::wcout << "\n\tImport Dirs:\n";

  hadesmem::PeFile pe_file(process, module, type);
  hadesmem::ImportDirList import_dirs(process, pe_file);
  for (auto const& dir : import_dirs)
  {
    std::wcout << std::boolalpha;

    std::wcout << "\n";
    std::wcout << "\t\tOriginalFirstThunk: " << std::hex <<
      dir.GetOriginalFirstThunk() << std::dec << "\n";
    std::wcout << "\t\tTimeDateStamp: " << dir.GetTimeDateStamp() << "\n";
    std::wcout << "\t\tForwarderChain: " << dir.GetForwarderChain() << "\n";
    std::wcout << "\t\tName (Raw): " << std::hex << dir.GetNameRaw() <<
      std::dec << "\n";
    std::wcout << "\t\tName: " << dir.GetName().c_str() << "\n";
    std::wcout << "\t\tFirstThunk: " << std::hex << dir.GetFirstThunk() <<
      std::dec << "\n";

    std::wcout << "\n\t\tImport Thunks:\n";

    // Certain information gets destroyed by the Windows PE loader in
    // some circumstances. Nothing we can do but ignore it or resort to
    // reading the original data from disk.
    if (type == hadesmem::PeFileType::Image)
    {
      // Images without an INT are valid, but after an image like this is loaded
      // it is impossible to recover the name table.
      if (!dir.GetOriginalFirstThunk())
      {
        std::wcout << "\n\t\t\tWARNING! No INT for this module.\n";
        continue;
      }

      // Some modules (packed modules are the only ones I've found so far) have
      // import directories where the IAT RVA is the same as the INT RVA which
      // effectively means there is no INT once the module is loaded.
      if (dir.GetOriginalFirstThunk() == dir.GetFirstThunk())
      {
        std::wcout << "\n\t\t\tWARNING! IAT is same as INT for this module.\n";
        continue;
      }
    }

    hadesmem::ImportThunkList import_thunks(process, pe_file,
      dir.GetOriginalFirstThunk());
    for (auto const& thunk : import_thunks)
    {
      std::wcout << "\n";
      std::wcout << "\t\t\tAddressOfData: " << std::hex <<
        thunk.GetAddressOfData() << std::dec << "\n";
      std::wcout << "\t\t\tOrdinalRaw: " << thunk.GetOrdinalRaw() << "\n";
      if (thunk.ByOrdinal())
      {
        std::wcout << "\t\t\tOrdinal: " << thunk.GetOrdinal() << "\n";
      }
      else
      {
        std::wcout << "\t\t\tHint: " << thunk.GetHint() << "\n";
        std::wcout << "\t\t\tName: " << thunk.GetName().c_str() << "\n";
      }
      std::wcout << "\t\t\tFunction: " << std::hex << thunk.GetFunction() <<
        std::dec << "\n";
    }

    std::wcout << std::noboolalpha;
  }
}

void DumpModules(hadesmem::Process const& process)
{
  std::wcout << "\nModules:\n";

  hadesmem::ModuleList const modules(process);
  for (auto const& module : modules)
  {
    std::wcout << "\n";
    std::wcout << "\tHandle: " << PtrToString(module.GetHandle()) << "\n";
    std::wcout << "\tSize: " << std::hex << module.GetSize() << std::dec
      << "\n";
    std::wcout << "\tName: " << module.GetName() << "\n";
    std::wcout << "\tPath: " << module.GetPath() << "\n";

    DumpExports(process, module.GetHandle(), hadesmem::PeFileType::Image);

    DumpImports(process, module.GetHandle(), hadesmem::PeFileType::Image);
  }
}

void DumpProcessEntry(hadesmem::ProcessEntry const& process_entry)
{
  std::wcout << "\n";
  std::wcout << "ID: " << process_entry.GetId() << "\n";
  std::wcout << "Threads: " << process_entry.GetThreads() << "\n";
  std::wcout << "Parent: " << process_entry.GetParentId() << "\n";
  std::wcout << "Priority: " << process_entry.GetPriority() << "\n";
  std::wcout << "Name: " << process_entry.GetName() << "\n";

  std::unique_ptr<hadesmem::Process> process;
  try
  {
    process.reset(new hadesmem::Process(process_entry.GetId()));
  }
  catch (std::exception const& /*e*/)
  {
    std::wcout << "\nCould not open process for further inspection.\n\n";
    return;
  }

  std::wcout << "Path: " << hadesmem::GetPath(*process) << "\n";
  std::wcout << "WoW64: " << (hadesmem::IsWoW64(*process) ? "Yes" : "No")
    << "\n";

  DumpModules(*process);

  DumpRegions(*process);
}

// TODO: Cleanup.
void DumpFile(boost::filesystem::path const& path)
{
  std::ifstream file(path.c_str(), std::ios::binary | std::ios::ate);
  if (!file)
  {
    std::wcout << "\nFailed to open file.\n";
    return;
  }

  std::streampos const size = file.tellg();
  if (!size || size < 0)
  {
    std::wcout << "\nEmpty or invalid file.\n";
    return;
  }

  if (!file.seekg(0))
  {
    std::wcout << "\nWARNING! Seeking to beginning of file failed.\n";
    return;
  }

  // Pick some arbitrary maximum size
  // TODO: Fix this. Ideally we should only peek the first N bytes (however
  // big the PE headers are) and check if it's a valid target or not, then read
  // the rest of the file.
  if (static_cast<long long>(size) > 0x40000000LL) // 1GB
  {
    std::wcout << "\nFile too big.\n";
    return;
  }

  // TODO: Fix all the unsafe integer downcasting.

  std::vector<char> buf(static_cast<std::size_t>(size));

  if (!file.read(buf.data(), static_cast<std::streamsize>(size)))
  {
    std::wcout << "\nWARNING! Failed to read file data.\n";
    return;
  }

  if (buf.size() != static_cast<std::size_t>(size))
  {
    std::wcout << "\nWARNING! Buffer size does not match file size.\n";
    return;
  }

  hadesmem::Process const process(GetCurrentProcessId());

  try
  {
    hadesmem::PeFile const pe_file(process, buf.data(),
      hadesmem::PeFileType::Data);
    hadesmem::NtHeaders const nt_hdr(process, pe_file);
#if defined(HADESMEM_ARCH_X86)
    if (nt_hdr.GetMachine() != IMAGE_FILE_MACHINE_I386)
#elif defined(HADESMEM_ARCH_X64)
    if (nt_hdr.GetMachine() != IMAGE_FILE_MACHINE_AMD64)
#else
#error [HadesMem] Unsupported architecture.
#endif
    {
      return;
    }
  }
  catch (std::exception const& /*e*/)
  {
    return;
  }

  DumpExports(process, buf.data(), hadesmem::PeFileType::Data);

  DumpImports(process, buf.data(), hadesmem::PeFileType::Data);
}

// Doing directory recursion 'manually' because recursive_directory_iterator
// throws on increment, even when you construct it as no-throw.
void DumpDir(boost::filesystem::path const& path)
{
  std::wcout << "\nEntering dir: " << path << ".\n";

  boost::system::error_code ec;
  boost::filesystem::directory_iterator iter(path, ec);
  boost::filesystem::directory_iterator end;

  while (iter != end && !ec);
  {
    auto const& cur_path = *iter;

    std::wcout << "\nCurrent path: " << cur_path << ".\n";

    if (boost::filesystem::is_directory(cur_path) &&
      !boost::filesystem::is_symlink(cur_path))
    {
      DumpDir(cur_path);
    }

    if (boost::filesystem::is_regular_file(cur_path))
    {
      DumpFile(cur_path);
    }

    ++iter;
  }
}

}

int main(int /*argc*/, char* /*argv*/[])
{
  try
  {
    hadesmem::detail::DisableUserModeCallbackExceptionFilter();
    hadesmem::detail::EnableCrtDebugFlags();
    hadesmem::detail::EnableTerminationOnHeapCorruption();
    hadesmem::detail::EnableBottomUpRand();
    hadesmem::detail::ImbueAllDefault();

    std::cout << "HadesMem Dumper\n";

    boost::program_options::options_description opts_desc(
      "General options");
    opts_desc.add_options()
      ("help", "produce help message")
      ("pid", boost::program_options::value<DWORD>(), "process id")
      ;

    std::vector<std::wstring> const args = boost::program_options::
      split_winmain(GetCommandLine());
    boost::program_options::variables_map var_map;
    boost::program_options::store(boost::program_options::wcommand_line_parser(
      args).options(opts_desc).run(), var_map);
    boost::program_options::notify(var_map);

    if (var_map.count("help"))
    {
      std::cout << '\n' << opts_desc << '\n';
      return 1;
    }

    DWORD pid = 0;
    if (var_map.count("pid"))
    {
      pid = var_map["pid"].as<DWORD>();
    }

    try
    {
      hadesmem::GetSeDebugPrivilege();

      std::wcout << "\nAcquired SeDebugPrivilege.\n";
    }
    catch (std::exception const& /*e*/)
    {
      std::wcout << "\nFailed to acquire SeDebugPrivilege.\n";
    }

    if (pid)
    {
      hadesmem::ProcessList const processes;
      auto iter = std::find_if(std::begin(processes), std::end(processes),
        [pid] (hadesmem::ProcessEntry const& process_entry)
        {
          return process_entry.GetId() == pid;
        });
      if (iter != std::end(processes))
      {
        DumpProcessEntry(*iter);
      }
      else
      {
        HADESMEM_THROW_EXCEPTION(hadesmem::Error() <<
          hadesmem::ErrorString("Failed to find requested process."));
      }
    }
    else
    {
      std::wcout << "\nProcesses:\n";

      hadesmem::ProcessList const processes;
      for (auto const& process_entry : processes)
      {
        DumpProcessEntry(process_entry);
      }

      std::wcout << "\nFiles:\n";

      boost::filesystem::path const self_path =
        hadesmem::detail::GetSelfPath();
      boost::filesystem::path const root_dir = self_path.root_path();
      DumpDir(root_dir);
    }

    return 0;
  }
  catch (std::exception const& e)
  {
    std::cerr << "\nError!\n";
    std::cerr << boost::diagnostic_information(e) << '\n';

    return 1;
  }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2004 by Jorrit Tyberghein
	      (C) 2004 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/databuf.h"
#include "csutil/scanstr.h"
#include "csutil/stringquote.h"
#include "csutil/util.h"
#include "csutil/xmltiny.h"
#include "csgfx/shaderexp.h"

#include "imap/services.h"
#include "iutil/verbositymanager.h"
#include "iutil/vfs.h"
#include "ivaria/reporter.h"

#include "csplugincommon/shader/shaderprogram.h"

void csShaderProgram::ProgramParam::SetValue (float val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

void csShaderProgram::ProgramParam::SetValue (const csVector4& val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

//---------------------------------------------------------------------------

CS_LEAKGUARD_IMPLEMENT (csShaderProgram);

csShaderProgram::csShaderProgram (iObjectRegistry* objectReg)
  : scfImplementationType (this)
{
  InitCommonTokens (commonTokens);

  csShaderProgram::objectReg = objectReg;
  synsrv = csQueryRegistry<iSyntaxService> (objectReg);
  stringsSvName = csQueryRegistryTagInterface<iShaderVarStringSet>
    (objectReg, "crystalspace.shader.variablenameset");

  csRef<iVerbosityManager> verbosemgr (
    csQueryRegistry<iVerbosityManager> (objectReg));
  if (verbosemgr)
    doVerbose = verbosemgr->Enabled("renderer.shader");
  else
    doVerbose = false;
}

csShaderProgram::~csShaderProgram ()
{
}

bool csShaderProgram::ProgramParamParser::ParseProgramParam (
  iDocumentNode* node, ProgramParam& param, uint types)
{
  const char* type = node->GetAttributeValue ("type");
  if (type == 0)
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "No %s attribute",
      CS::Quote::Single ("type"));
    return false;
  }

  // Var for static data
  csRef<csShaderVariable> var;
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));

  ProgramParamType paramType = ParamInvalid;
  if (strcmp (type, "shadervar") == 0)
  {
    const char* value = node->GetContentsValue();
    if (!value)
    {
      synsrv->Report ("crystalspace.graphics3d.shader.common",
	CS_REPORTER_SEVERITY_WARNING,
	node,
	"Node has no contents");
      return false;
    }

    CS::Graphics::ShaderVarNameParser nameParse (value);
    param.name = stringsSvName->Request (nameParse.GetShaderVarName());
    for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
    {
      param.indices.Push (nameParse.GetIndexValue (n));
    }
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "int") == 0)
  {
    paramType = ParamInt;
  }
  else if (strcmp (type, "float") == 0)
  {
    paramType = ParamFloat;
  }
  else if (strcmp (type, "vector2") == 0)
  {
    paramType = ParamVector2;
  }
  else if (strcmp (type, "vector3") == 0)
  {
    paramType = ParamVector3;
  }
  else if (strcmp (type, "vector4") == 0)
  {
    paramType = ParamVector4;
  }
  else if (strcmp (type, "matrix") == 0)
  {
    paramType = ParamMatrix;
  }
  else if (strcmp (type, "transform") == 0)
  {
    paramType = ParamTransform;
  }
  else if ((strcmp (type, "expression") == 0) || (strcmp (type, "expr") == 0))
  {
    // Parse exp and save it
    csRef<iShaderVariableAccessor> acc = synsrv->ParseShaderVarExpr (node);
    var->SetAccessor (acc);
    param.var = var;
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "array") == 0)
  {
    csArray<ProgramParam> allParams;
    ProgramParam tmpParam;
    csRef<iDocumentNodeIterator> it = node->GetNodes ();
    while (it->HasNext ())
    {
      csRef<iDocumentNode> child = it->Next ();
      ParseProgramParam (child, tmpParam, types & 0x3F);
      allParams.Push (tmpParam);
    }

    //Save the params
    var->SetType (csShaderVariable::ARRAY);
    var->SetArraySize (allParams.GetSize ());

    for (uint i = 0; i < allParams.GetSize (); i++)
    {
      var->SetArrayElement (i, allParams[i].var);
    }
    paramType = ParamArray;
  }
  else
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Unknown type %s", CS::Quote::Single (type));
    return false;
  }

  if (!(types & paramType))
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Type %s not supported by this parameter", CS::Quote::Single (type));
    return false;
  }

  const uint directValueTypes = ParamInt | ParamFloat | ParamVector2
    | ParamVector3 | ParamVector4 | ParamMatrix | ParamTransform;
  switch (paramType & directValueTypes)
  {
    case ParamInvalid:
      return false;
      break;
    case ParamInt:
      {
	int x = node->GetContentsValueAsInt ();
	var->SetValue (x);
      }
      break;
    case ParamFloat:
      {
	float x = node->GetContentsValueAsFloat ();
	var->SetValue (x);
      }
      break;
    case ParamVector2:
      {
	float x, y;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f", &x, &y) != 2)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector2 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector2 (x,y));
      }
      break;
    case ParamVector3:
      {
	float x, y, z;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f", &x, &y, &z) != 3)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector3 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector3 (x,y,z));
      }
      break;
    case ParamVector4:
      {
	float x, y, z, w;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f,%f", &x, &y, &z, &w) != 4)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector4 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector4 (x,y,z,w));
      }
      break;
    case ParamMatrix:
      {
        csMatrix3 matrix;
	if (!synsrv->ParseMatrix (node, matrix))
	  return false;
        var->SetValue (matrix);
      }
      break;
    case ParamTransform:
      {
        csReversibleTransform t;
        csRef<iDocumentNode> matrix_node = node->GetNode ("matrix");
        if (matrix_node)
        {
          csMatrix3 m;
          if (!synsrv->ParseMatrix (matrix_node, m))
            return false;
          t.SetT2O (m);
        }
        csRef<iDocumentNode> vector_node = node->GetNode ("v");
        if (vector_node)
        {
          csVector3 v;
          if (!synsrv->ParseVector (vector_node, v))
            return false;
          t.SetOrigin (v);
        }
        var->SetValue (t);
      }
      break;
  }

  param.var = var;
  param.valid = true;
  return true;
}

bool csShaderProgram::ParseCommon (iDocumentNode* child)
{
  const char* value = child->GetValue ();
  csStringID id = commonTokens.Request (value);
  switch (id)
  {
    case XMLTOKEN_VARIABLEMAP:
      {
        //@@ REWRITE
	const char* destname = child->GetAttributeValue ("destination");
	if (!destname)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING, child,
	    "<variablemap> has no %s attribute",
	    CS::Quote::Single ("destination"));
	  return false;
	}

	const char* varname = child->GetAttributeValue ("variable");
	if (!varname)
	{
	  // "New style" variable mapping
	  VariableMapEntry vme (CS::InvalidShaderVarStringID, destname);
	  if (!ParseProgramParam (child, vme.mappingParam,
	    ParamInt | ParamFloat | ParamVector2 | ParamVector3 | ParamVector4))
	    return false;
	  variablemap.Push (vme);
	}
	else
	{
	  // "Classic" variable mapping
	  CS::Graphics::ShaderVarNameParser nameParse (varname);
	  VariableMapEntry vme (
	    stringsSvName->Request (nameParse.GetShaderVarName()),
	    destname);
	  for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
	  {
	    vme.mappingParam.indices.Push (nameParse.GetIndexValue (n));
	  }
	  variablemap.Push (vme);
	}
      }
      break;
    case XMLTOKEN_PROGRAM:
      {
	const char* filename = child->GetAttributeValue ("file");
	if (filename != 0)
	{
	  programFileName = filename;

	  csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg);
	  csRef<iFile> file = vfs->Open (filename, VFS_FILE_READ);
	  if (!file.IsValid())
	  {
	    synsrv->Report ("crystalspace.graphics3d.shader.common",
	      CS_REPORTER_SEVERITY_WARNING, child,
	      "Could not open %s", CS::Quote::Single (filename));
	    return false;
	  }

	  programFile = file;
	}
	else
	  programNode = child;
      }
      break;

    case XMLTOKEN_DESCRIPTION:
      description = child->GetContentsValue();
      break;
    default:
      synsrv->ReportBadToken (child);
      return false;
  }
  return true;
}

#include "csutil/custom_new_disable.h"
iDocumentNode* csShaderProgram::GetProgramNode ()
{
  if (programNode.IsValid ())
    return programNode;

  if (programFile.IsValid ())
  {
    csRef<iDocumentSystem> docsys =
      csQueryRegistry<iDocumentSystem> (objectReg);
    if (!docsys)
      docsys.AttachNew (new csTinyDocumentSystem ());
    csRef<iDocument> doc (docsys->CreateDocument ());

    const char* err = doc->Parse (programFile, true);
    if (err != 0)
    {
      csReport (objectReg,
	CS_REPORTER_SEVERITY_WARNING,
	"crystalspace.graphics3d.shader.common",
	"Error parsing %s: %s", programFileName.GetData(), err);
      return 0;
    }
    programNode = doc->GetRoot ();
    programFile = 0;
    return programNode;
  }

  return 0;
}

csPtr<iDataBuffer> csShaderProgram::GetProgramData ()
{
  if (programFile.IsValid())
  {
    return programFile->GetAllData ();
  }

  if (programNode.IsValid())
  {
    char* data = CS::StrDup (programNode->GetContentsValue ());

    csRef<iDataBuffer> newbuff;
    newbuff.AttachNew (new CS::DataBuffer<> (data, data ? strlen (data) : 0));
    return csPtr<iDataBuffer> (newbuff);
  }

  return 0;
}
#include "csutil/custom_new_enable.h"

void csShaderProgram::DumpProgramInfo (csString& output)
{
  output << "Program description: " <<
    (description.Length () ? description.GetData () : "<none>") << "\n";
  output << "Program file name: " << programFileName << "\n";
}

void csShaderProgram::DumpVariableMappings (csString& output)
{
  for (size_t v = 0; v < variablemap.GetSize (); v++)
  {
    const VariableMapEntry& vme = variablemap[v];

    output << stringsSvName->Request (vme.name);
    output << '(' << vme.name << ") -> ";
    output << vme.destination << ' ';
    output << vme.userVal << ' ';
    output << '\n';
  }
}

void csShaderProgram::GetUsedShaderVarsFromVariableMappings (
  csBitArray& bits) const
{
  for (size_t i = 0; i < variablemap.GetSize(); i++)
  {
    TryAddUsedShaderVarName (variablemap[i].name, bits);
  }
}

void csShaderProgram::GetUsedShaderVars (csBitArray& bits) const
{
  GetUsedShaderVarsFromVariableMappings (bits);
}

iShaderProgram::CacheLoadResult csShaderProgram::LoadFromCache (
  iHierarchicalCache* cache, iBase* previous, iDocumentNode* programNode,
  csRef<iString>* failReason, csRef<iString>* tag)
{
  csRef<iShaderDestinationResolver> resolver =
    scfQueryInterfaceSafe<iShaderDestinationResolver> (previous);

  if (Load (resolver, programNode) && Compile (0, tag))
    return loadSuccessShaderValid;
  else
    return loadSuccessShaderInvalid;
}
<commit_msg>- Made sure that program file/node are invalidated when parsing subsequent times.<commit_after>/*
    Copyright (C) 2004 by Jorrit Tyberghein
	      (C) 2004 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/databuf.h"
#include "csutil/scanstr.h"
#include "csutil/stringquote.h"
#include "csutil/util.h"
#include "csutil/xmltiny.h"
#include "csgfx/shaderexp.h"

#include "imap/services.h"
#include "iutil/verbositymanager.h"
#include "iutil/vfs.h"
#include "ivaria/reporter.h"

#include "csplugincommon/shader/shaderprogram.h"

void csShaderProgram::ProgramParam::SetValue (float val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

void csShaderProgram::ProgramParam::SetValue (const csVector4& val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

//---------------------------------------------------------------------------

CS_LEAKGUARD_IMPLEMENT (csShaderProgram);

csShaderProgram::csShaderProgram (iObjectRegistry* objectReg)
  : scfImplementationType (this)
{
  InitCommonTokens (commonTokens);

  csShaderProgram::objectReg = objectReg;
  synsrv = csQueryRegistry<iSyntaxService> (objectReg);
  stringsSvName = csQueryRegistryTagInterface<iShaderVarStringSet>
    (objectReg, "crystalspace.shader.variablenameset");

  csRef<iVerbosityManager> verbosemgr (
    csQueryRegistry<iVerbosityManager> (objectReg));
  if (verbosemgr)
    doVerbose = verbosemgr->Enabled("renderer.shader");
  else
    doVerbose = false;
}

csShaderProgram::~csShaderProgram ()
{
}

bool csShaderProgram::ProgramParamParser::ParseProgramParam (
  iDocumentNode* node, ProgramParam& param, uint types)
{
  const char* type = node->GetAttributeValue ("type");
  if (type == 0)
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "No %s attribute",
      CS::Quote::Single ("type"));
    return false;
  }

  // Var for static data
  csRef<csShaderVariable> var;
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));

  ProgramParamType paramType = ParamInvalid;
  if (strcmp (type, "shadervar") == 0)
  {
    const char* value = node->GetContentsValue();
    if (!value)
    {
      synsrv->Report ("crystalspace.graphics3d.shader.common",
	CS_REPORTER_SEVERITY_WARNING,
	node,
	"Node has no contents");
      return false;
    }

    CS::Graphics::ShaderVarNameParser nameParse (value);
    param.name = stringsSvName->Request (nameParse.GetShaderVarName());
    for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
    {
      param.indices.Push (nameParse.GetIndexValue (n));
    }
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "int") == 0)
  {
    paramType = ParamInt;
  }
  else if (strcmp (type, "float") == 0)
  {
    paramType = ParamFloat;
  }
  else if (strcmp (type, "vector2") == 0)
  {
    paramType = ParamVector2;
  }
  else if (strcmp (type, "vector3") == 0)
  {
    paramType = ParamVector3;
  }
  else if (strcmp (type, "vector4") == 0)
  {
    paramType = ParamVector4;
  }
  else if (strcmp (type, "matrix") == 0)
  {
    paramType = ParamMatrix;
  }
  else if (strcmp (type, "transform") == 0)
  {
    paramType = ParamTransform;
  }
  else if ((strcmp (type, "expression") == 0) || (strcmp (type, "expr") == 0))
  {
    // Parse exp and save it
    csRef<iShaderVariableAccessor> acc = synsrv->ParseShaderVarExpr (node);
    var->SetAccessor (acc);
    param.var = var;
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "array") == 0)
  {
    csArray<ProgramParam> allParams;
    ProgramParam tmpParam;
    csRef<iDocumentNodeIterator> it = node->GetNodes ();
    while (it->HasNext ())
    {
      csRef<iDocumentNode> child = it->Next ();
      ParseProgramParam (child, tmpParam, types & 0x3F);
      allParams.Push (tmpParam);
    }

    //Save the params
    var->SetType (csShaderVariable::ARRAY);
    var->SetArraySize (allParams.GetSize ());

    for (uint i = 0; i < allParams.GetSize (); i++)
    {
      var->SetArrayElement (i, allParams[i].var);
    }
    paramType = ParamArray;
  }
  else
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Unknown type %s", CS::Quote::Single (type));
    return false;
  }

  if (!(types & paramType))
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Type %s not supported by this parameter", CS::Quote::Single (type));
    return false;
  }

  const uint directValueTypes = ParamInt | ParamFloat | ParamVector2
    | ParamVector3 | ParamVector4 | ParamMatrix | ParamTransform;
  switch (paramType & directValueTypes)
  {
    case ParamInvalid:
      return false;
      break;
    case ParamInt:
      {
	int x = node->GetContentsValueAsInt ();
	var->SetValue (x);
      }
      break;
    case ParamFloat:
      {
	float x = node->GetContentsValueAsFloat ();
	var->SetValue (x);
      }
      break;
    case ParamVector2:
      {
	float x, y;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f", &x, &y) != 2)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector2 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector2 (x,y));
      }
      break;
    case ParamVector3:
      {
	float x, y, z;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f", &x, &y, &z) != 3)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector3 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector3 (x,y,z));
      }
      break;
    case ParamVector4:
      {
	float x, y, z, w;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f,%f", &x, &y, &z, &w) != 4)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector4 %s", CS::Quote::Single (value));
	  return false;
	}
	var->SetValue (csVector4 (x,y,z,w));
      }
      break;
    case ParamMatrix:
      {
        csMatrix3 matrix;
	if (!synsrv->ParseMatrix (node, matrix))
	  return false;
        var->SetValue (matrix);
      }
      break;
    case ParamTransform:
      {
        csReversibleTransform t;
        csRef<iDocumentNode> matrix_node = node->GetNode ("matrix");
        if (matrix_node)
        {
          csMatrix3 m;
          if (!synsrv->ParseMatrix (matrix_node, m))
            return false;
          t.SetT2O (m);
        }
        csRef<iDocumentNode> vector_node = node->GetNode ("v");
        if (vector_node)
        {
          csVector3 v;
          if (!synsrv->ParseVector (vector_node, v))
            return false;
          t.SetOrigin (v);
        }
        var->SetValue (t);
      }
      break;
  }

  param.var = var;
  param.valid = true;
  return true;
}

bool csShaderProgram::ParseCommon (iDocumentNode* child)
{
  const char* value = child->GetValue ();
  csStringID id = commonTokens.Request (value);
  switch (id)
  {
  case XMLTOKEN_VARIABLEMAP:
    {
      //@@ REWRITE
      const char* destname = child->GetAttributeValue ("destination");
      if (!destname)
      {
        synsrv->Report ("crystalspace.graphics3d.shader.common",
          CS_REPORTER_SEVERITY_WARNING, child,
          "<variablemap> has no %s attribute",
          CS::Quote::Single ("destination"));
        return false;
      }

      const char* varname = child->GetAttributeValue ("variable");
      if (!varname)
      {
        // "New style" variable mapping
        VariableMapEntry vme (CS::InvalidShaderVarStringID, destname);
        if (!ParseProgramParam (child, vme.mappingParam,
          ParamInt | ParamFloat | ParamVector2 | ParamVector3 | ParamVector4))
          return false;
        variablemap.Push (vme);
      }
      else
      {
        // "Classic" variable mapping
        CS::Graphics::ShaderVarNameParser nameParse (varname);
        VariableMapEntry vme (
          stringsSvName->Request (nameParse.GetShaderVarName()),
          destname);
        for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
        {
          vme.mappingParam.indices.Push (nameParse.GetIndexValue (n));
        }
        variablemap.Push (vme);
      }
    }
    break;
  case XMLTOKEN_PROGRAM:
    {
      const char* filename = child->GetAttributeValue ("file");
      if (filename != 0)
      {
        programFileName = filename;

        csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg);
        csRef<iFile> file = vfs->Open (filename, VFS_FILE_READ);
        if (!file.IsValid())
        {
          synsrv->Report ("crystalspace.graphics3d.shader.common",
            CS_REPORTER_SEVERITY_WARNING, child,
            "Could not open %s", CS::Quote::Single (filename));
          return false;
        }

        programFile = file;
        programNode.Invalidate ();
      }
      else
      {
        programNode = child;
        programFile.Invalidate ();
      }
    }
    break;

  case XMLTOKEN_DESCRIPTION:
    description = child->GetContentsValue();
    break;
  default:
    synsrv->ReportBadToken (child);
    return false;
  }
  return true;
}

#include "csutil/custom_new_disable.h"
iDocumentNode* csShaderProgram::GetProgramNode ()
{
  if (programNode.IsValid ())
    return programNode;

  if (programFile.IsValid ())
  {
    csRef<iDocumentSystem> docsys =
      csQueryRegistry<iDocumentSystem> (objectReg);
    if (!docsys)
      docsys.AttachNew (new csTinyDocumentSystem ());
    csRef<iDocument> doc (docsys->CreateDocument ());

    const char* err = doc->Parse (programFile, true);
    if (err != 0)
    {
      csReport (objectReg,
	CS_REPORTER_SEVERITY_WARNING,
	"crystalspace.graphics3d.shader.common",
	"Error parsing %s: %s", programFileName.GetData(), err);
      return 0;
    }
    programNode = doc->GetRoot ();
    programFile = 0;
    return programNode;
  }

  return 0;
}

csPtr<iDataBuffer> csShaderProgram::GetProgramData ()
{
  if (programFile.IsValid())
  {
    return programFile->GetAllData ();
  }

  if (programNode.IsValid())
  {
    char* data = CS::StrDup (programNode->GetContentsValue ());

    csRef<iDataBuffer> newbuff;
    newbuff.AttachNew (new CS::DataBuffer<> (data, data ? strlen (data) : 0));
    return csPtr<iDataBuffer> (newbuff);
  }

  return 0;
}
#include "csutil/custom_new_enable.h"

void csShaderProgram::DumpProgramInfo (csString& output)
{
  output << "Program description: " <<
    (description.Length () ? description.GetData () : "<none>") << "\n";
  output << "Program file name: " << programFileName << "\n";
}

void csShaderProgram::DumpVariableMappings (csString& output)
{
  for (size_t v = 0; v < variablemap.GetSize (); v++)
  {
    const VariableMapEntry& vme = variablemap[v];

    output << stringsSvName->Request (vme.name);
    output << '(' << vme.name << ") -> ";
    output << vme.destination << ' ';
    output << vme.userVal << ' ';
    output << '\n';
  }
}

void csShaderProgram::GetUsedShaderVarsFromVariableMappings (
  csBitArray& bits) const
{
  for (size_t i = 0; i < variablemap.GetSize(); i++)
  {
    TryAddUsedShaderVarName (variablemap[i].name, bits);
  }
}

void csShaderProgram::GetUsedShaderVars (csBitArray& bits) const
{
  GetUsedShaderVarsFromVariableMappings (bits);
}

iShaderProgram::CacheLoadResult csShaderProgram::LoadFromCache (
  iHierarchicalCache* cache, iBase* previous, iDocumentNode* programNode,
  csRef<iString>* failReason, csRef<iString>* tag)
{
  csRef<iShaderDestinationResolver> resolver =
    scfQueryInterfaceSafe<iShaderDestinationResolver> (previous);

  if (Load (resolver, programNode) && Compile (0, tag))
    return loadSuccessShaderValid;
  else
    return loadSuccessShaderInvalid;
}
<|endoftext|>