web-dev-qa-db-ja.com

固定バイトオフセットのバイナリデータをバイト位置で分割しますか?

xxd -psで16進形式で確認するバイナリデータがあります。区切り文字がfafafafaである2つのヘッダー間のバイト距離が48300(= 805 * 60)バイトであることに気付きました。スキップする必要があるファイルの先頭があります。

取得できるヘッダーfafafafa間の48300バイトの16進データの例 ここ 呼び出されたdata26.6.2015.txtここで、3つのヘッダーとそのほぼ同等のバイナリ ここ 呼び出されたtest_27.6.2015.binこれには最初の2つのヘッダーしかありません。どちらのファイルでも、最後のヘッダーのデータは完全な長さではありません。それ以外の場合は、バイトオフセットが固定されている、つまりヘッダー間のデータの長さであると見なすことができます。

アルゴリズムの擬似コード

  1. ヘッダーの終了位置を見る
  2. 最初の2つのヘッダー位置を調べ、これらの位置の差(d2 --d1)をイベント間の距離に設定します。このイベントの長さは固定です(777)
  3. データをバイト位置で分割(777)-TODOは、バイナリ形式またはxxd -ps変換データとして分割する必要がありますか?バイト位置別(777)

xxd -rのようにxxd -ps | split and store | xxd -rでデータをバイナリに戻すことができますが、これが必要かどうかはまだわかりません。

どの段階でバイナリデータを分割できますか? xxd -ps変換形式またはバイナリデータとしてのみ。

xxd -ps変換された形式で分割する場合、forループはファイルを通過する方法だけだと思います。 csplitsplit、...を分割するための可能なツール、わからない。しかし、私にはわかりません。

16進データのgrep(ggrepはgnu grep)からの出力

$ xxd -ps r328.raw  | ggrep -b -a -o -P 'fafa' | head
49393:fafa
49397:fafa
98502:fafa
98506:fafa
147611:fafa
147615:fafa
196720:fafa
196725:fafa
245830:fafa
245834:fafa

バイナリファイルで同様のgrepを実行している間、出力としてのみemptylineを指定します。

$ ggrep -b -a -o '\xfa' r328.raw 

ドキュメンテーション

私に与えられたドキュメントは見つかりました ここ そしてここに写真として一般的なSRSデータフォーマット:

enter image description here

どの段階でバイナリデータを分割できますか(バイナリデータまたはxxd -ps変換データとして)?

Great meuhの answer 彼がデータを使用した場所data26.6.2015.txtに出力します。

#1

