unsafe class Decompressor
{
byte* _pSrc;
uint _srcLen;
byte* _pDst;
uint _dstLen;
uint _dstLenBeforeWriteNonVertexesData;
bool _toDoubleCoordValue;
double _factor_toDoubleCoordValue;
uint MerelyReadUInt32()
{
if (_srcLen < sizeof(uint))
throw new ArgumentException();
var result = *(uint*)_pSrc;
_pSrc += sizeof(uint);
_srcLen -= sizeof(uint);
return result;
}
ushort MerelyReadUInt16()
{
if (_srcLen < sizeof(ushort))
throw new ArgumentException();
var result = *(ushort*)_pSrc;
_pSrc += sizeof(ushort);
_srcLen -= sizeof(ushort);
return result;
}
void ReadRaw(uint numBytes)
{
if (_srcLen < numBytes || _dstLen < numBytes)
throw new ArgumentException();
Buffer.MemoryCopy(_pSrc, _pDst, _dstLen, numBytes);
_pSrc += numBytes;
_srcLen -= numBytes;
_pDst += numBytes;
_dstLen -= numBytes;
}
void ReadNonVertexesData()
{
var numBytes = MerelyReadUInt32();
ReadRaw(numBytes);
}
void ReadVertexesData()
{
//读取几何头的位置
var offset_GeomHead = MerelyReadUInt16();
if (offset_GeomHead != 0)
{
if (_dstLen + offset_GeomHead > _dstLenBeforeWriteNonVertexesData || offset_GeomHead < 8)
throw new ArgumentException();
var pCoordDim = (int*)(_pDst + (4 - offset_GeomHead));
if (*pCoordDim != 0x80)
throw new ArgumentException();
if (_toDoubleCoordValue)//更改坐标维度(消除“单精度”标志)
*pCoordDim = 0;
}
//读取首顶点
if (_srcLen < sizeof(int) * 2)
throw new ArgumentException();
var vLast = *(Vertex2I*)_pSrc;
_pSrc += sizeof(int) * 2;
_srcLen -= sizeof(int) * 2;
if (_toDoubleCoordValue)
{
if (_dstLen < sizeof(double) * 2)
throw new ArgumentException();
var pDst = (Vertex2d*)_pDst;
pDst->x = _factor_toDoubleCoordValue * vLast.x;
pDst->y = _factor_toDoubleCoordValue * vLast.y;
_pDst += sizeof(double) * 2;
_dstLen -= sizeof(double) * 2;
}
else
{
if (_dstLen < sizeof(int) * 2)
throw new ArgumentException();
*(Vertex2I*)_pDst = vLast;
_pDst += sizeof(int) * 2;
_dstLen -= sizeof(int) * 2;
}
var numVeretxes = MerelyReadUInt32();
if (numVeretxes == 0)
throw new ArgumentException();
uint numVertexesRead = 1;
while (numVertexesRead < numVeretxes)
{
var cnt = MerelyReadUInt16();
var cnt0 = (uint)(cnt & 0x7FFF);
long cnt1 = numVertexesRead;
cnt1 += cnt0;
if (cnt1 == numVertexesRead || cnt1 > numVeretxes)
throw new ArgumentException();
if ((cnt & 0x8000) != 0)
{//
if (_toDoubleCoordValue)
{
var srcLenChange = (uint)sizeof(int) * 2 * cnt0;
var dstLenChange = (uint)sizeof(double) * 2 * cnt0;
if (_srcLen < srcLenChange || _dstLen < dstLenChange)
throw new ArgumentException();
for (uint i = 0; i < cnt0; ++i)
{
((double*)_pDst)[i * 2] = _factor_toDoubleCoordValue * ((int*)_pSrc)[i * 2];
((double*)_pDst)[i * 2 + 1] = _factor_toDoubleCoordValue * ((int*)_pSrc)[i * 2 + 1];
}
_pSrc += srcLenChange;
_srcLen -= srcLenChange;
_pDst += dstLenChange;
_dstLen -= dstLenChange;
}
else
{
ReadRaw(cnt0 * sizeof(int) * 2);
}
vLast = ((Vertex2I*)_pSrc)[-1];
}
else
{
var srcLenChange = (uint)sizeof(short) * 2 * cnt0;
var dstLenChange = (uint)(_toDoubleCoordValue ? sizeof(double) : sizeof(int)) * 2 * cnt0;
if (_srcLen < srcLenChange || _dstLen < dstLenChange)
throw new ArgumentException();
if (_toDoubleCoordValue)
{
for (uint i = 0; i < cnt0; ++i)
{
((double*)_pDst)[i * 2] = _factor_toDoubleCoordValue * (vLast.x += ((short*)_pSrc)[i * 2]);
((double*)_pDst)[i * 2 + 1] = _factor_toDoubleCoordValue * (vLast.y += ((short*)_pSrc)[i * 2 + 1]);
}
}
else
{
for (uint i = 0; i < cnt0; ++i)
{
((int*)_pDst)[i * 2] = vLast.x += ((short*)_pSrc)[i * 2];
((int*)_pDst)[i * 2 + 1] = vLast.y += ((short*)_pSrc)[i * 2 + 1];
}
}
_pSrc += srcLenChange;
_srcLen -= srcLenChange;
_pDst += dstLenChange;
_dstLen -= dstLenChange;
}
numVertexesRead = (uint)cnt1;
}
}
public byte[] Result { get; }
internal Decompressor(byte[] compressedData, uint offset, uint length, double? factor_toDoubleCoordValue)
{
_srcLen = (uint)compressedData.Length;
if (_srcLen < offset)
throw new ArgumentException();
_srcLen -= offset;
if (_srcLen < length)
throw new ArgumentException();
_srcLen = length;
fixed (byte* pSrc0 = &compressedData[offset]) //fixed禁止垃圾回收器重定位可移动的变量。fixed语句只能出现在不安全的上下文中。
{
_pSrc = pSrc0; //
//读取顶点数量
if (_srcLen < sizeof(uint))
throw new ArgumentException();
var cntVertexes = *(uint*)(_pSrc + (_srcLen - sizeof(uint)));
_srcLen -= sizeof(uint);
//准备结果缓冲区
_dstLen = MerelyReadUInt32();
var numNonVertexDataBytes = _dstLen - (long)cntVertexes * sizeof(int) * 2;
if (numNonVertexDataBytes <= 0)
throw new ArgumentException();
if (_toDoubleCoordValue = factor_toDoubleCoordValue.HasValue)
_factor_toDoubleCoordValue = factor_toDoubleCoordValue.Value;
Result = new byte[numNonVertexDataBytes + cntVertexes * (_toDoubleCoordValue ? sizeof(double) : sizeof(int)) * 2];
_dstLen = (uint)Result.Length;
fixed (byte* pDst0 = &Result[0])
{
_pDst = pDst0;
//
while (_srcLen != 0 || _dstLen != 0)
{
_dstLenBeforeWriteNonVertexesData = _dstLen;
ReadNonVertexesData();
ReadVertexesData();
}
}
}
}
}
能否更新成js书写
该回答引用ChatGPT
class Decompressor {
constructor(compressedData, offset, length, factor_toDoubleCoordValue) {
var buffer = new ArrayBuffer(compressedData.length);
var uint8Array = new Uint8Array(buffer);
for (var i = 0; i < compressedData.length; i++) {
uint8Array[i] = compressedData[i];
}
var pSrc0 = uint8Array.slice(offset);
this.result = new ArrayBuffer(0);
this.pDst = new Uint8Array(this.result);
this.pSrc = new Uint8Array(pSrc0);
this._srcLen = compressedData.length - offset;
this._srcLen -= offset;
if (this._srcLen < length) {
throw new Error("decoded data too large");
}
this._srcLen = length;
this._dstLen = this.merelyReadUInt32();
var cntVertexes = this.merelyReadUInt32();
var numNonVertexDataBytes = this._dstLen - cntVertexes * 2 * 4;
if (numNonVertexDataBytes <= 0) {
throw new Error("decoded data has invalid format");
}
if (factor_toDoubleCoordValue !== undefined) {
this._toDoubleCoordValue = true;
this._factor_toDoubleCoordValue = factor_toDoubleCoordValue;
}
this.result = new ArrayBuffer(numNonVertexDataBytes + cntVertexes * (this._toDoubleCoordValue ? 2 * 8 : 2 * 4));
this.pDst = new Uint8Array(this.result);
this._dstLen = this.result.byteLength;
var numVertexesRead = 1;
while (this._srcLen != 0 || this._dstLen != 0) {
var dstLenBeforeWriteNonVertexesData = this._dstLen;
this.readNonVertexesData();
this.readVertexesData(numVertexesRead);
numVertexesRead = this.merelyReadUInt32();
if (numVertexesRead == 0) {
break;
}
}
}
readDouble(pVal) {
if (this._srcLen < 8) {
throw new Error("data underflow");
}
this._srcLen -= 8;
pVal[0] = new Float64Array(this.pSrc.slice(0, 8).buffer)[0];
for (var i = 0; i < 8; i++) {
this.pSrc = this.pSrc.slice(1);
}
}
readInt(pVal) {
if (this._srcLen < 4) {
throw new Error("data underflow");
}
this._srcLen -= 4;
pVal[0] = new Int32Array(this.pSrc.slice(0, 4).buffer)[0];
for (var i = 0; i < 4; i++) {
this.pSrc = this.pSrc.slice(1);
}
}
merelyReadUInt32() {
if (this._srcLen < 4) {
throw new Error("data underflow");
}
this._srcLen -= 4;
var uint32Array = new Uint32Array(this.pSrc.slice(0, 4).buffer);
var result = uint32Array[0];
for (var i = 0; i < 4; i++) {
this.pSrc = this.pSrc.slice(1);
}
return result;
}
merelyReadUInt16() {
if (this._srcLen < 2) {
throw new Error("data underflow");
}
this._srcLen -= 2;
var uint16Array = new Uint16Array
js你要看什么环境,如果是浏览器配合客户端,或者手机app小程序,那么应该不行。
如果是nodejs这种服务器的或者 Electronjs,还差不多
class Decompressor {
constructor(compressedData, offset, length, factor_toDoubleCoordValue) {
this.compressedData = compressedData;
this.srcLen = compressedData.length - offset < length ? compressedData.length - offset : length;
this.pSrc = new Uint8Array(compressedData.buffer, offset + compressedData.byteOffset, this.srcLen);
this.dstLen = 0;
this.pDst = null;
this.dstLenBeforeWriteNonVertexesData = 0;
this.toDoubleCoordValue = false;
this.factor_toDoubleCoordValue = NaN;
this.result = null;
// Start decompression
let cntVertexes = this.merelyReadUInt32();
this.dstLen = this.merelyReadUInt32();
let numNonVertexDataBytes = this.dstLen - cntVertexes * 2 * 4;
if (numNonVertexDataBytes <= 0)
throw new Error("Invalid compressed data");
if (factor_toDoubleCoordValue) {
this.toDoubleCoordValue = true;
this.factor_toDoubleCoordValue = factor_toDoubleCoordValue;
}
this.result = new Uint8Array(numNonVertexDataBytes + cntVertexes * (this.toDoubleCoordValue ? 2 * 8 : 2 * 4));
this.pDst = new DataView(this.result.buffer);
while (this.srcLen > 0 || this.dstLen > 0) {
this.dstLenBeforeWriteNonVertexesData = this.dstLen;
this.readNonVertexesData();
this.readVertexesData();
}
}
merelyReadUInt32() {
if (this.srcLen < 4)
throw new Error("Invalid compressed data");
let result = this.pSrc[0] | (this.pSrc[1] << 8) | (this.pSrc[2] << 16) | (this.pSrc[3] << 24);
this.pSrc = this.pSrc.subarray(4);
this.srcLen -= 4;
return result >>> 0;
}
merelyReadUInt16() {
if (this.srcLen < 2)
throw new Error("Invalid compressed data");
let result = this.pSrc[0] | (this.pSrc[1] << 8);
this.pSrc = this.pSrc.subarray(2);
this.srcLen -= 2;
return result >>> 0;
}
readRaw(numBytes) {
if (this.srcLen < numBytes || this.dstLen < numBytes)
throw new Error("Invalid compressed data");
for (let i = 0; i < numBytes; i++) {
this.pDst.setUint8(this.dstLen - numBytes + i, this.pSrc[i]);
}
this.pSrc = this.pSrc.subarray(numBytes);
this.srcLen -= numBytes;
this.dstLen -= numBytes;
}
readNonVertexesData() {
let numBytes = this.merelyReadUInt32();
this.readRaw(numBytes);
}
readVertexesData() {
let offset_GeomHead = this.merelyReadUInt16();
if (offset_GeomHead != 0) {
if (this.dstLen + offset_GeomHead > this.dstLenBeforeWriteNonVertexesData || offset_GeomHead < 8)
throw new Error("Invalid compressed data");
let pCoordDim = new Int32Array(this.result.buffer, this.result.byteLength - this.dstLenBeforeWriteNonVertexesData + 4 - offset_GeomHead, 1);
if (pCoordDim[0] != 0x80)
throw new Error("Invalid compressed data");
if (this.toDoubleCoordValue) // Change coordinate dimensions (remove the "single-precision" flag)
pCoordDim[0] = 0;
}
let vLast = { x: 0, y: 0 };
vLast.x = this.merelyReadUInt32();
vLast.y = this.merelyReadUInt32();
if (this.toDoubleCoordValue) {
if (this.dstLen < 2 * 8)
throw new Error("Invalid compressed data");
this.pDst.setFloat64(this.result.byteLength - this.dstLen, this.factor_toDoubleCoordValue * vLast.x, true);
this.pDst.setFloat64(this.result.byteLength - this.dstLen + 8, this.factor_toDoubleCoordValue * vLast.y, true);
this.dstLen -= 2 * 8;
} else {
if
引用chatGPT作答,以下是转换成js的代码:
class Decompressor {
constructor(pSrc, srcLen, pDst, dstLen, dstLenBeforeWriteNonVertexesData, toDoubleCoordValue, factor_toDoubleCoordValue) {
this._pSrc = pSrc;
this._srcLen = srcLen;
this._pDst = pDst;
this._dstLen = dstLen;
this._dstLenBeforeWriteNonVertexesData = dstLenBeforeWriteNonVertexesData;
this._toDoubleCoordValue = toDoubleCoordValue;
this._factor_toDoubleCoordValue = factor_toDoubleCoordValue;
}
MerelyReadUInt32() {
if (this._srcLen < 4) {
throw new Error('ArgumentException');
}
const result = new DataView(this._pSrc).getUint32(0, true);
this._pSrc += 4;
this._srcLen -= 4;
return result;
}
MerelyReadUInt16() {
if (this._srcLen < 2) {
throw new Error('ArgumentException');
}
const result = new DataView(this._pSrc).getUint16(0, true);
this._pSrc += 2;
this._srcLen -= 2;
return result;
}
ReadRaw(numBytes) {
if (this._srcLen < numBytes || this._dstLen < numBytes) {
throw new Error('ArgumentException');
}
const srcView = new DataView(this._pSrc);
const dstView = new DataView(this._pDst.buffer);
for (let i = 0; i < numBytes; i++) {
dstView.setUint8(i, srcView.getUint8(i));
}
this._pSrc += numBytes;
this._srcLen -= numBytes;
this._pDst += numBytes;
this._dstLen -= numBytes;
}
ReadNonVertexesData() {
const numBytes = this.MerelyReadUInt32();
this.ReadRaw(numBytes);
}
ReadVertexesData() {
const offset_GeomHead = this.MerelyReadUInt16();
if (offset_GeomHead !== 0) {
if (this._dstLen + offset_GeomHead > this._dstLenBeforeWriteNonVertexesData || offset_GeomHead < 8) {
throw new Error('ArgumentException');
}
const pCoordDim = new Int32Array(this._pDst.buffer, (4 - offset_GeomHead));
if (pCoordDim[0] !== 0x80) {
throw new Error('ArgumentException');
}
if (this._toDoubleCoordValue) {
pCoordDim[0] = 0;
}
}
if (this._srcLen < 8) {
throw new Error('ArgumentException');
}
const vLast = new Int32Array(this._pSrc.buffer, 0, 2);
this._pSrc += 8;
this._srcLen -= 8;
if (this._toDoubleCoordValue) {
if (this._dstLen < 16) {
throw new Error('ArgumentException');
}
const pDst = new Float64Array(this._pDst.buffer);
pDst[0] = this._factor_toDoubleCoordValue * vLast[0];
pDst[1] = this._factor_toDoubleCoordValue * vLast[1];
this._pDst += 16;
this._dstLen -= 16;
} else {
}
else
{
// 将顶点坐标写入输出缓冲区
for (int i = 0; i < cnt0; ++i)
{
((Vertex2I*)_pDst)[i] = vLast;
vLast.x += ((short*)_pSrc)[i * 2];
vLast.y += ((short*)_pSrc)[i * 2 + 1];
}
_pSrc += srcLenChange;
_srcLen -= srcLenChange;
_pDst += dstLenChange;
_dstLen -= dstLenChange;
}
}
numVertexesRead = cnt1;
}
}
public byte[] Decompress(byte[] src, uint dstLen, bool toDoubleCoordValue, double factor_toDoubleCoordValue)
{
if (src == null)
throw new ArgumentNullException();
if (dstLen < src.Length)
throw new ArgumentException();
unsafe
{
fixed (byte* pSrc = &src[0])
{
_pSrc = pSrc;
_srcLen = (uint)src.Length;
_toDoubleCoordValue = toDoubleCoordValue;
_factor_toDoubleCoordValue = factor_toDoubleCoordValue;
_dstLenBeforeWriteNonVertexesData = 0;
// 获取压缩数据中非顶点数据的长度,并跳过
ReadNonVertexesData();
// 获取输出缓冲区的首地址,并跳过写入非顶点数据的部分
fixed (byte* pDst = new byte[dstLen])
{
_pDst = pDst;
_dstLen = dstLen;
_dstLenBeforeWriteNonVertexesData = _dstLen;
ReadVertexesData();
return new Span<byte>(pDst, (int)(_pDst - pDst)).ToArray();
}
}
}
}
}
}
//读取拓扑结构
ReadRaw(numTopoBytes);
}
public void Decompress(byte[] src, byte[] dst, uint dstLenBeforeWriteNonVertexesData, bool toDoubleCoordValue, double factor_toDoubleCoordValue)
{
if (src == null || dst == null)
throw new ArgumentNullException();
if (dstLenBeforeWriteNonVertexesData > (uint)dst.Length)
throw new ArgumentException();
_pSrc = (byte*)src;
_srcLen = (uint)src.Length;
_pDst = (byte*)dst;
_dstLen = (uint)dst.Length;
_dstLenBeforeWriteNonVertexesData = dstLenBeforeWriteNonVertexesData;
_toDoubleCoordValue = toDoubleCoordValue;
_factor_toDoubleCoordValue = factor_toDoubleCoordValue;
//读取并跳过“TBR”字节(TrueBendRelaxer压缩器的标识)
ReadRaw(3);
//读取并跳过最初的四字节
ReadRaw(4);
//读取顶点和非顶点数据
ReadVertexesData();
ReadNonVertexesData();
}
}
该回答引用ChatGPTjs
class Vertex2I {
constructor() {
this.x = 0;
this.y = 0;
}
}
class Vertex2d {
constructor() {
this.x = 0.0;
this.y = 0.0;
}
}
class Decompressor {
constructor(compressedData, offset, length, factor_toDoubleCoordValue) {
this._srcLen = compressedData.length;
if (this._srcLen < offset) throw new Error('ArgumentOutOfRangeException');
this._srcLen -= offset;
if (this._srcLen < length) throw new Error('ArgumentOutOfRangeException');
this._srcLen = length;
this._pSrc = new Uint8Array(compressedData.buffer, compressedData.byteOffset + offset, length);
this._dstLen = this.MerelyReadUInt32();
const numVertexes = this.CountVertexes();
const numNonVertexDataBytes = this._dstLen - numVertexes * 8;
this._toDoubleCoordValue = false;
if (factor_toDoubleCoordValue) {
this._toDoubleCoordValue = true;
this._factor_toDoubleCoordValue = factor_toDoubleCoordValue;
}
this.result = new ArrayBuffer(numNonVertexDataBytes + numVertexes * (this._toDoubleCoordValue ? 16 : 8));
this.view = new DataView(this.result);
this._dstLen = this.result.byteLength;
this._dstPos = 0;
while (this._srcLen > 0 || this._dstLen > 0) {
this._dstLenBeforeWriteNonVertexesData = this._dstLen;
this.ReadNonVertexesData();
this.ReadVertexesData();
}
}
MerelyReadUInt16() {
if (this._srcLen < 2) throw new Error('ArgumentOutOfRangeException');
const result = this._view.getUint16(this._srcPos, true);
this._srcPos += 2;
this._srcLen -= 2;
return result;
}
MerelyReadUInt32() {
if (this._srcLen < 4) throw new Error('ArgumentOutOfRangeException');
const result = this._view.getUint32(this._srcLen - 4, true);
this._srcLen -= 4;
return result;
}
CountVertexes() {
if (this._srcLen < 4) throw new Error('ArgumentOutOfRangeException');
return this._view.getUint32(this._srcLen - 4, true);
}
ReadRaw(numBytes) {
if (this._srcLen < numBytes || this._dstLen < numBytes) throw new Error('ArgumentOutOfRangeException');
const srcArray = new Uint8Array(this._src.buffer, this._src.byteOffset + this._srcPos, numBytes);
const dstArray = new Uint8Array(this.result, this._dstPos, numBytes);
dstArray.set(srcArray);
this._srcPos += numBytes;
this._srcLen -= numBytes;
this._dstPos += numBytes;
this._dstLen -= numBytes;
}
ReadNonVertexesData() {
const numBytes = this.MerelyReadUInt32();
this.ReadRaw(numBytes);
}
以下内容部分参考ChatGPT模型:
由于涉及到指针、内存操作等不安全操作,在JavaScript中无法进行直接的转换。建议使用其他能够支持这些操作的语言进行转换。
如果我的建议对您有帮助、请点击采纳、祝您生活愉快