Everyday Pieces ::
  • Webサービス
  • ブログパーツ
  1. ホーム
  2. プログラミング

zip.jsを触ってみた(2)

2019年3月20日 プログラミング

 超久しぶりに zip.js を使ったりしたのですが、
なんか問題が起きたりしました(^_^;)

 調べてみた所、
ファイル名のエンコードが UTF8 の場合に起こるようです。
どうもオリジナルのコードに問題がありそうな雰囲気?
というか対応が不十分?

 ところで、
ZIP内部のファイル名エンコーディングは、
ASCII か UTF8 のいずれかになります。
一方、日本語版Windowsにおける既定の文字エンコーディングはSJIS。
Microsoft的にはCP932とか言ったりするようです。

 そんなわけで、マルチバイトなSJISのファイル名は、
ZIP内部ではASCIIとして扱われるのが通常?のようです。
ただ、場合によっては変換して UTF8 として扱うことがあるようです。
どちらになるのかの条件はよく分かってません。
使用したソフトによっても異なるかもしれません。

 ともかくも改善することにしました。
また、ASCIIとして扱われたマルチバイトな文字を
デコードするためにカスタマイズできるようにもしました。

 ということで、
"zip.js" の一部を以下のように改造しました。

function decodeASCII( bytes ) { // *** MOD ***
    var i, il, out = '', charCode, extendedASCII = [ '\u00C7', '\u00FC', '\u00E9', 
        .
        .
        .
    ];
    for (i = 0, il = bytes.length; i < il; i++) {
        charCode = bytes[i];
        out += charCode >= 128 ? extendedASCII[charCode - 128] : String.fromCharCode( charCode );
    }
    return out;
}

function decodeUTF8( bytes ) { // *** MOD ***
    // cf. https://ja.wikipedia.org/wiki/UTF-8
    // cf. https://qiita.com/YusukeHirao/items/2f0fb8d5bbb981101be0
    var c, s = '', i = 0, l = bytes.length;
    while ( l > 0 ) {
        c = bytes[i++];
        if ( (c & 0x80) === 0 ) {
            // 1 byte (7 bit)
            s += String.fromCharCode( c );
            l--;
        } else
        if ( ( c & 0xe0 ) === 0xc0 ) {
            // 2 bytes (11 bit)
            c &= 0x1f;
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            s += String.fromCharCode( c );
            l -= 2;
        } else
        if ( ( c & 0xf0 ) === 0xe0 ) {
            // 3 bytes (16 bit)
            c &= 0x0f;
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            s += String.fromCharCode( c );
            l -= 3;
        } else
        if ( ( c & 0xf8 ) === 0xf0 ) {
            // 4 bytes (21 bit)
            c &= 0x07;
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            c = ( c << 6 ) | ( bytes[i++] & 0x3f );
            c -= 0x10000;
            s += String.fromCharCode( 0xd800 | (c >>> 10), 0xdc00 | (c & 0x3ff) ); // surrogate pair
            l -= 4;
        } else {
            // ignore
            l--;
        }
    }
    return s;
}

function getString( utf8, bytes ) { // *** MOD ***
    if ( utf8 ) {
        return decodeUTF8( bytes );
    } else {
        if ( obj.zip.decodeString ) {
            return obj.zip.decodeString( bytes );
        } else {
            return decodeASCII( bytes );
        }
    }
}

    .
    .
    .

var zipReader = {
    getEntries : function(callback) {
        var worker = this._worker;
            .
            .
            .
            reader.readUint8Array(datalength, reader.size - datalength, function(bytes) {
                var i, index = 0, entries = [], entry, data = getDataHelper(bytes.length, bytes); // *** MOD ***
                for (i = 0; i < fileslength; i++) {
                    .
                    .
                    .
                    // *** MOD ***
                    //filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength));
                    //entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename);
                    entry.filename = getString((entry.bitFlag & 0x0800) === 0x0800, data.array.subarray(index + 46, index + 46 + entry.filenameLength));
                    if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/")
                        entry.directory = true;
                    // *** MOD ***
                    //comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength));
                    //entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment);
                    entry.comment = getString((entry.bitFlag & 0x0800) === 0x0800, data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength));
                    .
                    .
                    .
                }
                .
                .
                .
    },

    .
    .
    .

obj.zip = {
    Reader : Reader,
    Writer : Writer,
        .
        .
        .
    workerScripts : null,

    // *** ADD ***
    decodeString : null // function decodeString( bytes ) 
};

 なお、
例えば encoding.js を使って decodeString する際は
以下のようにしてください。
AUTO ではなく明示的に SJIS にしても構わないかもしれません。
bytes は Uint8Array な配列です。

zip.decodeString = function( bytes ) {
    return Encoding.convert( bytes, { to:'UNICODE', from:'AUTO', type:'string' } );
    // あるいは明示的に return Encoding.convert( bytes, { to:'UNICODE', from:'SJIS', type:'string' } );
};

関連記事
パーリンノイズを試してみた(2) zip.jsを触ってみた

コメントする キャンセル

アドレスが公開されることはありません。が付いている欄は必須項目です。

投稿ナビゲーション

落書きをリアルな風景写真に即変換な技術
日本の祝日や元号に対応したカレンダーを更新

カテゴリー

WordPress つぶやき トピック プログラミング

タグ

AS3 enchant.js FamilyTreeVis Flash Geolocation gif.js kinect Linux MMD MoneyTrackNote notifier.js OpenCV PDFカレンダー RISC-V three.js セキュリティ テーマ自作 ブログパーツ 動物 動画 麻雀

アーカイブ

© Everyday Pieces ::