2012年12月28日金曜日

SpamAssassin for xmailserver (windows) の解説を増やしました

 どもども、SpamAssassin Filter for XMailServer (Windows)に関する記事です。  最近、Windows にSpamAssassinをインストールするのがしんどいので、Ubuntu に SpamAssassin 日本語パッチ版をインストールする手順を書き加えました。 UbuntuにSpamAssassin日本語パッチ版をインストール  まぁ、仮想サーバも一般的になってきた事だし、こういう構成も気楽にできるようになってきたのでは?と思います。SpamAssassinの導入が、どうにも・・・と、お悩みの方も、これを機会に導入を検討されてみては、いかがでしょうか?

2017/4/18追記:https://github.com/oki-miyuki/xmspamc に移しました。Wikiとか放置ですみませんorz

2012年12月26日水曜日

std::move と asio

いやー、C++11 素晴らしいですね〜。 とりあえず、頭に描いたシナリオどおりに事が運ぶか、実験くんしてみました。 シナリオは、

  1. 所有権のあるコピーできない Foo クラスがあり
  2. ref では、まずいので、shared_ptr で asio のハンドラに Foo を保持させ
  3. io_service で処理されたら所定の vector へ move しながら Foo をぶっ込む
  4. へっへっへっ、リソース管理しなくても、適当に処理できるぜ!

#include <iostream>
#include <vector>
#include <boost/bind.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/ref.hpp>

class Foo {
private:
  int n_;
public:
  Foo() : n_() {}
  Foo(int n) : n_(n)  {
    std::cout << "Foo(" << n << ");" << std::endl;
  }
  
  Foo(Foo&& f) : n_(f.n_) {
    f.n_ = 0;
  }
  
  ~Foo() { std::cout << "~Foo(); /* " << n_ << " */" << std::endl; }
  
  Foo& operator = (Foo&& rhs) { n_ = rhs.n_; rhs.n_ = 0; return *this; }
  
  int n() const { return n_; }
};

void post_move( boost::shared_ptr<Foo> f, std::vector<Foo>& v ) {
  std::cout << "post_move push_back : " << f.get()->n() << std::endl;
  v.push_back( std::move( *f.get() ) );
}

int main() {
  boost::asio::io_service service;
  std::vector<Foo> v;
  
  for( int i = 0; i < 10; ++i ) {
    Foo f(i+1);
    boost::shared_ptr<Foo> nf( new Foo( std::move(f) ) );
    service.post( boost::bind( post_move, nf, boost::ref(v) ) );
  }  

  std::cout << ">>> run! <<<" << std::endl;
  service.run();
  
  std::cout << ">>> done! <<<" << std::endl;
  
  boost::for_each( v, [](const Foo& f) { std::cout << f.n() << std::endl; } );

  return 0;
}
結果
Foo(1);
~Foo(); /* 0 */
Foo(2);
~Foo(); /* 0 */
Foo(3);
~Foo(); /* 0 */
Foo(4);
~Foo(); /* 0 */
Foo(5);
~Foo(); /* 0 */
Foo(6);
~Foo(); /* 0 */
Foo(7);
~Foo(); /* 0 */
Foo(8);
~Foo(); /* 0 */
Foo(9);
~Foo(); /* 0 */
Foo(10);
~Foo(); /* 0 */
>>> run! <<<
post_move push_back : 1
~Foo(); /* 0 */
post_move push_back : 2
~Foo(); /* 0 */
~Foo(); /* 0 */
post_move push_back : 3
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
post_move push_back : 4
~Foo(); /* 0 */
post_move push_back : 5
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
post_move push_back : 6
~Foo(); /* 0 */
post_move push_back : 7
~Foo(); /* 0 */
post_move push_back : 8
~Foo(); /* 0 */
post_move push_back : 9
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
~Foo(); /* 0 */
post_move push_back : 10
~Foo(); /* 0 */
>>> done! <<<
1
2
3
4
5
6
7
8
9
10
~Foo(); /* 1 */
~Foo(); /* 2 */
~Foo(); /* 3 */
~Foo(); /* 4 */
~Foo(); /* 5 */
~Foo(); /* 6 */
~Foo(); /* 7 */
~Foo(); /* 8 */
~Foo(); /* 9 */
~Foo(); /* 10 */

2012年12月21日金曜日

std::move と std::set_difference

 ウィンドウズ系のプログラムは、win2k をサポートしないといけないとかいう理由で、vc8 を変える訳にはいかないのであった。そんな理由から、C++03 以外に選択肢が無い現状なのであった。  ただ、今回 android ndk でコードを書いてまして、所有権のあるクラスを管理する事になりました。そうなんです。コピー禁止で、std::move が、使いたくて使いたくてしょうがない症候群。これ、今までだと、リソースをマネージャクラスに保持させて管理するとかいう設計にしなくてはならず、スレッドが絡んでくると煩雑になってしょうがない部分でした。  android ndk r8b なんか Foo::Foo( Foo&& foo ) とかしてもコンパイル通るし、いろいろ調べてると、どうも c++11も使えるっぽい。まじめに gcc の状況を見たら、gcc-4.4.3 と gcc-4.6 が入っていて、gcc-4.6 の gnu-stl だと、まさに表にある通りで -std=gnu++0x のオプションでも一部機能には対応していました。ヘッダーの中身を確認しましたが、std::swap も std::move で実装されてます。  と、ここで std::set_difference の move を使うバージョンみたいなんが欲しくなって、実装してみました。コンパイルが通ってしまったんで、ついつい嬉しくなって、晒してみる事に…。あくまで、コンパイルが通っただけなんで、動作の保証はありません。はい。
#pragma once
#ifndef MOVE_DIFFERENCE_HPP
#define MOVE_DIFFERENCE_HPP

  template<typename ITER1, typename ITER2>
  ITER2 move(
    ITER1 first1, ITER1 last1,
    ITER2 first2
  ) {
    while( first1 != last1 ) {
      *first2 = std::move( *first1 );
      ++first1; ++first2;
    }
    return first2;
  }

  template<typename ITER1, typename ITER2, typename ITER3>
  void move_difference(
    ITER1& first1, ITER1 last1,
    ITER2  first2, ITER2 last2,
    ITER3& first3
  ) {
    ITER1 pos1 = first1;
    while( pos1 != last1 ) {
      if( first2 == last2) {
        first3 = std::move(pos1, last1, first3);
        return;
      }
      if( *pos1 < *first2 ) { // 取り除く候補
        *first3 = std::move( *pos1 );
        ++pos1;
        ++first3;
      } else if( *first2 < *pos1 ) { // 関係無い候補はスキップ
        ++first2;
      } else { // 等しいので双方インクリメント
        std::swap( *first1, *pos1 );
        ++first1; ++pos1;
        ++first2;
      }
    }
    return;
  }

  template<typename ITER1, typename ITER2, typename ITER3, typename COMP>
  void move_difference(
    ITER1& first1, ITER1 last1,
    ITER2  first2, ITER2 last2,
    ITER3& first3, COMP ope
  ) {
    ITER1 pos1 = first1;
    while( pos1 != last1 ) {
      if( first2 == last2) {
        first3 = std::move(pos1, last1, first3);
        return;
      }
      if( ope( *pos1, *first2) ) { // 取り除く候補
        *first3 = std::move( *pos1 );
        ++pos1;
        ++first3;
      } else if( ope( *first2, *pos1 ) ) { // 関係無い候補はスキップ
        ++first2;
      } else { // 等しいので双方インクリメント
        std::swap( *first1, *pos1 );
        ++first1; ++pos1;
        ++first2;
      }
    }
    return;
  }
  
#endif // MOVE_DIFFERENCE_HPP

2012年12月12日水曜日

