<commit_before>#include <core/stdafx.h>
#include <core/interpret/flags.h>
#include <core/utility/strings.h>
#include <core/addin/addin.h>
#include <core/addin/mfcmapi.h>

namespace flags
{
	// Interprets a flag value according to a flag name and returns a string
	// Will not return a string if the flag name is not recognized
	std::wstring InterpretFlags(ULONG ulFlagName, LONG lFlagValue)
	{
		ULONG ulCurEntry = 0;

		if (FlagArray.empty()) return L"";

		while (ulCurEntry < FlagArray.size() && FlagArray[ulCurEntry].ulFlagName != ulFlagName)
		{
			ulCurEntry++;
		}

		// Don't run off the end of the array
		if (FlagArray.size() == ulCurEntry) return L"";
		if (FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";

		// We've matched our flag name to the array - we SHOULD return a string at this point
		auto flags = std::vector<std::wstring>{};
		auto lTempValue = lFlagValue;
		for (; FlagArray[ulCurEntry].ulFlagName == ulFlagName; ulCurEntry++)
		{
			if (flagFLAG == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue & lTempValue)
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
				}
			}
			else if (flagVALUE == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue == lTempValue)
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = 0;
				}
			}
			else if (flagVALUEHIGHBYTES == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 16 & 0xFFFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 16);
				}
			}
			else if (flagVALUE3RDBYTE == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 8 & 0xFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 8);
				}
			}
			else if (flagVALUE4THBYTE == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0xFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
				}
			}
			else if (flagVALUELOWERNIBBLE == FlagArray[ulCurEntry].ulFlagType)
			{
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0x0F))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
				}
			}
			else if (flagCLEARBITS == FlagArray[ulCurEntry].ulFlagType)
			{
				// find any bits we need to clear
				const auto lClearedBits = FlagArray[ulCurEntry].lFlagValue & lTempValue;
				// report what we found
				if (0 != lClearedBits)
				{
					flags.push_back(strings::format(L"0x%X", lClearedBits)); // STRING_OK
						// clear the bits out
					lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
				}
			}
		}

		if (lTempValue || flags.empty())
		{
			flags.push_back(strings::format(L"0x%X", lTempValue)); // STRING_OK
		}

		return strings::join(flags, L" | ");
	}

	// Returns a list of all known flags/values for a flag name.
	// For instance, for flagFuzzyLevel, would return:
	// 0x00000000 FL_FULLSTRING\r\n\
	// 0x00000001 FL_SUBSTRING\r\n\
	// 0x00000002 FL_PREFIX\r\n\
	// 0x00010000 FL_IGNORECASE\r\n\
	// 0x00020000 FL_IGNORENONSPACE\r\n\
	// 0x00040000 FL_LOOSE
	//
	// Since the string is always appended to a prompt we include \r\n at the start
	std::wstring AllFlagsToString(ULONG ulFlagName, bool bHex)
	{
		if (!ulFlagName) return L"";
		if (FlagArray.empty()) return L"";

		ULONG ulCurEntry = 0;

		while (ulCurEntry < FlagArray.size() && FlagArray[ulCurEntry].ulFlagName != ulFlagName)
		{
			ulCurEntry++;
		}

		if (ulCurEntry == FlagArray.size() || FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";

		// We've matched our flag name to the array - we SHOULD return a string at this point
		auto flags = std::vector<std::wstring>{};
		while (FlagArray[ulCurEntry].ulFlagName == ulFlagName)
		{
			if (flagCLEARBITS != FlagArray[ulCurEntry].ulFlagType)
			{
				flags.push_back(strings::formatmessage(
					bHex ? IDS_FLAGTOSTRINGHEX : IDS_FLAGTOSTRINGDEC,
					FlagArray[ulCurEntry].lFlagValue,
					FlagArray[ulCurEntry].lpszName));
			}

			ulCurEntry++;
		}

		return strings::join(flags, L"\r\n");
	}
} // namespace flags
<commit_msg>rewrite as switch<commit_after>#include <core/stdafx.h>
#include <core/interpret/flags.h>
#include <core/utility/strings.h>
#include <core/addin/addin.h>
#include <core/addin/mfcmapi.h>

namespace flags
{
	// Interprets a flag value according to a flag name and returns a string
	// Will not return a string if the flag name is not recognized
	std::wstring InterpretFlags(ULONG ulFlagName, LONG lFlagValue)
	{
		ULONG ulCurEntry = 0;

		if (FlagArray.empty()) return L"";

		while (ulCurEntry < FlagArray.size() && FlagArray[ulCurEntry].ulFlagName != ulFlagName)
		{
			ulCurEntry++;
		}

		// Don't run off the end of the array
		if (FlagArray.size() == ulCurEntry) return L"";
		if (FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";

		// We've matched our flag name to the array - we SHOULD return a string at this point
		auto flags = std::vector<std::wstring>{};
		auto lTempValue = lFlagValue;
		while (FlagArray[ulCurEntry].ulFlagName == ulFlagName)
		{
			switch (FlagArray[ulCurEntry].ulFlagType)
			{
			case flagFLAG:
				if (FlagArray[ulCurEntry].lFlagValue & lTempValue)
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
				}
				break;
			case flagVALUE:
				if (FlagArray[ulCurEntry].lFlagValue == lTempValue)
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = 0;
				}
				break;
			case flagVALUEHIGHBYTES:
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 16 & 0xFFFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 16);
				}
				break;
			case flagVALUE3RDBYTE:
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue >> 8 & 0xFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - (FlagArray[ulCurEntry].lFlagValue << 8);
				}
				break;
			case flagVALUE4THBYTE:
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0xFF))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
				}
				break;
			case flagVALUELOWERNIBBLE:
				if (FlagArray[ulCurEntry].lFlagValue == (lTempValue & 0x0F))
				{
					flags.push_back(FlagArray[ulCurEntry].lpszName);
					lTempValue = lTempValue - FlagArray[ulCurEntry].lFlagValue;
				}
				break;
			case flagCLEARBITS:
				// find any bits we need to clear
				const auto lClearedBits = FlagArray[ulCurEntry].lFlagValue & lTempValue;
				// report what we found
				if (lClearedBits != 0)
				{
					flags.push_back(strings::format(L"0x%X", lClearedBits)); // STRING_OK
						// clear the bits out
					lTempValue &= ~FlagArray[ulCurEntry].lFlagValue;
				}
				break;
			}

			ulCurEntry++;
		}

		if (lTempValue || flags.empty())
		{
			flags.push_back(strings::format(L"0x%X", lTempValue)); // STRING_OK
		}

		return strings::join(flags, L" | ");
	}

	// Returns a list of all known flags/values for a flag name.
	// For instance, for flagFuzzyLevel, would return:
	// 0x00000000 FL_FULLSTRING\r\n\
	// 0x00000001 FL_SUBSTRING\r\n\
	// 0x00000002 FL_PREFIX\r\n\
	// 0x00010000 FL_IGNORECASE\r\n\
	// 0x00020000 FL_IGNORENONSPACE\r\n\
	// 0x00040000 FL_LOOSE
	//
	// Since the string is always appended to a prompt we include \r\n at the start
	std::wstring AllFlagsToString(ULONG ulFlagName, bool bHex)
	{
		if (!ulFlagName) return L"";
		if (FlagArray.empty()) return L"";

		ULONG ulCurEntry = 0;

		while (ulCurEntry < FlagArray.size() && FlagArray[ulCurEntry].ulFlagName != ulFlagName)
		{
			ulCurEntry++;
		}

		if (ulCurEntry == FlagArray.size() || FlagArray[ulCurEntry].ulFlagName != ulFlagName) return L"";

		// We've matched our flag name to the array - we SHOULD return a string at this point
		auto flags = std::vector<std::wstring>{};
		while (FlagArray[ulCurEntry].ulFlagName == ulFlagName)
		{
			if (flagCLEARBITS != FlagArray[ulCurEntry].ulFlagType)
			{
				flags.push_back(strings::formatmessage(
					bHex ? IDS_FLAGTOSTRINGHEX : IDS_FLAGTOSTRINGDEC,
					FlagArray[ulCurEntry].lFlagValue,
					FlagArray[ulCurEntry].lpszName));
			}

			ulCurEntry++;
		}

		return strings::join(flags, L"\r\n");
	}
} // namespace flags
<|endoftext|>


<commit_before>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>

