2009年7月29日水曜日

Flash Lite 1.1 のルートムービークリップの変数を動的生成してみた

swfの動的生成はswfmillmingという方法があるけれど、ひな形となるswfの変数だけを動的に変えるだけでよい場合にはswfバイナリを直接変更するという方法もあるという例。

生成した変数はルートムービークリップの変数になるようだ。変数名と同じ変数名でダイナミックTextインスタンスをステージに配置すれば、動的設定した文字列を表示することもできる。

ちなみに、検証にはFlash Lite 1.1で作成したswfを使った。

swf.rb
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

require 'stringio'

module SWF
def self.read(src)
header = src.read(9)
x = (header[8] >> 3) * 4 + 5
header_size = ((((8 - (x & 7)) & 7) + x) / 8) + 12 + 5
header << src.read(header_size - 9)
body = src.read
[header, body]
end

class Vars
HD = "\x3f\x03\x00\x00\x00\x00"
BE = "\x96"
ZE = "\x00"
ZB = ZE + BE
ED = "\x00\x1d"

def initialize
@vars = []
end

def add(key, value)
@vars << [key, value]
end

def to_bytes
bytes = StringIO.new
bytes << HD
@vars.each do |key, val|
bytes << BE << [key.size + 2].pack('v') << ZE << key
bytes << ZB << [val.size + 2].pack('v') << ZE << val << ED
end
bytes << ZE
bytes.seek 0
bytes = bytes.read
bytes[2, 4] = [bytes.size - 6].pack('V')
bytes
end

def apply(src_io, dst_io)
vars = to_bytes
header, body = SWF.read(src_io)
header[4, 4] = [header.size + body.size + vars.size].pack('V')
dst_io << header
dst_io << vars
dst_io << body
end
end
end

if __FILE__ == $0
require 'yaml'
require 'optparse'
dat, src, dst = nil
OptionParser.new do |opt|
opt.on('-v VARS.yaml'){|v| dat = v }
opt.on('-i INPUT.swf'){|v| src = v }
opt.on('-o OUTPUT.swf'){|v| dst = v }
opt.parse!(ARGV)
unless dat && src && dst
opt.parse!(["-help"])
end
end
vars = SWF::Vars.new
YAML.load_file(dat).each{|key, value| vars.add(key, value) }
File.open(src, 'rb') do |s|
File.open(dst, 'wb') do |d|
vars.apply(s, d)
end
end
end

2009年7月24日金曜日

Androidのタイトルバーにアイコンを表示してみた

import android.view.Window;
Window w = getWindow();
w.requestFeature(Window.FEATURE_LEFT_ICON);
setContentView(R.layout.search);
w.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon);
とっても簡単。
Window.FEATURE_???を調べたらいろいろできることが増えるのかも。

Eclipse 3.5 Galileo に ADT を入れてみた

Eclipse IDE for Java Developers
Build id: 20090619-0625
Android SDK: 1.5r3

デバッグ実行してブレークポイントで止まるし、特に問題無く動作している。

Android Emulatorの為にSDカードイメージを作ってみた

SDカードイメージを作成するには、2つの方法がある。
  1. Android Virtual Devices Managerを使う方法
  2. コマンドラインプログラムで作成する方法
どちらもできることは同じ。たぶん。

EclipseにADTを導入するとAndroid Virtual Devices Managerが使える。
Android Virtual Devices Managerを使う方が断然楽。

コマンドラインの場合Android SDKのtoolsにあるmksdcardコマンドを使う。

mksdcard.exe -l "ラベル名" サイズ SDカードイメージファイル名

サイズに単位を指定しないと、バイト単位になる。
Kをつけるとキビバイト、Mをつけるとメビバイトになる。

生成されたファイルは生のイメージなのでファイルのサイズは指定したサイズと等しくなる。
大きなサイズを指定すると生成にも時間がかかった。


Android EmulatorのSkinをHT-03Aにしてみた

白も黒もどっちもできる。

参考: Android Wiki

2009年7月22日水曜日

Android NDKってなに?

Androidでネイティブコードを動かすための開発ツールを見つけた。

Android NDKは、Androidアプリ開発者のみんなが、君たちのアプリケーションに、ネイティブコードで書かれたコンポーネントを埋め込むことができるようになるツールだよ。

AndroidアプリはDalvik仮想マシンの上で動くんだけど、このNDKを使えば、CやC++みたいなネイティブコード言語を使ってアプリケーションのパーツを開発できるようになるんだ。