カラーレーザープリンターを買った


 年賀状の季節。インクジェットプリンターの調子が悪く、いくらノズルをクリーニングして、ノズルチェックパターンを印刷しても、一向によくなる気配が無い。もうプリンターなんて、エア・プリントで良いし、年賀状は印刷頼んだ方が安上がりじゃね?と嫁さんに言った事があるけども、家にプリンターは必須なんだそうで・・・。

 正直、インクジェットプリンターには嫌気がさしていたのだ。インクは高いし、すぐにプリンターの調子は悪くなるし、ノズルを連続クリーニングすると、吹付け口のスポンジがベタベタになって、しばらく使えなくなるし、印刷は遅いし・・・。

 昨年、まじめにカラーレーザープリンタの購入を検討したけれども、インクジェット用紙の年賀状を買ってしまったのと、いまいち値段が高かったので諦めていました。ところが、価格.com で調べたら、NEC MultiWriter 5750cが 12,800円!!! これは凄いでー!!!

 嫁さんと相談した結果、インクジェット用紙の年賀状を交換してでも、カラーレーザープリンターを買おうという事になりました。

 そして・・・来ました・・・来ました・・・!
まぁ、プリンターは、ドデカイけれども、A4普通紙に印刷してみたら、めっちゃ綺麗!!!

先日、室蘭に行って食べた焼き鳥(豚串)が、美味しそうに印刷できました。もう、これ感動もんです。

 しかも、標準でネットワーク・ポートが付いてるので、ルータ(Time Capsule)に接続して、ネットワーク・プリンタに変身!!!今まで、印刷する時には、プリンタを用意してケーブルを繋いでとかしていたのが嘘のようです。

印刷も速い速い!

 気になるランニング・コストですが、トナー(小)でおよそ1000枚ほど印刷できるようなので、12,800/1,000 = 12.8 円です。実はプリンターを買うよりトナーを買った方が高いという・・・。トナーが3色 x 8,800 黒 4,100 なので、通常のランニングコストは (8,800 * 3 + 4,100) / 2,000 = 15.25円 となります。
 ただ、この枚数は、NECのHPより拝借した数字で、カラーが各色5%程度という前提で計算されております。従って、イラストや写真をA4フルで印刷すると、コストは6.7倍(5x3=15%より算出)になります。
 考えてもみてください。インクジェットプリンターで印刷されるのをジーっと見守りながら無駄な時間を過ごしたり、インクジェット用紙を買ったりとか、プリンターだめになったり印刷結果がすぐ汚くなったりとかストレス抱え込むぐらいなら、カラーレーザー買った方がマシってもんです。

 いやー、テンション上がるわwww 2012/12/13 コスト計算について訂正:トナーの型番を勘違いしていて1000枚計算していた部分を訂正しました。カラートナーは4色ではなく3色だったので計算式を訂正しました。Amazon で売っているトナーは新品とうたったリサイクル品なので正規価格による計算に修正しました。リサイクル品のトナーは品質が異なるので、考えて使わった方が良いと思います。

2012年12月5日水曜日

Android ndk 突っ込んでます

 忙しいとかで、ブログの更新も滞ってます。一応、アウトプットもしておかないと…。
最近は、Android ndk を突っ込んでます。まぁ、Java では限界があるんです。Java で大規模開発した事が無いので、パッケージの構成とかも失敗しました。もうちょい、ちゃんとパッケージを分けて作っておくんだったと…。モジュールの分離が、なかなか難しくて四苦八苦してたのも事実としてあります。

 ndk の情報で有益なサイトを見つけました。
  1. Windows 環境にて Android アプリを Eclipse と Cygwin を使わずにビルドする。
  2. Android NDKの中身はどうなっている? - アプリの定義を記す「Application.mk」 
  3. ファイルやライブラリの情報を定義する「Android.mk」
です。(1.)の構成は、Linux や mac の環境でも同じ事が言えます。android-cmake を使って楽したいです。(2.)(3.)Android NDK に付属のドキュメントを眺めましたが、書いてある事が要領を得ない感じでピンと来ませんでした。実際、適当に書いてると、ディレクトリの構成と Application.mk や Android.mk の配置で嵌りました。NDK のドキュメントには、jni ディレクトリ下の Application.mk が option であるかのような記述がされてますが、APP_ABI を指定できるのは、jni 直下の Application.mk だけであり、プロジェクト直下の Application.mk に記述しても丸無視されます。NDKの必要なポイントがコンパクトに記述されていて、分かりやすいです。

 しばらく ndk の話題が続きそう…

2012年11月21日水曜日

macbook vmware windows keyboard setting 備忘録

 macbook で VMWare fusion 5 を使って、ウィンドウズ環境構築してますが、素のままだと、キーボードの挙動が???となってストレスが溜まります。探せば回避方法の情報は載ってるんですが、ミニマルなセットが無いのと、探すのに意外と時間を食われるので、備忘録として書いとく事にしました。

 どう考えても、ウィンドウズでは command キーと option キーは入れ替えた方がいいので、レジストリを設定してキーを入れ替える事にします。

以下の部分を、keymap.reg とかいうファイルに保存してダブルクリックすると、レジストリが設定されます。
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,38,00,5b,e0,5b,e0,38,00,\
  00,00,00,00

VMWare Fusion のキーボード設定では、まあ、ウィンドウズで使う場合のマックのショートカットはパスしておきたいところ
   
次に、Command キーは入れ替えたので、キーマッピングは無効にしておきたい所。
 
そんで持って、Control キーを押しながら複数選択すると、マウスの右ボタンが押された状態になって、個別複数選択ができないので、これも無効にします。
 
Fusion ショートカットは、お好みで… Command 系は違うキーにアサインした方がいいかもしれません。

ウィンドウズの場合、ファンクションキーをよく使うので、マックのキーボード設定にてファンクションキーを有効にすると…。



2012年11月20日火曜日

ATL-ISAPI の受難

 いやー、出るわ出るわ、どんどん風化しますわ。 まじ、ウィンドウズ上で、ATLとかWTLとかWCFとかWPFとか、もう使いたくないわwww。 ATLISAPI を利用した Soapサービスを C++ でゴリゴリ書いたんですが、捨てられる捨てられる。その捨てられっぷりが見事で、IIS7になったら、まともに動作しないwww。  デバッグしようと思っても、プロセスが開始されず、アタッチもされないし、プロセス、即終了するしwww。 どないせぇちゅうねん。たまたま、Soap じゃない ISAPI.dll も作ってて、そっちは動いてたんで、同じ名前のアプリケーション・プールでそっちを動かしてプロセス・アタッチする事で、手がかりは掴めました。  原因は、ここに書いてあるような事で、とにかく、おかしい。リソース・リークしてるかもしれんけど、デバッグできんので、下のように修正してデバッグを続ける事に・・・。
  ~CRevertThreadToken() throw()
  {
    // should have been Restore()'d by now.
#ifdef _DEBUG
  // *****BUG****
  // if(m_hThreadToken != INVALID_HANDLE_VALUE) DebugBreak();
#endif
}
 おかしい、トレースしている範囲では、特におかしそうな所は無さそう…だけど、ハンドラが全く呼ばれない!でも、当たりを付けて探ったら、見つけました。Code Plex の方に情報が! あー、思い当たる節あるわ…つい先日、リソースハンドルがNULLで(#^ω^)ってなってたのと、同じや。 とりあえず、疲れた。

2012年11月12日月曜日

gdal patch 結末

 前回投下したパッチですが、-optfile というオプション自体をテキストファイルで受け渡すオプション(ややこしい)が追加されており、これを利用すると、UTF-8の文字コードでオプションを渡しても文字化けが起きないので、パッチは不要という事になりました。  この方法は確かにスマートで、自分も base64 でオプションを指定するオプションとか、似たような事を考えてました。UTF-8でオプションが使える事の利点は、QGISなどの既にマルチ言語で動作しているアプリケーションから、複数の言語をチャンポンにして扱える事が挙げられます。  チケットでのディスカッションは、こちら。なかなか話が通じなくて、困りました。多分、どちらも、そう思っていた事でしょう。  ま、自分の投下したパッチも、まるっきり無駄では無くて、コンソール画面にエラーを出力する場合には利用できると思います。ただ、クリティカルでは無いので、取り込まなくても支障は無いでしょう。とりあえず、何のためにあるねん chcp 65001 アホけ?という辺りで締めたいと思います。

2012年11月2日金曜日

GDAL patch 投下

 とりあえず、QGisのコミュニティのCavaliniさんに、パッチを渡してみましたが、QGis の問題というよりもGDALの問題なんで、GDAL-developer ML に投下した方が良いのかも?  ただ前回、短いpatchだからOKかも?と思ってGDAL-dev MLにパッチ投稿したら、MLへのpatch投下は、やっぱり遠慮して欲しいと言われたので、説明をした上で、どなたかにパッチを送るという手順になりそう。 アカウントは登録されているはずなんだけど、OSGeo の track にログインできないので、track に直接投下できなくて、困ってるのだ…。 パッチは、version 'gdal-2.0dev' https://svn.osgeo.org/gdal/trunk/gdal のもので、新しくコマンドライン引数を管理するクラスが生成されていたので、ちょこっと直すだけで、コマンドライン型アプリ全部に適用されそうです。
*** ogr/ogrutils.cpp Fri Nov  2 10:47:34 2012
--- ../gdal_new/ogr/ogrutils.cpp Fri Nov  2 12:28:33 2012
***************
*** 754,760 ****
  /* -------------------------------------------------------------------- */
          else
          {
!             papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
          }
      }
  
