2016-06-19 9 views
1

私は精神文法を書くことに取り組んでおり、16進数表現の文字列を取る基本ベース16を作成するために基本ベース16を作成しようとしています。スピリット文法文字数で文字列を分割するには

49276d206b696c 

(文字列が6の完全な倍数でない場合は少なくなります)を解析し、入力からベース64のエンコードされた文字列を生成します。私はおそらく働くだろう考え出し一つの文法は次のようなものです:

// 6 characters 
`(qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F")[/*action*/]) | 


// or 5 characters 
(qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F") >> qi::char_("0-9a-fA-F") >> 
qi::char_("0-9a-fA-F")[/*action*/]) | ...` 

など....すべての方法ダウン1つの文字、または文字の数ごとに定義された異なるルールを持つが、私はそこにあることが必要だと思います文法を指定する良い方法です。私は精神の繰り返しについて読んで、おそらく私は何かをすることができると思っていた +(boost::spirit::repeat(1, 6)[qi::char_("0-9a-fA-F")][/*action on characters*/]) しかし、コンパイラは、文法のセマンティックなアクション部分のため、これにエラーをスローします。一度に正確に6文字以下で動作する文法を指定する簡単な方法はありますか?

編集 ここでは、私がこれまでに行ったことある... base16convertergrammar.hpp

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp>  

#include <string> 
#include <iostream> 

namespace grammar { 
    namespace qi = boost::spirit::qi; 

    void toBase64(const std::string& p_input, std::string& p_output) 
    { 
     if (p_input.length() < 6) 
     { 
      // pad length 
     } 

     // use back inserter and generator to append to end of p_output. 
    } 

    template <typename Iterator> 
    struct Base16Grammar : qi::grammar<Iterator, std::string()> 
    { 
     Base16Grammar() : Base16Grammar::base_type(start, "base16grammar"), 
      m_base64String() 
     { 
      // get six characters at a time and send them off to be encoded 
      // if there is less than six characters just parse what we have 
      start = +(boost::spirit::repeat(1, 6)[qi::char_("0-9a-fA-F")][boost::phoenix::bind(toBase64, qi::_1, 
       boost::phoenix::ref(m_base64String))]); 
     } 

     qi::rule<Iterator, std::string()> start; 

     std::string m_base64String; 
    }; 
} 

そして、ここでは、使用され... base16converter.cpp

#include "base16convertergrammar.hpp" 

const std::string& convertHexToBase64(const std::string& p_hexString) 
{ 
    grammar::Base16Grammar<std::string::const_iterator> g; 
    bool r = boost::spirit::qi::parse(p_hexString.begin(), p_hexString.end(), g); 
} 


int main(int argc, char** argv) 
{ 
    std::string test("49276d206b696c6c"); 
    convertHexToBase64(test); 
} 
+1

が、あなたの例でセマンティックアクションは残りのものを無視して最後の文字にのみ付けられます。あなたが提案する代替案は、 'vector 'という属性を持っていなければなりません。あなたが(-nほとんど)完全な例を提供すれば、より簡単になり(あなたにとっては良いでしょう)。 – llonesmiz

+0

私はこれまでのものを加えました。 – joshu

答えて

2

ファーストrepeat()[]はベクトルを公開しますので、vector<char>、文字列ではありません。

void toBase64(const std::vector<char>& p_input, std::string& p_output) 

第2に、すべて動作しないでください。あなたは入力が何を意味するのか私たちには言いませんが、あなたが6つにグループ化したい限り、あなたはそれらを/ something /と解釈したいと思っています。たとえば、 int_parserを使用します。

Live On Coliru

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp>  

#include <string> 
#include <iostream> 

namespace grammar { 
    namespace qi = boost::spirit::qi; 
    namespace px = boost::phoenix; 

    template <typename Iterator> 
    struct Base16Grammar : qi::grammar<Iterator, std::string()> 
    { 
     Base16Grammar() : Base16Grammar::base_type(start, "base16grammar") 
     { 
      start = +qi::int_parser<uint64_t, 16, 1, 6>() [ qi::_val += to_string(qi::_1) + "; " ]; 
     } 

