2009/08/05


先日「jjencodeをApacheのmod_ext_filterに仕込む」という記事でhasegawaさんのjjencodeをgoogle chromeなんかで使われているjavascriptエンジン"v8"で動かしてみたのですが、あまりに遅いですし、一回javascriptエンジンが走ってしまうという事がボトルネックに繋がっているんだ...という勝手な推測の元、「jjencodeをv8に依存しない形でc++に移植しよう」と思い始めたのがこの記事をポストする30分前。今出来上がりました。テストしながら書いてます。
まず、オリジナルのまま関数で移植しました。ふつーのC++のコードです。
#include <sstream>
#include <iostream>
#include <string>

using namespace std;

string jjencode(string gv, string& text) {
  stringstream r, s;
  const char* b[] = { "___", "__$", "_$_", "_$$", "$__", "$_$", "$$_", "$$$", "$___", "$__$", "$_$_", "$_$$", "$$__", "$$_$", "$$$_", "$$$$" };

  for (int i = 0; i < text.size(); i++) {
    char n = text.at( i );
    if (n == 0x22 || n == 0x5c) {
      s << "\\\\\\" << dec << n;
    } else if ((0x20 <= n && n <= 0x2f) || (0x3A <= n == 0x40) || (0x5b <= n && n <= 0x60) || (0x7b <= n && n <= 0x7f)) {
      s << dec << n;
    } else if ((0x30 <= n && n <= 0x39) || (0x61 <= n && n <= 0x66)) {
      if (!s.str().empty()) r << "\"" << s.str() << "\"+";
      r << gv << "." << b[ n < 0x40 ? n - 0x30 : n - 0x57 ] << "+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x6c) { // 'l'
      if (!s.str().empty()) r << "\"" << s.str() << "\"+";
      r << "(![]+\"\")[" << gv << "._$_]+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x6f) { // 'o'
      if (!s.str().empty()) r << "\"" << s.str() << "\"+";
      r << gv << "._$+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x74) { // 'u'
      if( !s.str().empty() ) r << "\"" << s.str() << "\"+";
      r << gv << ".__+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x75) { // 'u'
      if( !s.str().empty() ) r << "\"" << s.str() << "\"+";
      r << gv << "._+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n < 128) {
      if (!s.str().empty()) r << "\"" << s.str();
      else r << "\"";
      r << "\\\\\"+";
      stringstream ss;
      string ns;
      ss << oct << int(n) && ss >> ns;
      string s08i = "01234567";
      for (string::iterator it = ns.begin(); it != ns.end(); it++) {
        if (s08i.find(*it) != string::npos)
          r << gv << "." << b[ *it-'0' ] << "+";
        else
          r << *it;
      }
      s.str("");
      s.clear(stringstream::goodbit);
    }else{
      if (!s.str().empty()) r << "\"" << s;
      else r << "\"";
      r << "\\\\\"+" << gv << "._+";
      stringstream ss;
      string ns;
      ss << hex << int(n) && ss >> ns;
      string s16i = "0123456789";
      string s16a = "abcdef";
      for (string::iterator it = ns.begin(); it != ns.end(); it++) {
        if (s16i.find(tolower(*it)) != string::npos)
          r << gv << "." << b[ *it-'0' ] << "+";
        else
          if (s16a.find(tolower(*it)) != string::npos)
            r << gv << "." << b[ tolower(*it)-'a'+10 ] << "+";
          else
            r << *it;
      }
      s.str("");
      s.clear(stringstream::goodbit);
    }
  }
  if (!s.str().empty()) r << "\"" << s.str() << "\"+";

  s.str("");
  s.clear(stringstream::goodbit);
  s <<
    gv << "=~[];" <<
    gv << "={___:++" << gv +",$$$$:(![]+\"\")["+gv+"],__$:++"+gv+",$_$_:(![]+\"\")["+gv+"],_$_:++" <<
    gv+",$_$$:({}+\"\")["+gv+"],$$_$:("+gv+"["+gv+"]+\"\")["+gv+"],_$$:++"+gv+",$$$_:(!\"\"+\"\")[" <<
    gv+"],$__:++"+gv+",$_$:++"+gv+",$$__:({}+\"\")["+gv+"],$$_:++"+gv+",$$$:++"+gv+",$___:++"+gv+",$__$:++"+gv+"};" <<
    gv+".$_=" <<
    "("+gv+".$_="+gv+"+\"\")["+gv+".$_$]+" <<
    "("+gv+"._$="+gv+".$_["+gv+".__$])+" <<
    "("+gv+".$$=("+gv+".$+\"\")["+gv+".__$])+" <<
    "((!"+gv+")+\"\")["+gv+"._$$]+" <<
    "("+gv+".__="+gv+".$_["+gv+".$$_])+" <<
    "("+gv+".$=(!\"\"+\"\")["+gv+".__$])+" <<
    "("+gv+"._=(!\"\"+\"\")["+gv+"._$_])+" <<
    gv+".$_["+gv+".$_$]+" <<
    gv+".__+" <<
    gv+"._$+" <<
    gv+".$;" <<
    gv+".$$=" <<
    gv+".$+" <<
    "(!\"\"+\"\")["+gv+"._$$]+" <<
    gv+".__+" <<
    gv+"._+" <<
    gv+".$+" <<
    gv+".$$;" <<
    gv+".$=("+gv+".___)["+gv+".$_]["+gv+".$_];" <<
    gv+".$("+gv+".$("+gv+".$$+\"\\\"\"+" << r.str() << "\"\\\"\")())();";

  return s.str();
}