#include <memory>
#include <sstream>

#include <kernel/userver.hh>
#include <kernel/uconnection.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/lobby.hh>
#include <object/list.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/call.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{

  rObject
  execute_parsed(runner::Runner& r,
                 parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = dynamic_cast<runner::Interpreter&>(r);

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      runner::raise_primitive_error(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    scheduler::rJob job = sub;
    libport::Finally finally;
    r.register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const scheduler::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    check_arg_count(args.size() - 1, 0);                                \
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);

    type_check(args[1], Float::proto);

    rFloat arg1 = args[1]->as<Float>();
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
    {
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000000.0);
      r.yield_until (deadline);
    }
    return void_class;
  }

  static rObject
  system_class_time(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(r.scheduler_get().get_time() / 1000000.0);
  }

  static rObject
  system_class_shiftedTime(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000000.0);
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 2);
    type_check(args[2], String::proto);
    rString arg2 = args[2]->as<String>();
    if (!is_true(args[1]))
      runner::raise_primitive_error("assertion `" + arg2->value_get() +
				    "' failed");
    return void_class;
  }

  static rObject
  system_class_eval(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    type_check(args[1], String::proto);
    rString arg1 = args[1]->as<String>();
    return
      execute_parsed(r, parser::parse(arg1->value_get()),
                     SYMBOL(eval),
                     "error executing command: " + arg1->value_get());
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 3);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_scopeTag(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    const scheduler::rTag& scope_tag =
      dynamic_cast<runner::Interpreter&>(r).scope_tag();
    return new Tag(scope_tag);
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    type_check(args[1], String::proto);
    const rString& arg1 = args[1]->as<String>();

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return new String(s.find_file(arg1->value_get()));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), arg1);
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    type_check(args[1], String::proto);
    const rString& arg1 = args[1]->as<String>();

    const std::string& filename = arg1->value_get();

    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(r, parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return r.as_task();
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new String(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

  static rObject
  system_class_spawn(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    rObject arg1 = args[1]->as<Code>();
    assert(arg1);

    runner::Interpreter* new_runner =
      new runner::Interpreter (dynamic_cast<runner::Interpreter&>(r),
			       rObject(arg1),
			       libport::Symbol::fresh(r.name_get()));
    new_runner->copy_tags (r);
    new_runner->time_shift_set (r.time_shift_get ());

    new_runner->start_job ();

    return object::void_class;
  }

  static rObject
  system_class_stats(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    Dictionary::value_type res;
    const scheduler::scheduler_stats_type& stats =
      r.scheduler_get().stats_get();
    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
#define ADDSTAT(Suffix, Function, Divisor)				\
    res[libport::Symbol( "cycles" # Suffix)] = new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1000.0);
    ADDSTAT(Mean, mean, 1000.0);
    ADDSTAT(Min, min, 1000.0);
    ADDSTAT(StdDev, standard_deviation, 1000.0);
    ADDSTAT(Variance, variance, 1000.0);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static rObject
  system_class_platform(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
#ifdef WIN32
    return to_urbi(SYMBOL(WIN32));
#else
    return to_urbi(SYMBOL(POSIX));
#endif
  }

  // This should give a backtrace as an urbi object.
  static rObject
  system_class_backtrace(runner::Runner& r, objects_type args)
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    check_arg_count(args.size() - 1, 0);
    runner::Runner::backtrace_type bt = r.backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      r.send_message("backtrace", elt.first + " (" + elt.second + ")");
    return void_class;
  }

  static rObject
  system_class_jobs(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    List::value_type res;
    foreach(scheduler::rJob job, r.scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return new List(res);
  }

  static rObject
  system_class_aliveJobs(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(scheduler::Job::alive_jobs());
  }

  static rObject
  system_class_breakpoint(runner::Runner&, objects_type)
  {
    return void_class;
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    check_arg_count(args.size() - 1, 0);                                \
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject system_getenv(rObject, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : 0;
  }

  static rObject system_setenv(runner::Runner& r, rObject,
                               const std::string& name, rObject value)
  {
    rString v = urbi_call(r, value, SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject system_unsetenv(rObject, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type system_lobbies()
  {
    return Lobby::instances_get();
  }

  void
  system_class_initialize ()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set                                              \
      (SYMBOL(Name),                                                    \
       make_primitive(&system_##Name))                                  \

    DECLARE(getenv);
    DECLARE(lobbies);
    DECLARE(setenv);
    DECLARE(unsetenv);

#undef DECLARE

    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(aliveJobs);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(stats);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stopall);
    DECLARE(platform);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<commit_msg>Make "loadFile" and "searchFile" accept a "Path" object.<commit_after>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>
#include <libport/cstdlib>

#include <memory>
#include <sstream>

#include <kernel/userver.hh>
#include <kernel/uconnection.hh>

#include <object/code.hh>
#include <object/cxx-primitive.hh>
#include <object/dictionary.hh>
#include <object/float.hh>
#include <object/global.hh>
#include <object/lobby.hh>
#include <object/list.hh>
#include <object/path.hh>
#include <object/system.hh>
#include <object/tag.hh>
#include <object/task.hh>
#include <parser/transform.hh>
#include <runner/at-handler.hh>
#include <runner/call.hh>
#include <runner/interpreter.hh>
#include <runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace object
{

  // Extract a filename from a String or a Path object
  static std::string
  filename_get(const rObject& o)
  {
    if (o.is_a<Path>())
      return o->as<Path>()->as_string();
    type_check(o, String::proto);
    return o->as<String>()->value_get();
  }

  rObject
  execute_parsed(runner::Runner& r,
                 parser::parse_result_type p,
                 libport::Symbol fun, std::string e)
  {
    runner::Interpreter& run = dynamic_cast<runner::Interpreter&>(r);

    // Report potential errors
    {
      ast::rNary errs = new ast::Nary();
      p->process_errors(*errs);
      run(errs.get());
    }

    ast::rConstAst ast = parser::transform(p->ast_get());
    if (!ast)
      runner::raise_primitive_error(e);

    runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
    // So that it will resist to the call to yield_until_terminated,
    // and will be reclaimed at the end of the scope.
    scheduler::rJob job = sub;
    libport::Finally finally;
    r.register_child(sub, finally);
    sub->start_job();
    try
    {
      run.yield_until_terminated(*job);
    }
    catch (const scheduler::ChildException& ce)
    {
      // Kill the sub-job and propagate.
      ce.rethrow_child_exception();
    }
    return sub->result_get();
  }

  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    check_arg_count(args.size() - 1, 0);                                \
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);

    type_check(args[1], Float::proto);

    rFloat arg1 = args[1]->as<Float>();
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      r.yield_until_terminated(r);
    else
    {
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000000.0);
      r.yield_until (deadline);
    }
    return void_class;
  }

  static rObject
  system_class_time(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(r.scheduler_get().get_time() / 1000000.0);
  }

  static rObject
  system_class_shiftedTime(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000000.0);
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 2);
    type_check(args[2], String::proto);
    rString arg2 = args[2]->as<String>();
    if (!is_true(args[1]))
      runner::raise_primitive_error("assertion `" + arg2->value_get() +
				    "' failed");
    return void_class;
  }

  static rObject
  system_class_eval(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    type_check(args[1], String::proto);
    rString arg1 = args[1]->as<String>();
    return
      execute_parsed(r, parser::parse(arg1->value_get()),
                     SYMBOL(eval),
                     "error executing command: " + arg1->value_get());
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 3);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_scopeTag(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    const scheduler::rTag& scope_tag =
      dynamic_cast<runner::Interpreter&>(r).scope_tag();
    return new Tag(scope_tag);
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    const std::string filename = filename_get(args[1]);

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return new Path(s.find_file(filename));
    }
    catch (libport::file_library::Not_found&)
    {
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    const std::string filename = filename_get(args[1]);

    if (!libport::path(filename).exists())
      runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
    return
      execute_parsed(r, parser::parse_file(filename),
                     SYMBOL(loadFile),
		     "error loading file: " + filename);
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return r.as_task();
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new String(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

  static rObject
  system_class_spawn(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 1);
    rObject arg1 = args[1]->as<Code>();
    assert(arg1);

    runner::Interpreter* new_runner =
      new runner::Interpreter (dynamic_cast<runner::Interpreter&>(r),
			       rObject(arg1),
			       libport::Symbol::fresh(r.name_get()));
    new_runner->copy_tags (r);
    new_runner->time_shift_set (r.time_shift_get ());

    new_runner->start_job ();

    return object::void_class;
  }

  static rObject
  system_class_stats(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    Dictionary::value_type res;
    const scheduler::scheduler_stats_type& stats =
      r.scheduler_get().stats_get();
    // The space after "Symbol(" is mandatory to avoid triggering an error in
    // symbol generation code
#define ADDSTAT(Suffix, Function, Divisor)				\
    res[libport::Symbol( "cycles" # Suffix)] = new Float(stats.Function() / Divisor)
    ADDSTAT(, size, 1);
    ADDSTAT(Max, max, 1000.0);
    ADDSTAT(Mean, mean, 1000.0);
    ADDSTAT(Min, min, 1000.0);
    ADDSTAT(StdDev, standard_deviation, 1000.0);
    ADDSTAT(Variance, variance, 1000.0);
#undef ADDSTAT
    return new Dictionary(res);
  }

  static rObject
  system_class_platform(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
#ifdef WIN32
    return to_urbi(SYMBOL(WIN32));
#else
    return to_urbi(SYMBOL(POSIX));
#endif
  }

  // This should give a backtrace as an urbi object.
  static rObject
  system_class_backtrace(runner::Runner& r, objects_type args)
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    check_arg_count(args.size() - 1, 0);
    runner::Runner::backtrace_type bt = r.backtrace_get();
    bt.pop_back();
    foreach (const runner::Runner::frame_type& elt,
	     boost::make_iterator_range(boost::rbegin(bt),
					boost::rend(bt)))
      r.send_message("backtrace", elt.first + " (" + elt.second + ")");
    return void_class;
  }

  static rObject
  system_class_jobs(runner::Runner& r, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    List::value_type res;
    foreach(scheduler::rJob job, r.scheduler_get().jobs_get())
      res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_task());
    return new List(res);
  }

  static rObject
  system_class_aliveJobs(runner::Runner&, objects_type args)
  {
    check_arg_count(args.size() - 1, 0);
    return new Float(scheduler::Job::alive_jobs());
  }

  static rObject
  system_class_breakpoint(runner::Runner&, objects_type)
  {
    return void_class;
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    check_arg_count(args.size() - 1, 0);                                \
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  static rObject system_getenv(rObject, const std::string& name)
  {
    char* res = getenv(name.c_str());
    return res ? new String(res) : 0;
  }

  static rObject system_setenv(runner::Runner& r, rObject,
                               const std::string& name, rObject value)
  {
    rString v = urbi_call(r, value, SYMBOL(asString))->as<String>();
    setenv(name.c_str(), v->value_get().c_str(), 1);
    return v;
  }

  static rObject system_unsetenv(rObject, const std::string& name)
  {
    rObject res = system_getenv(0, name);
    unsetenv(name.c_str());
    return res;
  }

  static libport::InstanceTracker<Lobby>::set_type system_lobbies()
  {
    return Lobby::instances_get();
  }

  void
  system_class_initialize ()
  {
#define DECLARE(Name)                                                   \
    system_class->slot_set                                              \
      (SYMBOL(Name),                                                    \
       make_primitive(&system_##Name))                                  \

    DECLARE(getenv);
    DECLARE(lobbies);
    DECLARE(setenv);
    DECLARE(unsetenv);

#undef DECLARE

    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(aliveJobs);
    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(breakpoint);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(jobs);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(scopeTag);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(stats);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(spawn);
    DECLARE(stopall);
    DECLARE(platform);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/net/gaia/oauth_request_signer.h"

#include <cctype>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "base/base64.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "crypto/hmac.h"
#include "googleurl/src/gurl.h"

namespace {

static const int kHexBase = 16;
static char kHexDigits[] = "0123456789ABCDEF";
static const size_t kHmacDigestLength = 20;
static const int kMaxNonceLength = 30;
static const int kMinNonceLength = 15;

static const char kOAuthConsumerKeyLabel[] = "oauth_consumer_key";
static const char kOAuthConsumerSecretLabel[] = "oauth_consumer_secret";
static const char kOAuthNonceCharacters[] =
    "abcdefghijklmnopqrstuvwyz"
    "ABCDEFGHIJKLMNOPQRSTUVWYZ"
    "0123456789_";
static const char kOAuthNonceLabel[] = "oauth_nonce";
static const char kOAuthSignatureLabel[] = "oauth_signature";
static const char kOAuthSignatureMethodLabel[] = "oauth_signature_method";
static const char kOAuthTimestampLabel[] = "oauth_timestamp";
static const char kOAuthTokenLabel[] = "oauth_token";
static const char kOAuthTokenSecretLabel[] = "oauth_token_secret";
static const char kOAuthVersion[] = "1.0";
static const char kOAuthVersionLabel[] = "oauth_version";

enum ParseQueryState {
  START_STATE,
  KEYWORD_STATE,
  VALUE_STATE,
};

const std::string HttpMethodName(OAuthRequestSigner::HttpMethod method) {
  switch (method) {
    case OAuthRequestSigner::GET_METHOD:
      return "GET";
    case OAuthRequestSigner::POST_METHOD:
      return "POST";
  }
  NOTREACHED();
  return *(new std::string());
}

const std::string SignatureMethodName(
    OAuthRequestSigner::SignatureMethod method) {
  switch (method) {
    case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
      return "HMAC-SHA1";
    case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
      return "RSA-SHA1";
    case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
      return "PLAINTEXT";
  }
  NOTREACHED();
  return *(new std::string());
}

std::string BuildBaseString(const GURL& request_base_url,
                            OAuthRequestSigner::HttpMethod http_method,
                            const std::string base_parameters) {
  return StringPrintf("%s&%s&%s",
                      HttpMethodName(http_method).c_str(),
                      OAuthRequestSigner::Encode(
                          request_base_url.spec()).c_str(),
                      OAuthRequestSigner::Encode(
                          base_parameters).c_str());
}

std::string BuildBaseStringParameters(
    const OAuthRequestSigner::Parameters& parameters) {
  std::string result = "";
  OAuthRequestSigner::Parameters::const_iterator cursor;
  OAuthRequestSigner::Parameters::const_iterator limit;
  bool first = true;
  for (cursor = parameters.begin(), limit = parameters.end();
       cursor != limit;
       ++cursor) {
    if (first)
      first = false;
    else
      result += '&';
    result += OAuthRequestSigner::Encode(cursor->first);
    result += '=';
    result += OAuthRequestSigner::Encode(cursor->second);
  }
  return result;
}

std::string GenerateNonce() {
  char result[kMaxNonceLength + 1];
  int length = base::RandUint64() % (kMaxNonceLength - kMinNonceLength + 1) +
      kMinNonceLength;
  result[length] = '\0';
  for (int index = 0; index < length; ++index)
    result[index] = kOAuthNonceCharacters[
        base::RandUint64() % (sizeof(kOAuthNonceCharacters) - 1)];
  return result;
}

std::string GenerateTimestamp() {
  return base::StringPrintf(
      "%" PRId64,
      (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()).InSeconds());
}

// Creates a string-to-string, keyword-value map from a parameter/query string
// that uses ampersand (&) to seperate paris and equals (=) to seperate
// keyword from value.
bool ParseQuery(const std::string& query,
                OAuthRequestSigner::Parameters* parameters_result) {
  std::string::const_iterator cursor;
  std::string keyword;
  std::string::const_iterator limit;
  OAuthRequestSigner::Parameters parameters;
  ParseQueryState state;
  std::string value;

  state = START_STATE;
  for (cursor = query.begin(), limit = query.end();
       cursor != limit;
       ++cursor) {
    char character = *cursor;
    switch (state) {
      case KEYWORD_STATE:
        switch (character) {
          case '&':
            parameters[keyword] = value;
            keyword = "";
            value = "";
            state = START_STATE;
            break;
          case '=':
            state = VALUE_STATE;
            break;
          default:
            keyword += character;
        }
        break;
      case START_STATE:
        switch (character) {
          case '&':  // Intentionally falling through
          case '=':
            return false;
          default:
            keyword += character;
            state = KEYWORD_STATE;
        }
        break;
      case VALUE_STATE:
        switch (character) {
          case '=':
            return false;
          case '&':
            parameters[keyword] = value;
            keyword = "";
            value = "";
            state = START_STATE;
            break;
          default:
            value += character;
        }
        break;
    }
  }
  switch (state) {
    case START_STATE:
      break;
    case KEYWORD_STATE:  // Intentionally falling through
    case VALUE_STATE:
      parameters[keyword] = value;
      break;
    default:
      NOTREACHED();
  }
  *parameters_result = parameters;
  return true;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is HMAC-SHA1.
bool SignHmacSha1(const std::string& text,
                  const std::string& key,
                  std::string* signature_return) {
  crypto::HMAC hmac(crypto::HMAC::SHA1);
  DCHECK(hmac.DigestLength() == kHmacDigestLength);
  unsigned char digest[kHmacDigestLength];
  bool result = hmac.Init(key) &&
      hmac.Sign(text, digest, kHmacDigestLength) &&
      base::Base64Encode(std::string(reinterpret_cast<const char*>(digest),
                                     kHmacDigestLength),
                         signature_return);
  return result;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is PLAINTEXT.
//
// Not yet implemented, and might never be.
bool SignPlaintext(const std::string& text,
                   const std::string& key,
                   std::string* result) {
  NOTIMPLEMENTED();
  return false;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is RSA-SHA1.
//
// Not yet implemented, and might never be.
bool SignRsaSha1(const std::string& text,
                 const std::string& key,
                 std::string* result) {
  NOTIMPLEMENTED();
  return false;
}

// Adds parameters that are required by OAuth added as needed to |parameters|.
void PrepareParameters(OAuthRequestSigner::Parameters* parameters,
                       OAuthRequestSigner::SignatureMethod signature_method,
                       OAuthRequestSigner::HttpMethod http_method,
                       const std::string& consumer_key,
                       const std::string& token_key) {
  if (parameters->find(kOAuthNonceLabel) == parameters->end())
    (*parameters)[kOAuthNonceLabel] = GenerateNonce();

  if (parameters->find(kOAuthTimestampLabel) == parameters->end())
    (*parameters)[kOAuthTimestampLabel] = GenerateTimestamp();

  (*parameters)[kOAuthConsumerKeyLabel] = consumer_key;
  (*parameters)[kOAuthSignatureMethodLabel] =
      SignatureMethodName(signature_method);
  (*parameters)[kOAuthTokenLabel] = token_key;
  (*parameters)[kOAuthVersionLabel] = kOAuthVersion;
}

// Implements shared signing logic, generating the signature and storing it in
// |parameters|. Returns true if the signature has been generated succesfully.
bool SignParameters(const GURL& request_base_url,
                    OAuthRequestSigner::SignatureMethod signature_method,
                    OAuthRequestSigner::HttpMethod http_method,
                    const std::string& consumer_key,
                    const std::string& consumer_secret,
                    const std::string& token_key,
                    const std::string& token_secret,
                    OAuthRequestSigner::Parameters* parameters) {
  DCHECK(request_base_url.is_valid());
  PrepareParameters(parameters, signature_method, http_method,
                    consumer_key, token_key);
  std::string base_parameters = BuildBaseStringParameters(*parameters);
  std::string base = BuildBaseString(request_base_url, http_method,
                                     base_parameters);
  std::string key = consumer_secret + '&' + token_secret;
  bool is_signed = false;
  std::string signature;
  switch (signature_method) {
    case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
      is_signed = SignHmacSha1(base, key, &signature);
      break;
    case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
      is_signed = SignRsaSha1(base, key, &signature);
      break;
    case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
      is_signed = SignPlaintext(base, key, &signature);
      break;
    default:
      NOTREACHED();
  }
  if (is_signed)
    (*parameters)[kOAuthSignatureLabel] = signature;
  return is_signed;
}

}  // namespace

// static
bool OAuthRequestSigner::Decode(const std::string& text,
                                std::string* decoded_text) {
  std::string accumulator = "";
  std::string::const_iterator cursor;
  std::string::const_iterator limit;
  for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
    char character = *cursor;
    if (character == '%') {
      ++cursor;
      if (cursor == limit)
        return false;
      char* first = strchr(kHexDigits, *cursor);
      if (!first)
        return false;
      int high = first - kHexDigits;
      DCHECK(high >= 0 && high < kHexBase);

      ++cursor;
      if (cursor == limit)
        return false;
      char* second = strchr(kHexDigits, *cursor);
      if (!second)
        return false;
      int low = second - kHexDigits;
      DCHECK(low >= 0 || low < kHexBase);

      char decoded = static_cast<char>(high * kHexBase + low);
      DCHECK(!(IsAsciiAlpha(decoded) || IsAsciiDigit(decoded)));
      DCHECK(!(decoded && strchr("-._~", decoded)));
      accumulator += decoded;
    } else {
      accumulator += character;
    }
  }
  *decoded_text = accumulator;
  return true;
}

// static
std::string OAuthRequestSigner::Encode(const std::string& text) {
  std::string result = "";
  std::string::const_iterator cursor;
  std::string::const_iterator limit;
  for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
    char character = *cursor;
    if (IsAsciiAlpha(character) || IsAsciiDigit(character)) {
      result += character;
    } else {
      switch (character) {
        case '-':
        case '.':
        case '_':
        case '~':
          result += character;
          break;
        default:
          unsigned char byte = static_cast<unsigned char>(character);
          result = result + '%' + kHexDigits[byte / kHexBase] +
              kHexDigits[byte % kHexBase];
      }
    }
  }
  return result;
}

// static
bool OAuthRequestSigner::ParseAndSign(const GURL& request_url_with_parameters,
                                      SignatureMethod signature_method,
                                      HttpMethod http_method,
                                      const std::string& consumer_key,
                                      const std::string& consumer_secret,
                                      const std::string& token_key,
                                      const std::string& token_secret,
                                      std::string* result) {
  DCHECK(request_url_with_parameters.is_valid());
  Parameters parameters;
  if (request_url_with_parameters.has_query()) {
    const std::string& query = request_url_with_parameters.query();
    if (!query.empty()) {
      if (!ParseQuery(query, &parameters))
        return false;
    }
  }
  std::string spec = request_url_with_parameters.spec();
  std::string url_without_parameters = spec;
  std::string::size_type question = spec.find("?");
  if (question != std::string::npos)
    url_without_parameters = spec.substr(0,question);
  return SignURL(GURL(url_without_parameters), parameters, signature_method,
                 http_method, consumer_key, consumer_secret, token_key,
                 token_secret, result);
}

// static
bool OAuthRequestSigner::SignURL(
    const GURL& request_base_url,
    const Parameters& request_parameters,
    SignatureMethod signature_method,
    HttpMethod http_method,
    const std::string& consumer_key,
    const std::string& consumer_secret,
    const std::string& token_key,
    const std::string& token_secret,
    std::string* signed_text_return) {
  DCHECK(request_base_url.is_valid());
  Parameters parameters(request_parameters);
  bool is_signed = SignParameters(request_base_url, signature_method,
                                  http_method, consumer_key, consumer_secret,
                                  token_key, token_secret, &parameters);
  if (is_signed) {
    std::string signed_text;
    switch (http_method) {
      case GET_METHOD:
        signed_text = request_base_url.spec() + '?';
        // Intentionally falling through
      case POST_METHOD:
        signed_text += BuildBaseStringParameters(parameters);
        break;
      default:
        NOTREACHED();
    }
    *signed_text_return = signed_text;
  }
  return is_signed;
}

// static
bool OAuthRequestSigner::SignAuthHeader(
    const GURL& request_base_url,
    const Parameters& request_parameters,
    SignatureMethod signature_method,
    HttpMethod http_method,
    const std::string& consumer_key,
    const std::string& consumer_secret,
    const std::string& token_key,
    const std::string& token_secret,
    std::string* signed_text_return) {
  DCHECK(request_base_url.is_valid());
  Parameters parameters(request_parameters);
  bool is_signed = SignParameters(request_base_url, signature_method,
                                  http_method, consumer_key, consumer_secret,
                                  token_key, token_secret, &parameters);
  if (is_signed) {
    std::string signed_text = "OAuth ";
    bool first = true;
    for (Parameters::const_iterator param = parameters.begin();
         param != parameters.end();
         ++param) {
      if (first)
        first = false;
      else
        signed_text += ", ";
      signed_text +=
          StringPrintf("%s=\"%s\"",
                       OAuthRequestSigner::Encode(param->first).c_str(),
                       OAuthRequestSigner::Encode(param->second).c_str());
    }
    *signed_text_return = signed_text;
  }
  return is_signed;
}
<commit_msg>[Coverity] Fix pass-by-val to pass-by-ref<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/net/gaia/oauth_request_signer.h"

#include <cctype>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "base/base64.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "crypto/hmac.h"
#include "googleurl/src/gurl.h"

namespace {

static const int kHexBase = 16;
static char kHexDigits[] = "0123456789ABCDEF";
static const size_t kHmacDigestLength = 20;
static const int kMaxNonceLength = 30;
static const int kMinNonceLength = 15;

static const char kOAuthConsumerKeyLabel[] = "oauth_consumer_key";
static const char kOAuthConsumerSecretLabel[] = "oauth_consumer_secret";
static const char kOAuthNonceCharacters[] =
    "abcdefghijklmnopqrstuvwyz"
    "ABCDEFGHIJKLMNOPQRSTUVWYZ"
    "0123456789_";
static const char kOAuthNonceLabel[] = "oauth_nonce";
static const char kOAuthSignatureLabel[] = "oauth_signature";
static const char kOAuthSignatureMethodLabel[] = "oauth_signature_method";
static const char kOAuthTimestampLabel[] = "oauth_timestamp";
static const char kOAuthTokenLabel[] = "oauth_token";
static const char kOAuthTokenSecretLabel[] = "oauth_token_secret";
static const char kOAuthVersion[] = "1.0";
static const char kOAuthVersionLabel[] = "oauth_version";

enum ParseQueryState {
  START_STATE,
  KEYWORD_STATE,
  VALUE_STATE,
};

const std::string HttpMethodName(OAuthRequestSigner::HttpMethod method) {
  switch (method) {
    case OAuthRequestSigner::GET_METHOD:
      return "GET";
    case OAuthRequestSigner::POST_METHOD:
      return "POST";
  }
  NOTREACHED();
  return *(new std::string());
}

const std::string SignatureMethodName(
    OAuthRequestSigner::SignatureMethod method) {
  switch (method) {
    case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
      return "HMAC-SHA1";
    case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
      return "RSA-SHA1";
    case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
      return "PLAINTEXT";
  }
  NOTREACHED();
  return *(new std::string());
}

std::string BuildBaseString(const GURL& request_base_url,
                            OAuthRequestSigner::HttpMethod http_method,
                            const std::string& base_parameters) {
  return StringPrintf("%s&%s&%s",
                      HttpMethodName(http_method).c_str(),
                      OAuthRequestSigner::Encode(
                          request_base_url.spec()).c_str(),
                      OAuthRequestSigner::Encode(
                          base_parameters).c_str());
}

std::string BuildBaseStringParameters(
    const OAuthRequestSigner::Parameters& parameters) {
  std::string result = "";
  OAuthRequestSigner::Parameters::const_iterator cursor;
  OAuthRequestSigner::Parameters::const_iterator limit;
  bool first = true;
  for (cursor = parameters.begin(), limit = parameters.end();
       cursor != limit;
       ++cursor) {
    if (first)
      first = false;
    else
      result += '&';
    result += OAuthRequestSigner::Encode(cursor->first);
    result += '=';
    result += OAuthRequestSigner::Encode(cursor->second);
  }
  return result;
}

std::string GenerateNonce() {
  char result[kMaxNonceLength + 1];
  int length = base::RandUint64() % (kMaxNonceLength - kMinNonceLength + 1) +
      kMinNonceLength;
  result[length] = '\0';
  for (int index = 0; index < length; ++index)
    result[index] = kOAuthNonceCharacters[
        base::RandUint64() % (sizeof(kOAuthNonceCharacters) - 1)];
  return result;
}

std::string GenerateTimestamp() {
  return base::StringPrintf(
      "%" PRId64,
      (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()).InSeconds());
}

// Creates a string-to-string, keyword-value map from a parameter/query string
// that uses ampersand (&) to seperate paris and equals (=) to seperate
// keyword from value.
bool ParseQuery(const std::string& query,
                OAuthRequestSigner::Parameters* parameters_result) {
  std::string::const_iterator cursor;
  std::string keyword;
  std::string::const_iterator limit;
  OAuthRequestSigner::Parameters parameters;
  ParseQueryState state;
  std::string value;

  state = START_STATE;
  for (cursor = query.begin(), limit = query.end();
       cursor != limit;
       ++cursor) {
    char character = *cursor;
    switch (state) {
      case KEYWORD_STATE:
        switch (character) {
          case '&':
            parameters[keyword] = value;
            keyword = "";
            value = "";
            state = START_STATE;
            break;
          case '=':
            state = VALUE_STATE;
            break;
          default:
            keyword += character;
        }
        break;
      case START_STATE:
        switch (character) {
          case '&':  // Intentionally falling through
          case '=':
            return false;
          default:
            keyword += character;
            state = KEYWORD_STATE;
        }
        break;
      case VALUE_STATE:
        switch (character) {
          case '=':
            return false;
          case '&':
            parameters[keyword] = value;
            keyword = "";
            value = "";
            state = START_STATE;
            break;
          default:
            value += character;
        }
        break;
    }
  }
  switch (state) {
    case START_STATE:
      break;
    case KEYWORD_STATE:  // Intentionally falling through
    case VALUE_STATE:
      parameters[keyword] = value;
      break;
    default:
      NOTREACHED();
  }
  *parameters_result = parameters;
  return true;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is HMAC-SHA1.
bool SignHmacSha1(const std::string& text,
                  const std::string& key,
                  std::string* signature_return) {
  crypto::HMAC hmac(crypto::HMAC::SHA1);
  DCHECK(hmac.DigestLength() == kHmacDigestLength);
  unsigned char digest[kHmacDigestLength];
  bool result = hmac.Init(key) &&
      hmac.Sign(text, digest, kHmacDigestLength) &&
      base::Base64Encode(std::string(reinterpret_cast<const char*>(digest),
                                     kHmacDigestLength),
                         signature_return);
  return result;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is PLAINTEXT.
//
// Not yet implemented, and might never be.
bool SignPlaintext(const std::string& text,
                   const std::string& key,
                   std::string* result) {
  NOTIMPLEMENTED();
  return false;
}

// Creates the value for the oauth_signature parameter when the
// oauth_signature_method is RSA-SHA1.
//
// Not yet implemented, and might never be.
bool SignRsaSha1(const std::string& text,
                 const std::string& key,
                 std::string* result) {
  NOTIMPLEMENTED();
  return false;
}

// Adds parameters that are required by OAuth added as needed to |parameters|.
void PrepareParameters(OAuthRequestSigner::Parameters* parameters,
                       OAuthRequestSigner::SignatureMethod signature_method,
                       OAuthRequestSigner::HttpMethod http_method,
                       const std::string& consumer_key,
                       const std::string& token_key) {
  if (parameters->find(kOAuthNonceLabel) == parameters->end())
    (*parameters)[kOAuthNonceLabel] = GenerateNonce();

  if (parameters->find(kOAuthTimestampLabel) == parameters->end())
    (*parameters)[kOAuthTimestampLabel] = GenerateTimestamp();

  (*parameters)[kOAuthConsumerKeyLabel] = consumer_key;
  (*parameters)[kOAuthSignatureMethodLabel] =
      SignatureMethodName(signature_method);
  (*parameters)[kOAuthTokenLabel] = token_key;
  (*parameters)[kOAuthVersionLabel] = kOAuthVersion;
}

// Implements shared signing logic, generating the signature and storing it in
// |parameters|. Returns true if the signature has been generated succesfully.
bool SignParameters(const GURL& request_base_url,
                    OAuthRequestSigner::SignatureMethod signature_method,
                    OAuthRequestSigner::HttpMethod http_method,
                    const std::string& consumer_key,
                    const std::string& consumer_secret,
                    const std::string& token_key,
                    const std::string& token_secret,
                    OAuthRequestSigner::Parameters* parameters) {
  DCHECK(request_base_url.is_valid());
  PrepareParameters(parameters, signature_method, http_method,
                    consumer_key, token_key);
  std::string base_parameters = BuildBaseStringParameters(*parameters);
  std::string base = BuildBaseString(request_base_url, http_method,
                                     base_parameters);
  std::string key = consumer_secret + '&' + token_secret;
  bool is_signed = false;
  std::string signature;
  switch (signature_method) {
    case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
      is_signed = SignHmacSha1(base, key, &signature);
      break;
    case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
      is_signed = SignRsaSha1(base, key, &signature);
      break;
    case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
      is_signed = SignPlaintext(base, key, &signature);
      break;
    default:
      NOTREACHED();
  }
  if (is_signed)
    (*parameters)[kOAuthSignatureLabel] = signature;
  return is_signed;
}

}  // namespace

// static
bool OAuthRequestSigner::Decode(const std::string& text,
                                std::string* decoded_text) {
  std::string accumulator = "";
  std::string::const_iterator cursor;
  std::string::const_iterator limit;
  for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
    char character = *cursor;
    if (character == '%') {
      ++cursor;
      if (cursor == limit)
        return false;
      char* first = strchr(kHexDigits, *cursor);
      if (!first)
        return false;
      int high = first - kHexDigits;
      DCHECK(high >= 0 && high < kHexBase);

      ++cursor;
      if (cursor == limit)
        return false;
      char* second = strchr(kHexDigits, *cursor);
      if (!second)
        return false;
      int low = second - kHexDigits;
      DCHECK(low >= 0 || low < kHexBase);

      char decoded = static_cast<char>(high * kHexBase + low);
      DCHECK(!(IsAsciiAlpha(decoded) || IsAsciiDigit(decoded)));
      DCHECK(!(decoded && strchr("-._~", decoded)));
      accumulator += decoded;
    } else {
      accumulator += character;
    }
  }
  *decoded_text = accumulator;
  return true;
}

// static
std::string OAuthRequestSigner::Encode(const std::string& text) {
  std::string result = "";
  std::string::const_iterator cursor;
  std::string::const_iterator limit;
  for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
    char character = *cursor;
    if (IsAsciiAlpha(character) || IsAsciiDigit(character)) {
      result += character;
    } else {
      switch (character) {
        case '-':
        case '.':
        case '_':
        case '~':
          result += character;
          break;
        default:
          unsigned char byte = static_cast<unsigned char>(character);
          result = result + '%' + kHexDigits[byte / kHexBase] +
              kHexDigits[byte % kHexBase];
      }
    }
  }
  return result;
}

// static
bool OAuthRequestSigner::ParseAndSign(const GURL& request_url_with_parameters,
                                      SignatureMethod signature_method,
                                      HttpMethod http_method,
                                      const std::string& consumer_key,
                                      const std::string& consumer_secret,
                                      const std::string& token_key,
                                      const std::string& token_secret,
                                      std::string* result) {
  DCHECK(request_url_with_parameters.is_valid());
  Parameters parameters;
  if (request_url_with_parameters.has_query()) {
    const std::string& query = request_url_with_parameters.query();
    if (!query.empty()) {
      if (!ParseQuery(query, &parameters))
        return false;
    }
  }
  std::string spec = request_url_with_parameters.spec();
  std::string url_without_parameters = spec;
  std::string::size_type question = spec.find("?");
  if (question != std::string::npos)
    url_without_parameters = spec.substr(0,question);
  return SignURL(GURL(url_without_parameters), parameters, signature_method,
                 http_method, consumer_key, consumer_secret, token_key,
                 token_secret, result);
}

// static
bool OAuthRequestSigner::SignURL(
    const GURL& request_base_url,
    const Parameters& request_parameters,
    SignatureMethod signature_method,
    HttpMethod http_method,
    const std::string& consumer_key,
    const std::string& consumer_secret,
    const std::string& token_key,
    const std::string& token_secret,
    std::string* signed_text_return) {
  DCHECK(request_base_url.is_valid());
  Parameters parameters(request_parameters);
  bool is_signed = SignParameters(request_base_url, signature_method,
                                  http_method, consumer_key, consumer_secret,
                                  token_key, token_secret, &parameters);
  if (is_signed) {
    std::string signed_text;
    switch (http_method) {
      case GET_METHOD:
        signed_text = request_base_url.spec() + '?';
        // Intentionally falling through
      case POST_METHOD:
        signed_text += BuildBaseStringParameters(parameters);
        break;
      default:
        NOTREACHED();
    }
    *signed_text_return = signed_text;
  }
  return is_signed;
}

// static
bool OAuthRequestSigner::SignAuthHeader(
    const GURL& request_base_url,
    const Parameters& request_parameters,
    SignatureMethod signature_method,
    HttpMethod http_method,
    const std::string& consumer_key,
    const std::string& consumer_secret,
    const std::string& token_key,
    const std::string& token_secret,
    std::string* signed_text_return) {
  DCHECK(request_base_url.is_valid());
  Parameters parameters(request_parameters);
  bool is_signed = SignParameters(request_base_url, signature_method,
                                  http_method, consumer_key, consumer_secret,
                                  token_key, token_secret, &parameters);
  if (is_signed) {
    std::string signed_text = "OAuth ";
    bool first = true;
    for (Parameters::const_iterator param = parameters.begin();
         param != parameters.end();
         ++param) {
      if (first)
        first = false;
      else
        signed_text += ", ";
      signed_text +=
          StringPrintf("%s=\"%s\"",
                       OAuthRequestSigner::Encode(param->first).c_str(),
                       OAuthRequestSigner::Encode(param->second).c_str());
    }
    *signed_text_return = signed_text;
  }
  return is_signed;
}
<|endoftext|>


<commit_before>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef _Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_
#define _Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_ 1

#include "../../../Debug/Trace.h"

namespace Stroika::Foundation::Database::SQL::ORM {

    /*
     ********************************************************************************
     ******************************** TableConnection *******************************
     ********************************************************************************
     */
    template <typename T, typename TRAITS>
    TableConnection<T, TRAITS>::TableConnection (const Connection::Ptr& conn, const Schema::Table& tableSchema, const ObjectVariantMapper& objectVariantMapper)
        : fConnection_{conn}
        , fTableSchema_{tableSchema}
        , fObjectVariantMapper_{objectVariantMapper}
        , fGetByID_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetByID ())}
        , fGetAll_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetAllElements ())}
        , fAddNew_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.Insert ())}
        , fUpdate_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.UpdateByID ())}
    {
        Require (conn != nullptr); // too late, but good docs
    }
    template <typename T, typename TRAITS>
    optional<T> TableConnection<T, TRAITS>::GetByID (const typename TRAITS::IDType& id)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fGetByID_Statement_.Reset ();
        fGetByID_Statement_.Bind (initializer_list<KeyValuePair<String, VariantValue>>{{fTableSchema_.GetIDField ()->fName, VariantValue{static_cast<Memory::BLOB> (id)}}});
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace ("SQL: %s", fGetByID_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        auto rows = fGetByID_Statement_.GetAllRows ()
                        .Select<T> ([this] (const Statement::Row& r) {
                            return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)});
                        });
        if (rows.empty ()) {
            return nullopt;
        }
        Ensure (rows.size () == 1); // cuz arg sb a key
        return *rows.First ();
    }
    template <typename T, typename TRAITS>
    Sequence<T> TableConnection<T, TRAITS>::GetAll ()
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace ("SQL: %s", fGetAll_Statement_.GetSQL ().c_str ());
        }
        auto rows = fGetAll_Statement_.GetAllRows ()
                        .Select<T> ([this] (const Statement::Row& r) {
                            return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)});
                        });
        return rows;
    }
    template <typename T, typename TRAITS>
    void TableConnection<T, TRAITS>::AddNew (const T& v)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fAddNew_Statement_.Reset ();
        fAddNew_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).As<Mapping<String, VariantValue>> ()));
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace ("SQL: %s", fAddNew_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        fAddNew_Statement_.Execute ();
    }
    template <typename T, typename TRAITS>
    void TableConnection<T, TRAITS>::Update (const T& v)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fUpdate_Statement_.Reset ();
        fUpdate_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).As<Mapping<String, VariantValue>> ()));
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace ("SQL: %s", fUpdate_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        fUpdate_Statement_.Execute ();
    }

}

