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.
 
 
 
 
 
 

201 lines
4.3 KiB

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;
}
}
}
}