--- 754,762 ----
  /* -------------------------------------------------------------------- */
          else
          {
!             char* pszTmp = CPLRecodeCommandInput( papszArgv[iArg] );
!             papszReturn = CSLAddString( papszReturn, pszTmp );
!             CPLFree(pszTmp);
          }
      }
  
*** port/cpl_string.h Fri Nov  2 10:47:29 2012
--- ../gdal_new/port/cpl_string.h Fri Nov  2 12:29:27 2012
***************
*** 177,182 ****
--- 177,184 ----
                                     const char *pszDstEncoding ) CPL_WARN_UNUSED_RESULT;
  int CPL_DLL CPLIsUTF8(const char* pabyData, int nLen);
  char CPL_DLL *CPLForceToASCII(const char* pabyData, int nLen, char chReplacementChar) CPL_WARN_UNUSED_RESULT;
+ char CPL_DLL *CPLRecodeCommandInput( const char* pszSource ) CPL_WARN_UNUSED_RESULT;
+ char CPL_DLL *CPLRecodeCommandOutput( const char* pszSource ) CPL_WARN_UNUSED_RESULT;
  
  CPL_C_END
  
*** port/cpl_recode.cpp Fri Nov  2 10:47:30 2012
--- ../gdal_new/port/cpl_recode.cpp Fri Nov  2 12:16:08 2012
***************
*** 324,329 ****
--- 324,372 ----
          return -1;
  }
  
+ 
+ /************************************************************************/
+ /*                    CPLRecodeCommandInput()                           */
+ /************************************************************************/
+ /**
+  * Convert a string from a platform encoding to UTF-8, effects only windows platform.
+  *
+  * There is a I/O problem in windows command line character arguments.
+  * Unfortunately, Run batch file written in UTF-8 fails some case.
+  *
+  * @return a NULL terminated string which should be freed with CPLFree().
+  */
+ 
+ char CPL_DLL *CPLRecodeCommandInput( const char* pszSource )
+ 
+ {
+ #ifdef _WIN32
+   return CPLRecode( pszSource, "CP0", CPL_ENC_UTF8 );
+ #else
+   return CPLStrdup(pszSource);
+ #endif
+ }
+ 
+ /************************************************************************/
+ /*                    CPLRecodeCommandOutput()                          */
+ /************************************************************************/
+ /**
+  * Convert a string from UTF-8 to a platform encoding, effects only windows platform.
+  *
+  * There is a I/O problem in windows command line character arguments.
+  *
+  * @return a NULL terminated string which should be freed with CPLFree().
+  */
+ char CPL_DLL *CPLRecodeCommandOutput( const char* pszSource )
+ 
+ {
+ #ifdef _WIN32
+   return CPLRecode( pszSource, CPL_ENC_UTF8, "CP0" );
+ #else
+   return CPLStrdup(pszSource);
+ #endif
+ }
+ 
  /************************************************************************/
  /*                    CPLClearRecodeWarningFlags()                      */
  /************************************************************************/
*** port/cpl_recode_stub.cpp Fri Nov  2 10:47:29 2012
--- ../gdal_new/port/cpl_recode_stub.cpp Fri Nov  2 11:43:30 2012
***************
*** 166,172 ****
          && strcmp(pszDstEncoding,CPL_ENC_UTF8) == 0 )
      {
          int nCode = atoi( pszSrcEncoding + 2 );
!         if( nCode > 0 ) {
             return CPLWin32Recode( pszSource, nCode, CP_UTF8 );
          }
      }
--- 166,172 ----
          && strcmp(pszDstEncoding,CPL_ENC_UTF8) == 0 )
      {
          int nCode = atoi( pszSrcEncoding + 2 );
!         if( nCode >= 0 ) {
             return CPLWin32Recode( pszSource, nCode, CP_UTF8 );
          }
      }
***************
*** 178,184 ****
          && strncmp(pszDstEncoding,"CP",2) == 0 )
      {
           int nCode = atoi( pszDstEncoding + 2 );
!          if( nCode > 0 ) {
               return CPLWin32Recode( pszSource, CP_UTF8, nCode );
           }
      }
--- 178,184 ----
          && strncmp(pszDstEncoding,"CP",2) == 0 )
      {
           int nCode = atoi( pszDstEncoding + 2 );
!          if( nCode >= 0 ) {
               return CPLWin32Recode( pszSource, CP_UTF8, nCode );
           }
      }
 
2012/11/05 追記:やっぱ、GDAL-dev ML に投下しました。

Windows CMD args character conversion problem.

 ウィンドウズ環境におけるコマンドプロンプトの問題を説明するために、簡単なプログラムを書いてみました。ここが理解できないと、パッチが受け入れられないだろうとおもったので・・・
//
// 'Command Prompt Argument' check program
//
//  To compile, type below
//
//  cl /EHa /GR /MD chkarg.cpp
//

#include <iostream>
#include <iomanip>


void showHex(const char* str) {
  for( const unsigned char* p = reinterpret_cast<const unsigned char*>(str); *p != 0; ++p ) {
     std::cout << std::hex << "0x" << (int)*p << " ";
  }
  std::cout << std::endl;
}


int main(int argc, char* argv[]) {
  if( argc <= 1 ) return 1;

  showHex(argv[1]);

  return 0;
}
これを実行するバッチファイルは、こんなんです。
@echo off
echo Bad case UTF-8 arg command check
echo This text file was written in UTF-8 with Kanji.
echo result must be 
echo 0xe5 0x85 0x88
echo ===> run chkarg.
chkarg 先
 実行結果は
Bad case UTF-8 arg command check
This text file was written in UTF-8 with Kanji.
result must be
0xe5 0x85 0x88
0xe5 0x85 0x81 0x45
となります。chcp 65001 を行なっても状況に変わりはありません。

2012年10月26日金曜日

android proguard support.v4 error 対処 備忘録

なんか、久々に apk ファイルを作成しようと思ったら、
Proguard returned with error code 1. See console
というメッセージが出て、失敗する。 エラーの原因は、 android.support.v4 を処理しようとしているからって感じ。 対処法は、プロジェクト直下に作成した proguard.cfg ファイルに以下の2行を追加してやる
-dontwarn android.support.v4.**

-keep class android.support.** { *; }
と、これだけ。 参考:http://stackoverflow.com/questions/8723088/error-when-proguard-android-project

2012年10月3日水曜日

今時廃れた ISAPI Extension dll ではまる。

 Visual Studio 2005 から IIS の ISAPI Extension のウィザードが消失しました。しかし、一応 CHttpServer が残ってたんで、そっちを使ってたんですが、リソースのロードができない。 デバッガで追ってると、AfxGetResourceHandle() が NULL を返してきます。なんじゃこれ? DLLMain は既に定義されていて、自前で、ここの制御が不可能な状態に持ってきて、hInstance が、どこにも保存されていないなんて、何の罰ゲームだよ?とぼやきながら、なんやかんやと、半日潰しました(環境整えたり、原因調べたりで)。  結局、Hoge.dll という ISAPI Extension だったとすると、
  static HINSTANCE g_hInstance;
  HINSTANCE AhoGetResourceHandle() { return g_hInstance; }
