I have identified a random series of bytes inserted into any blob field when the database is manipulated via Adobe AIR. (from my results it appear to always start with b
Thanks to FluorineFX (AMF for .NET) opensource project here is the answer.
Because in my Adobe AIR project I have to pass my air.ByteArray object as a parameter to store everything in the sqlite Blob field; AIR will serialize everything into AMF, a compact binary actionscript message format.
Page 11 Secion 3.14 ByteArray type
http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf
The doc stipulate :
AMF 3 serializes this type using a variable length encoding 29-bit integer for the byte-length prefix followed by the raw bytes of the ByteArray.
But thats not all, I searched for an AMF .NET opensource project and founded FluorineFX. Looking into the code I identified that every AMF binaries is prefixed with a byte TypeCode which is 12 for a ByteArray:
///
/// AMF ByteArray data type.
///
public const byte ByteArray = 12;
Further search and again I found in the FluorineFX sources AMFReader.ReadAMF3ByteArray() and AMFWriter.WriteByteArray()
Which help me to quickly build what I need :
private static byte[] RemoveAMF3ByteArrayPrefixBytes(byte[] ar)
{
var ms = new MemoryStream(ar);
var br = new BinaryReader(ms);
// if first byte is AMF TypeCode for ByteArray
if (br.Read() != 12)
return ar;
int handle = ReadAMF3IntegerData(br);
bool inline = ((handle & 1) != 0);
handle = handle >> 1;
if (inline)
{
int length = handle;
byte[] buffer = br.ReadBytes(length);
return buffer;
}
return ar;
}
private static byte[] AddAMF3ByteArrayPrefixBytes(byte[] ar)
{
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);
bw.Write((byte)12); // AMF TypeCode for ByteArray
var handle = (int)ar.Length;
handle = handle << 1;
handle = handle | 1;
WriteAMF3IntegerData(bw, handle);
bw.Write(ar);
return ms.ToArray();
}
///
/// Handle decoding of the variable-length representation which gives seven bits of value per serialized byte by using the high-order bit
/// of each byte as a continuation flag.
///
///
private static int ReadAMF3IntegerData(BinaryReader br)
{
int acc = br.ReadByte();
if(acc < 128)
return acc;
else
{
acc = (acc & 0x7f) << 7;
int tmp = br.ReadByte();
if(tmp < 128)
acc = acc | tmp;
else
{
acc = (acc | tmp & 0x7f) << 7;
tmp = br.ReadByte();
if(tmp < 128)
acc = acc | tmp;
else
{
acc = (acc | tmp & 0x7f) << 8;
tmp = br.ReadByte();
acc = acc | tmp;
}
}
}
//To sign extend a value from some number of bits to a greater number of bits just copy the sign bit into all the additional bits in the new format.
//convert/sign extend the 29bit two's complement number to 32 bit
int mask = 1 << 28; // mask
int r = -(acc & mask) | acc;
return r;
//The following variation is not portable, but on architectures that employ an
//arithmetic right-shift, maintaining the sign, it should be fast.
//s = 32 - 29;
//r = (x << s) >> s;
}
private static void WriteAMF3IntegerData(BinaryWriter bw, int value)
{
//Sign contraction - the high order bit of the resulting value must match every bit removed from the number
//Clear 3 bits
value &= 0x1fffffff;
if (value < 0x80)
bw.Write((byte)value);
else
if (value < 0x4000)
{
bw.Write((byte)(value >> 7 & 0x7f | 0x80));
bw.Write((byte)(value & 0x7f));
}
else
if (value < 0x200000)
{
bw.Write((byte)(value >> 14 & 0x7f | 0x80));
bw.Write((byte)(value >> 7 & 0x7f | 0x80));
bw.Write((byte)(value & 0x7f));
}
else
{
bw.Write((byte)(value >> 22 & 0x7f | 0x80));
bw.Write((byte)(value >> 15 & 0x7f | 0x80));
bw.Write((byte)(value >> 8 & 0x7f | 0x80));
bw.Write((byte)(value & 0xff));
}
}
I hope that will help someone else.