JScriptによるバイナリファイルの書き出し

JScriptにおいて、バイナリファイルの扱いには癖があります。どちらも`ADODB.Stream`を利用します。

まず、読み込みでは`VBArray`クラスを経由する必要があります（[参考](https://learn.microsoft.com/en-us/windows/win32/com/translating-to-vbscript-from-jscript)）。

```javascript
// PS > cmd /c "chcp 65001 > nul && cscript //Nologo //E:JScript read-bin.js"

/** https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/streamtypeenum */
var adTypeBinary = 1;
/** https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/streamreadenum */
var adReadAll = -1;

/**
 * @param {string} fileName 
 * @returns {number[]}
 */
function readBinaryFile(fileName) {
  var stream = WScript.CreateObject("ADODB.Stream");
  stream.Type = adTypeBinary;
  stream.Open();
  stream.LoadFromFile(fileName);
  var safeArray = stream.Read(adReadAll);
  return new VBArray(safeArray).toArray();
}

var file = readBinaryFile("out.bin");
WScript.StdOut.WriteLine(file[0]);
```

書き込みはさらに困難です。

```javascript
// PS > cmd /c "chcp 65001 > nul && cscript //Nologo //E:JScript write-bin.js"

var adTypeBinary = 1;
/** https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/saveoptionsenum */
var adSaveCreateOverWrite = 2;

var stream = WScript.CreateObject("ADODB.Stream");
stream.Type = adTypeBinary;
stream.Open();

stream.Write(0x80);
// ^~~~~~~~~~~~~~~~
// JavaScript runtime error: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.

stream.Write([0x80]);
// ^~~~~~~~~~~~~~~~~~
// JavaScript runtime error: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.

function toSafeArray(array) {
  var dict = WScript.CreateObject("Scripting.Dictionary");
  for (var i = 0; i < array.length; i++) {
    dict.Add(i, array[i]);
  }
  return dict.Items();
}
stream.Write(toSafeArray([0x80]));
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JavaScript runtime error: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.

stream.SaveToFile("out.bin", adSaveCreateOverWrite);
stream.Close();
```

[`System.IO.MemoryStream`](https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream)を経由する方法が、唯一の有効な手段のようです（[参考](https://stackoverflow.com/a/77459751)）。

```javascript
// PS > cmd /c "chcp 65001 > nul && cscript //Nologo //E:JScript write-bin.js"

var adTypeBinary = 1;
var adSaveCreateOverWrite = 2;

var stream = WScript.CreateObject("ADODB.Stream");
stream.Type = adTypeBinary;
stream.Open();

var memoryStream = WScript.CreateObject("System.IO.MemoryStream");
memoryStream.WriteByte(0x80);
var memoryArray = memoryStream.ToArray();

stream.Write(memoryArray);

stream.SaveToFile("out.bin", adSaveCreateOverWrite);
stream.Close();
```

この`Byte[]`は、`WScript.StdOut`/`StdErr`にも書き込むことができるようです。

```javascript
// PS > cmd /c "chcp 65001 > nul && cscript //Nologo //E:JScript write-bin-stdout.js"

var memoryStream = WScript.CreateObject("System.IO.MemoryStream");
for (var i = 0; i <= 0xff; i++) {  
  memoryStream.WriteByte(i);
}
var memoryArray = memoryStream.ToArray();
WScript.StdOut.Write(memoryArray);

// Ā̂Ԅ܆ईଊഌ༎ᄐጒᔔ᜖ᤘᬚᴜ἞℠⌢┤✦⤨⬪⴬⼮㄰㌲㔴㜶㤸㬺㴼㼾䅀䍂䕄䝆䥈䭊䵌低児卒啔坖奘孚嵜彞慠换敤杦楨歪浬潮煰獲畴睶祸筺絼罾膀莂薄螆覈變趌辎醐鎒閔鞖馘鮚鶜龞ꆠꎢꖤꞦꦨꮪ궬꾮놰뎲떴랶릸뮺붼뾾쇀쏂엄쟆질쯊췌쿎퇐폒헔ퟖ�􆧜�笠ﯺ﷼￾
// 127文字しかないが……
```

ところが、`WScript.StdOut`/`StdErr`への書き込みは、サブプロセスとして実行すると失敗します。詳細は不明です。

```python
import subprocess

result = subprocess.run(
    [
        "cmd",
        "/c",
        "chcp 65001 > nul && cscript //Nologo //E:JScript write-bin-stdout.js",
    ],
    capture_output=True,
)

print("stdout:")
print(result.stdout)
print("stderr:")
print(result.stderr)
```

```
> py -3.12 test.py
stdout:
b''
stderr:
b'C:\\Users\\mukai\\temp\\jscript-utf8\\write-bin-stdout.js(6, 1) JavaScript runtime error: Invalid procedure call or argument\r\n\r\n'
```