...

  CHogeExtension::CHogeExtension() {
    ...
    g_hInstance = GetModuleHandle("hoge.dll");
  }
と、こんな感じの対応でいけました。

2012年10月1日月曜日

近況

 なんか、ブログの更新が滞ってます。というよりも、GDAL/OGR のMLにも投稿しとこうと思いつつも、そっちも滞ってます。室蘭にキャンプに行った話や、登別伊達時代村が思ってたよりも面白かった話なども書きたいのですが、滞ってます。趣味のプログラミングでも、試してみたい事はあるんですが、現在、全く手をつけられません。家庭を御座なりにしても、ディスられてしまいます。仕事の方も、やっぱ案件抱えながら、色々やると破綻してる気がします。リソースの配分が難しいです。  個人情報管理責任者、重たいです。ついこの間、審査を受けて、口頭では、色々と改善点を指摘されました。まず、何がシンドいかと言うと、国語が徹底的に苦手な自分が、文章管理をするというのは、徹底的にダメです。そして、今回の定期審査を受けて理解したのですが、自分が引き継ぐ前の状態のマネージメントレビュー関連の記録文書の整理がされていないので、何に使うのかサッパリわからない意味不明な様式が混ざっていたり、一度、自分なりにPマークの要求事項と照らし合わせて整合を取りながら、リファクタリングしないとダメです。国語の試験は、文章題の意味がわからず、論理的に答えたつもりでも、いつも50点前後しか取れた事が無いので、規格の要求する意味の理解が、めっちゃシンドいです。そして、このJISQ15001:2006を元に作成された社内文書のマニュアルと規定は、マネジメントの問題が絡むので、他の人に手伝ってもらう事はできても、やってもらうわけにもいきません。ざっと見積もっても、なんだかんだと丸々1週間は飛んで行きます。  次にクリティカル・パスの多さ、社内システムのライブラリの脂っこいところは他に書ける人がいません。C++わかる人間いません。それでも、やらせてみるんですが、新しい機能とかデッサン力の必要な部分は、濃すぎて、しょうがないかな?と思える点。で、こういう部分にリソース取られると、あっという間に時間消費します。  加えて、現在開発中の仕事。やらなければならない事は山ほどあって、やりたいのですが、足りないリソースを補って、食うための仕事を片付けないといけません。他には、お客さんから、あれこれ言われると、そちらも放置できないので、何か考えて対応していかないと、やっぱダメです。  そして、ちょこまかとイベントが発生するので、そちらにもリソースを取られます。  俺も出来ま専務、わかりま専務とか、言ってみたいぜ…。  皆さん、どんなに忙しくても読書しましょうね。読書しないと阿呆になりますよ?特に、こういう厳しい時代、変化の激しい時代は、読書が大切です。ダメになっていった人は、100%読書で勉強なんてしていませんから。勉強会に興味の無いプログラマーもダメです。だいたい、今の技術はトレンドも変化も速くて、直ぐに勢力が変わります。ひとつの技術でやっていけると思っているシステム系の人、生き残れませんよ。  ちょっと愚痴っぽくなってしまったか?

2012年9月13日木曜日

vc proj4 libgeotiff 忘備録

 書かないと忘れるので…

関連: libtiffのコンパイル
まずは、proj4 から… これを書いてる時のバージョンは、proj-4.8.0
nmake.opt を編集し、INSTDIR="C:\libs\proj" とかインストールしたい場所に設定しておく。後は、簡単に
C:\Downloads\proj-4.8.0> nmake -f makefile.vc
C:\Downloads\proj-4.8.0> nmake -f makefile.vc install-all
でオッケー
 次は、geotiff の方。
geo_config.vc を geo_config.h として利用する。
C:\Downloads\libgeotiff-1.4.0> copy geo_config.vc geo_config.h
makefile.vc を編集する。デフォルトは、C:\OSGEO4W というオープンソースGISのセットとして設定されているが、まじめにライブラリを利用する場合は、proj の設定が省略されているので、以下のような感じで編集する
#
# Typically the only thing that needs to be changed are the paths to the
# TIFF tree.  Note that we expect an existing build tree, in part because we
# need private include files from libtiff, but also we need access to getopt.h.
# in the ports directory.
#
# You may want to add optimization options to the CFLAGS macro as well. 
#

OSGEO4W = C:\OSGEO4W
LIBTIFF_DIR = C:\libs\libtiff
PROJ_DIR = C:\libs\proj

TIFF_INC = -I$(LIBTIFF_DIR)\include -I$(PROJ_DIR)\include
TIFF_LIB_DLL = $(LIBTIFF_DIR)\lib\libtiff_i.lib $(PROJ_DIR)\lib\proj_i.lib

# 必要に応じて、インストール先の prefix も設定します
...
...
...
そして、
C:\Downloads\libgeotiff-1.4.0> nmake -f makefile.vc
C:\Downloads\libgeotiff-1.4.0> nmake -f makefile.vc devinstall
以上。

2012年9月10日月曜日

C++Now読書会に参加した

 とりあえず、たまたま、うちの坊ちゃんと嫁さんが2週連続で出かけたので、C++Now読書会に参加できました。 一人で読むより効率的です。ゆるーい感じで、やっているので、我こそは!と思う方は、ROMでもいいから参加しましょう。  metaparse の方は、まだ Type, Value を map に登録する辺りが、もやっもやっとして納得できてません。mac 環境で、何故か g++ や clang++ が、まともにコンパイルできなかったので、手足をもがれたような状況も、ちょっと辛かったです。  で、コンパイルができない原因が、どうやら、ライセンス認証処理をしていなかった事にあるみたいでした。わかんねぇーよ。Moutain Lion になってから、どうも c++のコンパイルができないよーと嘆いている方は、多いのではないでしょうか? これをやらないと、iostream のヘッダーが見つからんとか、x86_64 アーキテクチャの iostream 系ライブラリが見つからんとか、いろいろと怒られます。

2012年8月30日木曜日

QGis Python Plugin と日本語の周辺3

 前回、UTF8で保存したバッチファイルを実行すればOKです。なんて書きましたが、問題がありました。 ウィンドウズのコマンドプロンプトが、コマンドラインの一部の文字コードの値を変更してしまうのです。そのため、使う文字コードによっては、まともに動作しません。  とりあえず、判明したのは「先」という漢字です。バイナリで表現すると、0xE5,0x85,0x88 の組みになります。もしかしたら、ANSI.SYS とかが組み込まれてて悪さしてるのかな?というのが頭を過ぎったのですが、Windows7 あたりでは、config.nt ファイルや、autoexec.nt ファイルなんて、ありませんでした。  コマンドプロンプトで chcp 65001(=UTF8) とか指定できますが、コンソールを通過すると文字化けするので、現時点では、まともに動作しません。よって、コマンドラインから入力される文字列は、MBCS (日本の場合 CP932=SJIS=ShiftJIS)に限定され、選択肢はありません。ウィンドウズだけのために、UNICODE文字セットを標準としてコンパイルするのは、問題があると思いますので、最小限の対処法は、入力値を MBCS から UTF8 に変換してやる事になります。  では、これを国際的に実装しようと思ったら、MultiByteToWideChar API を使って CPACP (= CP0) から、UNICODE に変換し、WideCharToMultiByte で UTF8 (=CP65001) にする以外に方法がありません。そうです、CPLWin32Recode 関数に "CP0" , "CP65001" という変換を促してやればいいのです。リポジトリに取り込まれたコードでは、CP0 は使わないだろうと思って、入力条件として コードページ > 0 としてしまったので、この条件を >= 0 とするよりありません。後、内部でUNICODEに相互変換する関数の実装があるのですが、変に複雑なんでウィンドウズの場合は MultiByteToWideChar と WideCharToMultiByte の関数に置き換えてあげた方が良いと考えてます。これらの変更を加えた上で、ogr2ogr 等の全てのコマンドプログラムに対して、コマンドの引数の文字コード変換を行うコードを挿入する必要があります。CPLArgumentConvert とかいう関数を設置してあげて、コーディング・ガイドラインを提示してあげた方が良いのかもしれません。という辺りを GDAL/OGR Develpment ML に投げてみようかと考えてます。 追記:GDAL_FILENAME_IS_UTF8 というのは、ウィンドウズの場合必須になります。ここを NO に設定すると、英語圏以外の文字コードは動作しません。  