そうすれば、ある種のアプリケーションにはメリットがあるんだ。それらの言語で書かれたコードを再利用することができるとか、時にはスピードアップとかね。

このNDKに入れてあるもの

  • CやC++のソースコードからネイティブコードライブラリを生成する事ができるツールやビルドファイル。
  • ネイティブコードライブラリをAndroidデバイスにデプロイ可能なアプリケーションパッケージファイル(.apks)に埋め込む方法。
  • ネイティブシステムヘッダーやライブラリのセット。これらは将来にわたってAndroid 1.5以降の全てのAndroidプラットフォームでサポートされるよ。
  • ドキュメント、サンプル、それにチュートリアル

このリリースのNDKはARMv5TEのマシン語をサポートしている。それに、安定したlibcのヘッダーファイル(Cライブラリ)やlibm(数学ライブラリ)、JNIインターフェースやその他のライブラリを入れてあるよ。

このNDKは、ほとんどのアプリケーションには役に立たないだろうな。開発者として、メリットとデメリットのバランスを見極める必要があるよ。特に、ネイティブコードを使っても、自動的にパフォーマンスが向上するわけじゃないし、そのくせ必ずアプリケーションを複雑にしてしまうからね。

NDKを使うよい例は、自己完結的で、メモリアロケーションを伴わない、CPUをこき使うような処理だね。例えば、シグナル処理とか物理シミュレーションとかね。なにかのメソッドを単純にCで書き換えたとしても、たいていはたいしてパフォーマンス向上につながらないよ。でもね、NDKは既に世の中に存在するCやC++のコードを再利用する時には効率的な手段になり得るんだ。

注意して欲しいんだけど、NDKを使ってもネイティブコードだけのアプリケーションを作ることはできないよ。AndroidのメインのランタイムはDalvik仮想マシンのままだからね。


2009年7月21日火曜日

HTC-03AでHello, Androidをデバッグ実行してみた

PC: Intel 32bit
OS: WindowsXP SP3
IDE: Eclipse Java EE IDE for Java Developers, Version: 3.4.2 Build id: M20090211-1700
Android SDK: 1.5r3

最初に実機をPCに接続した時、デバッグモードにせずにつないでしまったためか、USB記憶装置として認識されてしまった。デバイスを削除して、再インストールしようとしても、.infファイルのハードウェアの記述が異なるみたいで該当なしと言われる。

同じ状態になってしまった人もたくさんいるみたいで、探してみたらいくつか情報が。


とりあえず、HTCのサイトから
デバイスドライバのアップデータ(?!)をダウンロードして、実行。
実機を接続していなかったので「実機つないでくれんと・・・」と怒られる。

しかし、ここで思い立って、先に、Android SDKに付属の
usb_driver\x86\android_usb\infをインストールしてから、デバッグモードに
した実機をUSBに接続したら、デバイスドライバをインストールするウィザードが開いてくれた。
手動でドライバを選択したら待通りにインストール完了。

Eclipse経由でHello, Androidを動かしてちょっと満足。

デバイスドライバのアップデータを実行したのが吉だったのかな・・。

2009年7月17日金曜日

Rubyの拡張モジュールでリソースを解放する方法

RubyはGCを持っているので、Rubyの世界の中ではリソースの解放をそれほど気にしなくてもよいけれど、Cで記述したRubyの拡張モジュールではそうはいかない。

インスタンス生成で資源を確保し、GCがインスタンスを回収した時に資源を解放するサンプル。

foo.c
#include <ruby.h>
#include <rubysig.h>

static VALUE g_cFoo = Qnil;

struct FooData
{
int x;
int y;
};

static void
Foo_free_data(struct FooData* data)
{
fprintf(stderr, "free 0x%08x\n", data);
#if defined(USE_RUBY_XMALLOC)
ruby_xfree(data);
#else
free(data);
#endif
}

static VALUE
Foo_alloc_data(VALUE self)
{
return Data_Wrap_Struct(self, 0, &Foo_free_data, 0);
}

static struct FooData*
Foo_data(VALUE self)
{
struct FooData* sval = NULL;
Data_Get_Struct(self, struct FooData, sval);
return sval;
}

static VALUE
Foo_initialize(VALUE self)
{
#if defined(USE_RUBY_XMALLOC)
DATA_PTR(self) = ruby_xmalloc(sizeof(struct FooData));
#else
DATA_PTR(self) = malloc(sizeof(struct FooData));
#endif
fprintf(stderr, "alloc 0x%08x\n", DATA_PTR(self));
return self;
}

