File::Morkモジュールのマルチバイト対応

Firefox等のMozilla系ブラウザの履歴(= history.dat)を読み込むモジュールにFile::Morkがある。なかなか便利に使えそうなんだけど、マルチバイト対応しておらず、日本語が扱えない。なんで、File::Morkを日本語対応するようなパッチを書いた。

--- Mork_original.pm	2006-10-23 22:46:41.000000000 +0900
+++ Mork.pm	2006-10-23 22:46:07.000000000 +0900
@@ -3,6 +3,7 @@
 use strict;
 use vars qw($VERSION $ERROR);
 use POSIX qw(strftime);
+use Encode;
 
 $VERSION = "0.2";
 
@@ -331,12 +332,24 @@
               next;
         }
 
+        # recognize the byte order of UTF-16 encoding
+        if (! defined ($self->{byte_order}) && $val =~ m/(?:BE|LE)/) {
+            $self->{byte_order} = $val;
+        }
+
         # Assume that URLs and LastVisited are never hexilated; so
         # don't bother unhexilating if we won't be using Name, etc.
         if($val =~ m/\$/) {
-              # Approximate wchar_t -> ASCII and remove NULs
-              $val =~ s/\$00//g;  # faster if we remove these first
-              $val =~ s/\$([\dA-F]{2})/chr(hex($1))/ge;
+            if ( defined $self->{byte_order} ) {
+                my $encoding = 'UTF-16' . $self->{byte_order};
+                $val =~ s/\$([\dA-F]{2})/chr(hex($1))/ge;
+                $val = encode_utf8(decode($encoding, $val));
+            }
+            else {
+                # Approximate wchar_t -> ASCII and remove NULs
+                $val =~ s/\$00//g;  # faster if we remove these first
+                $val =~ s/\$([\dA-F]{2})/chr(hex($1))/ge;
+            }
         }
 
         $self->{val_table}->{$key} = $val;

history.datないではマルチバイト文字が現れるような場所では、文字列はUTF-16でエンコードされて記録されている。もともとのFile::MorkではUTF-16の2byte文字を強引に1byteに変更するような実装だったので、きちんとUTF-16として読み込んでUTF-8の普通の文字列で返すようにした。

ただし、UTF-16といっても環境に寄ってLitteEndianだったり、BigEndianだったりするらしい。幸い、history.datにはバイトオーダーが記録されていたので、バイトオーダーがわかれば、それにしたがってデコードするようにした。

File::MorkにはPlagger::Plugin::Subscription::Browserを手軽に利用するためにもマルチバイト対応してもらいたい。なんで、このパッチを作者の方にメールしたいところだ。しかし、英語のメールとかまともに送れるかはなはだ不安というか、そもそも、パッチ送るとかもはじめてなんだよね。不安。