2012年8月22日水曜日

boost range accumulate 習作

 対象のクラスが保持している要素数を数え上げるというパターンを range でチーンするには? 今回は、VC10で確認しました。 range でぶん回す対象と、加算する対象の型が違う時、どうするんだろ?と思ってたけど、ちゃんと考慮されているみたいです。
#include <boost/range/numeric.hpp>
#include <iostream>
#include <vector>

class foo {
public:
  int count_;
public:
  foo() : count_() {}
};

int take( int n, const foo& f ) { return n + f.count_; }


int main() {
  std::vector<foo> v;
  for( int i = 0; i < 20; ++i ) {
    foo f;
    f.count_ = i + 1;
    v.push_back( f );
  }

  int sum = boost::accumulate( v, 0, take );

  std::cout << sum << std::endl;

  return 0;
}

追伸:Bloggerの分類ラベル C++ が認識できない。全部 cpp に書き換えるのしんどい。どうしよう。以前は認識できてたのに…

2012年8月17日金曜日

台湾行ってきた(3日目)

 3日目の朝食は、「阜杭豆漿(フーハン・ドージャン)」という店に行きました。外まで人が、めっちゃ並んでますが、中は、大学の食堂のようというか、丸亀製麺方式というか、どんどん注文して流れる感じなので、そこそこ待ちますが、案外早く食べられました。

写真のように、ナンみたいにパンを炭火で焼くので、めっちゃ、美味しいです。白いのは温かい豆乳に砂糖を入れたもの。自転車通勤で豆乳飲んでる身としては、めっちゃストライクゾーン入ってます。冷たいバージョンの豆乳もあるみたいです。なんかわからんけど、ここも観光地化されてるので、注文を頼むオバちゃんの言うとおりに、適当に頼んでおけば大丈夫です。
その後、嫁さんが蒸し器が欲しいと、道具屋街みたいな所に行きました。

通り道という事で、またまた「冰讃」へ寄って、アップルマンゴーかき氷をwww。トッピングまでしました。

昼ごはんは、またまた小籠包の店「濟南鮮湯包」へ…。地下鉄に乗りマクローリン展開です。この店のジャコのチャーハン、凄い美味しかったんですが、1時間30分ぐらい待ちました…。4人掛けのテーブルが少ないので、3人は不利みたいです。2人組は、どんどん入ってました。ちょっと疲れた。

この後、電脳台北を満喫する予定でしたが、時間が押したので、このイベントはパスして、千と千尋の神隠しのモデルみたいな街、九份へと移動です。台北から直通のバスがあるらしいのですが、乗り場もわからないし、コロコロ変わって難度が高いみたいなんで、電車で台北駅から瑞芳駅まで乗る事にしました。時間帯が中途半端だったため、鈍行で移動です。瑞芳駅を降りたら、バス乗り場がサッパリわかりません。適当に、それらしき所に並んでたら、台湾のおっちゃん達が多分「おまえら、どこ行くねんタクシーあるで?九份へバス?あ?バスのりばは、あっちやあっち」という感じで話しかけて、バスのりばの方向を教えてもらいました。駅から、ちょっと離れているので、わかりにくいです。情報によると、九份ではなく違う名前のバス停で降りる感じだったんですが、今は「九份」というバス停で降りるみたいです。バスも、わからないので、もう九份行き乗っとけwwwみたいなノリで乗りました。バスの運ちゃんが「おまえら、ここで降りとけ(Hello, Hello...コンコンコン)」みたいに教えてくれました。

雰囲気は、四国の金刀比羅さん、という感じに近いです。ここは夜市と雰囲気も似てなくはないですが、食べ物が違う感じです。帰りは、適当に歩いてバスに乗ったら、行きと同じ運転手さんでした。瑞芳駅での夕景が綺麗で、思わず写真に収めました。

あわよくば、アップルマンゴーかき氷を…と思っていたんですが、嫁さんが暑さでやられてグロッキーになったので、台北駅からタクシーに乗って終了しました。瑞芳駅から台北駅まで急行に乗ったけど、座席が取れなかったのに、グロッキーな嫁さんに台湾の方が座席料金払ってると思うのだけど…席を譲ってくださいました(謝謝)。翌日は早朝5時30分にバスで空港へ移動です(格安ツアーなので)。
こんな台湾旅行でした。

2012年8月16日木曜日

台湾行ってきた(2日目:午後)

昼飯は、こんな感じ。どちらかと言うと、家庭料理っぽいものでした。牡蠣の料理が美味しかったです。

写真は無いですが、この後、漢方薬のセミナーか足ツボマッサージの2択で、せっかくだから足ツボマッサージを受けました。親指の爪の裏が痛いのなんの…寝不足なんだそうです…。目と耳(薬指と小指の付け根の裏)も痛かったです。体はなんともないと思っていたんですが、マッサージした後は、嘘のように軽く感じました。
その後、慌ただしく近衛兵の交代式を見に移動。動画も撮ったんですが、アップが面倒くさくて…orz

夜ご飯は、小籠包を食べました。

その後、士林夜市へ出かけました。写真はありません。1日目の夜市よりも規模が大きくて混雑してました。大きいけど、観光地化されているのか、マンゴージュースが150元で売ってました。1日目に飲んだマンゴージュースの3倍の価格です。地下の食品街に潜ったら、臭豆腐の匂いにやられて、坊ちゃん、またまた参ってました。延々と回って100円ショップみたいな所から、iPadのケースを 199元で買いました(およそ500円ぐらい)。坊ちゃんは、ここで LEGOもどきをゲット。240元ぐらいの大きいやつを買ってもいいぞ?と言ったのに、50元しないやつを3つにしました。後で「4つだとダメだよね?」と聞かれたので、「4つの値段足しても200元行かないから、買っても良かったんだよ残念だね?算数をちゃんと勉強してれば、4つ買えたのに…」と言ってやりました。
 なんか、いまいちパッとしなかったので、嫁さんが事前にリサーチしていた「冰讃」という店(ここは、23時までやっているみたいです)に、アップルマンゴーのかき氷を食べに移動しました。何でも、アップルマンゴーの季節にしか、このかき氷は出さないそうです。自分の中では、ベスト・デザートです。毎日でも食べたい(>_<)

2012年8月14日火曜日

台湾行ってきた(2日目:午前中)

 2日目は、市内観光ツアーに申し込みました。どっか飯の美味しいところ知らない?とホテルの人に聞いたら、近くの店を紹介してくれて、おまけに10%オフのカードまで渡してくれました。料理はまぁまぁだったけど、サービス料金が高い。頼んだ料理よりサービス料金の方が高いって、どんな店やねん?

 市内観光ツアーは、ナルワントツアーというやつで、ホテルの向かいからバスに乗り込みます。午前中に保安宮という寺院、孔子廟、お茶セミナー、中正記念堂と忙しい。お茶セミナーでは、ジャスミン茶、烏龍茶、高山烏龍茶、プーアル茶と頂いた。中正記念堂では、北海道で見た「地球最古の恐竜展」の恐竜さんに再会ww。慌ただしく時間が過ぎて行きました。

 台湾では、寺院に寄付する習慣があるそうで、寄付した分の税の控除があるそうです。そのため、お賽銭ではなく領収書をもらうとの事。皆さん信心深く寺院も寄付により立派になったとか…。東北沖大震災での義援金などは、こうした寺院から組織的に送られたと聞きました。寺院自体が風水や占いなどの日常の相談所などの役割を果たしているとか。ガイドさんの話、結構、勉強になりました。

2012年8月11日土曜日

台湾行ってきた(1日目)

