154 lines
5.3 KiB
JavaScript
154 lines
5.3 KiB
JavaScript
|
/*! https://mths.be/quoted-printable v1.0.0 by @mathias | MIT license */
|
|||
|
;(function(root) {
|
|||
|
|
|||
|
// Detect free variables `exports`.
|
|||
|
var freeExports = typeof exports == 'object' && exports;
|
|||
|
|
|||
|
// Detect free variable `module`.
|
|||
|
var freeModule = typeof module == 'object' && module &&
|
|||
|
module.exports == freeExports && module;
|
|||
|
|
|||
|
// Detect free variable `global`, from Node.js or Browserified code, and use
|
|||
|
// it as `root`.
|
|||
|
var freeGlobal = typeof global == 'object' && global;
|
|||
|
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
|
|||
|
root = freeGlobal;
|
|||
|
}
|
|||
|
|
|||
|
/*--------------------------------------------------------------------------*/
|
|||
|
|
|||
|
var stringFromCharCode = String.fromCharCode;
|
|||
|
var decode = function(input) {
|
|||
|
return input
|
|||
|
// https://tools.ietf.org/html/rfc2045#section-6.7, rule 3:
|
|||
|
// “Therefore, when decoding a `Quoted-Printable` body, any trailing white
|
|||
|
// space on a line must be deleted, as it will necessarily have been added
|
|||
|
// by intermediate transport agents.”
|
|||
|
.replace(/[\t\x20]$/gm, '')
|
|||
|
// Remove hard line breaks preceded by `=`. Proper `Quoted-Printable`-
|
|||
|
// encoded data only contains CRLF line endings, but for compatibility
|
|||
|
// reasons we support separate CR and LF too.
|
|||
|
.replace(/=(?:\r\n?|\n|$)/g, '')
|
|||
|
// Decode escape sequences of the form `=XX` where `XX` is any
|
|||
|
// combination of two hexidecimal digits. For optimal compatibility,
|
|||
|
// lowercase hexadecimal digits are supported as well. See
|
|||
|
// https://tools.ietf.org/html/rfc2045#section-6.7, note 1.
|
|||
|
.replace(/=([a-fA-F0-9]{2})/g, function($0, $1) {
|
|||
|
var codePoint = parseInt($1, 16);
|
|||
|
return stringFromCharCode(codePoint);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
var handleTrailingCharacters = function(string) {
|
|||
|
return string
|
|||
|
.replace(/\x20$/, '=20') // Handle trailing space.
|
|||
|
.replace(/\t$/, '=09') // Handle trailing tab.
|
|||
|
};
|
|||
|
|
|||
|
var regexUnsafeSymbols = /[\0-\x08\n-\x1F=\x7F-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|||
|
var encode = function(string) {
|
|||
|
|
|||
|
// Encode symbols that are definitely unsafe (i.e. unsafe in any context).
|
|||
|
var encoded = string.replace(regexUnsafeSymbols, function(symbol) {
|
|||
|
if (symbol > '\xFF') {
|
|||
|
throw RangeError(
|
|||
|
'`quotedPrintable.encode()` expects extended ASCII input only. ' +
|
|||
|
'Don\u2019t forget to encode the input first using a character ' +
|
|||
|
'encoding like UTF-8.'
|
|||
|
);
|
|||
|
}
|
|||
|
var codePoint = symbol.charCodeAt(0);
|
|||
|
var hexadecimal = codePoint.toString(16).toUpperCase();
|
|||
|
return '=' + ('0' + hexadecimal).slice(-2);
|
|||
|
});
|
|||
|
|
|||
|
// Limit lines to 76 characters (not counting the CRLF line endings).
|
|||
|
var lines = encoded.split(/\r\n?|\n/g);
|
|||
|
var lineIndex = -1;
|
|||
|
var lineCount = lines.length;
|
|||
|
var result = [];
|
|||
|
while (++lineIndex < lineCount) {
|
|||
|
var line = lines[lineIndex];
|
|||
|
// Leave room for the trailing `=` for soft line breaks.
|
|||
|
var LINE_LENGTH = 75;
|
|||
|
var index = 0;
|
|||
|
var length = line.length;
|
|||
|
while (index < length) {
|
|||
|
var buffer = encoded.slice(index, index + LINE_LENGTH);
|
|||
|
// If this line ends with `=`, optionally followed by a single uppercase
|
|||
|
// hexadecimal digit, we broke an escape sequence in half. Fix it by
|
|||
|
// moving these characters to the next line.
|
|||
|
if (/=$/.test(buffer)) {
|
|||
|
buffer = buffer.slice(0, LINE_LENGTH - 1);
|
|||
|
index += LINE_LENGTH - 1;
|
|||
|
} else if (/=[A-F0-9]$/.test(buffer)) {
|
|||
|
buffer = buffer.slice(0, LINE_LENGTH - 2);
|
|||
|
index += LINE_LENGTH - 2;
|
|||
|
} else {
|
|||
|
index += LINE_LENGTH;
|
|||
|
}
|
|||
|
result.push(buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Encode space and tab characters at the end of encoded lines. Note that
|
|||
|
// with the current implementation, this can only occur at the very end of
|
|||
|
// the encoded string — every other line ends with `=` anyway.
|
|||
|
var lastLineLength = buffer.length;
|
|||
|
if (/[\t\x20]$/.test(buffer)) {
|
|||
|
// There’s a space or a tab at the end of the last encoded line. Remove
|
|||
|
// this line from the `result` array, as it needs to change.
|
|||
|
result.pop();
|
|||
|
if (lastLineLength + 2 <= LINE_LENGTH + 1) {
|
|||
|
// It’s possible to encode the character without exceeding the line
|
|||
|
// length limit.
|
|||
|
result.push(
|
|||
|
handleTrailingCharacters(buffer)
|
|||
|
);
|
|||
|
} else {
|
|||
|
// It’s not possible to encode the character without exceeding the line
|
|||
|
// length limit. Remvoe the character from the line, and insert a new
|
|||
|
// line that contains only the encoded character.
|
|||
|
result.push(
|
|||
|
buffer.slice(0, lastLineLength - 1),
|
|||
|
handleTrailingCharacters(
|
|||
|
buffer.slice(lastLineLength - 1, lastLineLength)
|
|||
|
)
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// `Quoted-Printable` uses CRLF.
|
|||
|
return result.join('=\r\n');
|
|||
|
};
|
|||
|
|
|||
|
var quotedPrintable = {
|
|||
|
'encode': encode,
|
|||
|
'decode': decode,
|
|||
|
'version': '1.0.0'
|
|||
|
};
|
|||
|
|
|||
|
// Some AMD build optimizers, like r.js, check for specific condition patterns
|
|||
|
// like the following:
|
|||
|
if (
|
|||
|
typeof define == 'function' &&
|
|||
|
typeof define.amd == 'object' &&
|
|||
|
define.amd
|
|||
|
) {
|
|||
|
define(function() {
|
|||
|
return quotedPrintable;
|
|||
|
});
|
|||
|
} else if (freeExports && !freeExports.nodeType) {
|
|||
|
if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+
|
|||
|
freeModule.exports = quotedPrintable;
|
|||
|
} else { // in Narwhal or RingoJS v0.7.0-
|
|||
|
for (var key in quotedPrintable) {
|
|||
|
quotedPrintable.hasOwnProperty(key) && (freeExports[key] = quotedPrintable[key]);
|
|||
|
}
|
|||
|
}
|
|||
|
} else { // in Rhino or a web browser
|
|||
|
root.quotedPrintable = quotedPrintable;
|
|||
|
}
|
|||
|
|
|||
|
}(this));
|