int main(void) {
  string line, content;
  while(!cin.eof()) {
    getline(cin, line);
    content += line;
  }
  cout << jjencode("$", content) << endl;
}
これで前回失敗したjqueryで試してみました。結果は...




30秒以内では戻ってこず断念。
あれーと思って、「そうか。一回結果を格納しちゃってるのがまずいのか!そうなら逐次出力すればいい!」とまた勝手な推測の元、stringstreamに溜め込まずcoutに吐き出す様修正しました。
#include <sstream>
#include <iostream>
#include <string>

using namespace std;

int main(void) {
  const char* b[] = { "___", "__$", "_$_", "_$$", "$__", "$_$", "$$_", "$$$", "$___", "$__$", "$_$_", "$_$$", "$$__", "$$_$", "$$$_", "$$$$" };
  string gv = "$";
  cout <<
    gv << "=~[];" <<
    gv << "={___:++" << gv +",$$$$:(![]+\"\")["+gv+"],__$:++"+gv+",$_$_:(![]+\"\")["+gv+"],_$_:++" <<
    gv+",$_$$:({}+\"\")["+gv+"],$$_$:("+gv+"["+gv+"]+\"\")["+gv+"],_$$:++"+gv+",$$$_:(!\"\"+\"\")[" <<
    gv+"],$__:++"+gv+",$_$:++"+gv+",$$__:({}+\"\")["+gv+"],$$_:++"+gv+",$$$:++"+gv+",$___:++"+gv+",$__$:++"+gv+"};" <<
    gv+".$_=" <<
    "("+gv+".$_="+gv+"+\"\")["+gv+".$_$]+" <<
    "("+gv+"._$="+gv+".$_["+gv+".__$])+" <<
    "("+gv+".$$=("+gv+".$+\"\")["+gv+".__$])+" <<
    "((!"+gv+")+\"\")["+gv+"._$$]+" <<
    "("+gv+".__="+gv+".$_["+gv+".$$_])+" <<
    "("+gv+".$=(!\"\"+\"\")["+gv+".__$])+" <<
    "("+gv+"._=(!\"\"+\"\")["+gv+"._$_])+" <<
    gv+".$_["+gv+".$_$]+" <<
    gv+".__+" <<
    gv+"._$+" <<
    gv+".$;" <<
    gv+".$$=" <<
    gv+".$+" <<
    "(!\"\"+\"\")["+gv+"._$$]+" <<
    gv+".__+" <<
    gv+"._+" <<
    gv+".$+" <<
    gv+".$$;" <<
    gv+".$=("+gv+".___)["+gv+".$_]["+gv+".$_];" <<
    gv+".$("+gv+".$("+gv+".$$+\"\\\"\"+";
  cout.flush();

  stringstream s;
  while(!cin.eof()) {
    char n;
    cin.get(n);

    if (n == 0x22 || n == 0x5c) {
      s << "\\\\\\" << dec << n;
    } else if ((0x20 <= n && n <= 0x2f) || (0x3A <= n == 0x40) || (0x5b <= n && n <= 0x60) || (0x7b <= n && n <= 0x7f)) {
      s << dec << n;
    } else if ((0x30 <= n && n <= 0x39) || (0x61 <= n && n <= 0x66)) {
      if (!s.str().empty()) cout << "\"" << s.str() << "\"+";
      cout << gv << "." << b[ n < 0x40 ? n - 0x30 : n - 0x57 ] << "+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x6c) { // 'l'
      if (!s.str().empty()) cout << "\"" << s.str() << "\"+";
      cout << "(![]+\"\")[" << gv << "._$_]+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x6f) { // 'o'
      if (!s.str().empty()) cout << "\"" << s.str() << "\"+";
      cout << gv << "._$+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x74) { // 'u'
      if( !s.str().empty() ) cout << "\"" << s.str() << "\"+";
      cout << gv << ".__+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n == 0x75) { // 'u'
      if( !s.str().empty() ) cout << "\"" << s.str() << "\"+";
      cout << gv << "._+";
      s.str("");
      s.clear(stringstream::goodbit);
    } else if (n < 128) {
      if (!s.str().empty()) cout << "\"" << s.str();
      else cout << "\"";
      cout << "\\\\\"+";
      stringstream ss;
      string ns;
      ss << oct << int(n) && ss >> ns;
      string s08i = "01234567";
      for (string::iterator it = ns.begin(); it != ns.end(); it++) {
        if (s08i.find(*it) != string::npos)
          cout << gv << "." << b[ *it-'0' ] << "+";
        else
          cout << *it;
      }
      s.str("");
      s.clear(stringstream::goodbit);
    }else{
      if (!s.str().empty()) cout << "\"" << s;
      else cout << "\"";
      cout << "\\\\\"+" << gv << "._+";
      stringstream ss;
      string ns;
      ss << hex << int(n) && ss >> ns;
      string s16i = "0123456789";
      string s16a = "abcdef";
      for (string::iterator it = ns.begin(); it != ns.end(); it++) {
        if (s16i.find(tolower(*it)) != string::npos)
          cout << gv << "." << b[ *it-'0' ] << "+";
        else
          if (s16a.find(tolower(*it)) != string::npos)
            cout << gv << "." << b[ tolower(*it)-'a'+10 ] << "+";
          else
            cout << *it;
      }
      s.str("");
      s.clear(stringstream::goodbit);
    }
    cout.flush();
  }
  if (!s.str().empty()) cout << "\"" << s.str() << "\"+";

  cout << "\"\\\"\")())();" << endl;
}
これで前回失敗したjqueryで試してみました。結果は...




