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'; 17import { SessionHandShake } from '../message/SessionHandShake'; 18import { PayloadProtect } from '../message/PayloadProtect'; 19import { TransferConfig } from '../message/TransferConfig'; 20import { TransferPayload } from '../message/TransferPayload'; 21import { log } from '../../log/Log'; 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 version = this.serializeToString(6, handShake.version); 33 let mergedArray = new Uint8Array( 34 bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length + buf.length + version.length 35 ); 36 mergedArray.set(bannerValue); 37 mergedArray.set(authTypeValue, bannerValue.length); 38 mergedArray.set(sessionIdValue, bannerValue.length + authTypeValue.length); 39 mergedArray.set(connectKey, bannerValue.length + authTypeValue.length + sessionIdValue.length); 40 mergedArray.set(buf, bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length); 41 mergedArray.set(version, bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length + buf.length); 42 return mergedArray; 43 } 44 45 static serializePayloadProtect(payloadProtect: PayloadProtect): Uint8Array { 46 let channelId = this.serializeU32(1, payloadProtect.channelId); 47 let commandFlag = this.serializeU32(2, payloadProtect.commandFlag); 48 let checkSum = this.serializeU8(3, payloadProtect.checkSum); 49 let vCode = this.serializeU8(4, payloadProtect.vCode); 50 let mergedArray = new Uint8Array(channelId.length + commandFlag.length + checkSum.length + vCode.length); 51 mergedArray.set(channelId); 52 mergedArray.set(commandFlag, channelId.length); 53 mergedArray.set(checkSum, channelId.length + commandFlag.length); 54 mergedArray.set(vCode, channelId.length + commandFlag.length + checkSum.length); 55 return mergedArray; 56 } 57 58 static serializeTransferConfig(transferConfig: TransferConfig): Uint8Array { 59 let fileSizeValue = this.serializeU64(1, transferConfig.fileSize); 60 let atimeValue = this.serializeU64(2, transferConfig.atime); 61 let mtimeValue = this.serializeU64(3, transferConfig.mtime); 62 let optionsValue = this.serializeToString(4, transferConfig.options); 63 let pathValue = this.serializeToString(5, transferConfig.path); 64 let optionalNameValue = this.serializeToString(6, transferConfig.optionalName); 65 let updateIfNewValue = this.serializeU32(7, transferConfig.updateIfNew ? 1 : 0); 66 let compressTypeValue = this.serializeU8(8, transferConfig.compressType); 67 let holdTimestampValue = this.serializeU32(9, transferConfig.holdTimestamp ? 1 : 0); 68 let functionNameValue = this.serializeToString(10, transferConfig.functionName); 69 let clientCwdValue = this.serializeToString(11, transferConfig.clientCwd); 70 let reserve1Value = this.serializeToString(12, transferConfig.reserve1); 71 let reserve2Value = this.serializeToString(13, transferConfig.reserve2); 72 let mergedArray = new Uint8Array( 73 fileSizeValue.length + 74 atimeValue.length + 75 mtimeValue.length + 76 optionsValue.length + 77 pathValue.length + 78 optionalNameValue.length + 79 updateIfNewValue.length + 80 compressTypeValue.length + 81 holdTimestampValue.length + 82 functionNameValue.length + 83 clientCwdValue.length + 84 reserve1Value.length + 85 reserve2Value.length 86 ); 87 let offset = 0; 88 mergedArray.set(fileSizeValue); 89 offset += fileSizeValue.length; 90 mergedArray.set(atimeValue, offset); 91 offset += atimeValue.length; 92 mergedArray.set(mtimeValue, offset); 93 offset += mtimeValue.length; 94 mergedArray.set(optionsValue, offset); 95 offset += optionsValue.length; 96 mergedArray.set(pathValue, offset); 97 offset += pathValue.length; 98 mergedArray.set(optionalNameValue, offset); 99 offset += optionalNameValue.length; 100 mergedArray.set(updateIfNewValue, offset); 101 offset += updateIfNewValue.length; 102 mergedArray.set(compressTypeValue, offset); 103 offset += compressTypeValue.length; 104 mergedArray.set(holdTimestampValue, offset); 105 offset += holdTimestampValue.length; 106 mergedArray.set(functionNameValue, offset); 107 offset += functionNameValue.length; 108 mergedArray.set(clientCwdValue, offset); 109 offset += clientCwdValue.length; 110 mergedArray.set(reserve1Value, offset); 111 offset += reserve1Value.length; 112 mergedArray.set(reserve2Value, offset); 113 return mergedArray; 114 } 115 116 static serializeTransferPayload(transferPayload: TransferPayload): Uint8Array { 117 let indexValue = this.serializeU64(1, transferPayload.index); 118 let compressTypeValue = this.serializeU8(2, transferPayload.compressType); 119 let compressSizeValue = this.serializeU32(3, transferPayload.compressSize); 120 let uncompressSizeValue = this.serializeU32(4, transferPayload.uncompressSize); 121 let mergedArray = new Uint8Array( 122 indexValue.length + compressTypeValue.length + compressSizeValue.length + uncompressSizeValue.length 123 ); 124 let offset = 0; 125 mergedArray.set(indexValue); 126 offset += indexValue.length; 127 mergedArray.set(compressTypeValue, offset); 128 offset += compressTypeValue.length; 129 mergedArray.set(compressSizeValue, offset); 130 offset += compressSizeValue.length; 131 mergedArray.set(uncompressSizeValue, offset); 132 return mergedArray; 133 } 134 135 static serializeToString(tag: number, value: string): Uint8Array { 136 let number = this.makeTagWireType(tag, WireType.LENGTH_DELIMETED); 137 let data = this.writeVarIntU32(number); 138 let dataLength = this.writeVarIntU32(value.length); 139 const encoder = new TextEncoder(); 140 const buffer = encoder.encode(value); 141 let stringValue = new Uint8Array(data.length + dataLength.length + buffer.length); 142 stringValue.set(data); 143 stringValue.set(dataLength, data.length); 144 stringValue.set(buffer, data.length + dataLength.length); 145 return stringValue; 146 } 147 148 static serializeU8(tag: number, value: number): Uint8Array { 149 return this.serializeU32(tag, value); 150 } 151 152 static serializeU32(tag: number, value: number): Uint8Array { 153 let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); 154 let writeVarInt = this.writeVarIntU32(value); 155 let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); 156 mergedArray.set(makeTagWireType); 157 mergedArray.set(writeVarInt, makeTagWireType.length); 158 return mergedArray; 159 } 160 161 static serializeU64(tag: number, value: number): Uint8Array { 162 let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); 163 let writeVarInt = this.writeVarIntU64(value); 164 let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); 165 mergedArray.set(makeTagWireType); 166 mergedArray.set(writeVarInt, makeTagWireType.length); 167 return mergedArray; 168 } 169 170 static writeTagWriteType(tag: number, wireType: number): Uint8Array { 171 let number = this.makeTagWireType(tag, wireType); 172 return this.writeVarIntU32(number); 173 } 174 175 static makeTagWireType(tag: number, wireType: number): number { 176 return (tag << 3) | wireType; 177 } 178 179 static writeVarIntU64(u64value: number): Uint8Array { 180 let uint64buffer: number[] = []; 181 for (let index = 0; index < 10; index++) { 182 uint64buffer[index] = u64value & 0b01111111; 183 u64value = u64value >> 7; 184 if (u64value) { 185 uint64buffer[index] = uint64buffer[index] | 0b10000000; 186 } else { 187 break; 188 } 189 } 190 return new Uint8Array(uint64buffer); 191 } 192 193 static writeVarIntU32(u32value: number): Uint8Array { 194 let u32buffer: number[] = []; 195 for (let index = 0; index < 5; index++) { 196 u32buffer[index] = u32value & 0b01111111; 197 u32value = u32value >> 7; 198 if (u32value) { 199 u32buffer[index] = u32buffer[index] | 0b10000000; 200 } else { 201 break; 202 } 203 } 204 return new Uint8Array(u32buffer); 205 } 206 207 static parseHandshake(data: Uint8Array): SessionHandShake { 208 // banner 209 let bannerBuffer = data.buffer; 210 let bannerTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bannerBuffer)); 211 let bannerLengthBuf = bannerBuffer.slice(this.writeVarIntU32(this.makeTagWireType(bannerTag, WireType.LENGTH_DELIMETED)).length); 212 let bannerSize = this.readVarIntU32(new DataView(bannerLengthBuf)); 213 let bannerDataBuffer = bannerLengthBuf.slice(this.writeVarIntU32(bannerSize).length); 214 // @ts-ignore 215 let banner = this.parseString(bannerDataBuffer, bannerSize); 216 217 // authType 218 let authBuffer = bannerDataBuffer.slice(bannerSize); 219 let authTypeTag = this.getTag(WireType.VARINT, new DataView(authBuffer)); 220 let authDataBuffer = authBuffer.slice(this.writeVarIntU32(this.makeTagWireType(authTypeTag, WireType.VARINT)).length); 221 let authType = this.parseU8(new DataView(authDataBuffer), 1); 222 let authTypeLenth = this.writeVarIntU32(authType).length; 223 224 // sessionId 225 let sessionIdBuffer = authDataBuffer.slice(authTypeLenth); 226 let sessionIdTag = this.getTag(WireType.VARINT, new DataView(sessionIdBuffer)); 227 let sessionDataBuffer = sessionIdBuffer.slice(this.writeVarIntU32(this.makeTagWireType(sessionIdTag, WireType.VARINT)).length); 228 let sessionId = this.parseU32(new DataView(sessionDataBuffer), 3); 229 let sessionIdLenth = this.writeVarIntU32(sessionId).length; 230 231 // connectKey 232 let connectKeyBuffer = sessionDataBuffer.slice(sessionIdLenth); 233 let connectKeyTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(connectKeyBuffer)); 234 let connectLengthBuffer = connectKeyBuffer.slice(this.writeVarIntU32(this.makeTagWireType(connectKeyTag, WireType.LENGTH_DELIMETED)).length); 235 let connectKeySize = this.readVarIntU32(new DataView(connectLengthBuffer)); 236 let connectDataBuffer = connectLengthBuffer.slice(this.writeVarIntU32(connectKeySize).length); 237 // @ts-ignore 238 let connectKey = this.parseString(connectDataBuffer, connectKeySize); 239 240 // buf 241 let bufBuffer = connectDataBuffer.slice(connectKeySize); 242 let bufTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bufBuffer)); 243 let lengthBuffer = bufBuffer.slice(this.writeVarIntU32(this.makeTagWireType(bufTag, WireType.LENGTH_DELIMETED)).length); 244 let bufSize = this.readVarIntU32(new DataView(lengthBuffer)); 245 let dataBuffer = lengthBuffer.slice(this.writeVarIntU32(bufSize).length); 246 // @ts-ignore 247 let buf = this.parseString(dataBuffer, bufSize); 248 249 // version 250 let versionBuffer = dataBuffer.slice(bufSize); 251 let versionTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(versionBuffer)); 252 let versionLengthBuffer = versionBuffer.slice(this.writeVarIntU32(this.makeTagWireType(versionTag, WireType.LENGTH_DELIMETED)).length); 253 let versionSize = this.readVarIntU32(new DataView(versionLengthBuffer)); 254 let versionDataBuffer = versionLengthBuffer.slice(this.writeVarIntU32(versionSize).length); 255 // @ts-ignore 256 let version = this.parseString(versionDataBuffer, versionSize); 257 return new SessionHandShake(banner, authType, sessionId, connectKey, buf, version); 258 } 259 260 static parseTransferConfig(data: ArrayBuffer): TransferConfig { 261 let uint8Array = new Uint8Array(data); 262 // channelId 263 let dataBuffer = uint8Array.buffer; 264 let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); 265 let channelDataBuffer = dataBuffer.slice(1); 266 let channelDataView = new DataView(channelDataBuffer); 267 let fileSize = this.parseU64(channelDataView, 1); 268 return new TransferConfig(fileSize, 0, 0, '', '', '', false, 0, false, '', '', '', ''); 269 } 270 271 static parsePayloadProtect(data: ArrayBuffer): PayloadProtect { 272 let uint8Array = new Uint8Array(data); 273 274 // channelId 275 let dataBuffer = uint8Array.buffer; 276 let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); 277 let channelDataBuffer = dataBuffer.slice(1); 278 let channelDataView = new DataView(channelDataBuffer); 279 let channelId = this.parseU32(channelDataView, 1); 280 281 // commandFlag 282 let commandTagBuffer = channelDataBuffer.slice(1); 283 let commandTag = this.getTag(WireType.VARINT, new DataView(commandTagBuffer)); 284 let commandDataBuffer = commandTagBuffer.slice(1); 285 let commandDataView = new DataView(commandDataBuffer); 286 let commandFlag = this.parseU32(commandDataView, 1); 287 288 // checkSum 289 let checkSumTagBuffer = commandDataBuffer.slice(1); 290 let checkSumTag = this.getTag(WireType.VARINT, new DataView(checkSumTagBuffer)); 291 let checkSumDataBuffer = checkSumTagBuffer.slice(1); 292 let checkSumDataView = new DataView(checkSumDataBuffer); 293 let checkSum = this.parseU8(checkSumDataView, 1); 294 295 // vCode 296 let vCodeTagBuffer = checkSumDataBuffer.slice(1); 297 let vCodeTag = this.getTag(WireType.VARINT, new DataView(vCodeTagBuffer)); 298 let vCodeDataBuffer = vCodeTagBuffer.slice(1); 299 let vCodeDataView = new DataView(vCodeDataBuffer); 300 let vCode = this.parseU8(vCodeDataView, 1); 301 302 return new PayloadProtect(channelId, commandFlag, checkSum, vCode); 303 } 304 305 static parseString(buffer: ArrayBuffer, size: number): string { 306 let arrayBuffer = buffer.slice(0, size); 307 let textDecoder = new TextDecoder(); 308 return textDecoder.decode(arrayBuffer); 309 } 310 311 static parseU8(dataView: DataView, size: number): number { 312 return this.parseU32(dataView, size); 313 } 314 315 static parseU32(dataView: DataView, size: number): number { 316 return this.readVarIntU32(dataView); 317 } 318 319 static parseU64(dataView: DataView, size: number): number { 320 return this.readVarIntU64(dataView); 321 } 322 323 static readVarIntU32(dataView: DataView): number { 324 let u32IntValue: number = 0; 325 for (let u32IntIndex = 0; u32IntIndex < 5; u32IntIndex++) { 326 if (dataView.byteLength < u32IntIndex + 1) { 327 return -1; 328 } 329 let int8 = dataView.getUint8(u32IntIndex); 330 let readValue = int8 & 0b01111111; 331 u32IntValue |= readValue << (7 * u32IntIndex); 332 if (!(int8 & 0b10000000)) { 333 return u32IntValue; 334 } 335 } 336 return -1; 337 } 338 339 static readVarIntU64(dataView: DataView): number { 340 let u62IntValue: number = 0; 341 for (let u62IntIndex = 0; u62IntIndex < 10; u62IntIndex++) { 342 if (dataView.byteLength < u62IntIndex + 1) { 343 return -1; 344 } 345 let int8 = dataView.getUint8(u62IntIndex); 346 let readValue = int8 & 0b01111111; 347 u62IntValue |= readValue << (7 * u62IntIndex); 348 if (!(int8 & 0b10000000)) { 349 return u62IntValue; 350 } 351 } 352 return -1; 353 } 354 355 static readTagWireType(tagKey: number): number { 356 let wireNewType: WireType = tagKey & 0b0111; 357 return tagKey >> 3; 358 } 359 360 static getTag(wireType: WireType, dataView: DataView): number { 361 let tagKey = this.readVarIntU32(dataView); 362 return this.readTagWireType(tagKey); 363 } 364} 365