日本語を含むテキストファイルをアップロードし、Binary Data Client SideのBinaryDataToTextを使ってText型に変換、画面上のExpressionに表示してみると文字化けする。
この現象の原因と対応策を検討する。
環境情報
ODC Studio (Version 1.5.28)
Binary Data Client Side (Version 1.11)
公式部品にもBinaryDataがあるが、サーバー側の部品しかないので、クライアント側でBinaryDataを操作する為のコンポーネント。
現象の再現
日本語を含むテキストファイルのBinary DataをBinaryDataToTextすると文字化け
EncodingをUTF-8にした以下のファイルで動作確認する。
dummy1,dummy2,dummy3
あ,い,う,え,お
か,き,く,け,こ
Upload Widgetを画面に配置し、File Contentプロパティに紐付けたBinaryDataVarがアップロードしたファイルのバイナリ持つ。このBinaryDataVarを対象にBinary Data Client Side/BinaryDataToTextを使う。

結果のText型変数を画面上のExpressionに表示してみると、以下のように日本語部分が文字化けする。ASCIIコードの範囲内の文字(アルファベットと数字)であるヘッダ部分(「dummy1,dummy2,dummy3」の部分)は問題なく表示されている。

サーバーサイドでBinaryDataToTextを呼ぶと問題なくText型に変換できる
標準で備わっているBinaryData/BinaryDataToTextに同じBinaryDataVarを渡すと、日本語部分も問題なく変換してくれる。

Encoding Input Parameterは変換対象のバイナリデータが、どのエンコーディングで作られたものかを指定するもの。↑で書いたようにUTF-8でエンコーディングしたファイルを使っており、デフォルトはUTF-8であるので未指定にしてある。
つまり、Binary Data Client Side/BinaryDataToTextの実装方法に、文字化けの何らかの理由がありそう。
Binary Data Client Side/BinaryDataToTextの実装を確認する
処理の実体はJavaScript要素なので、その中身を確認する。
var toBase64 = $parameters.Binary;
$parameters.Text = window.atob(toBase64);
- $parameters.Binaryの値を「toBase64」という名前で受けている
- window.atobはBASE64エンコードされた文字列を元の文字列に戻す(制約あり)
ということから、OutSystemsのBinary Dataが実行時にはBASE64エンコードされた文字列であることを前提に、window.atobででコードした結果を返すActionになっている。
によると、
A binary string containing raw bytes decoded from encodedData. Strings in JavaScript are encoded as UTF-16, so this means each character must have a code point less than 256, representing one byte of data.
太字の部分から、window.atobはおそらくマルチバイト文字には対応していない。
解決策
方針検討
window.atobでBASE64エンコードされた文字列(OutSystemsのBinary Data型)を、バイト単位でデコードしたもの(これをbinary stringと呼んでいるらしい)。
バイト単位だとそのまま文字列として扱ってしまうと日本語文字部分がバイト単位で分かれてしまう。そこで、TextDecoder.decode()を使ってJavaScript文字列に変換すれば良い。
TextDecoder.decodeはbufferというパラメータを受け取るが、その型としてTypedArrayが使え、その一種にUint8Arrayが含まれるので、binary stringをUint8Arrayに変換し、それをTextDecoder.decodeする。
サンプル実装(Geminiに考えてもらった)
色々試行錯誤しようと思いつつGeminiに聞いてみたら動作するコードを出してくれたので、これで。
JavaScript要素のParametersは以下の通り(型はそれぞれ名前通り)。

// 1. 受け取ったBinary Dataを"binary string"に変換する
const binaryString = atob($parameters.Binary);
// 2. "binary string"をUint8Arrayに詰め替える
const utf8Bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
utf8Bytes[i] = binaryString.charCodeAt(i);
}
// 3. TextDecoderで文字列に変換
$parameters.Text = new TextDecoder("utf-8").decode(utf8Bytes);

