FIREFOX HACKS' (4)

日課の散歩をしていたら、たんぼのあぜ道を、トコトコと散歩してるカモに出くわしました。 ヨウご同輩、あんた達も散歩ですかい? じっと見ていたら、田んぼの中へと移動してゆきました。 今度は、食事の時間なのでしょうか? しきりに水の中に首をつっこみ、何やらやっていましたよ。

もう大分前に終わっちゃったけど、この地は「ダッシュ村」になりうる場所だなあ。せいぜい、 たんぼを掻き回し、虫を食べて、糞をばらまいて、大きくなっておくれ。頑張れ、カモ夫婦。

コードを読む前に

前回は、javascript のコード見始めた。けれども、難航が予想されるので、先にコードが どんな生成物を出しているか見ておく事にする。久しぶりに、完全なUTF-8環境である Debian 上に移行し、変な事に気を回さなくても良いようにする。

FreeBSDの環境をそのまま持ってきたけど、やはり Jsonのデータをparseするとエラーになって しまった。生のJSONデータは、最密の一本糞であるから始末が悪い。何とか見やすくならないか? 10秒考えて、いい事を思いついた。ちょいとJSONデータを加工して、ruby風味にしちゃうのだ。

sakae@debian:~/json$ sed -e 's/:/=>/g' -e 's/null/nil/g' Bookmarks_2009-06-09.json >forruby

rubyでは、Hashのキーと値の区切りは => でしょ。nullの変わりは nil にしとくか。 こうして出来た、ruby用のデータを、下記スクリプトに食わせて、整形しちゃいます。(rubyでも、 read,eval,print ですよ。嗚呼、禁断のeval使っちゃった!)

require 'pp'

str = File.read('forruby')
h   = eval( str )
PP.pp h

スクリプトの結果は、美容整形の高須じゃなく output とか適当なファイルにリダイレクトします。 以下は、整形結果の冒頭と最後の部分です。

{"title"=>"",
 "id"=>1,
 "dateAdded"=>1244456288889743,
 "lastModified"=>1244456310537030,
 "type"=>"text/x-moz-place-container",
 "root"=>"placesRoot",
 "children"=>
  [{"title"=>"Bookmarks Menu",
    "id"=>2,
    "parent"=>1,
    "dateAdded"=>1244456288891942,
    "lastModified"=>1244505218280884,
    "type"=>"text/x-moz-place-container",
    "root"=>"bookmarksMenuFolder",
    "children"=>
     [{"title"=>"Windows",
   .................
   {"index"=>2,
    "title"=>"Tags",
    "id"=>4,
    "parent"=>1,
    "dateAdded"=>1244456288894095,
    "lastModified"=>1244456288898880,
    "type"=>"text/x-moz-place-container",
    "root"=>"tagsFolder",
    "children"=>[]},
   {"index"=>3,
    "title"=>"Unsorted Bookmarks",
    "id"=>5,
    "parent"=>1,
    "dateAdded"=>1244456288895191,
    "lastModified"=>1244456288898429,
    "type"=>"text/x-moz-place-container",
    "root"=>"unfiledBookmarksFolder",
    "children"=>[]}]}

木が生えてます。大きな木です。(葉は273枚ありました)

sakae@debian:~/json$ grep root output
 "root"=>"placesRoot",
    "root"=>"bookmarksMenuFolder",
    "root"=>"toolbarFolder",
    "root"=>"tagsFolder",
    "root"=>"unfiledBookmarksFolder",

sakae@debian:~/json$ grep parent output
    "parent"=>1,
       "parent"=>2,
          "parent"=>61,
          "parent"=>61,
      ..................
    "parent"=>1,
       "parent"=>3,
       "parent"=>3,
       "parent"=>3,
    "parent"=>1,
    "parent"=>1,

index及びid番号は、1がオリジンになってます。(js流?)

それにしても、Jsonのパーサーが2種類共エラーになる中、上記のような簡単(いんちき)な 変換で、ruby上に展開出来ちゃうって、どういう事?

utils.js を嫁

utilis.jsをemacsで開いてみたのですが、C++モードになっていました。jsモードって、無い んでしょうか? それはさておき、キーワードに従って、色がつくのは有難いのですが、途中から 文字列扱いの色に化けてしまいます。その部分を良く見たら、" のバランスが崩れていて、 次の行も文字列と思っているようです。ちょいと気持ちが悪いので、応急処置しました。

      var escJSONStringRegExp = /(["\\])/g;          // For emacs "

もっと、インテリジェントにしてくださいよ。> rms

  restoreBookmarksFromJSONString:
  function PU_restoreBookmarksFromJSONString(aString, aReplace, aExcludeItems) \
{
    // convert string to JSON
    var nodes = this.unwrapNodes(aString, this.TYPE_X_MOZ_PLACE_CONTAINER);

まず、nodesを取り出している。下記のように、[] で、包んでいるので、配列になって 返ってくる。

  unwrapNodes: function PU_unwrapNodes(blob, type) {
    // We split on "\n"  because the transferable system converts "\r\n" to "\n\
"
    var nodes = [];
    switch(type) {
      case this.TYPE_X_MOZ_PLACE:
      case this.TYPE_X_MOZ_PLACE_SEPARATOR:
      case this.TYPE_X_MOZ_PLACE_CONTAINER:
        var JSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
        nodes = JSON.decode("[" + blob + "]");
        break;

restoreBookmarksFromJSONString の続きを読んで行くと、確かに木の処理をしてるし、先のデータ 中に出てきたキーワード等も参照されているので、調べている場所としては間違いなさそうだ。 そうすると、後は JSON.decode が、どう定義されてるか見ればいいんだな。

[sakae@fb ~/mozilla]$ find . -type f | xargs grep JSON.decode
./toolkit/components/places/src/utils.js:        nodes = JSON.decode("[" + blob + "]");
./dom/src/json/test/unit/test_long_input.js:var z = nativeJSON.decode(y);
./dom/src/json/test/unit/test_decode.js:  var x = nativeJSON.decode("{}");
 .....
./dom/src/json/test/unit/test_decode.js:      var x = nativeJSON.decodeFromStream(istream, istream.available());

どうも、JSON.decode を定義してる所は見つからない。悔し紛れに、test_decode.js(名前と場所から 多分、試験機だろうけど)をちょいと覗いてみます。

  // nesting
  x = nativeJSON.decode('{"foo":[{}]}');
  do_check_eq(x.foo.constructor, Array);
  do_check_eq(x.foo.length, 1);
  do_check_eq(typeof x.foo[0], "object");
  x = nativeJSON.decode('{"foo":[{"foo":[{"foo":{}}]}]}');
  do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
  x = nativeJSON.decode('{"foo":[{"foo":[{"foo":[]}]}]}');
  do_check_eq(x.foo[0].foo[0].foo.constructor, Array);

  // strings
  x = nativeJSON.decode('{"foo":"bar"}');
  do_check_eq(x.foo, "bar");
  x = nativeJSON.decode('["foo", "bar", "baz"]');
  do_check_eq(x[0], "foo");
  do_check_eq(x[1], "bar");
  do_check_eq(x[2], "baz");

こんなのがずっと続いているだけでした。本当の JSON.decodeは何処に? どなたか、ここ見ろワンワン がありましたら、教えてください。なお、探っていたソースは、 firefox-3.0.10-source.tar.bz2 です。宜しくお願い致します。