mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Moved to src
This commit is contained in:
227
src/Binary/Decoder.ts
Normal file
227
src/Binary/Decoder.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
import { WA } from './Constants'
|
||||
|
||||
export default class Decoder {
|
||||
buffer: Buffer = null
|
||||
index = 0
|
||||
|
||||
checkEOS(length: number) {
|
||||
if (this.index + length > this.buffer.length) {
|
||||
throw 'end of stream'
|
||||
}
|
||||
}
|
||||
next() {
|
||||
const value = this.buffer[this.index]
|
||||
this.index += 1
|
||||
return value
|
||||
}
|
||||
readByte() {
|
||||
this.checkEOS(1)
|
||||
return this.next()
|
||||
}
|
||||
readStringFromChars(length: number) {
|
||||
this.checkEOS(length)
|
||||
const value = this.buffer.slice(this.index, this.index + length)
|
||||
|
||||
this.index += length
|
||||
return new TextDecoder().decode(value)
|
||||
}
|
||||
readBytes(n: number): Buffer {
|
||||
this.checkEOS(n)
|
||||
const value = this.buffer.slice(this.index, this.index + n)
|
||||
this.index += n
|
||||
return value
|
||||
}
|
||||
readInt(n: number, littleEndian = false) {
|
||||
this.checkEOS(n)
|
||||
let val = 0
|
||||
for (let i = 0; i < n; i++) {
|
||||
const shift = littleEndian ? i : n - 1 - i
|
||||
val |= this.next() << (shift * 8)
|
||||
}
|
||||
return val
|
||||
}
|
||||
readInt20() {
|
||||
this.checkEOS(3)
|
||||
return ((this.next() & 15) << 16) + (this.next() << 8) + this.next()
|
||||
}
|
||||
unpackHex(value: number) {
|
||||
if (value >= 0 && value < 16) {
|
||||
return value < 10 ? '0'.charCodeAt(0) + value : 'A'.charCodeAt(0) + value - 10
|
||||
}
|
||||
throw 'invalid hex: ' + value
|
||||
}
|
||||
unpackNibble(value: number) {
|
||||
if (value >= 0 && value <= 9) {
|
||||
return '0'.charCodeAt(0) + value
|
||||
}
|
||||
switch (value) {
|
||||
case 10:
|
||||
return '-'.charCodeAt(0)
|
||||
case 11:
|
||||
return '.'.charCodeAt(0)
|
||||
case 15:
|
||||
return '\0'.charCodeAt(0)
|
||||
default:
|
||||
throw 'invalid nibble: ' + value
|
||||
}
|
||||
}
|
||||
unpackByte(tag: number, value: number) {
|
||||
if (tag === WA.Tags.NIBBLE_8) {
|
||||
return this.unpackNibble(value)
|
||||
} else if (tag === WA.Tags.HEX_8) {
|
||||
return this.unpackHex(value)
|
||||
} else {
|
||||
throw 'unknown tag: ' + tag
|
||||
}
|
||||
}
|
||||
readPacked8(tag: number) {
|
||||
const startByte = this.readByte()
|
||||
let value = ''
|
||||
|
||||
for (let i = 0; i < (startByte & 127); i++) {
|
||||
const curByte = this.readByte()
|
||||
value += String.fromCharCode(this.unpackByte(tag, (curByte & 0xf0) >> 4))
|
||||
value += String.fromCharCode(this.unpackByte(tag, curByte & 0x0f))
|
||||
}
|
||||
if (startByte >> 7 !== 0) {
|
||||
value = value.slice(0, -1)
|
||||
}
|
||||
return value
|
||||
}
|
||||
readRangedVarInt(min, max, description = 'unknown') {
|
||||
// value =
|
||||
throw 'WTF; should not be called'
|
||||
}
|
||||
isListTag(tag: number) {
|
||||
return tag === WA.Tags.LIST_EMPTY || tag === WA.Tags.LIST_8 || tag === WA.Tags.LIST_16
|
||||
}
|
||||
readListSize(tag: number) {
|
||||
switch (tag) {
|
||||
case WA.Tags.LIST_EMPTY:
|
||||
return 0
|
||||
case WA.Tags.LIST_8:
|
||||
return this.readByte()
|
||||
case WA.Tags.LIST_16:
|
||||
return this.readInt(2)
|
||||
default:
|
||||
throw 'invalid tag for list size: ' + tag
|
||||
}
|
||||
}
|
||||
|
||||
readString(tag: number): string {
|
||||
if (tag >= 3 && tag <= 235) {
|
||||
const token = this.getToken(tag)
|
||||
return token === 's.whatsapp.net' ? 'c.us' : token
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case WA.Tags.DICTIONARY_0:
|
||||
case WA.Tags.DICTIONARY_1:
|
||||
case WA.Tags.DICTIONARY_2:
|
||||
case WA.Tags.DICTIONARY_3:
|
||||
return this.getTokenDouble(tag - WA.Tags.DICTIONARY_0, this.readByte())
|
||||
case WA.Tags.LIST_EMPTY:
|
||||
return null
|
||||
case WA.Tags.BINARY_8:
|
||||
return this.readStringFromChars(this.readByte())
|
||||
case WA.Tags.BINARY_20:
|
||||
return this.readStringFromChars(this.readInt20())
|
||||
case WA.Tags.BINARY_32:
|
||||
return this.readStringFromChars(this.readInt(4))
|
||||
case WA.Tags.JID_PAIR:
|
||||
const i = this.readString(this.readByte())
|
||||
const j = this.readString(this.readByte())
|
||||
if (i && j) {
|
||||
return i + '@' + j
|
||||
}
|
||||
throw 'invalid jid pair: ' + i + ', ' + j
|
||||
case WA.Tags.HEX_8:
|
||||
case WA.Tags.NIBBLE_8:
|
||||
return this.readPacked8(tag)
|
||||
default:
|
||||
throw 'invalid string with tag: ' + tag
|
||||
}
|
||||
}
|
||||
readAttributes(n: number) {
|
||||
if (n !== 0) {
|
||||
const attributes: WA.NodeAttributes = {}
|
||||
for (let i = 0; i < n; i++) {
|
||||
const key = this.readString(this.readByte())
|
||||
const b = this.readByte()
|
||||
|
||||
attributes[key] = this.readString(b)
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
return null
|
||||
}
|
||||
readList(tag: number) {
|
||||
const arr = [...new Array(this.readListSize(tag))]
|
||||
return arr.map(() => this.readNode())
|
||||
}
|
||||
getToken(index: number) {
|
||||
if (index < 3 || index >= WA.SingleByteTokens.length) {
|
||||
throw 'invalid token index: ' + index
|
||||
}
|
||||
return WA.SingleByteTokens[index]
|
||||
}
|
||||
getTokenDouble(index1, index2): string {
|
||||
const n = 256 * index1 + index2
|
||||
if (n < 0 || n > WA.DoubleByteTokens.length) {
|
||||
throw 'invalid double token index: ' + n
|
||||
}
|
||||
return WA.DoubleByteTokens[n]
|
||||
}
|
||||
readNode(): WA.Node {
|
||||
const listSize = this.readListSize(this.readByte())
|
||||
const descrTag = this.readByte()
|
||||
if (descrTag === WA.Tags.STREAM_END) {
|
||||
throw 'unexpected stream end'
|
||||
}
|
||||
|
||||
const descr = this.readString(descrTag)
|
||||
if (listSize === 0 || !descr) {
|
||||
throw 'invalid node'
|
||||
}
|
||||
|
||||
const attrs = this.readAttributes((listSize - 1) >> 1)
|
||||
let content: WA.NodeData = null
|
||||
|
||||
if (listSize % 2 === 0) {
|
||||
const tag = this.readByte()
|
||||
if (this.isListTag(tag)) {
|
||||
content = this.readList(tag)
|
||||
} else {
|
||||
let decoded: Buffer | string
|
||||
switch (tag) {
|
||||
case WA.Tags.BINARY_8:
|
||||
decoded = this.readBytes(this.readByte())
|
||||
break
|
||||
case WA.Tags.BINARY_20:
|
||||
decoded = this.readBytes(this.readInt20())
|
||||
break
|
||||
case WA.Tags.BINARY_32:
|
||||
decoded = this.readBytes(this.readInt(4))
|
||||
break
|
||||
default:
|
||||
decoded = this.readString(tag)
|
||||
break
|
||||
}
|
||||
|
||||
if (descr === 'message' && Buffer.isBuffer(decoded)) {
|
||||
content = WA.Message.decode(decoded)
|
||||
} else {
|
||||
content = decoded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [descr, attrs, content]
|
||||
}
|
||||
|
||||
read(buffer: Buffer) {
|
||||
this.buffer = buffer
|
||||
this.index = 0
|
||||
return this.readNode()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user