'use strict'; const ZIP_ENCODING_UNKNOWN = 0; const ZIP_ENCODING_ASCII = 1; const ZIP_ENCODING_UTF8_KNOWN = 2; const ZIP_ENCODING_UTF8_GUESSED = 3; const ZIP_ENCODING_CP437 = 4; const ZIP_ENCODING_ERROR = 5; module.exports.zipEncodings = { unknown: ZIP_ENCODING_UNKNOWN, ascii: ZIP_ENCODING_ASCII, utf8known: ZIP_ENCODING_UTF8_KNOWN, utf8guessed: ZIP_ENCODING_UTF8_GUESSED, cp437: ZIP_ENCODING_CP437, error: ZIP_ENCODING_ERROR } const UTF_8_LEN_2_MASK = 0xe0; const UTF_8_LEN_2_MATCH = 0xc0; const UTF_8_LEN_3_MASK = 0xf0; const UTF_8_LEN_3_MATCH = 0xe0; const UTF_8_LEN_4_MASK = 0xf8; const UTF_8_LEN_4_MATCH = 0xf0; const UTF_8_CONTINUE_MASK = 0xc0; const UTF_8_CONTINUE_MATCH = 0x80; module.exports.zipGuessEncoding = zipGuessEncoding; function zipGuessEncoding (buf, expectedEncoding) { let enc = ZIP_ENCODING_ASCII; if (!buf) { return enc; } for (let i=0; i < buf.length; ++i) { if ((buf[i] > 31 && buf[i] < 128) || buf[i] == '\r' || buf[i] == '\n' || buf[i] == '\t') { continue; } let ulen; enc = ZIP_ENCODING_UTF8_GUESSED; if ((buf[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) ulen = 1; else if ((buf[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) ulen = 2; else if ((buf[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) ulen = 3; else { enc = ZIP_ENCODING_CP437; break; } if (i + ulen >= buf.length) { enc = ZIP_ENCODING_CP437; break; } for (let j=1; j<=ulen; j++) { if ((buf[i+j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) { enc = ZIP_ENCODING_CP437; return done(); } } i += ulen; } return done(); function done () { const expected = expectedEncoding || ZIP_ENCODING_UNKNOWN; if (expected !== ZIP_ENCODING_UNKNOWN) { if (expected === ZIP_ENCODING_UTF8_KNOWN && enc === ZIP_ENCODING_UTF8_GUESSED) { enc = ZIP_ENCODING_UTF8_KNOWN; } if (expected !== enc && enc !== ZIP_ENCODING_ASCII) { return ZIP_ENCODING_ERROR; } } return enc; } }