static public IList Unpack (string description, byte [] buffer, int startIndex)
{
DataConverter conv = CopyConv;
var result = new List<object> ();
int idx = startIndex;
bool align = false;
int repeat = 0, n;
for (int i = 0; i < description.Length && idx < buffer.Length; ){
int save = i;
switch (description [i]){
case '^':
conv = BigEndian;
break;
case '_':
conv = LittleEndian;
break;
case '%':
conv = Native;
break;
case 'x':
idx++;
break;
case '!':
align = true;
break;
// Type Conversions
case 'i':
if (Prepare (buffer, ref idx, 4, ref align)){
result.Add (conv.GetInt32 (buffer, idx));
idx += 4;
}
break;
case 'I':
if (Prepare (buffer, ref idx, 4, ref align)){
result.Add (conv.GetUInt32 (buffer, idx));
idx += 4;
}
break;
case 's':
if (Prepare (buffer, ref idx, 2, ref align)){
result.Add (conv.GetInt16 (buffer, idx));
idx += 2;
}
break;
case 'S':
if (Prepare (buffer, ref idx, 2, ref align)){
result.Add (conv.GetUInt16 (buffer, idx));
idx += 2;
}
break;
case 'l':
if (Prepare (buffer, ref idx, 8, ref align)){
result.Add (conv.GetInt64 (buffer, idx));
idx += 8;
}
break;
case 'L':
if (Prepare (buffer, ref idx, 8, ref align)){
result.Add (conv.GetUInt64 (buffer, idx));
idx += 8;
}
break;
case 'f':
if (Prepare (buffer, ref idx, 4, ref align)){
result.Add (conv.GetFloat (buffer, idx));
idx += 4;
}
break;
case 'd':
if (Prepare (buffer, ref idx, 8, ref align)){
result.Add (conv.GetDouble (buffer, idx));
idx += 8;
}
break;
case 'b':
if (Prepare (buffer, ref idx, 1, ref align)){
result.Add (buffer [idx]);
idx++;
}
break;
case 'c': case 'C':
if (Prepare (buffer, ref idx, 1, ref align)){
char c;
if (description [i] == 'c')
c = ((char) ((sbyte)buffer [idx]));
else
c = ((char) ((byte)buffer [idx]));
result.Add (c);
idx++;
}
break;
// Repeat acount;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
repeat = ((short) description [i]) - ((short) '0');
save = i + 1;
break;
case '*':
repeat = Int32.MaxValue;
break;
case '[':
int count = -1, j;
for (j = i+1; j < description.Length; j++){
if (description [j] == ']')
break;
n = ((short) description [j]) - ((short) '0');
if (n >= 0 && n <= 9){
if (count == -1)
count = n;
else
count = count * 10 + n;
}
}
if (count == -1)
throw new ArgumentException ("invalid size specification");
i = j;
save = i + 1;
repeat = count;
break;
case '$': case 'z':
// bool with_null = description [i] == 'z';
i++;
if (i >= description.Length)
throw new ArgumentException ("$ description needs a type specified", "description");
char d = description [i];
Encoding e;
if (align){
idx = Align (idx, 4);
align = false;
}
if (idx >= buffer.Length)
break;
switch (d){
case '8':
e = Encoding.UTF8;
n = 1;
break;
case '6':
e = Encoding.Unicode;
n = 2;
break;
case '7':
e = Encoding.UTF7;
n = 1;
break;
case 'b':
e = Encoding.BigEndianUnicode;
n = 2;
break;
case '3':
e = Encoding.GetEncoding (12000);
n = 4;
break;
case '4':
e = Encoding.GetEncoding (12001);
n = 4;
break;
default:
throw new ArgumentException ("Invalid format for $ specifier", "description");
}
int k = idx;
switch (n){
case 1:
for (; k < buffer.Length && buffer [k] != 0; k++)
;
result.Add (e.GetChars (buffer, idx, k-idx));
if (k == buffer.Length)
idx = k;
else
idx = k+1;
break;
case 2:
for (; k < buffer.Length; k++){
if (k+1 == buffer.Length){
k++;
break;
}
if (buffer [k] == 0 && buffer [k+1] == 0)
break;
}
result.Add (e.GetChars (buffer, idx, k-idx));
if (k == buffer.Length)
idx = k;
else
idx = k+2;
break;
case 4:
for (; k < buffer.Length; k++){
if (k+3 >= buffer.Length){
k = buffer.Length;
break;
}
if (buffer[k]==0 && buffer[k+1] == 0 && buffer[k+2] == 0 && buffer[k+3]== 0)
break;
}
result.Add (e.GetChars (buffer, idx, k-idx));
if (k == buffer.Length)
idx = k;
else
idx = k+4;
break;
}
break;
default:
throw new ArgumentException (String.Format ("invalid format specified `{0}'",
description [i]));
}
if (repeat > 0){
if (--repeat > 0)
i = save;
} else
i++;
}
return result;
}