質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Perl

    461questions

    Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

スクリプト言語を使ってバイナリのデータを解析して不要な箇所を削除したい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,534

izuki_y

score 45

とあるJpegの送信を行ったTCP通信時のバイナリデータがあります。
そこから不要な情報を削除してJpegデータを復元したいと思っています。
条件は以下の通りです。

[前提条件]
以下のヘッダにJpegを分割してくっ付けて送っています。

identifier[4 byte] = "DCAA"
result[2 byte]
command_id[2 byte] = 0001H~02FFH
length[4 byte] = dataサイズ
data[n byte] = Jpegデータ

ここから分割したJpegデータを抜き出し復元したい(パケットのロスや重複は考えないものとします)

[手順]

  1. バイナリデータを先頭から見ていき"DCAA"が出るまで読み飛ばす
  2. "DCAA"が出てきたらcommand_idを見て0202Hであるか確認する(それ以外のコマンドが持っているdataはJpegではない)
  3. 0202Hであれば identifier~length を削除する
  4. 0202H以外であれば identifier~data を削除する
    以下ファイルの終端まで繰り返し

これをperlで実現しようと思っています。

MAIN:{
    my $buf, $size;

    #ファイルオープン
    open ( IN, "< $_$ARGV[0]" ) or die "$!";    # in
    open ( OUT, "> $ARGV[1]]" ) or die "$!";    # out

    binmode IN;
    binmode OUT;

    $size = -s $_$ARGV[0];

    read(IN, $buf, $size);

    my $identifier = "DCAA";

    # 16進バイナリ から 文字列 への変換
    my @ascii = unpack('H*', $buf);
    for my $i (0..$#ascii){
        if ( $#ascii eq $identifier ){
            # ....
        }
    }

ここまでやりました。

教えていただきたい事は

+ バイナリデータとアスキーデータの比較
+ バイナリデータの削除(これはバイナリ出力時に読み飛ばせばいいかな)
+ バイナリデータのシーク

の3つを教えてください。
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

unpackしないほうが楽そうだったので、readで少しずつ読みながら基本バイナリのままで処理してみました。
エラー処理など細かいところは省略してます。
なお、シークするにはそのままseekという関数があるのでこれでシークできます(以下のコードでは使ってませんが)。

use strict;
{
  open(my $in, "<:raw", $ARGV[0]) or die $!;

  # DCAAまで読み飛ばす
  my $last_4byte;
  read($in,$last_4byte,4); #readの戻り値チェックは省略
  while( $last_4byte ne "DCAA" ){
    # 1byte捨てて1byte読む
    $last_4byte = substr($last_4byte,1);
    if ( read($in,$last_4byte,1,3) < 1 ) {
      die "Not found.";
    }
  }

  # resultとcommand_id、command_idチェック
  my $result;
  my $command_id;
  read($in,$result,2);
  read($in,$command_id,2);
  if ( $command_id ne "\x02\x02" ) {
    die "No JPEG."; #読み飛ばしは省略、後ろで$data捨てれば良い
  }

  # length
  my $length;
  read($in,$length,4);
  my $length_val = unpack("N", $length); # 符号無し4バイト整数、ビッグエンディアン

  # data
  my $data;
  read($in,$data,$length_val);

  #必要なところだけ出力
  open(my $out, ">:raw", $ARGV[1]) or die $!;
  print $out $data;
  close($out);


  #繰り返し省略

  close($in);
}

それから、この部分ですが、

# 16進バイナリ から 文字列 への変換
my @ascii = unpack('H*', $buf);

このコメントは不正確で、正しくはバイナリを16進数文字列に変換します(1バイトが16進数2文字になる)。
要素数は1になるので、後ろのループは1回しか回らないですね。

my $hex_str = unpack('H*', "123");
if ( $hex_str eq "313233" ) {
  print "Match!\n";
}

#これだと各バイトを数値にした配列が得られる
my @bytes = unpack('C*', "123");
if ( $bytes[0] == 0x31 && $bytes[1] == 0x32 && $bytes[2] == 0x33 ) {
  print "Match!\n";
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/31 19:57

    回答ありがとうございます。

    unpackを使わない条件比較の方法など大変参考になりました。
    今は教えていただいた事を参考にしながら組んでいます。

    ```
    while( $last_4byte ne "DCAA" ){
    # 1byte捨てて1byte読む
    $last_4byte = substr($last_4byte,1);
    if ( read($in,$last_4byte,1,3) < 1 ) {
    die "Not found.";
    }
    }
    ```
    で読み取りが飛ばされる事がある気がしてましてそれを検証しています。
    本当なら整形する元データを提示したいのですが、申し訳ないです。
    また分かりしだいコメントを書かせてください。

    キャンセル

  • 2016/04/02 01:42

    失礼な事を言って申し訳ありませんでした。
    読み飛ばしてると感じたのはこちらの確認ミスでした。

    改めてもう一度やり直したら正しくデータを取得することが出来ました。
    本当にありがとうございました。

    キャンセル

関連した質問

  • 受付中

    perlの変数をphpへ渡したい

    perlの変数をphpへ渡すにはどうしたら良いでしょうか? phpはやっとこさ分かるのですが、perlは良くわかりません、perlで書かれたコードを使用しなければいけないので

  • 解決済

    System.out.printからSystem.out.writeへの書き換え

    単純な足し算プログラムの書き換えができません。 System.out.printではなく、System.out.writeを使用するプログラムに書き換えたいのですが、 うま

  • 解決済

    perl バイオインフォマティクス

    実現させたいこと ダウンロードしたmultifastaを一行ずつのものに分割し、NGSによるreadのようなものを作成したい。 先日同じような質問をさせて頂きましたが、今回もそ

  • 解決済

    perl でキーワードからキーワードの間の行を抽出したい

    perl本当の初心者です。とても苦戦しています。 地名1.csv 地名2.csv の2つのファイルがあったとします。 ==地名1.csv== a,b,札幌,c,d,

  • 受付中

    perlでsedの置換ができない

    perlでsedの置換ができなくて困っています。 $sr1="123"; $sr2="456"; $answer = sed -i -e s/$sr1/$sr2/ /

  • 解決済

    perlスクリプトの不具合

    いつもお世話になっております。自身で書いたperlスクリプトが思うように動かずに困っています。どなたか御教授頂けたら幸いです。 入力ファイルについて ・ file.fa >1-

  • 解決済

    SNMPのOidを16進数にしてbyte配列に格納したい

    前提・実現したいこと C#でSNMPTrapをライブラリを使わずにパケットを直に 送信したいと考えています。 作成している最中にOidのパケット変換で躓いてしまったので質問をさ

  • 解決済

    ファイルを更新するといらぬスペース文字が入ってしまう。

    次のようにファイルを読み込み新しい行を行頭に入れそのファイルを保存すると、2行目から最終行まで、スペース文字が、2行目1個3行目2個4行目3個といった感じで最終行までスペース文字が

同じタグがついた質問を見る

  • Perl

    461questions

    Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。