$ cat 27.6.2015_1.sh && sh 27.6.2015_1.sh 
xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
pat=$(echo -e '\xfa\xfa\xfa\xfa')
set -- 0 $(ggrep -b -a -o "$pat" /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
   let count=$end-$start
   dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
   let i=i+1
   shift
done
72900+0 records in
72900+0 records out
72900 bytes (73 kB) copied, 0.160722 s, 454 kB/s

#2

$ cat 27.6.2015_2.sh && sh 27.6.2015_2.sh 
xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
set -- 0 $(ggrep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
   let count=$end-$start
   dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
   let i=i+1
   shift
done
72900+0 records in
72900+0 records out
72900 bytes (73 kB) copied, 0.147935 s, 493 kB/s

#3

$ cat 27.6.2015_3.sh && sh 27.6.2015_3.sh 
xxd -r -p <data26.6.2015.txt >r328.raw
tr -d '\n' <data26.6.2015.txt >f1
let size2=2*$(stat -c '%s' f1)
set -- 0 $(ggrep -b -a -o -P 'fafafafa' f1 | sed 's/:.*//') $size2
i=2
while [ $# -ge 2 ]
do  let start=$1/2
    let end=$2/2
    let count=$end-$start
    dd bs=1 count=$count skip=$start <r328.raw  >f$i
    let i=i+1
    shift
done
24292+0 records in
24292+0 records out
24292 bytes (24 kB) copied, 0.088345 s, 275 kB/s
24152+0 records in
24152+0 records out
24152 bytes (24 kB) copied, 0.061246 s, 394 kB/s
24152+0 records in
24152+0 records out
24152 bytes (24 kB) copied, 0.058611 s, 412 kB/s
304+0 records in
304+0 records out
304 bytes (304 B) copied, 0.001239 s, 245 kB/s

出力は、1つの16進ファイルと4つのバイナリファイルです。

$ less f1
$ less f2
"f2" may be a binary file.  See it anyway? 
$ less f3
"f3" may be a binary file.  See it anyway? 
$ less f4
"f4" may be a binary file.  See it anyway? 
$ less f5
"f5" may be a binary file.  See it anyway? 

最後のヘッダーの内容がスタブであるファイルdata26.6.2015.txtに3つのヘッダーしか指定していないため、fafafafaを持つファイルは3つだけである必要があります。 f2-f5の出力:

$ xxd -ps f2 |head -n3
48000000fe5a1eda480000000d00030001000000cd010000010000000000
000000000000000000000000000000000000000000000100000001000000
ffffffff57ea5e5580510b0048000000fe5a1eda480000000d0003000100
$ xxd -ps f3 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000200
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55b2eb0900105e000016000000010000000000
$ xxd -ps f4 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000300
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55f2ef0900105e000016000000010000000000
$ xxd -ps f5 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000400
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55a9f10900105e000016000000010000000000

どこ

  • f1はデータファイル全体ですdata26.6.2015.txt(含める必要はありません)
  • f2はファイルヘッダーです。つまり、ファイルの最初data26.6.2015.txtから最初のヘッダーfafafafaまでです(インクルードする必要はありません)。 )
  • f3は最初のヘッダーです、正解です!
  • f4は2番目のヘッダーです。正解です。
  • f5は3番目のヘッダーです。正解です。

Xxdを経由せずにバイナリファイルを操作できます。データをxxdに戻し、grep -bを使用して、バイナリファイル内のパターン(16進数から文字\xfaに変換)のバイトオフセットを表示しました。

一致した文字をsedで出力から削除して、数字だけを残しました。次に、シェルの位置引数を結果のオフセットに設定します(set -- ...)

xxd -r -p <data26.6.2015.txt >/tmp/f1
set -- $(grep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//')

これで、$ 1、$ 2、...にオフセットのリストができました。次に、ddで関心のある部分を抽出し、ブロックサイズを1(bs=1)に設定して、バイトごとに読み取ります。 skip=は入力でスキップするバイト数を示し、count=はコピーするバイト数を示します。

start=$1 end=$2
let count=$end-$start
dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f2

上記は、1番目のパターンの開始から2番目のパターンの直前までの抜粋です。パターンを含めないようにするには、開始に4を追加します(カウントは4減少します)。

すべての部分を抽出する場合は、この同じコードの周りのループを使用して、開始オフセット0と終了オフセットのファイルサイズを数値のリストに追加します。

xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
set -- 0 $(grep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
   let count=$end-$start
   dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
   let i=i+1
   shift
done

Grepがバイナリデータを処理できない場合は、xxd16進ダンプデータを使用できます。最初にすべての改行を削除して1つの巨大な行を作成し、次にエスケープされていない16進値を使用してgrepを実行しますが、次にすべてのオフセットを2で除算し、生ファイルでddを実行します。

xxd -r -p <data26.6.2015.txt >r328.raw
tr -d '\n' <data26.6.2015.txt >f1
let size2=2*$(stat -c '%s' f1)
set -- 0 $(grep -b -a -o -P 'fafafafa' f1 | sed 's/:.*//') $size2
i=2
while [ $# -ge 2 ]
do  let start=$1/2
    let end=$2/2
    let count=$end-$start
    dd bs=1 count=$count skip=$start <r328.raw  >f$i
    let i=i+1
    shift
done
2
meuh

それほど難しいことではありません。開始文字列を探し、末尾の文字列に名前を付けて一致させるだけです。それ以外の場合は、少なくとも近づくようにしてください。実際には16進数は必要ありませんが、次のように使用します。

fold -w2 <hexfile |
sed -e:t -e's/[[:xdigit:]]\{2\}$/\\x&/
    /f[af]$/N;/\(.\)..\1$/!s/.*\n/&\\x/;t
    /^.*\(.\)\(\n.*\)\n\(.*\n\).*/!bt
    s//\3\3\3 H_E_A_D \1 E_N_D \2\2\2/
    s/.* f//;s/a E.*//'

これにより、1行に1つの16進バイトコードが取得されます。各バイトの接頭辞は\xで、hexfileexceptのバイトコードごとにfaまたはffは4回連続して発生します。その場合、代わりにH_E_A_DまたはE_N_Dマーカーのいずれかを取得します。ここで、H_E_A_D =文字列は4つの\xfa文字列の最後を置き換え、E_N_D文字列は4つの連続する\xff文字列の最初を置き換えます-これもバイトオフセットを保持する必要があります行番号で同期します。

このような:

PIPELINE | grep -C8n _

出力:

(少しトリミング)

 
 72596-\x8b 
 72597-\xfa 
 72598-\xfa 
 72599-\xfa 
 72600:H_E_A_D 
 72601-\x58 
-
 72660-\x00 
 72661:E_N_D 
 72662-\xff 
 72663-\xff 
 72664-\xff 
 72665-\x72 
 

したがって、上記のコマンドの出力を次のように渡すことができます。

fold ... | sed ... | grep -n _

...ヘッダーがそれぞれ開始、終了する可能性のあるオフセットのリストを取得します。 GNU grepを使用すると、-Afterスイッチを使用して、コンテキストシーケンスで表示するバイト数を指定できます。したがって、使用することもできます。たとえば、-A777。このような出力を取得して、次のように渡すことができます。

... | grep -A777 E_N_D | sed -ne's/\\/&&/p' | xargs printf %b

...各シーケンスの各バイナリバイトを再現し、-m[num]で一致番号を指定できます。

1
mikeserv