2012-07-03 1 views
1

Я читаю кучу байтов из двоичного файла. Это файл RAR. Я заинтересован в 11-м и 12-м байтах файла, так как состояние спецификации заголовка:Как читать в шестнадцатеричных значениях из двоичного файла и расшифровывать некоторые байты, содержащие значения битфлага?

HEAD_FLAGS Битовые флаги: 2 байта

  0x0001 - Volume attribute (archive volume) 
      0x0002 - Archive comment present 
         RAR 3.x uses the separate comment block 
         and does not set this flag. 

      0x0004 - Archive lock attribute 
      0x0008 - Solid attribute (solid archive) 
      0x0010 - New volume naming scheme ('volname.partN.rar') 
      0x0020 - Authenticity information present 
         RAR 3.x does not set this flag. 

      0x0040 - Recovery record present 
      0x0080 - Block headers are encrypted 
      0x0100 - First volume (set only by RAR 3.0 and later) 

      other bits in HEAD_FLAGS are reserved for 
      internal use 

Файл, который я играю с имеет 00 и 0D как позиции 11 и 12 соответственно.

Я не могу понять эти два значения, поскольку они являются битовыми флагами (которые я не понял).

У меня эти два значения в массиве byte, длина которого составляет 12 байтов. Что мне нужно проверить в этой последовательности, установлен ли флаг 0x0100 и 0x0001.

Я потерялся с этим. Благодарю.


Я осмотрела некоторые файлы в редакторе Hex и то, что я видел в том, что 11-й и 12-й байт нужно читать вместе. Вот почему спецификации перечисляют все битовые флаги - это 4-х буквенные шестнадцатеричные коды. Проверка флажков бит индивидуально дает неверные результаты.


Ассимилируя как можно больше информации из ответов/советов, «ве решил эту проблему следующим образом:

FileInputStream fisFileInputStream = new FileInputStream((new File("C:\\testarchive.r00")); 

byte[] bytHeader = new byte[20]; //The first 20 bytes are the RAR header. 
fisFileInputStream.read(bytHeader); 

short val=(short)(((bytHeader[10]&0xFF)<<8) | (bytHeader[11]&0xFF)); //Joining the two bytes into a short 

System.out.println("Volume Attribute (0x0001): " + ((val & 0x0001) != 0)); 
System.out.println("First volume (0x0100): " + ((val & 0x0100) != 0)); 

Я попробовал этот код с несколькими RAR архивов - охватывали те, не натянутый один, первый файл сложенного архива, другой файл запатентованного архива.

Сам код работает отлично, за исключением очень незначительной причуды. Я получаю противоположные результаты моих шестнадцатеричных значений, т.е.

При проверке файла, который не является первым файлом в составном архиве, я получаю объем atrribute 0x0001 не установлен (false) и «Первый том» 0x100 as комплект (true).

При проверке файла, который является первым файлом, который находится в развернутом архиве, я получаю абсолютно противоположные результаты.

Теперь я могу изменить свой код, чтобы поверить, что исходные данные неверны (очень маловероятно), и что 0x0001 означает, что является первым файл в составном архиве и 0x0100 означает, что является составным архив, то все в порядке.

.. но я думаю, что я делаю что-то не так с моей логикой битового флага. Есть идеи?

+1

Это может помочь: http://stackoverflow.com/questions/1092411/java-checking-if-a-bit-is-0-or-1-in-a-long – biziclop

+0

Это выглядело полезным.Я думал, что попробую это решение: http://stackoverflow.com/a/1092551/304151. Поскольку мои флаги находятся в двух байтах, я должен суммировать их, когда я инициализирую объект BigInteger. Согласно JavaDocs, он принимает 'Long'. Спасибо, –

ответ

3

Идея битовых флагов, которые вы можете напихать кучу флагов в небольшое количество байтов, добавляя их вместе.

В этом случае они не говорят, что каждое значение, которое вы видите в этом списке, представляет собой отдельную пару байтов. Все они переполнены двумя байтами. Если вы пишете файл, вы должны добавить эти значения вместе, чтобы получить значение для записи.

Например, предположим, что мы хотим сказать «Атрибут блокировки архива», «Новая схема имен томов» и «Заблокировать заголовки блоков». Это означает, что мы хотим установить 0x0004, 0x0010 и 0x0080. Поэтому мы добавляем все это вместе: 0x0004 + 0x0010 + 0x0080 = 0x0094, и это значение, которое мы пишем. Чтобы это сработало, все значения должны быть одноразрядными, иначе говоря, все должны быть равны 2.

Так что эта документация не описывает 18 байтов. Он описывает только 2.

Для его чтения вам необходимо выполнить операции И (&) с желаемым значением флага. Если вы хотите узнать, задано ли «Заблокированные заголовки блоков», прочитайте значение и И с помощью 0x0010. Поскольку это двухбайтовое значение, вы либо хотите сделать его коротким, либо вам нужно выбрать правильный байт. Скажем, ради аргумента, что мы получим его в короткий срок. Тогда мы скажем

if ((flags & 0x0010) != 0) 

Если это выражение истинно, бит устанавливается. Если он неверен, бит не установлен.

Кстати, если вы читаете это, как поток байтов, вы можете поместить их в короткий, написав: (.. Вы, возможно, потребуется бросок в там я забыл)

short flags = b[0] | b[1]<<8; 

Или вам, возможно, придется переключать b [0] и b [1], в зависимости от того, записан ли файл с низким или высоким уровнем.

+0

Привет, Джей. У меня есть некоторые сомнения, что, может быть, вы могли бы мне помочь. Таким образом, они упомянули 2 байта, то есть 16 бит. Означает ли это, теоретически может иметь 16-битные флаги? Другое дело, что они указали только 9 флагов и указали остальные как зарезервированные. Означает ли это, что первые 8-битные флаги хранятся в первом байте, а последний бит-бит во втором байте? Один из файлов rar, которые я проверил, имел эти двоичные значения в 11-м и 12-м битах: '00000001' (' 0x01') и '00000001' (' 0x01'). Как я должен их интерпретировать? Должен ли я суммировать их сначала? –

+0

Да, 2 байта могут содержать 16-битные флаги, по 8 в каждом байте. В этом случае они определили 9 флагов, 8 в одном байте и 1 в другой. Я не знаю, хранится ли младший байт сначала в этом файле или в высоком байте. Вам придется иметь дополнительную документацию или посмотреть на некоторые примеры, чтобы понять это. – Jay

+0

HI jay, вчера я сделал подробное редактирование на мой вопрос. Я решил проблему, но результаты противоположны для флагов '0x0100' и' 0x0001'. Может ли это произойти из-за контентоспособности файла/системы? Благодарю. –

2
 FileInputStream fis = new FileInputStream("file.rar"); 
     byte[] ba = new byte[13]; 
     fis.read(ba); 
     byte b11 = ba[11]; 
     byte b12 = ba[12]; 
     boolean flagIs0x10 = b12 == 0x10; 
     System.out.println("flag is 0x10 = "+flagIs0x10); 

Если оба байта вместе должны иметь значение 0x10, т.е.если это 16bit слово, то

 boolean flagIs0x10 = b11 == 0 && b12 == 0x10; 

или

 boolean flagIs0x10 = b12 == 0 && b11 == 0x10; 
+0

+1 Обратите внимание, что в этом вопросе сказано «11-е и 12-е» байты, которые будут соответственно ba [10] и ba [11]. – biziclop

+0

Это были «позиции 11 и 12», и я предположил, что вы считаете от 0. Если бы это означало подсчет от одного, то замените в ответе 13 на 12, 12 на 11 и 11 на 10. –

+0

Майкл, вам не хватает ' == 'в двух последних фрагментах. Вы использовали '='. –

0

Вот простой способ справиться с арифметикой. Следующая функция утилиты изменяет java BitSet для установки битовых флагов на основе содержимого байтового значения.

static void setByte(BitSet bitSet, int byteNum, byte b) { 
    int base = byteNum * 8; 
    bitSet.set(base + 7, (b & 0x80) != 0); 
    bitSet.set(base + 6, (b & 0x40) != 0); 
    bitSet.set(base + 5, (b & 0x20) != 0); 
    bitSet.set(base + 4, (b & 0x10) != 0); 
    bitSet.set(base + 3, (b & 0x08) != 0); 
    bitSet.set(base + 2, (b & 0x04) != 0); 
    bitSet.set(base + 1, (b & 0x02) != 0); 
    bitSet.set(base + 0, (b & 0x01) != 0); 
} 

Он принимает параметр «byteNum», в случае, если вы хотите иметь несколько байтов, помещенные в BitSet, в вашем случае вы делаете.

байты 0 будут BitSet позиции 0-7 байты 1 будет BitSet позиции 8-15 и т.д. ....

И в течение каждого байта, бит высокий порядок позиция 7, низкий порядок битовой позиции 0.

Тогда вы могли бы просто сделать это, если у вас есть два байта. Я предполагаю, что первым байтом являются биты высокого порядка (0x0800 - 0x8000), а второй байт - младшие разряды (0x0001 - 0x0080), хотя ваша спецификация должна сказать вам об этом.

byte buf[] = new byte[2]; 
inputStream.read(buf, 0, 2); 

BitSet bitSet = new BitSet(); 
// low order byte is the second one 
setByte(bitSet, 0, bytes[1]); 
// high order byte is first 
setByte(bitSet, 1, byte1[0]); 

boolean archiveVolume = bitSet.get(0); 
boolean commentPresent = bitSet.get(1); 
... 
boolean firstVolume = bitSet.get(8); 
Смежные вопросы