またもや30秒以内では戻ってこず断念。

おかしいな...と思ってmod_ext_filterを通さず実行したらjqueryのファイル全体でも1.5秒程で終了しているので、どうやらmod_ext_filter側が蓄積してしまっているのが原因だと分かりました。 ... orz

まーそうやわなー。あたりまえやなー。勝手な推測しすぎです。

ただ、一度作ったjavascriptファイルをこのツールで変換して静的ファイルとして置く事は出来るはずですので、利用価値がない...とまでは言えないかもしれません。なお、jQueryの場合は$を潰すので変数gvを$以外のものにしないと動きません。
Posted at by




そもそもvimでOOはしんどい。
function! Class_Prototype() dict
  return self
endfunction

function! Class_Override(...) dict
  if a:0 == 0|throw "Invalid Parameter"|endif
  let class = copy(self)
  let class.__NAME__ = a:1
  if type(a:2) == type(class.New)
    let class.New = a:2
  else
    let class.New = self.New
  endif
  let class.Super = self
  return class
endfunction

function! Class_New(...) dict
  let instance = copy(self)
  call remove(instance, "New")
  call remove(instance, "Override")
  let instance.Super = self
  return instance
endfunction

function! Class_ToString() dict
    return self.__NAME__
endfunction

let Object = {
 \ "__NAME__" : "Object",
 \ "Prototype"function("Class_Prototype"),
 \ "Override"function("Class_Override"),
 \ "Super"{},
 \ "New"function("Class_New"),
 \ "ToString"function("Class_ToString")}


function! Human_Sing() dict
  echo self.perfix . "は" . self.name . "。" . self.title . "\n"
  return self
endfunction
function! Human_New(...) dict
  let instance = copy(self)
  let instance.perfix = a:1
  let instance.name = a:2
  let instance.title = a:3
  let instance.Sing = function("Human_Sing")
  return instance
