WSH:JavaScriptでADODB.Streamなしにバイナリー出力する
気が向いたので、ADODB.Streamが使用できない環境で、バイナリー出力する方法を考えてみた。
以下の制約がのめるなら、なんとかなる。
- 先頭2Byteは、ASCII範囲内(0〜128)
- 全体は偶数バイトであること、もしくは、奇数バイトの場合偶数位置にASCII範囲内がある
- Scripting.FileSystemObjectは使える
なんかややこしい制約ですが、Windowsのexeファイルやzipファイルであれば問題ないかと。
スクリプト
/* * LimitedBinaryStream.js,v 0.1 2014/07/28 june * * GNU General Public License, version 2 (GPL-2.0), or (at your option) any later version. * http://opensource.org/licenses/GPL-2.0 */ (function(ctx){ if(!ctx.LimitedBinaryStream) ctx.LimitedBinaryStream = function() { this.Log = function(msg) { //WScript.Echo((new Date()).toLocaleString() + ' ' + msg); } this.Open = function() { if(arguments.length > 0) this._path = arguments[0]; if(arguments.length > 1) this._mode = arguments[1]; this.Log('Open start Path:' + this._path + ' Mode:' + this._mode); this._fso = new ActiveXObject('Scripting.FileSystemObject'); this.LoadFromFile(this._path); this.Log('Open end'); } this.LoadFromFile = function(path) { this.Log('LoadFromFile start'); this._path = path; var mode = this._mode; if(this._mode == this.ModeWrite) mode = 8; var type = this.TristateTrue; if(arguments.length > 1) type = arguments[1]; this.Log('LoadFromFile args:' + type + ' ' + mode); this._size = 0; //this.Size = 0; this._position = this._size; //this.Position = this.Size; if(this._fso.FileExists(path)) { var f = this._fso.GetFile(path); this._size = f.Size; //this.Size = f.Size; f = null; } if(mode == 8) { this._position = this._size; //this.Position = this.Size; } this.EOS = (this._position >= this._size); this.Log('LoadFromFile pos:' + this._position); if(this._stream) { this._stream.Close(); } this._stream = null; var create = (mode == 8); if(this._path && this._path.length && (this._fso.FileExists(this._path) || (create && type == this.TristateFalse))) { this._stream = this._fso.OpenTextFile(path, mode, create, type); } this._partRead = null; this._partWrite = null; this.Log('LoadFromFile end'); } this.Read = function(num) { this.Log('Read start ' + this._position); var n = Math.floor(num / 2), p = (num & 1); var ret = Array(), i = 0, b; if(this._partRead != null && num > 0) { ret[i++] = this._partRead; this._partRead = null; if(p) { p = false; } else { p = true; n--; } } for(var j = 0; j < n; j++) { b = this._stream.Read(1); b = b.charCodeAt(0); ret[i++] = b % 256; ret[i++] = Math.floor(b / 256); } if(p) { b = this._stream.Read(1); b = b.charCodeAt(0); ret[i++] = b % 256; this._partRead = Math.floor(b / 256); } this._position += i; this.EOS = (this._position >= this._size); this.Log('Read end'); return ret; } this.Write = function(da) { this.Log('Write start ' + this._position); var ret = false, i = 0; if(this._partWrite != null) { da.unshift(this._partWrite); this._partWrite = null; } if(this._position < 2) { this.LoadFromFile(this._path, this.TristateFalse); } while(this._position < 2 && i < da.length) { this._stream.Write(String.fromCharCode(da[i++])); this._position++; } if(i < da.length) { this.LoadFromFile(this._path, this.TristateTrue); } var p = (da.length - i) & 1; while(i < da.length - 1) { if(p && da[i] < 128) { this.LoadFromFile(this._path, this.TristateFalse); this._stream.Write(String.fromCharCode(da[i++])); this.LoadFromFile(this._path, this.TristateTrue); this._position++; p = false; } else { this._stream.Write(String.fromCharCode(da[i++] + da[i++] * 256)); this._position += 2; } } this.Log('Write ' + i + " " + da.length); if(i < da.length) { this._partWrite = da[i++]; } ret = (i == da.length); this.Log('Write end'); return ret; } this.Close = function() { this.Log('Close start'); if(this._stream) { this._stream.Close(); this._stream = null; } this._mode = this.ModeUnknown; this._path = null; this._fso = null; this.Log('Close end'); } this.ModeUnknown = 0; this.ModeRead = 1; this.ModeWrite = 2; this.TristateTrue = -1; this.TristateFalse = 0; } // Test function lbsTest() { var ret = 0; var lbs = new ctx.LimitedBinaryStream(); lbs.Log(WScript.ScriptName + ' test start'); lbs.Open('C:\\windows\\system32\\calc.exe', lbs.ModeRead); lbs.Log(lbs._size + ' ' + lbs.Read(16)); lbs.Close(); lbs.Open('C:\\windows\\system32\\calc.exe', lbs.ModeRead); var lbsCopy = new ctx.LimitedBinaryStream(); lbsCopy.Open('E:\\calc.exe', lbs.ModeWrite); lbsCopy.Write(lbs.Read(lbs._size)); lbs.Close(); lbsCopy.Close(); lbs.Log(WScript.ScriptName + ' test fin ' + ret); } //lbsTest(); })(this);
ライセンス表記は出来心。
問題があれば言ってくれれば変更します。
使い方
lbsTest関数を見てもらえれば、わかると思います。
calc.exeをeドライブにコピーしているわけですが、fc.exeのバイナリチェックで差分はありませんでした!
基本、ADODB.Streamと同じような感じ(SaveToFile関数はありません)。
ReadやWriteで扱うのが、数値のArrayなので、メモリーの無駄遣い。
適当に書いたので、JavaScriptにおけるオブジェクト指向のお作法は考慮してません。
(勉強しなくちゃね、、、)
備考
一か月以上ブログ更新がなかったことに気づいてのやっつけ仕事。
テストが足りてません!
以前検討したものを進めたものになります。
http://d.hatena.ne.jp/junjun777/20080612/wsh_text_to_binary