#endif /*_Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_*/
<commit_msg>small fixes to new ORM code (stricly c++ gcc and other bugfixes)<commit_after>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef _Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_
#define _Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_ 1

#include "../../../Debug/Trace.h"

namespace Stroika::Foundation::Database::SQL::ORM {

    /*
     ********************************************************************************
     ******************************** TableConnection *******************************
     ********************************************************************************
     */
    template <typename T, typename TRAITS>
    TableConnection<T, TRAITS>::TableConnection (const Connection::Ptr& conn, const Schema::Table& tableSchema, const ObjectVariantMapper& objectVariantMapper)
        : fConnection_{conn}
        , fTableSchema_{tableSchema}
        , fObjectVariantMapper_{objectVariantMapper}
        , fGetByID_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetByID ())}
        , fGetAll_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.GetAllElements ())}
        , fAddNew_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.Insert ())}
        , fUpdate_Statement_{conn->mkStatement (Schema::StandardSQLStatements{tableSchema}.UpdateByID ())}
    {
        Require (conn != nullptr); // too late, but good docs
    }
    template <typename T, typename TRAITS>
    optional<T> TableConnection<T, TRAITS>::GetByID (const typename TRAITS::IDType& id)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fGetByID_Statement_.Reset ();
        fGetByID_Statement_.Bind (initializer_list<KeyValuePair<String, VariantValue>>{{fTableSchema_.GetIDField ()->fName, VariantValue{static_cast<Memory::BLOB> (id)}}});
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace (L"SQL: %s", fGetByID_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        auto rows = fGetByID_Statement_.GetAllRows ()
                        .Select<T> ([this] (const Statement::Row& r) {
                            return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)});
                        });
        if (rows.empty ()) {
            return nullopt;
        }
        Ensure (rows.size () == 1); // cuz arg sb a key
        return *rows.First ();
    }
    template <typename T, typename TRAITS>
    Sequence<T> TableConnection<T, TRAITS>::GetAll ()
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace (L"SQL: %s", fGetAll_Statement_.GetSQL ().c_str ());
        }
        auto rows = fGetAll_Statement_.GetAllRows ()
                        .Select<T> ([this] (const Statement::Row& r) {
                            return fObjectVariantMapper_.ToObject<T> (VariantValue{fTableSchema_.MapFromDB (r)});
                        });
        return rows;
    }
    template <typename T, typename TRAITS>
    void TableConnection<T, TRAITS>::AddNew (const T& v)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fAddNew_Statement_.Reset ();
        fAddNew_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ()));
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace (L"SQL: %s", fAddNew_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        fAddNew_Statement_.Execute ();
    }
    template <typename T, typename TRAITS>
    void TableConnection<T, TRAITS>::Update (const T& v)
    {
        lock_guard<const AssertExternallySynchronizedLock> critSec{*this};
        using DataExchange::VariantValue;
        using Stroika::Foundation::Common::KeyValuePair;
        fUpdate_Statement_.Reset ();
        fUpdate_Statement_.Bind (fTableSchema_.MapToDB (fObjectVariantMapper_.FromObject (v).template As<Mapping<String, VariantValue>> ()));
        if constexpr (TRAITS::kTraceLogEachRequest) {
            DbgTrace (L"SQL: %s", fUpdate_Statement_.GetSQL (Statement::WhichSQLFlag::eExpanded).c_str ());
        }
        fUpdate_Statement_.Execute ();
    }

}