Init_foo()
{
g_cFoo = rb_define_class("Foo", rb_cObject);

rb_define_alloc_func(g_cFoo, &Foo_alloc_data);
rb_define_method(g_cFoo, "initialize", &Foo_initialize, 0);
}

※注意!このモジュールを使って ruby 1.8.7 p174 {mingw32|linux}で ruby -rfoo -e 'loop{Foo.new}' したら Segmentation faultになった。原因不明>_<

2009年7月16日木曜日

ruby embedded into c++

2003年に書かれたものだから、古いかもしれないけれど、Rubyの拡張モジュールを作成する時の参考になるかもしれない。
http://metaeditor.sourceforge.net/embed/

2009年7月8日水曜日

emacsでruby-modeを使う設定

.emacs
;;;;
;;;; Ruby
;;;;
(add-to-list 'load-path "c:/somewhere/site-lisp")
(autoload 'ruby-mode "ruby-mode"
"Mode for editing ruby source files" t)
(setq auto-mode-alist
(append '(("\\.rb$" . ruby-mode)) auto-mode-alist))
(setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
interpreter-mode-alist))
(autoload 'run-ruby "inf-ruby"
"Run an inferior Ruby process")
(autoload 'inf-ruby-keys "inf-ruby"
"Set local key defs for inf-ruby in ruby-mode")
(add-hook 'ruby-mode-hook
'(lambda ()
(inf-ruby-keys)))

2009年7月7日火曜日

Dokan Ruby 0.1.4 のパッチ

Windows用の仮想ファイルシステムドライバDokanライブラリを使ってみた。
Dokan Rubyを使うとRubyで手軽にファイルシステムを書けてしまうという
素晴らしいライブラリだ。

そのサンプルにmirror.rbというものがある。
任意のフォルダを指定して、ドライブにマウントするサンプルだ。
SUBSTコマンドのようなもの。

しかし、このmirror.rbでマウントしたドライブは、
Explorerでファイルを見ることはできるものの、
コマンドプロンプトで cd FolderName を実行しても
「指定されたパスが見つかりません。」と言われる。

ばぐ?

Dokanライブラリのreadme.ja.txtに答えが書いてあった。

ディレクトリに対するアクセスで有るのにも関わらず,CreateFile が呼ばれることもあります.その場合は,DokanFileInfo->IsDirectory は FALSE がセットされています.ディレクトリの属性を取得する場合などに OpenDirectory ではなく,CreateFileが呼ばれるようです.ディレクトリに対するアクセスなのにも関わらず,CreateFile が呼ばれた場合は,必ず DokanFileInfo->IsDirectory にTRUEをセットしてからreturnしてください.正しくセットされていないと,Dokanライブラリは,そのアクセスがディレクトリに対するアクセスかどうか判断できず,Dokanファイルシステムで Windows に対して正確な情報を返すことが出来なくなります.

mirror.rbはopenでFile.file?(path)の結果を返していて、ディレクトリの場合に対応できていない。
そもそも、dokan_lib.soでFileInfo#directory=が定義されていないし、instans_eval等で無理矢理値を変えたとしても、FileInfoをDokanFileInfoに書き戻すコードは無かった。

dokan_lib.cとmirror.rbを少しだけ書き換えたらうまくいった。めでたしめでたし♪

dokan_lib.c.patch
110a111,118
> static VALUE
> DR_FileInfo_set_directory_p(
> VALUE self,
> VALUE value)
> {
> rb_iv_set(self, "@is_directory", value);
> return self;
> }
151a160
> VALUE is_dir;
154a164,166
>
> is_dir = rb_iv_get(FileInfo, "@is_directory");
> DokanFileInfo->IsDirectory = (Qfalse != is_dir && Qnil != is_dir);
> /* DokanFileInfo->IsDirectory = RTEST(is_dir); */ /* 普通はこう書くのかな? */
173c185,186
< rb_define_method(g_cFileInfo, "directory?", DR_FileInfo_directory_p, 0);
---
> rb_define_method(g_cFileInfo, "directory?", DR_FileInfo_directory_p, 0);
> rb_define_method(g_cFileInfo, "directory=", DR_FileInfo_set_directory_p, 1);
mirror.rb.patch
19c19,24
< File.file?(get_path(path))
---
> s = File.stat(get_path(path)) rescue nil
> if s
> fileinfo.directory = s.directory?
> true
> else
> false
> end