     private: 
     struct to_string_f { template <typename T> std::string operator()(T const& v) const { return std::to_string(v); } }; 
     px::function<to_string_f> to_string; 

     qi::rule<Iterator, std::string()> start; 
    }; 
} 

std::string convertHexToBase64(const std::string& p_hexString) 
{ 
    grammar::Base16Grammar<std::string::const_iterator> g; 
    std::string result; 
    bool r = boost::spirit::qi::parse(p_hexString.begin(), p_hexString.end(), g, result); 
    assert(r); 
    return result; 
} 

int main() 
{ 
    for (std::string test : {"49276d206b696c6c"}) 
     std::cout << test << " -> " << convertHexToBase64(test) << "\n"; 
} 

プリント

49276d206b696c6c -> 4794221; 2124649; 27756; 
1

は手足に出て行く、あなただけのBASE64に16進数でエンコードされたバイナリをトランスコードします。すでにブースト使用しているので

Live On Coliru

#include <boost/archive/iterators/base64_from_binary.hpp> 
#include <boost/archive/iterators/insert_linebreaks.hpp> 
#include <boost/archive/iterators/transform_width.hpp> 

// for hex decoding 
#include <boost/iterator/function_input_iterator.hpp> 

#include <string> 
#include <iostream> 
#include <functional> 

std::string convertHexToBase64(const std::string &hex) { 
    struct get_byte_f { 
     using result_type = uint8_t; 

     std::string::const_iterator hex_it; 

     result_type operator()() { 
      auto nibble = [](uint8_t ch) { 
       if (!std::isxdigit(ch)) throw std::runtime_error("invalid hex input"); 
       return std::isdigit(ch) ? ch - '0' : std::tolower(ch) - 'a' + 10; 
      }; 

      auto hi = nibble(*hex_it++); 
      auto lo = nibble(*hex_it++); 
      return hi << 4 | lo; 
     } 
    } get_byte{ hex.begin() }; 

    using namespace boost::archive::iterators; 

    using It = boost::iterators::function_input_iterator<get_byte_f, size_t>; 

    typedef insert_linebreaks< // insert line breaks every 72 characters 
     base64_from_binary<  // convert binary values to base64 characters 
      transform_width<  // retrieve 6 bit integers from a sequence of 8 bit bytes 
      It, 6, 8> >, 
     72> B64;     // compose all the above operations in to a new iterator 

    return { B64(It{get_byte, 0}), B64(It{get_byte, hex.size()/2}) }; 
} 

int main() { 
    for (std::string test : { 
      "49276d206b696c6c", 
      "736f6d65206c656e67746879207465787420746f2073686f77207768617420776f756c642068617070656e206174206c696e6520777261700a" 
     }) 
    { 
     std::cout << " === hex: " << test << "\n" << convertHexToBase64(test) << "\n"; 
    } 
} 

プリントを

=== hex: 49276d206b696c6c 
SSdtIGtpbGw 
=== hex: 736f6d65206c656e67746879207465787420746f2073686f77207768617420776f756c642068617070656e206174206c696e6520777261700a 
c29tZSBsZW5ndGh5IHRleHQgdG8gc2hvdyB3aGF0IHdvdWxkIGhhcHBlbiBhdCBsaW5lIHdy 
YXAK 
転写しながら、それは誤りだ場合、私は知らない
+0

それは私がやっていることです。私は実際にこの挑戦https:// cryptopalsを開始しました。今日はココ/セット/ 1 /チャレンジ/ 1になってしまいましたが、基盤64をベースにして16エンコーダーにするのは簡単すぎると思っていましたので、2羽の鳥を1石で殺し、精神を学ぶことにしました。 – joshu

+0

お返事いただきありがとうございます。両方とも非常に役に立ちます! – joshu

関連する問題