#endif /*_Stroika_Foundation_Database_SQL_ORM_TableConnection_inl_*/
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperCompositeApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbOGRDataToSamplePositionFilter.h"

namespace otb
{
namespace Wrapper
{

class TrainRegressionFileHandler
{
public:
  void AddFileNameList(const std::string& key, const std::vector<std::string> & fileNameList)
  {
    fileNameMap[key] = fileNameList;
  }

  std::vector<std::string> GetFileNameList(const std::string& key)
  {
    return fileNameMap[key];
  }

  bool Clear()
  {
    bool res = true;
    for (const auto & fileNameList : fileNameMap)
      for (const auto & fileName : fileNameList.second)
        res = res && RemoveFile(fileName);

    fileNameMap.clear();
    return res;
  }

private:
  std::map< std::string, std::vector<std::string>> fileNameMap;

  bool RemoveFile(const std::string & filename)
  {
    bool res = true;
    if( itksys::SystemTools::FileExists( filename ) )
    {
      size_t posExt = filename.rfind( '.' );
      if( posExt != std::string::npos && filename.compare( posExt, std::string::npos, ".shp" ) == 0 )
      {
        std::string shxPath = filename.substr( 0, posExt ) + std::string( ".shx" );
        std::string dbfPath = filename.substr( 0, posExt ) + std::string( ".dbf" );
        std::string prjPath = filename.substr( 0, posExt ) + std::string( ".prj" );
        RemoveFile( shxPath );
        RemoveFile( dbfPath );
        RemoveFile( prjPath );
      }
    res = itksys::SystemTools::RemoveFile( filename );
    }
  return res;
  }
};

class TrainImagesRegression : public CompositeApplication
{
public:
  /** Standard class typedefs. */
  typedef TrainImagesRegression Self;
  typedef CompositeApplication Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  /** Standard macro */
  itkTypeMacro( TrainImagesRegression, Superclass );

protected:

