Firefox ExtensionでC++プログラムを動かしてみるテスト 〜その6 文字列を扱ってみる〜

かーねる・う゛いえむにっきからの続き。

前回までに作ったExtentionはキー・バリューをlongにしていたので文字列が扱えなかった。また、一定以上の数値をkeyに渡すことが出来なかった。これではカッコ悪い。
という訳で、前回までに実装したXPCOMモジュールに手を加えて文字列を扱えるようにし、storeは配列ではなくC++のstd::mapを使ったハッシュテーブルにしてみる。

testIKVS.idl
#include "nsISupports.idl"

[scriptable, uuid(3A5769F0-8F50-465A-8682-4C0F0F76AE4F)]
interface testIKVS : nsISupports
{
     void open();
     string get(in string key);
     void put(in string key, in string value);
     void close();
};

longだった所をstringにする。これはxpidlに渡すとchar *になる:

testIKVS.h
class NS_NO_VTABLE NS_SCRIPTABLE testIKVS : public nsISupports {
 public:

  NS_DECLARE_STATIC_IID_ACCESSOR(TESTIKVS_IID)

  /* void open (); */
  NS_SCRIPTABLE NS_IMETHOD Open(void) = 0;

  /* string get (in string key); */
  NS_SCRIPTABLE NS_IMETHOD Get(const char *key, char **_retval NS_OUTPARAM) = 0;

  /* void put (in string key, in string value); */
  NS_SCRIPTABLE NS_IMETHOD Put(const char *key, const char *value) = 0;

  /* void close (); */
  NS_SCRIPTABLE NS_IMETHOD Close(void) = 0;

};

さて、実装してみよう。

testKVS.h
#ifndef __TESTKVS_H__
#define __TESTKVS_H__

#include <map>
#include <string>
#include "testIKVS.h"

class testKVSImpl : public testIKVS
{
public:
     NS_DECL_ISUPPORTS
     NS_DECL_TESTIKVS
     testKVSImpl();

private:
     ~testKVSImpl();
     std::map<std::string, std::string> store;
};

#endif

storeをmapにし、プライベートメンバ変数として定義。

testKVS.cpp
#include "testKVS.h"

NS_IMPL_ISUPPORTS1(testKVSImpl, testIKVS)

testKVSImpl::testKVSImpl()
{
}

testKVSImpl::~testKVSImpl()
{
}

/* void open (); */
NS_IMETHODIMP testKVSImpl::Open()
{
    return NS_OK;
}

/* long get (in long key); */
NS_IMETHODIMP testKVSImpl::Get(const char *key, char **_retval NS_OUTPARAM)
{
     std::string _key(key), _val = store[_key];
     char *retval = (char *)calloc(_val.length(), sizeof(char));
     strncpy(retval, _val.c_str(), _val.length());
     *_retval = retval;
     return NS_OK;
}

/* void put (in long key, in long value); */
NS_IMETHODIMP testKVSImpl::Put(const char *key, const char *val)
{
     std::string _key(key), _val(val);
     store[_key] = _val;
     return NS_OK;
}

/* void close (); */
NS_IMETHODIMP testKVSImpl::Close()
{
    return NS_OK;
}

/* End of implementation class template. */

変える事になるのはGet()とPut()。
入出力はchar *だがstoreへはstd::stringで記録するので、毎度インスタンスを生成する。
Get()でわざわざアロケート・コピーしているのは、どうやら_retvalはブラウザ側でfree()したいらしいから。
# _val.c_str()を直接returnするとfirefoxデバッグモードでエラーが出る。

出来上がったらビルドしてextentionにコピー。

$ make DEPTH=~/191src topsrcdir=~/191src
$ cp ./_xpidlgen/testIKVS.xpt ~/Library/Application\ Support/Firefox/Profiles/*/extensions/testkvs\@dokukino.com/components/
$ cp libtestkvs.dylib ~/Library/Application\ Support/Firefox/Profiles/*/extensions/testkvs\@dokukino.com/platform/Darwin_x86-gcc3/components

Firefoxを起動して、get, putしてみる。

文字列でもきちんとget, putできている。
が、しかし、日本語が扱えない。
実は、これを扱うにはMozilla内部のワイドキャラクタ対応文字列クラスを使う必要がある。
この話はまた今度。