...pudding - diary

この日記は https://yapud.hatenablog.com/ に引っ越し中


2013-11-21

_ [Software] オライリー「電子メールプロトコル」サンプルの base64 が微妙にバグってた

O'Reilly Japan - 電子メールプロトコル のなかで使用されている mail.pl のサンプルコードが WEB にある → examples.oreilly.com/9781565924796/mail.pl

ちょびっとメールを送信するようなバッチに組み込んだりするのに便利なので昔ながらの unix の中でも使ったりしてるんだけど。

このコードの中にある「添付ファイルを base64 エンコードする部分」が微妙におかしい。

base64 は 3バイトのバイナリを 4文字のテキストにエンコードするもの。

ファイルサイズが 3の倍数じゃなかった場合、末尾に 1バイトもしくは 2バイト余る。

余ったところは処理できないので 3バイトになるよう末尾を埋めておくのだけど、その埋める処理のところが変で。

だからこの mail.pl をつかって、3で割り切れないファイルサイズの添付ファイルを送ると、末尾 1~2バイトがちょびっと化けてくる。

対処するために手を入れるところはこの辺。

まず、通常処理するバイト数を決めてるところ。一律 2を引いてるのはなんでなんだろう。そういうプログラミングテクニックがあるのかな。ちょうど 3で割りきれる数にしたらちょうど良くなるはずなので、必ず 3の倍数になるようにしてみた。

<       for ($i=0; $i < ( @decoded_attachment_data - 2 ); $i+=3) {
---
> for ($i=0; $i < ( int(@decoded_attachment_data /3)*3 ); $i+=3) {

そのあと、余ってしまった1バイトもしくは2バイトを誤魔化す処理のところだけど、処理すべきバイト数を決めている変数 $i から 3 引いてる。なんだろうこれ。 コメントアウトしよう。

<         $i -= 3;
---
> #$i -= 3;

1バイトだけ余りだったときの処理。ここはカウンタ進めないといかんだろう。

<         $buffer[$encode_count] = $encode_table[((vec($decoded_attachment_data[$i],0,8) & 0x03) << 4)];
---
> $buffer[$encode_count++] = $encode_table[((vec($decoded_attachment_data[$i],0,8) & 0x03) << 4)];

もう1バイトあまりだったときの処理。ここはカウンタ進めたらダメなんじゃないの。

<           $buffer[$encode_count++] = $encode_table[(((vec($decoded_attachment_data[$i-1],0,8) & 0x03) << 4) | ((vec($decoded_attachment_data[$i],0,8) & 0xF0) >>
---
> $buffer[$encode_count] = $encode_table[(((vec($decoded_attachment_data[$i-1],0,8) & 0x03) << 4) | ((vec($decoded_attachment_data[$i],0,8) & 0xF0) >>

これで手元のファイルをいくつか添付ファイルとして送信してみたけどうまいこと行ってるように思う。

コレが添付されんのがテキストファイルだったら気付かなかったろうと思う。このコードを使って添付されてくるのが gzip ファイルで時々展開できない (length error になる) のがあってなんでかなーと思って追いかけたらここでしたっていう。


2013年
11月
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Twitter : @moriya_jp