  void AddRegressionField(const std::string &inVectorFileName,
                       const std::string &outVectorFileName,
                       const std::string &fieldName)
  {
    auto setFieldAppli = GetInternalApplication("setfield");

    setFieldAppli->SetParameterString("in", inVectorFileName);
    setFieldAppli->SetParameterString("out", outVectorFileName);
    setFieldAppli->SetParameterString("fn", fieldName);
    setFieldAppli->SetParameterString("fv", "0");

    ExecuteInternal("setfield");
  }

  void ComputePolygonStatistics(const std::string &inVectorFileName,
                                FloatVectorImageType * inputImage,
                                const std::string &statisticFileName,
                                const std::string &fieldName)
  {
    auto polygonClassAppli = GetInternalApplication("polystat");

    polygonClassAppli->SetParameterInputImage( "in", inputImage );
    polygonClassAppli->SetParameterString( "vec", inVectorFileName);
    polygonClassAppli->SetParameterString( "out", statisticFileName);

    polygonClassAppli->UpdateParameters();
    polygonClassAppli->SetParameterString( "field", fieldName);

    ExecuteInternal( "polystat" );
  }

  void ComputeSamplingRate(const std::vector<std::string> & statisticsFileNames,
                           const std::string & outputFileName,
                           int numberOfSample = 0)
  {
    auto samplingRateAppli = GetInternalApplication("rates");

    samplingRateAppli->SetParameterStringList( "il", statisticsFileNames);
    samplingRateAppli->SetParameterString("out", outputFileName);

    if (numberOfSample)
    {
      samplingRateAppli->SetParameterString("strategy", "constant");

      // TODO why nb is a string in MultiImageSamplingRate + MultiImageSamplingRate seems to return nb-1 samples ...
      samplingRateAppli->SetParameterString("strategy.constant.nb", std::to_string(numberOfSample));
    }
    else
    {
      samplingRateAppli->SetParameterString("strategy", "all");
    }

    ExecuteInternal( "rates");
  }

