// decodeZipName — декодирование имени из ZIP: UTF-8-флаг / эвристика (UTF-8 → CP437 → CP866). export function decodeZipName(bytes, isUtf8) { if (isUtf8) return new TextDecoder('utf-8').decode(bytes); // Многие архиваторы пишут имя в UTF-8, но НЕ выставляют UTF-8-флаг (bit 11). // Сначала строго пробуем UTF-8: если байты — валидный UTF-8 с кириллицей/текстом, // берём их как есть (иначе декодирование CP437→CP866 превратит их в «╨╣…»-мусор). try { const s = new TextDecoder('utf-8', { fatal: true }).decode(bytes); // Кириллица — точно UTF-8; либо чистый печатаемый текст без управляющих символов. if (/[\u0400-\u04FF]/.test(s) || !/[^\u0020-\u007e]/.test(s)) return s; } catch (e) { /* не UTF-8 — legacy (CP437/CP866) */ } let name; try { name = new TextDecoder('ibm437').decode(bytes); } catch (e) { name = new TextDecoder('utf-8').decode(bytes); } // Кириллица из 1С (CP866) — перекодировать, если имя пришло как CP437-мусор if (/[^\x00-\x7f]/.test(name)) { try { name = new TextDecoder('ibm866').decode(bytes); } catch (e) { /* оставить как есть */ } } return name; }