endfunction
let Human = Object.Override("Human", function("Human_New"))

function! Gian_Boxing(who) dict
  echo a:who . "のくせに生意気だぞ!!!\n"
  return self
endfunction
let Gian = Human.Override("Gian", {})
let Gian.Boxing = function("Gian_Boxing")
let Dekisugi = Human.Override("Dekisugi", {})

silent! unlet gian
silent! unlet dekisugi
let gian = Gian.New("俺", "ジャイアン", "ガキ大将")
let dekisugi = Dekisugi.New("僕", "出来杉", "優等生")

call dekisugi.Sing()
call gian.Sing().Boxing("のび太").Boxing("スネ夫")

僕は出来杉。優等生
俺はジャイアン。ガキ大将
のび太のくせに生意気だぞ!!!
スネ夫のくせに生意気だぞ!!!
つかわねー!

参考文献
JSでthisをそのまま返す関数を作っておくと便利?
PHP で引数をそのまま返す関数を作っておくと便利
Posted at by



2009/08/04


smegheadさんがtthttpdのpatchを書いてくれました。感謝!

その後、デフォルトページがCGIの場合に上手く動かないバグを修正しました。
お礼とは言っては何ですが(Windowsなんかイラネかもしれませんが)、smegheadさんが作っておられるC言語で書かれたBTS「starbug1」をWindowsにポーティングしてみました。
以下patch
diff -u starbug1-1.3.01.orig/hook.c starbug1-1.3.01/hook.c
--- starbug1-1.3.01.orig/hook.c 2009-07-12 20:37:55.000000000 +0900
+++ starbug1-1.3.01/hook.c  2009-08-04 10:11:19.125000000 +0900
@@ -4,7 +4,11 @@
 #include <cgic.h>
 #include <dirent.h>
 #include <sys/stat.h>
+#ifndef _WIN32
 #include <dlfcn.h>
+#else
+#include <windows.h>
+#endif
 #include "data.h"
 #include "alloc.h"
 #include "util.h"
@@ -12,6 +16,24 @@
 #include "hook_data.h"
 #include "simple_string.h"
 
+#ifdef _WIN32
+#define dlopen(x,y) (void*)LoadLibrary(x)
+#define dlsym(x,y) (void*)GetProcAddress((HMODULE)x,y)
+#define dlclose(x) FreeLibrary((HMODULE)x)
+const char* dlerror() {
+    static char szMsgBuf[256];
+    FormatMessage(
+            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+            NULL,
+            GetLastError(),
+            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+            szMsgBuf,
+            sizeof szMsgBuf,
+            NULL);
+    return szMsgBuf;
+}
+#endif
+
 static void put_env_a(char* name, char* value, char* buf)
 {
     sprintf(buf, "%s=%s", name, value);
diff -u starbug1-1.3.01.orig/util.c starbug1-1.3.01/util.c
--- starbug1-1.3.01.orig/util.c 2009-07-25 22:38:03.000000000 +0900
+++ starbug1-1.3.01/util.c  2009-08-04 11:39:35.078125000 +0900
@@ -698,9 +698,21 @@
     char locale_utf8[DEFAULT_LENGTH];
     sprintf(locale_utf8, "%s.UTF-8", locale);
     d("locale: %s\n", locale_utf8);
+#ifndef _WIN32
     setenv("LANG", locale_utf8, 1); /* FreeBSD(さくらインターネット)でsetlocaleが動作しない場合があったため、環境変数を書き換える。 */
+#else
+    {
+        char envstr[256];
+        strcpy(envstr, "LANG=");
+        strcat(envstr, locale_utf8);
+        putenv(envstr);
+    }
+#endif
     d("setlocale: %s\n", setlocale(LC_ALL, locale_utf8));
     d("bindtextdomain: %s\n", bindtextdomain("starbug1", "locale"));
     d("textdomain: %s\n", textdomain("starbug1"));
+#ifdef _WIN32
+    bind_textdomain_codeset("starbug1", "utf-8");
+#endif
 }
 /* vim: set ts=4 sw=4 sts=4 expandtab fenc=utf-8: */
ビルドに必要なツール類はgnuwin32なんかで取得して下さい。
見事起動出来ました。
starbug1-win32
ありがとうございました。
Posted at by