  void PerformSampleSelection()
  {

  }

  void PerformSampleExtraction()
  {

  }

  void InitIO()
  {
    AddParameter( ParameterType_Group, "io", "Input and output data" );
    SetParameterDescription( "io", "This group of parameters allows setting input and output data." );

    AddParameter( ParameterType_InputImageList, "io.il", "Input Image List" );
    SetParameterDescription( "io.il", "A list of input images." );
    MandatoryOn( "io.il" );

    AddParameter( ParameterType_InputVectorDataList, "io.vd", "Input Vector Data List" );
    SetParameterDescription( "io.vd", "A list of vector data to select the training samples." );
    MandatoryOn( "io.vd" );
  }

  void InitSampling()
  {
    AddApplication( "VectorDataSetField", "setfield", "Set additional vector field");
    AddApplication( "PolygonClassStatistics", "polystat", "Polygon analysis" );
    AddApplication( "MultiImageSamplingRate", "rates", "Sampling rates" );

    AddParameter( ParameterType_Group, "sample", "Sampling parameters" );
    SetParameterDescription( "sample", "This group of parameters allows setting sampling parameters" );

    AddParameter( ParameterType_Int, "sample.nt", "Number of training samples" );
    SetParameterDescription( "sample.nt", "Number of training samples." );
    MandatoryOff( "sample.nt" );

    AddApplication( "SampleSelection", "select", "Sample selection" );
    //AddApplication( "SampleExtraction", "extraction", "Sample extraction" );

  }

