added support for quoted printable dencoding
This commit is contained in:
parent
8e673b4d81
commit
d914f277c5
4 changed files with 405 additions and 8 deletions
14
dencode.js
14
dencode.js
|
@ -88,8 +88,8 @@
|
||||||
"convert": function (input) {
|
"convert": function (input) {
|
||||||
try {
|
try {
|
||||||
return {
|
return {
|
||||||
"status": "ERROR",
|
"status": "OK",
|
||||||
"content": "Sorry, not supported yet!"
|
"content": utf8.decode(quotedPrintable.decode(input))
|
||||||
};
|
};
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
return {
|
return {
|
||||||
|
@ -97,8 +97,7 @@
|
||||||
"content": "Invalid quoted printable string."
|
"content": "Invalid quoted printable string."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"disabled": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "base64encode",
|
"id": "base64encode",
|
||||||
|
@ -151,11 +150,10 @@
|
||||||
"name": "Encode quoted printable",
|
"name": "Encode quoted printable",
|
||||||
"convert": function (input) {
|
"convert": function (input) {
|
||||||
return {
|
return {
|
||||||
"status": "ERROR",
|
"status": "OK",
|
||||||
"content": "Sorry, not supported yet!"
|
"content": quotedPrintable.encode(utf8.encode(input))
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
"disabled": true
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>encoder-decoder</title>
|
<title>encoder-decoder</title>
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
|
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
|
||||||
|
<script type="text/javascript" src="utf8.js"></script>
|
||||||
|
<script type="text/javascript" src="quoted-printable.js"></script>
|
||||||
<script type="text/javascript" src="dencode.js"></script>
|
<script type="text/javascript" src="dencode.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="dencode.css" />
|
<link rel="stylesheet" type="text/css" href="dencode.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
153
quoted-printable.js
Normal file
153
quoted-printable.js
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/*! 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));
|
244
utf8.js
Normal file
244
utf8.js
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
/*! https://mths.be/utf8js v2.0.0 by @mathias */
|
||||||
|
;(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;
|
||||||
|
|
||||||
|
// Taken from https://mths.be/punycode
|
||||||
|
function ucs2decode(string) {
|
||||||
|
var output = [];
|
||||||
|
var counter = 0;
|
||||||
|
var length = string.length;
|
||||||
|
var value;
|
||||||
|
var extra;
|
||||||
|
while (counter < length) {
|
||||||
|
value = string.charCodeAt(counter++);
|
||||||
|
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
||||||
|
// high surrogate, and there is a next character
|
||||||
|
extra = string.charCodeAt(counter++);
|
||||||
|
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
|
||||||
|
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
||||||
|
} else {
|
||||||
|
// unmatched surrogate; only append this code unit, in case the next
|
||||||
|
// code unit is the high surrogate of a surrogate pair
|
||||||
|
output.push(value);
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from https://mths.be/punycode
|
||||||
|
function ucs2encode(array) {
|
||||||
|
var length = array.length;
|
||||||
|
var index = -1;
|
||||||
|
var value;
|
||||||
|
var output = '';
|
||||||
|
while (++index < length) {
|
||||||
|
value = array[index];
|
||||||
|
if (value > 0xFFFF) {
|
||||||
|
value -= 0x10000;
|
||||||
|
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
|
||||||
|
value = 0xDC00 | value & 0x3FF;
|
||||||
|
}
|
||||||
|
output += stringFromCharCode(value);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkScalarValue(codePoint) {
|
||||||
|
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
|
||||||
|
throw Error(
|
||||||
|
'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
|
||||||
|
' is not a scalar value'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function createByte(codePoint, shift) {
|
||||||
|
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeCodePoint(codePoint) {
|
||||||
|
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
|
||||||
|
return stringFromCharCode(codePoint);
|
||||||
|
}
|
||||||
|
var symbol = '';
|
||||||
|
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
|
||||||
|
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
|
||||||
|
}
|
||||||
|
else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
|
||||||
|
checkScalarValue(codePoint);
|
||||||
|
symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
|
||||||
|
symbol += createByte(codePoint, 6);
|
||||||
|
}
|
||||||
|
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
|
||||||
|
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
|
||||||
|
symbol += createByte(codePoint, 12);
|
||||||
|
symbol += createByte(codePoint, 6);
|
||||||
|
}
|
||||||
|
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
function utf8encode(string) {
|
||||||
|
var codePoints = ucs2decode(string);
|
||||||
|
var length = codePoints.length;
|
||||||
|
var index = -1;
|
||||||
|
var codePoint;
|
||||||
|
var byteString = '';
|
||||||
|
while (++index < length) {
|
||||||
|
codePoint = codePoints[index];
|
||||||
|
byteString += encodeCodePoint(codePoint);
|
||||||
|
}
|
||||||
|
return byteString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function readContinuationByte() {
|
||||||
|
if (byteIndex >= byteCount) {
|
||||||
|
throw Error('Invalid byte index');
|
||||||
|
}
|
||||||
|
|
||||||
|
var continuationByte = byteArray[byteIndex] & 0xFF;
|
||||||
|
byteIndex++;
|
||||||
|
|
||||||
|
if ((continuationByte & 0xC0) == 0x80) {
|
||||||
|
return continuationByte & 0x3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we end up here, it’s not a continuation byte
|
||||||
|
throw Error('Invalid continuation byte');
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSymbol() {
|
||||||
|
var byte1;
|
||||||
|
var byte2;
|
||||||
|
var byte3;
|
||||||
|
var byte4;
|
||||||
|
var codePoint;
|
||||||
|
|
||||||
|
if (byteIndex > byteCount) {
|
||||||
|
throw Error('Invalid byte index');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteIndex == byteCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read first byte
|
||||||
|
byte1 = byteArray[byteIndex] & 0xFF;
|
||||||
|
byteIndex++;
|
||||||
|
|
||||||
|
// 1-byte sequence (no continuation bytes)
|
||||||
|
if ((byte1 & 0x80) == 0) {
|
||||||
|
return byte1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2-byte sequence
|
||||||
|
if ((byte1 & 0xE0) == 0xC0) {
|
||||||
|
var byte2 = readContinuationByte();
|
||||||
|
codePoint = ((byte1 & 0x1F) << 6) | byte2;
|
||||||
|
if (codePoint >= 0x80) {
|
||||||
|
return codePoint;
|
||||||
|
} else {
|
||||||
|
throw Error('Invalid continuation byte');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3-byte sequence (may include unpaired surrogates)
|
||||||
|
if ((byte1 & 0xF0) == 0xE0) {
|
||||||
|
byte2 = readContinuationByte();
|
||||||
|
byte3 = readContinuationByte();
|
||||||
|
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
|
||||||
|
if (codePoint >= 0x0800) {
|
||||||
|
checkScalarValue(codePoint);
|
||||||
|
return codePoint;
|
||||||
|
} else {
|
||||||
|
throw Error('Invalid continuation byte');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4-byte sequence
|
||||||
|
if ((byte1 & 0xF8) == 0xF0) {
|
||||||
|
byte2 = readContinuationByte();
|
||||||
|
byte3 = readContinuationByte();
|
||||||
|
byte4 = readContinuationByte();
|
||||||
|
codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
|
||||||
|
(byte3 << 0x06) | byte4;
|
||||||
|
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
|
||||||
|
return codePoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error('Invalid UTF-8 detected');
|
||||||
|
}
|
||||||
|
|
||||||
|
var byteArray;
|
||||||
|
var byteCount;
|
||||||
|
var byteIndex;
|
||||||
|
function utf8decode(byteString) {
|
||||||
|
byteArray = ucs2decode(byteString);
|
||||||
|
byteCount = byteArray.length;
|
||||||
|
byteIndex = 0;
|
||||||
|
var codePoints = [];
|
||||||
|
var tmp;
|
||||||
|
while ((tmp = decodeSymbol()) !== false) {
|
||||||
|
codePoints.push(tmp);
|
||||||
|
}
|
||||||
|
return ucs2encode(codePoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
var utf8 = {
|
||||||
|
'version': '2.0.0',
|
||||||
|
'encode': utf8encode,
|
||||||
|
'decode': utf8decode
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 utf8;
|
||||||
|
});
|
||||||
|
} else if (freeExports && !freeExports.nodeType) {
|
||||||
|
if (freeModule) { // in Node.js or RingoJS v0.8.0+
|
||||||
|
freeModule.exports = utf8;
|
||||||
|
} else { // in Narwhal or RingoJS v0.7.0-
|
||||||
|
var object = {};
|
||||||
|
var hasOwnProperty = object.hasOwnProperty;
|
||||||
|
for (var key in utf8) {
|
||||||
|
hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // in Rhino or a web browser
|
||||||
|
root.utf8 = utf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}(this));
|
Loading…
Reference in a new issue