自分と嫁と坊ちゃんで、3泊4日の格安台湾ツアーに行ってきました。札幌から中華航空で台湾直行便に乗って4時間ぐらい?中華航空、そこそこ美味しい食事も付いて、ワインも飲めて、結構サービス良かったです。一人5万円台のツアーだったんですが、土壇場で鎖骨を骨折するなど、やれキャンセルのキャンセルだのしてたら、ホテルがスタンダードにグレードアップしたり、キャンセル料を取られたりで、一人1万円ぐらい割高になってしまいました。  まぁ、台湾からの北海道旅行にスケジュールを合わせているためか、昼に出発して夜に着き、帰りはホテル出が5時台とか2.3日ぐらいが行動時間になります。初日の夜は、さっそく夜市に行ってきました。交通も、よくわからないので、歩いて行ける近場の夜市に…。まぁ、人が多いのなんの。それと臭豆腐の匂いが独特で、坊ちゃんは、かなり参ってました。なんか、わからんけど晩飯は地元のもん食っとけ的なノリで庶民的な感じの中華屋さんに突入。 水餃子に餃子に牛なんとか麺。飯食った後は、マンゴージュースを1つ50元で買って3人で飲みました。
アップルマンゴーが、ちょうど旬らしく、ものすごい美味しかったです。後日、大きい夜市に行ったら、マンゴージュースが150元で売ってて、どんだけwwwwwと思いました。中華屋さんでも、食事が坊ちゃんには、いまいち合わなかったらしく、少食気味。それが、あの出店のあれが食べたいとか言い出して買ったのが、また怪しげなもの。説明を聞くと、なんか、美味しそうに思えて来たけど、よくわからない。黒糖、紫芋、かぼちゃの三種類の生地があり、それを油で揚げて、マヨネーズみたいなやつと黒いソースをまぶす。肉を間にトッピングする事もできるけど、肉は要らんのだと…。
ホテルに持ち帰って食べてみてわかったのですが、揚げパンでした。パン好きの坊ちゃんの嗅覚するどい!  2日目に続く

2012年8月1日水曜日

手術無しでOKになった

院長先生にみてもらったら、T字型になっているけど、コルセットで押さえとくだけでOKという感じになりました。真っ二つだと思ってたのは、感違いでした。今回、肩を上げるのが痛いけど内出血の症状も無いので、ヒビぐらいかな?と感じてたのは、だいたい、イイ線をいってたみたいです。コルセットは、結構しっかりと締めます。 入院もパラダイスと言えばパラダイスなんですが…。タスクが多過ぎて、リソースが足りない感じです。

2012年7月30日月曜日

右鎖骨骨折

7/25の夜に自転車で転けて右鎖骨を骨折しました。上り坂を漕いでて、段差が無いと思って歩道上に上がろうと乗り上げたら、段差があって、引っかかって転んだという、間抜けな話です。思いっきり体重かけて右に傾けたから、そのまま右肩の方から落ちました。  前回は、左肩の上から打ち付けたので、3つに割れてしまいましたが、今回は、右肩の背中側から打ち付けたので、右端が真っ二つに折れました。今回は重たいザックを背負っていたので、背中側の衝撃が緩和された分、肩に集中してしまった側面もありそうです。  考えるに、自転車のフレーム・サイズが体格と比べて小さ目なので、転けた時にテコの原理で勢いよく肩の方へ衝撃が大きくなるのかな?というのを感じました。それは、前回に怪我した時から感じてた事なのですが・・・。嫁さんに、もう自転車通勤危ないから止めた方がいいんじゃない?と言われて、フレームサイズの話をしたら、ぶち切られました。買う時に嫁さんも乗れるよう、ギリギリ小さめのサイズだけど選択した事なんか、すっかり忘れてて、サイズ合わせたのに小さいは無いだろみたいな事言われました。  チャリの鎖骨を保護する通勤用の簡単なプロテクター欲しいです。シリコン系の衝撃吸収素材(卵が割れないやつ)を肩甲骨から肩の上部ぐらいまでを覆ってしまい、タスキがけのスタイルで装着というぐらいで、用足りる気がしてます。いろいろとググっても、なんかピンとくるやつが無いです。LEATT のが、ネック・プロテクターぐらいのもので、肩用があればいいんだけど…  とりあえず、手術してプレート埋め込みと除去は、ほぼ確定な感じですね orz

2012年7月19日木曜日

QGis Python Plugin と日本語の周辺2

環境

  • Windows 7 x64
  • Quantum GIS Lisboa 1.8
  • GDAL/OGR 1.9.1

   いろいろと思考錯誤していて、GDAL/OGR がどのように多言語に対応しようとしているのか、わかってきました。
QGis Python Plugin と日本語の周辺1 に書いていたコードは、実はベストプラクティスでは無い事が判明いたしました。

  まずは、基本的なおさらいから…
Linux, mac 等の環境では、UTF8 で文字コードを取り扱うのが基本になります。それに対して Windows では MBCS がベースで、プログラム内部の文字コードは、MBCS か UNICODE(UCS2) を選択します。Visual C++ のコンパイルオプションで、どちらを選択するか可能なのですが、もう少し中身を説明すると、Windows API には、MBCS 系の文字コードを引数にとる HogeA という大文字 A をサフィックスにとるものと、UNICODEの文字コードを引数にとる HogeW という大文字 W をサフィックスにとるものが対になって存在します。C言語では、単に
#ifdef _UNICODE
#define Hoge HogeW
#else
#define Hoge HogeA
#endif
というように、マクロで切り替えているだけなのです。   ですので、MBCS系の文字コードでコンパイルをしていても、UNICODE系のAPIをコールする事は可能となっています。

  ここから、本題に入ります。QGIS では、GDAL_FILENAME_IS_UTF8 = YES を前提としています。それは、どのようなトリックかというと、ogr2ogr.exe 等の実行ファイルのパスは MBCS でないと実行できません。ところが、コマンドラインのオプション引数は MBCS である必要は、ありません。極端な話、UTF8 の文字コードをコマンドラインのオプション引数に渡しても問題ありません。   GDAL/OGR の shape ドライバでは、Windows 環境かつ、GDAL_FILENAME_IS_UTF8 = YES であれば、UTF8で引き渡された文字コードを内部で UNICODEに変換して、ファイル操作を行うように書かれていました。この手法でいけば、windows 付属の iconv.dll では、UTF8 と UNICODE 間の変換さえ、うまく行けば、IO(入出力回り)の文字化けに対応できる事になります。

  では、どうすれば日本語のファイルをコマンドラインから扱う事ができるか?
GDAL_FILENAME_IS_UTF8 = NO というような設定は、実は一切不要でして、サクラエディタなどのUTF8が扱えるエディタを使って、バッチファイルを作成し、ファイルを保存する時に、文字コードを「UTF8」にして保存してやればOKでした。QGISのインストール先を日本語の混じったフォルダ下にしなければ、これで、問題なく動くはずです。
UTF-8で書かれたバッチファイルを実行する事です。

問題は、Python で、どうやって UTF-8 な文字コードを subprocess.call に引き渡す事ができるのか。ここが、わかりませんorz...。decode encode('utf-8') してやっても、文字化けします。どうも、スクリプトは自由度が低くて相性の悪さを感じます(>_<)。 2012/07/24 追記:"日本語" の "語" が python の文字コード変換で文字化けするので、自前で DLL を作成して、その中で文字コード変換するようにした。 2012/08/30 追記:その3に続く

2012年7月18日水曜日

GDAL shape driver を深追いしてみた…

どうにも、GDAL(1.9.1)/OGR shape driver が日本語のファイル名を受け付けないので、コードを追ってみました。
VSIFilesystemHandler *VSIFileManager::GetHandler( const char *pszPath )

