-
Notifications
You must be signed in to change notification settings - Fork 0
/
wbc.js
151 lines (123 loc) · 4.14 KB
/
wbc.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
const path = require('path');
//each part of header length
const HEADER_LENGTH = 4;
const HEADER_CHUNK_TYPE = 4;
const HEADER_COMPRESSION_METHOD = 1;
const HEADER_COMPILE_LEVEL = 1;
const HEADER_BYTECODE_VERSION = 1;
const HEADER_ADDITIONAL_DATA = 3;
const HEADER_CRC32 = 4;
//each part of body length
const BODY_LENGTH = 4;
const BODY_CHUNK_TYPE = 4;
const BODY_CRC32 = 4;
//each part of end length
const END_LENGTH = 4;
const END_CHUNK_TYPE = 4;
const HEADER_FIELDS = [
HEADER_LENGTH,
HEADER_CHUNK_TYPE,
HEADER_COMPRESSION_METHOD,
HEADER_COMPILE_LEVEL,
HEADER_BYTECODE_VERSION,
HEADER_ADDITIONAL_DATA,
HEADER_CRC32
];
class Wbc {
constructor(options = {}) {
const rootDir = path.resolve(__dirname, '.');
this._bindings = require('node-gyp-build')(rootDir);
}
getAdler32(buffer) {
return this._bindings.getAdler32(buffer);
}
generateWbcBytecode(oriBody) {
let signatureBuffer = this.generateSignature();
let headerBuffer = this.generateHeader();
let bodyBuffer = this.generateBody(oriBody);
let endBuffer = this.generateEnd();
let totalLength = signatureBuffer.length + headerBuffer.length + bodyBuffer.length + endBuffer.length;
let bytecodeBuffer = Buffer.concat([signatureBuffer, headerBuffer, bodyBuffer, endBuffer], totalLength);
return bytecodeBuffer;
}
//0x89 0x57 0x42 0x43 0x31 0x0D 0x0A 0x1A 0x0A
generateSignature() {
const buffer = Buffer.alloc(9);
buffer.writeUInt8(0x89, 0);
buffer.writeUInt8(0x57, 1);
buffer.writeUInt8(0x42, 2);
buffer.writeUInt8(0x43, 3);
buffer.writeUInt8(0x31, 4);
buffer.writeUInt8(0x0D, 5);
buffer.writeUInt8(0x0A, 6);
buffer.writeUInt8(0x1A, 7);
buffer.writeUInt8(0x0A, 8);
return buffer;
}
generateHeader() {
let pointer = 0;
let length = this.calculateHeaderLength();
const headerBuffer = Buffer.alloc(length);
// Length
headerBuffer.writeUInt32BE(length, 0);
pointer += HEADER_LENGTH;
// ASCII value for the letter WBHD (0x57 0x42 0x48 0x44 in hexadecimal)
headerBuffer.writeUInt32BE(0x57424844, pointer);
pointer += HEADER_CHUNK_TYPE;
// Compression method
headerBuffer.writeUInt8(0, pointer);
pointer += HEADER_COMPRESSION_METHOD;
// Compile level
headerBuffer.writeUInt8(0, pointer);
pointer += HEADER_COMPILE_LEVEL;
// Bytecode version
headerBuffer.writeUInt8(0, pointer);
pointer += HEADER_BYTECODE_VERSION;
// Additional data zone
for (let i = 0; i < HEADER_ADDITIONAL_DATA; i++) {
headerBuffer.writeUint8(0, pointer);
pointer += 1;
}
// Checksum
const adler32Value = this.getAdler32(headerBuffer.slice(0, pointer));
// Only the CRC32 value of the first 14 bytes is calculated because the last CRC32 field is reserved
// Write the calculated CRC32 value to the last 4 bytes of the Buffer
headerBuffer.writeUInt32BE(adler32Value, pointer);
return headerBuffer;
}
calculateHeaderLength() {
return HEADER_FIELDS.reduce((sum, value) => sum + value, 0);
}
generateBody(oriBody) {
let pointer = 0;
var bodyChunk = oriBody;
let length = BODY_LENGTH + BODY_CHUNK_TYPE + bodyChunk.length + BODY_CRC32;
const bodyBuffer = Buffer.alloc(length);
//length
bodyBuffer.writeUInt32BE(length, 0);
//ASCII value for the letter WBDY (0x57 0x42 0x44 0x59 in hexadecimal)
pointer += BODY_LENGTH;
bodyBuffer.writeUInt32BE(0x57424459, pointer);
//body chunk
pointer += BODY_CHUNK_TYPE;
bodyChunk.copy(bodyBuffer, pointer);
//crc32
pointer += bodyChunk.length;
const adler32Value = this.getAdler32(bodyBuffer.slice(0, pointer));
// Write the calculated CRC32 value to the last 4 bytes of the Buffer
bodyBuffer.writeUInt32BE(adler32Value, pointer);
return bodyBuffer;
}
generateEnd() {
let pointer = 0;
let length = END_LENGTH + END_CHUNK_TYPE;
const endBuffer = Buffer.alloc(length);
//length
endBuffer.writeUInt32BE(length, 0);
//The ASCII values for the letters 'WEND' (0x57 0x45 0x4e 0x44 in hexadecimal).
pointer += END_LENGTH;
endBuffer.writeUInt32BE(0x57454e44, pointer);
return endBuffer;
}
}
exports.Wbc = Wbc