-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
117 lines (96 loc) · 3.07 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
const iconv = require('iconv-lite');
const XMLDeclBeginnings = [
{
encoding: 'utf8', // This is common for more encodings, all of them can be used to read the declaration
buffer: Buffer.from([0x3C, 0x3F, 0x78, 0x6D])
},
{
encoding: 'utf16le',
buffer: Buffer.from([0x3C, 0x00, 0x3F, 0x00])
},
{
encoding: 'utf16be',
buffer: Buffer.from([0x00, 0x3C, 0x00, 0x3F])
}
];
const BOMs = [
{
encoding: 'utf8',
buffer: Buffer.from([0xEF, 0xBB, 0xBF])
},
{
encoding: 'utf16le',
buffer: Buffer.from([0xFF, 0xFE])
},
{
encoding: 'utf16be',
buffer: Buffer.from([0xFE, 0xFF])
}
];
// XML => nodejs
const ENCODING_MAP = {
'UTF-8': 'utf8',
'UTF-16': ['utf16le','utf16be']
};
function normalizeEncoding(xmlEncoding, detectedEncoding) {
const encoding = ENCODING_MAP[xmlEncoding];
if (!encoding) { return xmlEncoding; }
if (Array.isArray(encoding)) {
return encoding.find(e => e === detectedEncoding);
} else {
return encoding;
}
}
function bufferStartsWith(buffer, beginning) {
return buffer.slice(0, beginning.length).equals(beginning);
}
function getXMLDeclTagEncoding(xmlBuffer) {
const found = XMLDeclBeginnings.find(beginning => bufferStartsWith(xmlBuffer, beginning.buffer));
return found ? found.encoding : null;
}
function getXMLDeclaration(xmlBuffer, encoding) {
const closeTag = iconv.encode('?>', encoding);
const xmlDeclEnd = xmlBuffer.indexOf(closeTag);
if (xmlDeclEnd === -1) { return null; } // no ?> found
return iconv.decode(xmlBuffer.slice(0, xmlDeclEnd), encoding); // End index not included
}
function getEncodingAttr(xmlDecl) {
const result = /encoding=['"]([A-Za-z]([A-Za-z0-9._]|-)*)['"]/.exec(xmlDecl);
return result ? result[1] : null;
}
function getBOM(textBuffer) {
return BOMs.find(bom => bufferStartsWith(textBuffer, bom.buffer));
}
function xmlEncoding(xmlBuffer) {
var detectedEncoding;
var xmlDeclFound;
var xmlDeclEncoding
const bom = getBOM(xmlBuffer);
if (bom) {
xmlBuffer = xmlBuffer.slice(bom.buffer.length);
detectedEncoding = bom.encoding;
} else {
detectedEncoding = getXMLDeclTagEncoding(xmlBuffer);
xmlDeclFound = !!detectedEncoding;
}
if (!detectedEncoding) {
return null;
}
if (xmlDeclFound) {
xmlDeclEncoding = normalizeEncoding(getEncodingAttr(getXMLDeclaration(xmlBuffer, detectedEncoding)), detectedEncoding);
}
// We should check if xmlDeclEncoding and detectedEncoding match, for now we
// give precedence to the encoding in the xml declaration if it exists
return xmlDeclEncoding ? xmlDeclEncoding : detectedEncoding;
}
function bufferToString(xmlBuffer, options) {
if (!Buffer.isBuffer(xmlBuffer)) {
throw new Error('buffer expected, found: ' + typeof xmlBuffer);
}
options = options || {};
const encoding = xmlEncoding(xmlBuffer);
const defaultEncoding = iconv.encodingExists(options.defaultEncoding) ? options.defaultEncoding : 'utf8';
return iconv.decode(xmlBuffer, iconv.encodingExists(encoding) ? encoding : defaultEncoding);
}
module.exports = bufferToString;
module.exports.xmlEncoding = xmlEncoding;