You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
4.3 KiB
202 lines
4.3 KiB
1 month ago
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
namespace Sproto
|
||
|
{
|
||
|
public class SprotoPack
|
||
|
{
|
||
|
private MemoryStream buffer;
|
||
|
private byte[] tmp;
|
||
|
|
||
|
public SprotoPack () {
|
||
|
this.buffer = new MemoryStream ();
|
||
|
this.tmp = new byte[8] {0, 0, 0, 0, 0, 0, 0, 0};
|
||
|
}
|
||
|
|
||
|
private void write_ff(byte[] src, int offset, long pos, int n) {
|
||
|
int align8_n = (n+7)&(~7);
|
||
|
long cur_pos = this.buffer.Position;
|
||
|
|
||
|
this.buffer.Seek (pos, SeekOrigin.Begin);
|
||
|
|
||
|
this.buffer.WriteByte (0xff);
|
||
|
this.buffer.WriteByte ((byte)(align8_n/8 - 1));
|
||
|
|
||
|
this.buffer.Write (src, offset, n);
|
||
|
for (int i = 0; i < align8_n-n; i++) {
|
||
|
this.buffer.WriteByte (0);
|
||
|
}
|
||
|
|
||
|
this.buffer.Seek (cur_pos, SeekOrigin.Begin);
|
||
|
}
|
||
|
|
||
|
private int pack_seg(byte[] src, long offset, int ff_n) {
|
||
|
byte header = 0;
|
||
|
int notzero = 0;
|
||
|
|
||
|
long header_pos = this.buffer.Position;
|
||
|
this.buffer.Seek (1, SeekOrigin.Current);
|
||
|
|
||
|
for (int i = 0; i < 8; i++) {
|
||
|
if (src [offset + i] != 0) {
|
||
|
notzero++;
|
||
|
header |= (byte)(1 << i);
|
||
|
this.buffer.WriteByte (src[offset + i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((notzero == 7 || notzero == 6) &&ff_n > 0) {
|
||
|
notzero = 8;
|
||
|
}
|
||
|
if (notzero == 8) {
|
||
|
if (ff_n > 0) {
|
||
|
this.buffer.Seek (header_pos, SeekOrigin.Begin);
|
||
|
return 8;
|
||
|
} else {
|
||
|
this.buffer.Seek (header_pos, SeekOrigin.Begin);
|
||
|
return 10;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.buffer.Seek (header_pos, SeekOrigin.Begin);
|
||
|
this.buffer.WriteByte (header);
|
||
|
this.buffer.Seek (header_pos, SeekOrigin.Begin);
|
||
|
return notzero + 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
public byte[] pack (byte[] data, int len=0) {
|
||
|
this.clear ();
|
||
|
|
||
|
int srcsz = (len==0)?(data.Length):(len);
|
||
|
byte[] ff_src = null;
|
||
|
int ff_srcstart = 0;
|
||
|
long ff_desstart = 0;
|
||
|
|
||
|
int ff_n = 0;
|
||
|
|
||
|
byte[] src = data;
|
||
|
int offset = 0;
|
||
|
|
||
|
for (int i = 0; i < srcsz; i += 8) {
|
||
|
offset = i;
|
||
|
|
||
|
int padding = i + 8 - srcsz;
|
||
|
if (padding > 0) {
|
||
|
for (int j = 0; j < 8 - padding; j++) {
|
||
|
this.tmp [j] = src [i + j];
|
||
|
}
|
||
|
for (int j = 0; j < padding; j++) {
|
||
|
this.tmp [7 - j] = 0;
|
||
|
}
|
||
|
|
||
|
src = this.tmp;
|
||
|
offset = 0;
|
||
|
}
|
||
|
|
||
|
int n = this.pack_seg (src, offset, ff_n);
|
||
|
if (n == 10) {
|
||
|
// first FF
|
||
|
ff_src = src;
|
||
|
ff_srcstart = offset;
|
||
|
ff_desstart = this.buffer.Position;
|
||
|
ff_n = 1;
|
||
|
} else if (n == 8 && ff_n > 0) {
|
||
|
++ff_n;
|
||
|
if (ff_n == 256) {
|
||
|
this.write_ff (ff_src, ff_srcstart, ff_desstart, 256*8);
|
||
|
ff_n = 0;
|
||
|
}
|
||
|
} else {
|
||
|
if (ff_n > 0) {
|
||
|
this.write_ff (ff_src, ff_srcstart, ff_desstart, ff_n*8);
|
||
|
ff_n = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.buffer.Seek (n, SeekOrigin.Current);
|
||
|
}
|
||
|
|
||
|
if (ff_n == 1) {
|
||
|
this.write_ff (ff_src, ff_srcstart, ff_desstart, 8);
|
||
|
} else if (ff_n > 1) {
|
||
|
int length = (ff_src == data)?(srcsz):(ff_src.Length);
|
||
|
this.write_ff (ff_src, ff_srcstart, ff_desstart, length - ff_srcstart);
|
||
|
}
|
||
|
|
||
|
long maxsz = (srcsz + 2047) / 2048 * 2 + srcsz + 2;
|
||
|
if (maxsz < this.buffer.Position) {
|
||
|
SprotoTypeSize.error ("packing error, return size="+this.buffer.Position);
|
||
|
}
|
||
|
|
||
|
byte[] pack_buffer = new byte[this.buffer.Position];
|
||
|
this.buffer.Seek (0, SeekOrigin.Begin);
|
||
|
this.buffer.Read (pack_buffer, 0, pack_buffer.Length);
|
||
|
|
||
|
return pack_buffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
public byte[] unpack (byte[] data, int len=0) {
|
||
|
this.clear ();
|
||
|
|
||
|
len = (len==0)?(data.Length):(len);
|
||
|
int srcsz = len;
|
||
|
|
||
|
while (srcsz > 0) {
|
||
|
byte header = data [len - srcsz];
|
||
|
--srcsz;
|
||
|
|
||
|
if (header == 0xff) {
|
||
|
if (srcsz < 0) {
|
||
|
SprotoTypeSize.error ("invalid unpack stream.");
|
||
|
}
|
||
|
|
||
|
int n = (data [len - srcsz] + 1) * 8;
|
||
|
|
||
|
if (srcsz < n + 1) {
|
||
|
SprotoTypeSize.error ("invalid unpack stream.");
|
||
|
}
|
||
|
|
||
|
this.buffer.Write (data, len - srcsz + 1, n);
|
||
|
srcsz -= n + 1;
|
||
|
} else {
|
||
|
for (int i = 0; i < 8; i++) {
|
||
|
int nz = (header >> i) & 1;
|
||
|
if (nz == 1) {
|
||
|
if (srcsz < 0) {
|
||
|
SprotoTypeSize.error ("invalid unpack stream.");
|
||
|
}
|
||
|
|
||
|
this.buffer.WriteByte (data [len - srcsz]);
|
||
|
--srcsz;
|
||
|
} else {
|
||
|
this.buffer.WriteByte (0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
byte[] unpack_data = new byte[this.buffer.Position];
|
||
|
this.buffer.Seek (0, SeekOrigin.Begin);
|
||
|
|
||
|
this.buffer.Read (unpack_data, 0, unpack_data.Length);
|
||
|
return unpack_data;;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
private void clear() {
|
||
|
this.buffer.Seek (0, SeekOrigin.Begin);
|
||
|
|
||
|
for (int i = 0; i < this.tmp.Length; i++) {
|
||
|
this.tmp [i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|