1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import {WireType} from "../message/WireType.js"; 17import {SessionHandShake} from "../message/SessionHandShake.js"; 18import {PayloadProtect} from "../message/PayloadProtect.js"; 19import {TransferConfig} from "../message/TransferConfig.js"; 20import {TransferPayload} from "../message/TransferPayload.js"; 21import {log} from "../../log/Log.js"; 22 23export class Serialize { 24 static bannerByteLength: number = 8 25 26 static serializeSessionHandShake(handShake: SessionHandShake): Uint8Array { 27 let bannerValue = this.serializeToString(1, handShake.banner); 28 let authTypeValue = this.serializeU8(2, handShake.authType); 29 let sessionIdValue = this.serializeU32(3, handShake.sessionId); 30 let connectKey = this.serializeToString(4, handShake.connectKey); 31 let buf = this.serializeToString(5, handShake.buf); 32 let mergedArray = new Uint8Array(bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length + buf.length); 33 mergedArray.set(bannerValue) 34 mergedArray.set(authTypeValue, bannerValue.length) 35 mergedArray.set(sessionIdValue, bannerValue.length + authTypeValue.length) 36 mergedArray.set(connectKey, bannerValue.length + authTypeValue.length + sessionIdValue.length) 37 mergedArray.set(buf, bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length) 38 return mergedArray; 39 } 40 41 static serializePayloadProtect(payloadProtect: PayloadProtect): Uint8Array { 42 let channelId = this.serializeU32(1, payloadProtect.channelId); 43 let commandFlag = this.serializeU32(2, payloadProtect.commandFlag); 44 let checkSum = this.serializeU8(3, payloadProtect.checkSum); 45 let vCode = this.serializeU8(4, payloadProtect.vCode); 46 let mergedArray = new Uint8Array(channelId.length + commandFlag.length + checkSum.length + vCode.length); 47 mergedArray.set(channelId) 48 mergedArray.set(commandFlag, channelId.length) 49 mergedArray.set(checkSum, channelId.length + commandFlag.length) 50 mergedArray.set(vCode, channelId.length + commandFlag.length + checkSum.length) 51 return mergedArray; 52 } 53 54 static serializeTransferConfig(transferConfig: TransferConfig): Uint8Array { 55 let fileSizeValue = this.serializeU64(1, transferConfig.fileSize); 56 let atimeValue = this.serializeU64(2, transferConfig.atime); 57 let mtimeValue = this.serializeU64(3, transferConfig.mtime); 58 let optionsValue = this.serializeToString(4, transferConfig.options); 59 let pathValue = this.serializeToString(5, transferConfig.path); 60 let optionalNameValue = this.serializeToString(6, transferConfig.optionalName); 61 let updateIfNewValue = this.serializeU32(7, transferConfig.updateIfNew ? 1 : 0); 62 let compressTypeValue = this.serializeU8(8, transferConfig.compressType); 63 let holdTimestampValue = this.serializeU32(9, transferConfig.holdTimestamp ? 1 : 0); 64 let functionNameValue = this.serializeToString(10, transferConfig.functionName); 65 let clientCwdValue = this.serializeToString(11, transferConfig.clientCwd); 66 let reserve1Value = this.serializeToString(12, transferConfig.reserve1); 67 let reserve2Value = this.serializeToString(13, transferConfig.reserve2); 68 let mergedArray = new Uint8Array(fileSizeValue.length + atimeValue.length + mtimeValue.length + optionsValue.length + pathValue.length 69 + optionalNameValue.length + updateIfNewValue.length + compressTypeValue.length + holdTimestampValue.length 70 + functionNameValue.length + clientCwdValue.length + reserve1Value.length + reserve2Value.length); 71 let offset = 0; 72 mergedArray.set(fileSizeValue) 73 offset += fileSizeValue.length; 74 mergedArray.set(atimeValue, offset) 75 offset += atimeValue.length; 76 mergedArray.set(mtimeValue, offset) 77 offset += mtimeValue.length; 78 mergedArray.set(optionsValue, offset) 79 offset += optionsValue.length; 80 mergedArray.set(pathValue, offset) 81 offset += pathValue.length; 82 mergedArray.set(optionalNameValue, offset) 83 offset += optionalNameValue.length; 84 mergedArray.set(updateIfNewValue, offset) 85 offset += updateIfNewValue.length; 86 mergedArray.set(compressTypeValue, offset) 87 offset += compressTypeValue.length; 88 mergedArray.set(holdTimestampValue, offset) 89 offset += holdTimestampValue.length; 90 mergedArray.set(functionNameValue, offset) 91 offset += functionNameValue.length; 92 mergedArray.set(clientCwdValue, offset) 93 offset += clientCwdValue.length; 94 mergedArray.set(reserve1Value, offset) 95 offset += reserve1Value.length; 96 mergedArray.set(reserve2Value, offset) 97 return mergedArray; 98 } 99 100 static serializeTransferPayload(transferPayload: TransferPayload): Uint8Array { 101 let indexValue = this.serializeU64(1, transferPayload.index); 102 let compressTypeValue = this.serializeU8(2, transferPayload.compressType); 103 let compressSizeValue = this.serializeU32(3, transferPayload.compressSize); 104 let uncompressSizeValue = this.serializeU32(4, transferPayload.uncompressSize); 105 let mergedArray = new Uint8Array(indexValue.length + compressTypeValue.length + compressSizeValue.length + uncompressSizeValue.length); 106 let offset = 0; 107 mergedArray.set(indexValue) 108 offset += indexValue.length; 109 mergedArray.set(compressTypeValue, offset) 110 offset += compressTypeValue.length; 111 mergedArray.set(compressSizeValue, offset) 112 offset += compressSizeValue.length; 113 mergedArray.set(uncompressSizeValue, offset) 114 return mergedArray; 115 } 116 117 static serializeToString(tag: number, value: string): Uint8Array { 118 let number = this.makeTagWireType(tag, WireType.LENGTH_DELIMETED); 119 let data = this.writeVarIntU32(number) 120 let dataLength = this.writeVarIntU32(value.length); 121 const encoder = new TextEncoder(); 122 const buffer = encoder.encode(value); 123 let stringValue = new Uint8Array(data.length + dataLength.length + buffer.length); 124 stringValue.set(data); 125 stringValue.set(dataLength, data.length); 126 stringValue.set(buffer, data.length + dataLength.length); 127 return stringValue; 128 } 129 130 static serializeU8(tag: number, value: number): Uint8Array { 131 return this.serializeU32(tag, value); 132 } 133 134 static serializeU32(tag: number, value: number): Uint8Array { 135 let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); 136 let writeVarInt = this.writeVarIntU32(value); 137 let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); 138 mergedArray.set(makeTagWireType); 139 mergedArray.set(writeVarInt, makeTagWireType.length); 140 return mergedArray; 141 } 142 143 static serializeU64(tag: number, value: number): Uint8Array { 144 let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); 145 let writeVarInt = this.writeVarIntU64(value); 146 let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); 147 mergedArray.set(makeTagWireType); 148 mergedArray.set(writeVarInt, makeTagWireType.length); 149 return mergedArray; 150 } 151 152 static writeTagWriteType(tag: number, wireType: number): Uint8Array { 153 let number = this.makeTagWireType(tag, wireType); 154 return this.writeVarIntU32(number); 155 } 156 157 static makeTagWireType(tag: number, wireType: number): number { 158 return (tag << 3) | wireType; 159 } 160 161 static writeVarIntU64(value: number): Uint8Array { 162 let buffer: number[] = [] 163 for (let index = 0; index < 10; index++) { 164 buffer[index] = value & 0b01111111; 165 value = value >> 7 166 if (value) { 167 buffer[index] = buffer[index] | 0b10000000; 168 } else { 169 break; 170 } 171 } 172 return new Uint8Array(buffer); 173 } 174 175 static writeVarIntU32(value: number): Uint8Array { 176 let buffer: number[] = [] 177 for (let index = 0; index < 5; index++) { 178 buffer[index] = value & 0b01111111; 179 value = value >> 7 180 if (value) { 181 buffer[index] = buffer[index] | 0b10000000; 182 } else { 183 break; 184 } 185 } 186 return new Uint8Array(buffer); 187 } 188 189 static parseHandshake(data: Uint8Array): SessionHandShake { 190 // banner 191 let bannerBuffer = data.buffer; 192 let bannerTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bannerBuffer)); 193 let bannerLengthBuf = bannerBuffer.slice(1); 194 let bannerSize = this.readVarIntU32(new DataView(bannerLengthBuf)); 195 let bannerDataBuffer = bannerLengthBuf.slice(1); 196 let banner = this.parseString(bannerDataBuffer, bannerSize); 197 198 // authType 199 let authBuffer = bannerDataBuffer.slice(bannerSize); 200 let authTypeTag = this.getTag(WireType.VARINT, new DataView(authBuffer)); 201 let authDataBuffer = authBuffer.slice(1); 202 let authTypeDataView = new DataView(authDataBuffer); 203 let authType = this.parseU8(authTypeDataView, 1); 204 205 // sessionId 206 let sessionIdBuffer = authDataBuffer.slice(1); 207 let sessionIdTag = this.getTag(WireType.VARINT, new DataView(sessionIdBuffer)); 208 let sessionDataBuffer = sessionIdBuffer.slice(1); 209 let sessionIdDataView = new DataView(sessionDataBuffer); 210 let sessionId = this.parseU32(sessionIdDataView, 3); 211 212 // connectKey 213 let connectKeyBuffer = sessionDataBuffer.slice(3); 214 let connectKeyTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(connectKeyBuffer)); 215 let connectLengthBuffer = connectKeyBuffer.slice(1); 216 let connectKeyDataView = new DataView(connectLengthBuffer); 217 let connectKeySize = this.readVarIntU32(connectKeyDataView); 218 let connectDataBuffer = connectLengthBuffer.slice(1); 219 let connectKey = this.parseString(connectDataBuffer, connectKeySize); 220 221 // buf 222 let bufBuffer = connectDataBuffer.slice(connectKeySize); 223 let bufTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bufBuffer)); 224 let lengthBuffer = bufBuffer.slice(1); 225 let bufDataView = new DataView(lengthBuffer); 226 let bufSize = this.readVarIntU32(bufDataView); 227 let dataBuffer = lengthBuffer.slice(1); 228 let buf = this.parseString(dataBuffer, bufSize); 229 return new SessionHandShake(banner, authType, sessionId, connectKey, buf); 230 } 231 232 static parseTransferConfig(data: ArrayBuffer): TransferConfig { 233 let uint8Array = new Uint8Array(data); 234 // channelId 235 let dataBuffer = uint8Array.buffer 236 let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); 237 let channelDataBuffer = dataBuffer.slice(1); 238 let channelDataView = new DataView(channelDataBuffer); 239 let fileSize = this.parseU64(channelDataView, 1); 240 console.log("parseTransferConfig fileSize,", fileSize) 241 return new TransferConfig(fileSize, 0, 0, "", "", 242 "", false, 0, false, 243 "", "", "", ""); 244 } 245 246 247 static parsePayloadProtect(data: ArrayBuffer): PayloadProtect { 248 let uint8Array = new Uint8Array(data); 249 250 // channelId 251 let dataBuffer = uint8Array.buffer 252 let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); 253 let channelDataBuffer = dataBuffer.slice(1); 254 let channelDataView = new DataView(channelDataBuffer); 255 let channelId = this.parseU32(channelDataView, 1); 256 257 // commandFlag 258 let commandTagBuffer = channelDataBuffer.slice(1); 259 let commandTag = this.getTag(WireType.VARINT, new DataView(commandTagBuffer)); 260 let commandDataBuffer = commandTagBuffer.slice(1); 261 let commandDataView = new DataView(commandDataBuffer); 262 let commandFlag = this.parseU32(commandDataView, 1); 263 264 // checkSum 265 let checkSumTagBuffer = commandDataBuffer.slice(1); 266 let checkSumTag = this.getTag(WireType.VARINT, new DataView(checkSumTagBuffer)); 267 let checkSumDataBuffer = checkSumTagBuffer.slice(1); 268 let checkSumDataView = new DataView(checkSumDataBuffer); 269 let checkSum = this.parseU8(checkSumDataView, 1); 270 271 // vCode 272 let vCodeTagBuffer = checkSumDataBuffer.slice(1); 273 let vCodeTag = this.getTag(WireType.VARINT, new DataView(vCodeTagBuffer)); 274 let vCodeDataBuffer = vCodeTagBuffer.slice(1); 275 let vCodeDataView = new DataView(vCodeDataBuffer); 276 let vCode = this.parseU8(vCodeDataView, 1); 277 278 return new PayloadProtect(channelId, commandFlag, checkSum, vCode); 279 } 280 281 static parseString(buffer: ArrayBuffer, size: number): string { 282 let arrayBuffer = buffer.slice(0, size); 283 let textDecoder = new TextDecoder(); 284 return textDecoder.decode(arrayBuffer); 285 } 286 287 static parseU8(dataView: DataView, size: number): number { 288 return this.parseU32(dataView, size) 289 } 290 291 static parseU32(dataView: DataView, size: number): number { 292 return this.readVarIntU32(dataView); 293 } 294 295 static parseU64(dataView: DataView, size: number): number { 296 return this.readVarIntU64(dataView); 297 } 298 299 static readVarIntU32(dataView: DataView): number { 300 let value: number = 0; 301 for (let index = 0; index < 5; index++) { 302 if (dataView.byteLength < index + 1) { 303 return -1; 304 } 305 let int8 = dataView.getUint8(index); 306 let readValue = int8 & 0b01111111 307 value |= readValue << 7 * index; 308 if (!(int8 & 0b10000000)) { 309 return value; 310 } 311 } 312 return -1; 313 } 314 315 static readVarIntU64(dataView: DataView): number { 316 let value: number = 0; 317 for (let index = 0; index < 10; index++) { 318 if (dataView.byteLength < index + 1) { 319 return -1; 320 } 321 let int8 = dataView.getUint8(index); 322 let readValue = int8 & 0b01111111 323 value |= readValue << 7 * index; 324 if (!(int8 & 0b10000000)) { 325 return value; 326 } 327 } 328 return -1; 329 } 330 331 static readTagWireType(tagKey: number) { 332 let wireNewType: WireType = (tagKey & 0b0111); 333 return tagKey >> 3 334 } 335 336 static getTag(wireType: WireType, dataView: DataView) { 337 let tagKey = this.readVarIntU32(dataView); 338 return this.readTagWireType(tagKey); 339 } 340}