  void InitLearning()
  {
  }

private:

  void DoInit() override
  {
    SetName("TrainImagesRegression");
    SetDescription(" ");

    SetDocLongDescription(" ");
    SetDocLimitations(" ");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Learning);

    SetOfficialDocLink();

    ClearApplications();

    InitIO();
    InitSampling();
    InitLearning();
  }

  void DoUpdateParameters() override
  {
  }

  void DoExecute() override
  {
    std::string predictorFieldName = "regclass";

    auto vectorFileNames = GetParameterStringList( "io.vd" );
    FloatVectorImageListType* inputImageList = GetParameterImageList( "io.il" );

    std::vector<std::string> statisticsFileNames;

    for (unsigned int i =0; i < vectorFileNames.size(); i++)
    {
      std::string outfile = "setfield"+ std::to_string(i) +".shp";// TODO io file handler
      AddRegressionField(vectorFileNames[i], outfile, predictorFieldName);

      std::cout << "Regression field added" << std::endl;

      statisticsFileNames.push_back("polygonstat"+ std::to_string(i) +".xml");

      ComputePolygonStatistics(outfile, inputImageList->GetNthElement(i), statisticsFileNames[i], predictorFieldName);

      std::cout << "Polygon class statistic done" << std::endl;
    }

    //TODO validation set ??

    std::string samplingRateFileName = "rates.xml";

    if (HasValue("sample.nt"))
      ComputeSamplingRate(statisticsFileNames, samplingRateFileName, GetParameterInt("sample.nt"));
    else
      ComputeSamplingRate(statisticsFileNames, samplingRateFileName);

    std::cout << "Sampling rate computation done" << std::endl;

    for (unsigned int i =0; i < vectorFileNames.size(); i++)
    {
      PerformSampleSelection();
      PerformSampleExtraction();
    }

  }
};

} //end namespace Wrapper
} //end namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::TrainImagesRegression)
<commit_msg>ENH: refactor the file handler<commit_after>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperCompositeApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbOGRDataToSamplePositionFilter.h"

