UNPKG

gltf-pipeline

Version:

Content pipeline tools for optimizing glTF assets.

134 lines (121 loc) 4.15 kB
"use strict"; const { Check, RuntimeError } = require("cesium"); const os = require("os"); const path = require("path"); const { domainToUnicode, URL } = require("url"); module.exports = { fileURLToPath: fileURLToPath, pathToFileURL: pathToFileURL, }; const isWindows = os.platform() === "win32"; const forwardSlashRegEx = /\//g; const CHAR_LOWERCASE_A = 97; const CHAR_LOWERCASE_Z = 122; const CHAR_FORWARD_SLASH = 47; const CHAR_BACKWARD_SLASH = 92; const percentRegEx = /%/g; const backslashRegEx = /\\/g; const newlineRegEx = /\n/g; const carriageReturnRegEx = /\r/g; const tabRegEx = /\t/g; // The following function is copied from Node.js implementation of url module // https://github.com/nodejs/node/blob/7237eaa3353aacf284289c8b59b0a5e0fa5744bb/lib/internal/url.js#L1345-L1383 // pathToFileURL & fileURLToPath were added in 10.12 so we want to maintain ability run under older versions. function fileURLToPath(path) { Check.defined("path", path); if (typeof path === "string") { path = new URL(path); } if (path.protocol !== "file:") { throw new RuntimeError("Expected path.protocol to start with file:"); } return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); } function pathToFileURL(filepath) { let resolved = path.resolve(filepath); // path.resolve strips trailing slashes so we must add them back const filePathLast = filepath.charCodeAt(filepath.length - 1); if ( (filePathLast === CHAR_FORWARD_SLASH || (isWindows && filePathLast === CHAR_BACKWARD_SLASH)) && resolved[resolved.length - 1] !== path.sep ) { resolved += "/"; } const outURL = new URL("file://"); if (resolved.includes("%")) { resolved = resolved.replace(percentRegEx, "%25"); } // in posix, "/" is a valid character in paths if (!isWindows && resolved.includes("\\")) { resolved = resolved.replace(backslashRegEx, "%5C"); } if (resolved.includes("\n")) { resolved = resolved.replace(newlineRegEx, "%0A"); } if (resolved.includes("\r")) { resolved = resolved.replace(carriageReturnRegEx, "%0D"); } if (resolved.includes("\t")) { resolved = resolved.replace(tabRegEx, "%09"); } outURL.pathname = resolved; return outURL; } function getPathFromURLWin32(url) { const hostname = url.hostname; let pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === "%") { const third = pathname.codePointAt(n + 2) | 0x20; if ( (pathname[n + 1] === "2" && third === 102) || // 2f 2F / (pathname[n + 1] === "5" && third === 99) ) { // 5c 5C \ throw new RuntimeError( "file URL must not include encoded \\ or / characters" ); } } } pathname = pathname.replace(forwardSlashRegEx, "\\"); pathname = decodeURIComponent(pathname); if (hostname !== "") { // If hostname is set, then we have a UNC path // Pass the hostname through domainToUnicode just in case // it is an IDN using punycode encoding. We do not need to worry // about percent encoding because the URL parser will have // already taken care of that for us. Note that this only // causes IDNs with an appropriate `xn--` prefix to be decoded. return `\\\\${domainToUnicode(hostname)}${pathname}`; } // Otherwise, it's a local path that requires a drive letter const letter = pathname.codePointAt(1) | 0x20; const sep = pathname[2]; if ( letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || // a..z A..Z sep !== ":" ) { throw new RuntimeError("file URL must be absolute"); } return pathname.slice(1); } function getPathFromURLPosix(url) { if (url.hostname !== "") { throw new RuntimeError("Invalid platform"); } const pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === "%") { const third = pathname.codePointAt(n + 2) | 0x20; if (pathname[n + 1] === "2" && third === 102) { throw new RuntimeError( "file URL must not include encoded \\ or / characters" ); } } } return decodeURIComponent(pathname); }