jellyfin-web/src/components/sanitizeFilename.js

91 lines
2.6 KiB
JavaScript
Raw Normal View History

2019-01-23 04:33:34 -07:00
// From https://github.com/parshap/node-sanitize-filename
2020-03-19 18:20:47 -07:00
const illegalRe = /[\/\?<>\\:\*\|":]/g;
// eslint-disable-next-line no-control-regex
const controlRe = /[\x00-\x1f\x80-\x9f]/g;
const reservedRe = /^\.+$/;
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
const windowsTrailingRe = /[\. ]+$/;
2020-03-19 18:20:47 -07:00
function isHighSurrogate(codePoint) {
return codePoint >= 0xd800 && codePoint <= 0xdbff;
}
2018-10-22 15:05:09 -07:00
2020-03-19 18:20:47 -07:00
function isLowSurrogate(codePoint) {
return codePoint >= 0xdc00 && codePoint <= 0xdfff;
}
2018-10-22 15:05:09 -07:00
2020-03-19 18:20:47 -07:00
function getByteLength(string) {
2020-05-04 03:44:12 -07:00
if (typeof string !== 'string') {
throw new Error('Input must be string');
2018-10-22 15:05:09 -07:00
}
2020-03-19 18:20:47 -07:00
const charLength = string.length;
let byteLength = 0;
let codePoint = null;
let prevCodePoint = null;
for (let i = 0; i < charLength; i++) {
codePoint = string.charCodeAt(i);
// handle 4-byte non-BMP chars
// low surrogate
if (isLowSurrogate(codePoint)) {
// when parsing previous hi-surrogate, 3 is added to byteLength
if (prevCodePoint != null && isHighSurrogate(prevCodePoint)) {
byteLength += 1;
2020-03-19 18:20:47 -07:00
} else {
byteLength += 3;
}
2020-03-19 18:20:47 -07:00
} else if (codePoint <= 0x7f) {
byteLength += 1;
} else if (codePoint >= 0x80 && codePoint <= 0x7ff) {
byteLength += 2;
} else if (codePoint >= 0x800 && codePoint <= 0xffff) {
byteLength += 3;
}
2020-03-19 18:20:47 -07:00
prevCodePoint = codePoint;
2018-10-22 15:05:09 -07:00
}
2020-03-19 18:20:47 -07:00
return byteLength;
}
2020-03-19 18:20:47 -07:00
function truncate(string, byteLength) {
2020-05-04 03:44:12 -07:00
if (typeof string !== 'string') {
throw new Error('Input must be string');
2020-03-19 18:20:47 -07:00
}
2020-03-19 18:20:47 -07:00
const charLength = string.length;
let curByteLength = 0;
let codePoint;
let segment;
2020-03-19 18:20:47 -07:00
for (let i = 0; i < charLength; i += 1) {
codePoint = string.charCodeAt(i);
segment = string[i];
2020-03-19 18:20:47 -07:00
if (isHighSurrogate(codePoint) && isLowSurrogate(string.charCodeAt(i + 1))) {
i += 1;
segment += string[i];
}
2020-03-19 18:20:47 -07:00
curByteLength += getByteLength(segment);
2020-03-19 18:20:47 -07:00
if (curByteLength === byteLength) {
return string.slice(0, i + 1);
} else if (curByteLength > byteLength) {
return string.slice(0, i - segment.length + 1);
2018-10-22 15:05:09 -07:00
}
2020-03-19 18:20:47 -07:00
}
return string;
}
export function sanitize(input, replacement) {
const sanitized = input
.replace(illegalRe, replacement)
.replace(controlRe, replacement)
.replace(reservedRe, replacement)
.replace(windowsReservedRe, replacement)
.replace(windowsTrailingRe, replacement);
return truncate(sanitized, 255);
}