namespace otb
{
namespace Wrapper
{

class TrainImagesRegression : public CompositeApplication
{
public:
  /** Standard class typedefs. */
  typedef TrainImagesRegression Self;
  typedef CompositeApplication Superclass;
  typedef itk::SmartPointer<Self> Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  /** Standard macro */
  itkTypeMacro( TrainImagesRegression, Superclass );

protected:

  void AddRegressionField()
  {
    auto setFieldAppli = GetInternalApplication("setfield");
    auto inputFileNames = GetParameterStringList( "io.vd" );
    auto& outputFileNames =  m_FileHandler[ "inputWithClassField" ];

    setFieldAppli->SetParameterString("fn", m_PredictorFieldName);
    setFieldAppli->SetParameterString("fv", "0");

    for (unsigned int i =0; i < inputFileNames.size(); i++)
    {
      outputFileNames.push_back("setfield"+ std::to_string(i) +".shp");// TODO io file handler
      setFieldAppli->SetParameterString("in", inputFileNames[i]);
      setFieldAppli->SetParameterString("out", outputFileNames[i]);

      // Call ExecuteAndWriteOutput because VectorDataSetField's ExecuteInternal() does not write vector data.
      setFieldAppli->ExecuteAndWriteOutput();
    }
  }

  void ComputePolygonStatistics()
  {
    auto polygonClassAppli = GetInternalApplication("polystat");
    auto& input = m_FileHandler[ "inputWithClassField" ];
    auto& output = m_FileHandler[ "statsFiles" ];
    FloatVectorImageListType* inputImageList = GetParameterImageList( "io.il" );

    for (unsigned int i =0; i < input.size(); i++)
    {
      output.push_back("polygonstat"+ std::to_string(i) +".xml");

      polygonClassAppli->SetParameterInputImage( "in", inputImageList->GetNthElement(i) );
      polygonClassAppli->SetParameterString( "vec", input[i]);
      polygonClassAppli->SetParameterString( "out", output[i]);

      polygonClassAppli->UpdateParameters();
      polygonClassAppli->SetParameterString( "field", m_PredictorFieldName);

      ExecuteInternal( "polystat" );
    }

  }

  void ComputeSamplingRate()
  {
    auto samplingRateAppli = GetInternalApplication("rates");

    samplingRateAppli->SetParameterStringList( "il", m_FileHandler[ "statsFiles" ]);

    std::string outputFileName = "rates.xml";
    samplingRateAppli->SetParameterString("out", outputFileName);

    if (HasValue("sample.nt"))
    {
      samplingRateAppli->SetParameterString("strategy", "constant");

      // TODO why nb is a string in MultiImageSamplingRate + MultiImageSamplingRate seems to return nb-1 samples ...
      samplingRateAppli->SetParameterString("strategy.constant.nb", std::to_string(GetParameterInt("sample.nt")));
    }
    else
    {
      samplingRateAppli->SetParameterString("strategy", "all");
    }

    ExecuteInternal( "rates");

    //TODO add the created file (rates_i.xml) to the file handler for cleaning

  }

  void SelectSamples()
  {

  }

  void ExtractSamples()
  {

  }

  void TrainModel()
  {

  }

  void InitIO()
  {
    AddParameter( ParameterType_Group, "io", "Input and output data" );
    SetParameterDescription( "io", "This group of parameters allows setting input and output data." );

    AddParameter( ParameterType_InputImageList, "io.il", "Input Image List" );
    SetParameterDescription( "io.il", "A list of input images." );
    MandatoryOn( "io.il" );

    AddParameter( ParameterType_InputVectorDataList, "io.vd", "Input Vector Data List" );
    SetParameterDescription( "io.vd", "A list of vector data to select the training samples." );
    MandatoryOn( "io.vd" );
  }

  void InitSampling()
  {
    AddApplication( "VectorDataSetField", "setfield", "Set additional vector field");
    AddApplication( "PolygonClassStatistics", "polystat", "Polygon analysis" );
    AddApplication( "MultiImageSamplingRate", "rates", "Sampling rates" );

    AddParameter( ParameterType_Group, "sample", "Sampling parameters" );
    SetParameterDescription( "sample", "This group of parameters allows setting sampling parameters" );

    AddParameter( ParameterType_Int, "sample.nt", "Number of training samples" );
    SetParameterDescription( "sample.nt", "Number of training samples." );
    MandatoryOff( "sample.nt" );

    AddApplication( "SampleSelection", "select", "Sample selection" );
    //AddApplication( "SampleExtraction", "extraction", "Sample extraction" );

  }

  void InitLearning()
  {
  }

private:

  void DoInit() override
  {
    SetName("TrainImagesRegression");
    SetDescription(" ");

    SetDocLongDescription(" ");
    SetDocLimitations(" ");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(" ");

    AddDocTag(Tags::Learning);

    SetOfficialDocLink();

    ClearApplications();

    InitIO();
    InitSampling();
    InitLearning();
  }

  void DoUpdateParameters() override
  {
  }

  bool ClearFileHandler()
  {
    bool res = true;
    for (const auto & fileNameList : m_FileHandler)
    {
      for (const auto & filename : fileNameList.second)
      {
        res = true;
        if( itksys::SystemTools::FileExists( filename ) )
        {
          size_t posExt = filename.rfind( '.' );
          if( posExt != std::string::npos && filename.compare( posExt, std::string::npos, ".shp" ) == 0 )
          {
            std::string shxPath = filename.substr( 0, posExt ) + std::string( ".shx" );
            std::string dbfPath = filename.substr( 0, posExt ) + std::string( ".dbf" );
            std::string prjPath = filename.substr( 0, posExt ) + std::string( ".prj" );
            itksys::SystemTools::RemoveFile( shxPath );
            itksys::SystemTools::RemoveFile( dbfPath );
            itksys::SystemTools::RemoveFile( prjPath );
          }
        res = itksys::SystemTools::RemoveFile( filename );
        }
      }
    }
    m_FileHandler.clear();
    return res;
  }

  void DoExecute() override
  {
    //TODO validation set ??

    AddRegressionField();

    std::cout << "Regression field added" << std::endl;

    ComputePolygonStatistics();

    std::cout << "Polygon class statistic done" << std::endl;

    ComputeSamplingRate();

    std::cout << "Sampling rate computation done" << std::endl;

    SelectSamples();

    ExtractSamples();

    TrainModel();

    ClearFileHandler();
  }

  std::string m_PredictorFieldName = "regclass";
  std::map< std::string, std::vector<std::string>> m_FileHandler;

};

} //end namespace Wrapper
} //end namespace otb

OTB_APPLICATION_EXPORT(otb::Wrapper::TrainImagesRegression)
<|endoftext|>