/* * Code for autogenerating rules or filters from a message. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * Authors: * Michael Zucchi * Ettore Perazzoli * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "mail-vfolder.h" #include "mail-autofilter.h" #include "em-utils.h" #include "e-util/e-error.h" #include "e-util/e-util-private.h" #include "em-vfolder-context.h" #include "em-vfolder-rule.h" #include "em-vfolder-editor.h" #include "em-filter-context.h" #include "em-filter-rule.h" #include "em-filter-editor.h" #include "filter/filter-option.h" #include #include #define d(x) static void rule_match_recipients (RuleContext *context, FilterRule *rule, CamelInternetAddress *iaddr) { FilterPart *part; FilterElement *element; gint i; const gchar *real, *addr; gchar *namestr; /* address types etc should handle multiple values */ for (i = 0; camel_internet_address_get (iaddr, i, &real, &addr); i++) { part = rule_context_create_part (context, "to"); filter_rule_add_part ((FilterRule *)rule, part); element = filter_part_find_element (part, "recipient-type"); filter_option_set_current ((FilterOption *)element, "contains"); element = filter_part_find_element (part, "recipient"); filter_input_set_value ((FilterInput *)element, addr); namestr = g_strdup_printf (_("Mail to %s"), real && real[0] ? real : addr); filter_rule_set_name (rule, namestr); g_free (namestr); } } /* remove 're' part of a subject */ static const gchar * strip_re (const gchar *subject) { const guchar *s, *p; s = (guchar *) subject; while (*s) { while (isspace (*s)) s++; if (s[0] == 0) break; if ((s[0] == 'r' || s[0] == 'R') && (s[1] == 'e' || s[1] == 'E')) { p = s+2; while (isdigit (*p) || (ispunct (*p) && (*p != ':'))) p++; if (*p == ':') { s = p + 1; } else break; } else break; } return (gchar *) s; } #if 0 gint reg_match (gchar *str, gchar *regstr) { regex_t reg; gint error; gint ret; error = regcomp(®, regstr, REG_EXTENDED|REG_ICASE|REG_NOSUB); if (error != 0) { return 0; } error = regexec(®, str, 0, NULL, 0); regfree(®); return (error == 0); } #endif static void rule_add_subject (RuleContext *context, FilterRule *rule, const gchar *text) { FilterPart *part; FilterElement *element; /* dont match on empty strings ever */ if (*text == 0) return; part = rule_context_create_part (context, "subject"); filter_rule_add_part ((FilterRule *)rule, part); element = filter_part_find_element (part, "subject-type"); filter_option_set_current ((FilterOption *)element, "contains"); element = filter_part_find_element (part, "subject"); filter_input_set_value ((FilterInput *)element, text); } static void rule_add_sender (RuleContext *context, FilterRule *rule, const gchar *text) { FilterPart *part; FilterElement *element; /* dont match on empty strings ever */ if (*text == 0) return; part = rule_context_create_part (context, "sender"); filter_rule_add_part ((FilterRule *)rule, part); element = filter_part_find_element (part, "sender-type"); filter_option_set_current ((FilterOption *)element, "contains"); element = filter_part_find_element (part, "sender"); filter_input_set_value ((FilterInput *)element, text); } /* do a bunch of things on the subject to try and detect mailing lists, remove unneeded stuff, etc */ static void rule_match_subject (RuleContext *context, FilterRule *rule, const gchar *subject) { const gchar *s; const gchar *s1, *s2; gchar *tmp; s = strip_re (subject); /* dont match on empty subject */ if (*s == 0) return; /* [blahblah] is probably a mailing list, match on it separately */ s1 = strchr (s, '['); s2 = strchr (s, ']'); if (s1 && s2 && s1 < s2) { /* probably a mailing list, match on the mailing list name */ tmp = g_alloca (s2 - s1 + 2); memcpy (tmp, s1, s2 - s1 + 1); tmp[s2 - s1 + 1] = 0; g_strstrip (tmp); rule_add_subject (context, rule, tmp); s = s2 + 1; } /* Froblah: at the start is probably something important (e.g. bug number) */ s1 = strchr (s, ':'); if (s1) { tmp = g_alloca (s1 - s + 1); memcpy (tmp, s, s1-s); tmp[s1 - s] = 0; g_strstrip (tmp); rule_add_subject (context, rule, tmp); s = s1+1; } /* just lump the rest together */ tmp = g_alloca (strlen (s) + 1); strcpy (tmp, s); g_strstrip (tmp); rule_add_subject (context, rule, tmp); } static void rule_match_mlist(RuleContext *context, FilterRule *rule, const gchar *mlist) { FilterPart *part; FilterElement *element; if (mlist[0] == 0) return; part = rule_context_create_part(context, "mlist"); filter_rule_add_part(rule, part); element = filter_part_find_element(part, "mlist-type"); filter_option_set_current((FilterOption *)element, "is"); element = filter_part_find_element (part, "mlist"); filter_input_set_value((FilterInput *)element, mlist); } static void rule_from_address (FilterRule *rule, RuleContext *context, CamelInternetAddress* addr, gint flags) { rule->grouping = FILTER_GROUP_ANY; if (flags & AUTO_FROM) { const gchar *name, *address; gchar *namestr; camel_internet_address_get (addr, 0, &name, &address); rule_add_sender (context, rule, address); if (name == NULL || name[0] == '\0') name = address; namestr = g_strdup_printf(_("Mail from %s"), name); filter_rule_set_name (rule, namestr); g_free (namestr); } if (flags & AUTO_TO) { rule_match_recipients (context, rule, addr); } } static void rule_from_message (FilterRule *rule, RuleContext *context, CamelMimeMessage *msg, gint flags) { CamelInternetAddress *addr; rule->grouping = FILTER_GROUP_ANY; if (flags & AUTO_SUBJECT) { const gchar *subject = msg->subject ? msg->subject : ""; gchar *namestr; rule_match_subject (context, rule, subject); namestr = g_strdup_printf (_("Subject is %s"), strip_re (subject)); filter_rule_set_name (rule, namestr); g_free (namestr); } /* should parse the from address into an internet address? */ if (flags & AUTO_FROM) { const CamelInternetAddress *from; gint i; const gchar *name, *address; gchar *namestr; from = camel_mime_message_get_from (msg); for (i = 0; from && camel_internet_address_get (from, i, &name, &address); i++) { rule_add_sender(context, rule, address); if (name == NULL || name[0] == '\0') name = address; namestr = g_strdup_printf(_("Mail from %s"), name); filter_rule_set_name (rule, namestr); g_free (namestr); } } if (flags & AUTO_TO) { addr = (CamelInternetAddress *)camel_mime_message_get_recipients (msg, CAMEL_RECIPIENT_TYPE_TO); if (addr) rule_match_recipients (context, rule, addr); addr = (CamelInternetAddress *)camel_mime_message_get_recipients (msg, CAMEL_RECIPIENT_TYPE_CC); if (addr) rule_match_recipients (context, rule, addr); } if (flags & AUTO_MLIST) { gchar *name, *mlist; mlist = camel_header_raw_check_mailing_list (&((CamelMimePart *)msg)->headers); if (mlist) { rule_match_mlist(context, rule, mlist); name = g_strdup_printf (_("%s mailing list"), mlist); filter_rule_set_name(rule, name); g_free(name); } g_free(mlist); } } FilterRule * em_vfolder_rule_from_message (EMVFolderContext *context, CamelMimeMessage *msg, gint flags, const gchar *source) { EMVFolderRule *rule; gchar *euri = em_uri_from_camel(source); rule = em_vfolder_rule_new (); em_vfolder_rule_add_source (rule, euri); rule_from_message ((FilterRule *)rule, (RuleContext *)context, msg, flags); g_free(euri); return (FilterRule *)rule; } FilterRule * em_vfolder_rule_from_address (EMVFolderContext *context, CamelInternetAddress *addr, gint flags, const gchar *source) { EMVFolderRule *rule; gchar *euri = em_uri_from_camel(source); rule = em_vfolder_rule_new (); em_vfolder_rule_add_source (rule, euri); rule_from_address ((FilterRule *)rule, (RuleContext *)context, addr, flags); g_free(euri); return (FilterRule *)rule; } FilterRule * filter_rule_from_message (EMFilterContext *context, CamelMimeMessage *msg, gint flags) { EMFilterRule *rule; FilterPart *part; rule = em_filter_rule_new (); rule_from_message ((FilterRule *)rule, (RuleContext *)context, msg, flags); part = em_filter_context_next_action (context, NULL); em_filter_rule_add_action (rule, filter_part_clone (part)); return (FilterRule *)rule; } void filter_gui_add_from_message (CamelMimeMessage *msg, const gchar *source, gint flags) { EMFilterContext *fc; const gchar *data_dir; gchar *user, *system; FilterRule *rule; g_return_if_fail (msg != NULL); fc = em_filter_context_new (); data_dir = em_utils_get_data_dir (); user = g_build_filename (data_dir, "filters.xml", NULL); system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL); rule_context_load ((RuleContext *)fc, system, user); g_free (system); rule = filter_rule_from_message (fc, msg, flags); filter_rule_set_source (rule, source); rule_context_add_rule_gui ((RuleContext *)fc, rule, _("Add Filter Rule"), user); g_free (user); g_object_unref (fc); } void mail_filter_rename_uri(CamelStore *store, const gchar *olduri, const gchar *newuri) { EMFilterContext *fc; const gchar *data_dir; gchar *user, *system; GList *changed; gchar *eolduri, *enewuri; eolduri = em_uri_from_camel(olduri); enewuri = em_uri_from_camel(newuri); fc = em_filter_context_new (); data_dir = em_utils_get_data_dir (); user = g_build_filename (data_dir, "filters.xml", NULL); system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL); rule_context_load ((RuleContext *)fc, system, user); g_free (system); changed = rule_context_rename_uri((RuleContext *)fc, eolduri, enewuri, g_str_equal); if (changed) { d(printf("Folder rename '%s' -> '%s' changed filters, resaving\n", olduri, newuri)); if (rule_context_save((RuleContext *)fc, user) == -1) g_warning("Could not write out changed filter rules\n"); rule_context_free_uri_list((RuleContext *)fc, changed); } g_free(user); g_object_unref(fc); g_free(enewuri); g_free(eolduri); } void mail_filter_delete_uri(CamelStore *store, const gchar *uri) { EMFilterContext *fc; const gchar *data_dir; gchar *user, *system; GList *deleted; gchar *euri; euri = em_uri_from_camel(uri); fc = em_filter_context_new (); data_dir = em_utils_get_data_dir (); user = g_build_filename (data_dir, "filters.xml", NULL); system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL); rule_context_load ((RuleContext *)fc, system, user); g_free (system); deleted = rule_context_delete_uri ((RuleContext *) fc, euri, g_str_equal); if (deleted) { EShell *shell; GtkWindow *parent; GtkWidget *dialog; GList *windows; GString *s; GList *l; s = g_string_new(""); l = deleted; while (l) { g_string_append_printf (s, " %s\n", (gchar *)l->data); l = l->next; } shell = e_shell_get_default (); windows = e_shell_get_watched_windows (shell); parent = (windows != NULL) ? GTK_WINDOW (windows->data) : NULL; dialog = e_error_new(parent, "mail:filter-updated", s->str, euri, NULL); g_string_free(s, TRUE); em_utils_show_info_silent (dialog); d(printf("Folder delete/rename '%s' changed filters, resaving\n", euri)); if (rule_context_save ((RuleContext *) fc, user) == -1) g_warning ("Could not write out changed filter rules\n"); rule_context_free_uri_list ((RuleContext *) fc, deleted); } g_free(user); g_object_unref(fc); g_free(euri); } href='#n257'>257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
/*
    This file is part of solidity.

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

    solidity is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Instruction.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "./Instruction.h"

#include <functional>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
using namespace std;
using namespace dev;
using namespace dev::solidity;

const std::map<std::string, Instruction> dev::solidity::c_instructions =
{
    { "STOP", Instruction::STOP },
    { "ADD", Instruction::ADD },
    { "SUB", Instruction::SUB },
    { "MUL", Instruction::MUL },
    { "DIV", Instruction::DIV },
    { "SDIV", Instruction::SDIV },
    { "MOD", Instruction::MOD },
    { "SMOD", Instruction::SMOD },
    { "EXP", Instruction::EXP },
    { "NOT", Instruction::NOT },
    { "LT", Instruction::LT },
    { "GT", Instruction::GT },
    { "SLT", Instruction::SLT },
    { "SGT", Instruction::SGT },
    { "EQ", Instruction::EQ },
    { "ISZERO", Instruction::ISZERO },
    { "AND", Instruction::AND },
    { "OR", Instruction::OR },
    { "XOR", Instruction::XOR },
    { "BYTE", Instruction::BYTE },
    { "ADDMOD", Instruction::ADDMOD },
    { "MULMOD", Instruction::MULMOD },
    { "SIGNEXTEND", Instruction::SIGNEXTEND },
    { "SHA3", Instruction::SHA3 },
    { "ADDRESS", Instruction::ADDRESS },
    { "BALANCE", Instruction::BALANCE },
    { "ORIGIN", Instruction::ORIGIN },
    { "CALLER", Instruction::CALLER },
    { "CALLVALUE", Instruction::CALLVALUE },
    { "CALLDATALOAD", Instruction::CALLDATALOAD },
    { "CALLDATASIZE", Instruction::CALLDATASIZE },
    { "CALLDATACOPY", Instruction::CALLDATACOPY },
    { "CODESIZE", Instruction::CODESIZE },
    { "CODECOPY", Instruction::CODECOPY },
    { "GASPRICE", Instruction::GASPRICE },
    { "EXTCODESIZE", Instruction::EXTCODESIZE },
    { "EXTCODECOPY", Instruction::EXTCODECOPY },
    { "BLOCKHASH", Instruction::BLOCKHASH },
    { "COINBASE", Instruction::COINBASE },
    { "TIMESTAMP", Instruction::TIMESTAMP },
    { "NUMBER", Instruction::NUMBER },
    { "DIFFICULTY", Instruction::DIFFICULTY },
    { "GASLIMIT", Instruction::GASLIMIT },
    { "POP", Instruction::POP },
    { "MLOAD", Instruction::MLOAD },
    { "MSTORE", Instruction::MSTORE },
    { "MSTORE8", Instruction::MSTORE8 },
    { "SLOAD", Instruction::SLOAD },
    { "SSTORE", Instruction::SSTORE },
    { "JUMP", Instruction::JUMP },
    { "JUMPI", Instruction::JUMPI },
    { "PC", Instruction::PC },
    { "MSIZE", Instruction::MSIZE },
    { "GAS", Instruction::GAS },
    { "JUMPDEST", Instruction::JUMPDEST },
    { "PUSH1", Instruction::PUSH1 },
    { "PUSH2", Instruction::PUSH2 },
    { "PUSH3", Instruction::PUSH3 },
    { "PUSH4", Instruction::PUSH4 },
    { "PUSH5", Instruction::PUSH5 },
    { "PUSH6", Instruction::PUSH6 },
    { "PUSH7", Instruction::PUSH7 },
    { "PUSH8", Instruction::PUSH8 },
    { "PUSH9", Instruction::PUSH9 },
    { "PUSH10", Instruction::PUSH10 },
    { "PUSH11", Instruction::PUSH11 },
    { "PUSH12", Instruction::PUSH12 },
    { "PUSH13", Instruction::PUSH13 },
    { "PUSH14", Instruction::PUSH14 },
    { "PUSH15", Instruction::PUSH15 },
    { "PUSH16", Instruction::PUSH16 },
    { "PUSH17", Instruction::PUSH17 },
    { "PUSH18", Instruction::PUSH18 },
    { "PUSH19", Instruction::PUSH19 },
    { "PUSH20", Instruction::PUSH20 },
    { "PUSH21", Instruction::PUSH21 },
    { "PUSH22", Instruction::PUSH22 },
    { "PUSH23", Instruction::PUSH23 },
    { "PUSH24", Instruction::PUSH24 },
    { "PUSH25", Instruction::PUSH25 },
    { "PUSH26", Instruction::PUSH26 },
    { "PUSH27", Instruction::PUSH27 },
    { "PUSH28", Instruction::PUSH28 },
    { "PUSH29", Instruction::PUSH29 },
    { "PUSH30", Instruction::PUSH30 },
    { "PUSH31", Instruction::PUSH31 },
    { "PUSH32", Instruction::PUSH32 },
    { "DUP1", Instruction::DUP1 },
    { "DUP2", Instruction::DUP2 },
    { "DUP3", Instruction::DUP3 },
    { "DUP4", Instruction::DUP4 },
    { "DUP5", Instruction::DUP5 },
    { "DUP6", Instruction::DUP6 },
    { "DUP7", Instruction::DUP7 },
    { "DUP8", Instruction::DUP8 },
    { "DUP9", Instruction::DUP9 },
    { "DUP10", Instruction::DUP10 },
    { "DUP11", Instruction::DUP11 },
    { "DUP12", Instruction::DUP12 },
    { "DUP13", Instruction::DUP13 },
    { "DUP14", Instruction::DUP14 },
    { "DUP15", Instruction::DUP15 },
    { "DUP16", Instruction::DUP16 },
    { "SWAP1", Instruction::SWAP1 },
    { "SWAP2", Instruction::SWAP2 },
    { "SWAP3", Instruction::SWAP3 },
    { "SWAP4", Instruction::SWAP4 },
    { "SWAP5", Instruction::SWAP5 },
    { "SWAP6", Instruction::SWAP6 },
    { "SWAP7", Instruction::SWAP7 },
    { "SWAP8", Instruction::SWAP8 },
    { "SWAP9", Instruction::SWAP9 },
    { "SWAP10", Instruction::SWAP10 },
    { "SWAP11", Instruction::SWAP11 },
    { "SWAP12", Instruction::SWAP12 },
    { "SWAP13", Instruction::SWAP13 },
    { "SWAP14", Instruction::SWAP14 },
    { "SWAP15", Instruction::SWAP15 },
    { "SWAP16", Instruction::SWAP16 },
    { "LOG0", Instruction::LOG0 },
    { "LOG1", Instruction::LOG1 },
    { "LOG2", Instruction::LOG2 },
    { "LOG3", Instruction::LOG3 },
    { "LOG4", Instruction::LOG4 },
    { "CREATE", Instruction::CREATE },
    { "CALL", Instruction::CALL },
    { "CALLCODE", Instruction::CALLCODE },
    { "RETURN", Instruction::RETURN },
    { "DELEGATECALL", Instruction::DELEGATECALL },
    { "REVERT", Instruction::REVERT },
    { "INVALID", Instruction::INVALID },
    { "SELFDESTRUCT", Instruction::SELFDESTRUCT }
};

static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ //                                                Add, Args, Ret, SideEffects, GasPriceTier
    { Instruction::STOP,        { "STOP",           0, 0, 0, true,  Tier::Zero } },
    { Instruction::ADD,         { "ADD",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::SUB,         { "SUB",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::MUL,         { "MUL",            0, 2, 1, false, Tier::Low } },
    { Instruction::DIV,         { "DIV",            0, 2, 1, false, Tier::Low } },
    { Instruction::SDIV,        { "SDIV",           0, 2, 1, false, Tier::Low } },
    { Instruction::MOD,         { "MOD",            0, 2, 1, false, Tier::Low } },
    { Instruction::SMOD,        { "SMOD",           0, 2, 1, false, Tier::Low } },
    { Instruction::EXP,         { "EXP",            0, 2, 1, false, Tier::Special } },
    { Instruction::NOT,         { "NOT",            0, 1, 1, false, Tier::VeryLow } },
    { Instruction::LT,          { "LT",             0, 2, 1, false, Tier::VeryLow } },
    { Instruction::GT,          { "GT",             0, 2, 1, false, Tier::VeryLow } },
    { Instruction::SLT,         { "SLT",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::SGT,         { "SGT",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::EQ,          { "EQ",             0, 2, 1, false, Tier::VeryLow } },
    { Instruction::ISZERO,      { "ISZERO",         0, 1, 1, false, Tier::VeryLow } },
    { Instruction::AND,         { "AND",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::OR,          { "OR",             0, 2, 1, false, Tier::VeryLow } },
    { Instruction::XOR,         { "XOR",            0, 2, 1, false, Tier::VeryLow } },
    { Instruction::BYTE,        { "BYTE",           0, 2, 1, false, Tier::VeryLow } },
    { Instruction::ADDMOD,      { "ADDMOD",         0, 3, 1, false, Tier::Mid } },
    { Instruction::MULMOD,      { "MULMOD",         0, 3, 1, false, Tier::Mid } },
    { Instruction::SIGNEXTEND,  { "SIGNEXTEND",     0, 2, 1, false, Tier::Low } },
    { Instruction::SHA3,        { "SHA3",           0, 2, 1, false, Tier::Special } },
    { Instruction::ADDRESS,     { "ADDRESS",        0, 0, 1, false, Tier::Base } },
    { Instruction::BALANCE,     { "BALANCE",        0, 1, 1, false, Tier::Ext } },
    { Instruction::ORIGIN,      { "ORIGIN",         0, 0, 1, false, Tier::Base } },
    { Instruction::CALLER,      { "CALLER",         0, 0, 1, false, Tier::Base } },
    { Instruction::CALLVALUE,   { "CALLVALUE",      0, 0, 1, false, Tier::Base } },
    { Instruction::CALLDATALOAD,{ "CALLDATALOAD",   0, 1, 1, false, Tier::VeryLow } },
    { Instruction::CALLDATASIZE,{ "CALLDATASIZE",   0, 0, 1, false, Tier::Base } },
    { Instruction::CALLDATACOPY,{ "CALLDATACOPY",   0, 3, 0, true, Tier::VeryLow } },
    { Instruction::CODESIZE,    { "CODESIZE",       0, 0, 1, false, Tier::Base } },
    { Instruction::CODECOPY,    { "CODECOPY",       0, 3, 0, true, Tier::VeryLow } },
    { Instruction::GASPRICE,    { "GASPRICE",       0, 0, 1, false, Tier::Base } },
    { Instruction::EXTCODESIZE, { "EXTCODESIZE",    0, 1, 1, false, Tier::Ext } },
    { Instruction::EXTCODECOPY, { "EXTCODECOPY",    0, 4, 0, true, Tier::Ext } },
    { Instruction::BLOCKHASH,   { "BLOCKHASH",      0, 1, 1, false, Tier::Ext } },
    { Instruction::COINBASE,    { "COINBASE",       0, 0, 1, false, Tier::Base } },
    { Instruction::TIMESTAMP,   { "TIMESTAMP",      0, 0, 1, false, Tier::Base } },
    { Instruction::NUMBER,      { "NUMBER",         0, 0, 1, false, Tier::Base } },
    { Instruction::DIFFICULTY,  { "DIFFICULTY",     0, 0, 1, false, Tier::Base } },
    { Instruction::GASLIMIT,    { "GASLIMIT",       0, 0, 1, false, Tier::Base } },
    { Instruction::POP,         { "POP",            0, 1, 0, false, Tier::Base } },
    { Instruction::MLOAD,       { "MLOAD",          0, 1, 1, false, Tier::VeryLow } },
    { Instruction::MSTORE,      { "MSTORE",         0, 2, 0, true, Tier::VeryLow } },
    { Instruction::MSTORE8,     { "MSTORE8",        0, 2, 0, true, Tier::VeryLow } },
    { Instruction::SLOAD,       { "SLOAD",          0, 1, 1, false, Tier::Special } },
    { Instruction::SSTORE,      { "SSTORE",         0, 2, 0, true, Tier::Special } },
    { Instruction::JUMP,        { "JUMP",           0, 1, 0, true, Tier::Mid } },
    { Instruction::JUMPI,       { "JUMPI",          0, 2, 0, true, Tier::High } },
    { Instruction::PC,          { "PC",             0, 0, 1, false, Tier::Base } },
    { Instruction::MSIZE,       { "MSIZE",          0, 0, 1, false, Tier::Base } },
    { Instruction::GAS,         { "GAS",            0, 0, 1, false, Tier::Base } },
    { Instruction::JUMPDEST,    { "JUMPDEST",       0, 0, 0, true, Tier::Special } },
    { Instruction::PUSH1,       { "PUSH1",          1, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH2,       { "PUSH2",          2, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH3,       { "PUSH3",          3, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH4,       { "PUSH4",          4, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH5,       { "PUSH5",          5, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH6,       { "PUSH6",          6, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH7,       { "PUSH7",          7, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH8,       { "PUSH8",          8, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH9,       { "PUSH9",          9, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH10,      { "PUSH10",         10, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH11,      { "PUSH11",         11, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH12,      { "PUSH12",         12, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH13,      { "PUSH13",         13, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH14,      { "PUSH14",         14, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH15,      { "PUSH15",         15, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH16,      { "PUSH16",         16, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH17,      { "PUSH17",         17, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH18,      { "PUSH18",         18, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH19,      { "PUSH19",         19, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH20,      { "PUSH20",         20, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH21,      { "PUSH21",         21, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH22,      { "PUSH22",         22, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH23,      { "PUSH23",         23, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH24,      { "PUSH24",         24, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH25,      { "PUSH25",         25, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH26,      { "PUSH26",         26, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH27,      { "PUSH27",         27, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH28,      { "PUSH28",         28, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH29,      { "PUSH29",         29, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH30,      { "PUSH30",         30, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH31,      { "PUSH31",         31, 0, 1, false, Tier::VeryLow } },
    { Instruction::PUSH32,      { "PUSH32",         32, 0, 1, false, Tier::VeryLow } },
    { Instruction::DUP1,        { "DUP1",           0, 1, 2, false, Tier::VeryLow } },
    { Instruction::DUP2,        { "DUP2",           0, 2, 3, false, Tier::VeryLow } },
    { Instruction::DUP3,        { "DUP3",           0, 3, 4, false, Tier::VeryLow } },
    { Instruction::DUP4,        { "DUP4",           0, 4, 5, false, Tier::VeryLow } },
    { Instruction::DUP5,        { "DUP5",           0, 5, 6, false, Tier::VeryLow } },
    { Instruction::DUP6,        { "DUP6",           0, 6, 7, false, Tier::VeryLow } },
    { Instruction::DUP7,        { "DUP7",           0, 7, 8, false, Tier::VeryLow } },
    { Instruction::DUP8,        { "DUP8",           0, 8, 9, false, Tier::VeryLow } },
    { Instruction::DUP9,        { "DUP9",           0, 9, 10, false, Tier::VeryLow } },
    { Instruction::DUP10,       { "DUP10",          0, 10, 11, false, Tier::VeryLow } },
    { Instruction::DUP11,       { "DUP11",          0, 11, 12, false, Tier::VeryLow } },
    { Instruction::DUP12,       { "DUP12",          0, 12, 13, false, Tier::VeryLow } },
    { Instruction::DUP13,       { "DUP13",          0, 13, 14, false, Tier::VeryLow } },
    { Instruction::DUP14,       { "DUP14",          0, 14, 15, false, Tier::VeryLow } },
    { Instruction::DUP15,       { "DUP15",          0, 15, 16, false, Tier::VeryLow } },
    { Instruction::DUP16,       { "DUP16",          0, 16, 17, false, Tier::VeryLow } },
    { Instruction::SWAP1,       { "SWAP1",          0, 2, 2, false, Tier::VeryLow } },
    { Instruction::SWAP2,       { "SWAP2",          0, 3, 3, false, Tier::VeryLow } },
    { Instruction::SWAP3,       { "SWAP3",          0, 4, 4, false, Tier::VeryLow } },
    { Instruction::SWAP4,       { "SWAP4",          0, 5, 5, false, Tier::VeryLow } },
    { Instruction::SWAP5,       { "SWAP5",          0, 6, 6, false, Tier::VeryLow } },
    { Instruction::SWAP6,       { "SWAP6",          0, 7, 7, false, Tier::VeryLow } },
    { Instruction::SWAP7,       { "SWAP7",          0, 8, 8, false, Tier::VeryLow } },
    { Instruction::SWAP8,       { "SWAP8",          0, 9, 9, false, Tier::VeryLow } },
    { Instruction::SWAP9,       { "SWAP9",          0, 10, 10, false, Tier::VeryLow } },
    { Instruction::SWAP10,      { "SWAP10",         0, 11, 11, false, Tier::VeryLow } },
    { Instruction::SWAP11,      { "SWAP11",         0, 12, 12, false, Tier::VeryLow } },
    { Instruction::SWAP12,      { "SWAP12",         0, 13, 13, false, Tier::VeryLow } },
    { Instruction::SWAP13,      { "SWAP13",         0, 14, 14, false, Tier::VeryLow } },
    { Instruction::SWAP14,      { "SWAP14",         0, 15, 15, false, Tier::VeryLow } },
    { Instruction::SWAP15,      { "SWAP15",         0, 16, 16, false, Tier::VeryLow } },
    { Instruction::SWAP16,      { "SWAP16",         0, 17, 17, false, Tier::VeryLow } },
    { Instruction::LOG0,        { "LOG0",           0, 2, 0, true, Tier::Special } },
    { Instruction::LOG1,        { "LOG1",           0, 3, 0, true, Tier::Special } },
    { Instruction::LOG2,        { "LOG2",           0, 4, 0, true, Tier::Special } },
    { Instruction::LOG3,        { "LOG3",           0, 5, 0, true, Tier::Special } },
    { Instruction::LOG4,        { "LOG4",           0, 6, 0, true, Tier::Special } },
    { Instruction::CREATE,      { "CREATE",         0, 3, 1, true, Tier::Special } },
    { Instruction::CALL,        { "CALL",           0, 7, 1, true, Tier::Special } },
    { Instruction::CALLCODE,    { "CALLCODE",       0, 7, 1, true, Tier::Special } },
    { Instruction::RETURN,      { "RETURN",         0, 2, 0, true, Tier::Zero } },
    { Instruction::DELEGATECALL,    { "DELEGATECALL",   0, 6, 1, true, Tier::Special } },
    { Instruction::REVERT,          { "REVERT",             0, 2, 0, true, Tier::Zero } },
    { Instruction::INVALID,     { "INVALID",        0, 0, 0, true, Tier::Zero } },
    { Instruction::SELFDESTRUCT,    { "SELFDESTRUCT",       0, 1, 0, true, Tier::Zero } }
};

void dev::solidity::eachInstruction(
    bytes const& _mem,
    function<void(Instruction,u256 const&)> const& _onInstruction
)
{
    for (auto it = _mem.begin(); it < _mem.end(); ++it)
    {
        Instruction instr = Instruction(*it);
        size_t additional = 0;
        if (isValidInstruction(instr))
            additional = instructionInfo(instr).additional;
        u256 data;
        for (size_t i = 0; i < additional; ++i)
        {
            data <<= 8;
            if (++it < _mem.end())
                data |= *it;
        }
        _onInstruction(instr, data);
    }
}

string dev::solidity::disassemble(bytes const& _mem)
{
    stringstream ret;
    eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
        if (!isValidInstruction(_instr))
            ret << "0x" << hex << int(_instr) << " ";
        else
        {
            InstructionInfo info = instructionInfo(_instr);
            ret << info.name << " ";
            if (info.additional)
                ret << "0x" << hex << _data << " ";
        }
    });
    return ret.str();
}

InstructionInfo dev::solidity::instructionInfo(Instruction _inst)
{
    try
    {
        return c_instructionInfo.at(_inst);
    }
    catch (...)
    {
        return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0, false, Tier::Invalid});
    }
}

bool dev::solidity::isValidInstruction(Instruction _inst)
{
    return !!c_instructionInfo.count(_inst);
}