{
    VSIFileManager *poThis = Get();
    std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
    int nPathLen = strlen(pszPath);

    for( iter = poThis->oHandlers.begin();
         iter != poThis->oHandlers.end();
         ++iter )
    {
        const char* pszIterKey = iter->first.c_str();
        int nIterKeyLen = iter->first.size();
        if( strncmp(pszPath,pszIterKey,nIterKeyLen) == 0 )
            return iter->second;

        /* "/vsimem\foo" should be handled as "/vsimem/foo" */
        if (nIterKeyLen && nPathLen > nIterKeyLen &&
            pszIterKey[nIterKeyLen-1] == '/' &&
            pszPath[nIterKeyLen-1] == '\\' &&
            strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
            return iter->second;

        /* /vsimem should be treated as a match for /vsimem/ */
        if( nPathLen == nIterKeyLen - 1
            && strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
            return iter->second;
    }
    
    return poThis->poDefaultHandler;
}
  "\" 記号文字を "/" 記号文字で置き換えしようとしているのか?これ、SJIS だと典型的にハマるパターンですね。 "表" という SJIS コードは、16進数で表すと 0x955C になります。一方 "\" という ASCII コードは、16進数で表すと 0x5C になります。日本語SJISの取り扱いでは、それぞれの char コードの範囲が SJIS の第1バイトかどうかを調べて、第一バイトに該当した時には、第2バイトもSJISコードなので、ASCII コードとしては処理をしないという条件分岐が必要になります。  SJISが出来た当初は、ASCII と被らないで、なるべく2バイト内に納めて漢字の表現をしないといけなかった事情があるので、この設計は仕方ない事ではありますが、特殊すぎます。  とにかく、こういう罠があるので、内部では UNICODE(UCS2)か、UTF8にすべきなんですが、まじうざい。いっその事、標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 2012/07/19 追記: ここのコードをトレースしてみたが、何をやりたいのか、ちょっとピンと来ない…。
pszIterKey:/vsigzip/
pszIterKey:/vsimem/
pszIterKey:/vsisparse/
pszIterKey:/vsistdin/
pszIterKey:/vsistdout/
pszIterKey:/vsistdout_redirect/
pszIterKey:/vsisubfile/
pszIterKey:/vsitar/
pszIterKey:/vsizip/
ソースファイル名を渡して、そいつが、これらのデバイスにマッチするかどうかを見ているようである。日本語だと、何故、こんなところで失敗するのか?もっと他の部分をあたってみるか… 同日 追記: VSIFilesystemHandler というクラスで、ファイルシステムの文字コードによる違いを吸収しているようだ。なんとも壮大で、頭がクラクラする。 iConv を使っている場合もあるようだが、 ifdef で iConv を使うか、WinAPIを使うか、切り替えてるので、バイナリ配布物の状況がよくわからない。QGis で配布されているやつは、iConv を使うコードでコンパイルされているのだろう。ところが、FOSS4GJP の情報によると Windows版 iConv のコンパイルは、いろいろと文字コードセットに対する対応が足りないらしく、正しく動作していないらしい。  Windows では、環境変数 GDAL_FILENAME_IS_UTF8 = YES が設定されていた場合には、ファイル名を UTF8 から UNICODE に変換して、UNICODE(UCS2)のファイル名を _wstat にかけている。  どうも、この _wstat に渡すパスあたりで、こけている感じだ。一生懸命、wchar_t にしているが、内部で利用されているパスは、生のMBCSなので、_wstat にかけたいがためだけのコードに留まってしまっている。複雑になった割には報われていないという印象だ。 同日 さらに追記:  stat のコードで失敗してるのかなぁと思ったが、そういう訳でもないらしい。いろんなバージョンで、試行錯誤してたので、DLL HELL に陥ってたのかも…。

GDAL windows 版は何を想定しているのか?

日本語対応の処方箋をogr2ogrに施してみたが、どうも、マシンによって挙動が異なるので、深追いしていました。そしたら、こんなコードにぶつかった。
int VSIStat( const char * pszFilename, VSIStatBuf * pStatBuf )

{
#if defined(WIN32) && !defined(WIN32CE)
    if( CSLTestBoolean(
            CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" ) ) )
    {
        int nResult;
        wchar_t *pwszFilename = 
            CPLRecodeToWChar( pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2 );

        nResult = _wstat( pwszFilename, (struct _stat *) pStatBuf );

        CPLFree( pwszFilename );

        return nResult;
    }
    else
#endif 
        return( stat( pszFilename, pStatBuf ) );
}

 これ、何を意図しているかというと、Windows 環境では、GDAL_FILENAME_IS_UTF8 = YES と環境変数に設定されている場合には、ファイル名等の文字コードを UNICODE(UCS2) wchar_t 型から、UTF8UTF8から、UNICODE(UCS2)wchar_t型 に変更してあげましょうというコードになります。  ところが、おかしいです。まず、細かい事ですが、defined(_WIN32) であって、defined(WIN32)では無い。次に、windows ce の場合は、UNICODEのアプリケーションを組む事になってたと思います。そろそろ windows ce はオワコンなんで、この部分は、もう関係無くなります。次に、そもそも現在は MBCS(Multi Byte Code Set)でコンパイルされているので、UNICODEであるはずがありません。前提条件が異なっている。仮に UNICODE でコンパイルしたとしたら、今度は、他のコードが大混乱に陥る事が容易に想像できます…。  うーん・・・ここで MBCS を UTF8 に変換してあげても、既存のIO関係のコードが MBCS 前提で動いてたりすると、もうお手上げに近いですね。CPLFopen とか、CPLFclose CPLFseek みたいな関数を用意してあげないと、ちょっと厳しいですね。UTF8をUNICODEに変換する事で、ウィンドウズの文字コード問題を乗り切るという方針で組まれているようです。

2012年7月15日日曜日

アンチキュレーションの時代

  また、Google+の考え方が変わってきたので、ここらで書いておきたいと思います。

  まず、はじめに、Google+ の楽しみ方について語ってみたいと思います。 これは、あくまで自分の観測範囲での私見です。観測範囲が異なれば、また違った意見があるとも思います。 Google+に登録してみたけど、これって一体何が面白いの?Facebook と、どう違うの?登録したけど、何も起こらないし、訳がわからないよ!そう感じている人も多いのではないでしょうか?そう、SNSにロール(役割)があるとすれば、リアルな知り合いとの交友は facebook があるので、Google+ でリアルな知り合いとの交流を望んでも、無駄に交友コストが高くつくので、この方面での活用は、今の所無いと考えて良いと思います。そうすると、主体は、知らない人で、かつ、趣向が合いそうな人との交流がメインになってきます。そこを促進するためには、まず、自分のプロフィールに、どういう交流を望むのかを明確に表明しておく必要があります。サークルに入れるかどうかの判断で、プロフィールと直近の投稿は必ず目を通します。その上で、どのレベルのサークルに入れるかを決めて振り分けします。プロフィールは重要な要素だと思います。そうした上で、次にやる事は、サークル候補の中から、めぼしい人を探して、自分のサークルに入れるという作業が必要になります。最低でも30名ぐらいは、自分のサークルに登録しないと、スタートラインにすら立てないと思います。これは必須の作業です。いきなり知らない人をサークルに入れて大丈夫かな?と感じるかもしれませんが、大丈夫です。そうしないと、始まりません。今度は、サークルに入れた人の投稿が流れてくるのでコメントを入れるようにしましょう。SNSの根幹は交流なんで、コメントしない事には話になりません。ただ例外は、あります。人がコメントしたくなるような投稿を続ける事です。ここら辺は、バランスが難しいです。有用な投稿にコメントが来ても、無視していれば、あぁ、この人にコメントしても、のれんに腕押しだからなぁと思われてしまいます。かと言って、ベタベタとコメントされても、あぁ、コメントしたいけど、後がめんどくさいなぁ?なんて敬遠されるかもしれません。投稿していて、誰もコメントしてくれないから虚しいと感じるかもしれませんが、みんな意外とストリーム(投稿が流れる画面)を読んでいたりします。コメントが無いからと言って、いちいちガッカリしない事です。朝の挨拶ストリームというのがあって、挨拶するのも手です。これを拡大していくと、挨拶だけで無駄な時間を費やしてしまいますので、限界があり、善し悪しあるとは思いますが、挨拶し続けてると人と人との距離感は縮まります。

  大多数の人が歩いている道があれば、そこは、避けて通りたい自分は、やっぱり変な事を考えてしまいます。キュレーションは、あるとは思いますが、Google+を見てると、強烈なキュレーションというのは違うかな?と感じるようになりました。たまたま、Google+に凄い人が多いからなのかもしれません。なんで、この人にサクられた(サークルに入れられた)のかな?と思いながら、とりあえずサクり返す(サークルに入れかえす) 事は、よくあるのですが、ある日突然、コメントをもらって深い体験(掘り下げた話になる)入る事もあります。そういう体験が続くと、面白さも広がりも出てきます。あと、自分の趣向と異なる人に対する自分の許容度も上がってきたように思います。キュレーターはいますが、絶対的な存在でもない。キュレーションは才能だとも思いますが、キュレーターを軸に回っている感じでもない。キュレーターを目指してる人にとって、Google+は、難しいSNSかもしれません。とりあえず、今、自分の中ではGoogle+が面白いです。

2012年7月12日木曜日

小樽寿司食べ歩き祭り

 ここんところ、Google+ の投稿で済ませてしまっている傾向が強いので、ちょっと反省して、ブログを更新です。

 小樽の寿司食べ歩き祭りに行ってきました。5店舗が競演する形で4品づつ計20カン。たまに回転しない寿司を食べるのも良いもんです。チケット2枚分を自分・嫁・坊ちゃん(小学校2年)で分けました。


 最初は、しかま寿司さん。カウンターの前で握ってもらって、緊張感があります。中トロは坊ちゃんにとられて食べられませんでしたが、穴子がめちゃくちゃ旨い。エビも普段食べてるものとは格が違いました。


 腹が減っていて、大和屋さんでは写真を撮るの完全に忘れてしまいました(>_<)。中トロが肉厚でボワーン。甘エビも普段食っているのとは格が違う感じ。嫁さんは、大和屋さんが好きだと言ってました。

 政寿さんは、サービスが行き届いていました。イカの包丁の入り方がオツな感じで感動しました。カンパチも回転寿司で食べるカンパチとは違って、美味かったです。時しらずは、坊ちゃんに取られて食べられませんでした。



 町のさんは、庶民的な感じのお店、テーブルの上が汚いのは戴けませんが、安くて旨いものを!というのをモットーにされてました。もちろん、美味しいです。


日本橋さんは、今回、一番気合が入っていたように思います。緊張感があって、凄い良かったです。山わさびののったマグロも美味しく、ホタテも、ちょっと前まで生きてたコリコリの食感、ウニも美味しかった。タコが柔らかくて、いい仕事をしていたらしいのですが、坊ちゃんに取られて、食べられませんでした。


 各店、ガリと、お吸い物と、お茶が異なるので、味比べをするのも楽しかったです。

QGis Python Plugin と日本語の周辺1

QGIS の python plugin を書いていて、やはり日本語の処理に四苦八苦したので、判明した事をチビチビと書いていこうと思います。ノウハウが溜まる度に書き足すつもりなので、その1としました。どれぐらいの頻度で続くのかは、書いてる本人にもわかりません。

 文字コードの国際化に関する状況は、刻々と変化する可能性が高いので、環境を明記しときます。
  • Windows 7 (x64)
  • GDAL 1.9.1
  • Quatom GIS Lisboa 1.8.0

 Windows 環境において、GDAL/OGR あたりで、日本語のファイル名を使おうと思ったら、環境変数「GDAL_FILENAME_IS_UTF8」に「NO」と設定しないと、ogr2ogr 等のコマンドでファイル名が不正だとエラーにされてしまう現状があります。

 それなら、思い切ってコントロールパネルの「システム環境設定」に、GDAL_FILENAME_IS_UTF8 = NO と設定してしまえば良いじゃないか?と設定したら、ものの見事に嵌りました。なんと、QGISでshapefileを開こうとするとエラーになってしまいます。なんてこったい!QGIS内部では、UTF8でファイル名を扱っている雰囲気が漂ってます。これに関しては、現段階では確認できていません。

 プラグインのコードで、QFileDialog からファイル名を取得するコードを見てみましょう

    fileName = QFileDialog.getSaveFileName(None,QString.fromLocal8Bit("Select a file:"), "", "*.tapgis")
    if fileName.isNull():
      return
    fname = unicode(fileName.toLocal8Bit(),'mbcs')
  はい、ウィンドウズでは、ファイル名はOEMの文字コードセットになりますので、multi byte char set  つまり、SJIS(CP932)になっております。python なんて、ほとんど知らねぇよだったので、unicode という名前の関数が、文字コード・セットを指定して文字列を初期化する関数だと判るまでに丸一日費やしました。
  さて、こいつを ogr2ogr のコマンドに引き渡すとします。

  実はファイル名に半角スペースが混じっている場合には、”path" というようにダブルクォーテーションでパスを括ってやらなければなりません。逆に半角スペースが混じっていない場合には、path というようにダブルクォーテーションで囲ってはいけません(何この仕様・・・くたばれ)。という事情は、すっ飛ばします。
  # ogrvars には "-overwrite" 等のオプション文字列が渡される
  def CallRWTools(self, infile, outfile, ogrvars):
    import os
    try:
      import subprocess
      path = str(QgsApplication.prefixPath()).rsplit('/', 2)[0]
      pcmd = path + '\\bin\\ogr2ogr';
      fmt = '%s -f "tapgis" %s %s %s'
      cmd = fmt % (pcmd, outfile, infile, ogrvars)
      # ファイル名がUTF8ではないという状態に変更
      os.environ["GDAL_FILENAME_IS_UTF8"] = "NO"
      subprocess.call(cmd.encode('mbcs'), shell=True)
      #cmd3 = "echo " + cmd + " > " + outfile + ".txt"
      #subprocess.call(cmd3.encode('mbcs'), shell=True)
      #cmd2 = "notepad " + outfile + ".txt"
      #subprocess.call(cmd2.encode('mbcs'), shell=True)
    finally:
      # ファイル名がUTF8であるという状態に戻す
      os.environ["GDAL_FILENAME_IS_UTF8"] = "YES"
  はい、QGIS 内部では、GDAL_FILENAME_IS_UTF8 = YES を前提としているので、コマンドを呼び出す間だけ、GDAL_FILENAME_IS_UTF8 = NO に変えてコールします。あと、WIndows シェルでは mbcs なので、encode('mbcs') してやらないと、正しいコマンド引数になりません。

  ここまで書いても、日本語の問題は残ります。今度は、ogr2ogr のオプション文字列が mbcs のままドライバに渡されるためです。自分の書いたドライバでは、sqlite3_open という関数をコールしているので、OGRDriver の OGRDataSource::Open, OGRDataSource::Create という関数内で渡されたファイル名が mbcs なので utf8 へ文字コード変換してやる必要がありました。   また、OGRDataSource::CreateLayer に渡されるレイヤ名は、変換元のデータソースのOGRDriver の実装に依存している状態なので、どんな文字コードが渡されるのか、未知数です。shape driver の実装では、-nln オプションでレイヤ名を指定しない場合には、ファイル名からレイヤ名を生成しているので、mbcs の文字コードが来ました。注意しなければならないのは、これは Windows の日本語OS 独特の状況においてのみ発生します。Windows の Laten1なOSの環境では、おそらく Laten1の文字コードが来るという結果になるでしょう。-nln オプションも生の文字コードが渡されるので、同様の結果になります。

  このように、locale でなんとかしようという発想は、破綻するので utf8 で統一的に扱う必要性が高いと思います。いちいちロケール指定してたら大変です。ウィンドウズの場合は、CPACP を有効活用する方向が望ましいと思います。 2012/07/19 追記: その2に続く 2012/09/05 追記:結局、ウィンドウズ環境では、GDAL_FILENAME_IS_UTF8 = YES を前提にコードが書かれてあるので、その1のアプローチはダメダメでした。

2012年7月10日火曜日

旭川モクモク・フェスタ






モクモク・フェスタに行ってきました。家具の街でもある旭川市。モクモク・フェスタでは、掘り出し物もあり、楽しみです。
今回は、坊ちゃんのお守りで、トンカン・トンカン・・・木のロボットを制作しました。戦利品は、ソファーの皮の余り生地で作ったポーチと名刺入れ、それにニャンコな筆立て。ポーチには、mac の電源コードとかを入れてます(^^;