Каковы первые байты в столбце BLOB-объектов SQlite Adobe AIR?Blob Sizeinfo? - PullRequest
1 голос
/ 17 июня 2011

Я обнаружил случайную серию байтов, вставленных в любое поле большого двоичного объекта при работе с базой данных через Adobe AIR. (Судя по моим результатам, он всегда начинается с байтов [12, ...] , но я не уверен в этом)

Я думаю, что это sizeinfo байтов, позвольте мне объяснить, как я пришел к такому выводу.

Сначала мой контекст: я манипулирую базами данных sqlite через Adobe AIR (на стороне клиента) и System.data.sqlite (на стороне сервера C #)

При использовании System.data.sqlite, если я читаю базу данных Sqlite, заполненную BLOB от Adobe AIR, мне нужно проверить эти байты, добавленные в начале AIR, а затем у меня все двоичные данные хорошо сформированы. ИДЕАЛЬНО!

При использовании Adobe AIR, если я попытался прочитать sqlite db, заполненный BLOB-файлом System.data.Sqlite, данные повреждены, я получаю ошибку! Очевидно, потому что у меня нет пропущенных байтов, исследованных AIR.

Конечно, я пытался добавить эти байты, просто скопировав серию из 3 байтов, которые я удалил в моем первом случае, но затем он вернул данные частично, а в случае изображений последние строки пикселей стали серыми, а в некоторых изображения у меня более или менее серые линии. Поскольку данные соответствовали серии изображений одного размера ~ 4 КБ, и я добавил 3 байта из одного из них, и у меня был такой результат.

И Air также иногда выдаст эту ошибку:

Ошибка: ошибка № 2030: конец файла был встречаются.

Так что, очевидно, эти байты дают информацию о размере, но я не совсем понимаю, как это происходит!?!

Я попытался добавить байтовый массив длиной 4 КБ, он имеет тенденцию добавлять 3 байта, но я попытался добавить 4 МБ, и он достигает 5 байтов.

Я нашел этот вопрос Как преобразовать 3 байта в 24-битное число в C #? , и я подумал, что это может быть то, как хранится информация о размере.

Но я все еще не понимаю ...

Ответы [ 2 ]

1 голос
/ 19 июня 2011

Благодаря FluorineFX (AMF для .NET) проект с открытым исходным кодом - вот ответ.

Потому что в моем проекте Adobe AIR мне нужно передать мой объект air.ByteArray в качестве параметра для хранения всего в поле sqlite Blob; AIR будет сериализовать все в AMF, компактный двоичный формат сообщения ActionScript.

Page 11 Secion 3.14 Тип ByteArray

http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf

Документ предусматривает:

AMF 3 сериализует этот тип, используя кодирование переменной длины 29 бит целое число для префикса длины байта сопровождаемый необработанными байтами ByteArray.

Но это еще не все, я искал проект с открытым исходным кодом AMF .NET и основал FluorineFX. Глядя на код, я определил, что каждый двоичный файл AMF имеет префикс байтового TypeCode, который равен 12 для ByteArray:

   /// <summary>
   /// AMF ByteArray data type.
   /// </summary>
   public const byte ByteArray = 12;

Дальнейший поиск и снова я нашел в источниках FluorineFX AMFReader.ReadAMF3ByteArray () и AMFWriter.WriteByteArray ()

Что поможет мне быстро построить то, что мне нужно:

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

    /// <summary>
    /// 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.
    /// </summary>
    /// <returns></returns>
    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));
                }
    }

Надеюсь, это поможет кому-то еще.

0 голосов
/ 21 июня 2011

Большое спасибо, это помогло мне решить проблему.Вот как это сделать с помощью Java-кода:

Добавить зависимость org.granite granite-core к вашему проекту

Init GDS с шаблонным кодом

GraniteConfig graniteConfig = new GraniteConfig(null, null, null, null);
ServicesConfig servicesConfig = new ServicesConfig(null, null, false);
Map<String, Object> applicationMap = new HashMap<String, Object>();
SimpleGraniteContext.createThreadIntance(graniteConfig, servicesConfig, applicationMap);

В моем примере, я прочитал файл изображения, который я вставлю в BLOB:

fis = new FileInputStream(file);
ps = connection.prepareStatement(INSERT_PICTURE);
ps.setString(1, key);
byte[] fileBytes = FileUtils.readFileToByteArray(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
AMF3Serializer ser = new AMF3Serializer(out);
ser.writeObject(fileBytes);
ser.flush();
ps.setBytes(2, out.toByteArray());

Работает как шарм, спасибо за подсказку:)

Fabien

...