2022年1月24日月曜日

C++データを16進表記相互変換

ちょくちょくデータを暗号化して16進数表記文字列に変換して保存し、保存された16進表記文字列をデータに復元する事をやるので、忘備録として記録する事に。こういう、ちょっとしたものでも、書こうと思ったら時間を取られる。
#include <string>
#include <iostream>

static int atob( int c ) {
  static const unsigned char btbl[] = {
    // 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  1
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  2
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05,  0x06, 0x07,  0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  3
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,  0x0F, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  4
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  5
    0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,  0x0F, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  6
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  7
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  8
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  9
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  A
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  B
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  C
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  D
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  //  E
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   //  F
  };
  return btbl[ c ];
}


//! 16進文字列から unsigned char 配列への変換
/*
  @note 16進文字列は、0-9, A-F のみを利用した表記で
    1バイトを2文字で表記しているものとする。16進を示す 0x 等の
    接頭辞は含まれていない。
*/
void hexstr2str(
  const std::string& src,
  std::string& dst
) {
  dst.resize( (src.size() + 1) / 2 );
  for(size_t i = 0; i < src.size(); i++) {
    if( (i & 1) != 0 ) {
      dst[ i / 2 ] |= atob( src[i] );
    } else {
      dst[ i / 2 ] = atob( src[i] ) << 4;
    }
  }
}

//! unsigned char 配列から 16進文字列への変換
/*!
  @note 16進文字列は、0-9, A-F のみを利用した表記で
    1バイトを2文字で表記したものに変換される。16進を示す 0x 等の
    接頭辞は含まない。
*/
void str2hexstr(
  const std::string&  src,
  std::string&        dst
) {
  static const char atbl[] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
  };
  dst.resize( src.size() * 2 );
  for( size_t i = 0; i < src.size(); i++ ) {
    dst[i*2  ] = atbl[ ((src[i] >> 4) & 0x0F) ]; // & 0x0F しないと算術シフトでアウトでした
    dst[i*2+1] = atbl[ (src[i] & 0x0F) ];
  }
}

int main() {
  std::string src = "Hello world!";
  std::string hex, dst;
  std::cout << src << std::endl;
  str2hexstr( src, hex );
  std::cout << hex << std::endl;
  hexstr2str( hex, dst );
  std::cout << dst << std::endl;
  return 0;
}

結果

Hello world!
48656C6C6F20776F726C6421
Hello world!
2022/01/14 追記: str2hexstr のコメントに書いたバグ修正をしました

0 件のコメント: