Разбор байтов как BCD с помощью Indy C++ Builder

Я пытаюсь проанализировать длину полученного сообщения. Длина указана в BCD. Когда я использую ReadSmallInt(), я получаю показание, интерпретируемое как шестнадцатеричное значение, а не как двоично-десятичное.

Итак, если у меня есть такое сообщение:

00 84 60 00 00 00 19 02 10 70 38 00 00 0E C0 00
00 16 45 93 56 00 01 79 16 62 00 00 00 00 00 00
08 00 00 00 00 02 10 43 02 04 02 35 31 35 31 35
31 35 31 35 31 35 31 53 41 4C 45 35 31 30 30 31
32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 39
30 31 32 33

Я ожидаю, что ReadSmallInt() вернет 84, но вместо этого он возвращает 132, что правильно, если вы читаете шестнадцатеричное значение вместо двоично-десятичного.

Согласно этому ответу, ReadSmallInt() читается как BCD, так как в примерах он получает 11 и 13 (BCD) в качестве длины вместо 17 и 19 (шестнадцатеричный).

Я зафиксировал это клейкой лентой, но есть ли более элегантный способ?

int calculated_length;
// getting the length in Hexa
calculated_length = AContext->Connection->IOHandler->ReadSmallInt();
// converting from hex binary to hex string
UnicodeString bcdLength = UnicodeString().sprintf(L"%04x", calculated_length);
// converting from hex string to int
calculated_length = bcdLength.ToInt();

ucBuffer.Length = calculated_length -2;
AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length - 2);
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Согласно этому ответу, ReadSmallInt читается как BCD

Это неправильно. Вы неправильно истолковали то, что говорит этот ответ. НИЧТО в этом ответе не указывает на то, что ReadSmallInt() читается в двоично-десятичном коде, потому что это не так, поскольку Indy вообще НЕ поддерживает чтение/запись BCD. ReadSmallInt() просто считывает 2 байта и возвращает их как есть в виде 16-битного десятичного целого числа (при необходимости меняя порядок байтов). Итак, если вам нужно вместо этого прочитать BCD, вам придется читать байты, а затем анализировать их самостоятельно. Или найдите библиотеку BCD, которая сделает это за вас.

Если вы еще раз внимательно перечитаете этот другой вопрос, в двух примерах он дает:

24 24 00 11 12 34 56 FF FF FF FF 50 00 8B 9B 0D 0A
24 24 00 13 12 34 56 FF FF FF FF 90 02 00 0A 8F D4 0D 0A

3-й и 4-й байты представляют длину сообщения (x00 x11 и x00 x13 соответственно). Как 16-битные значения в сетевом порядке байтов, они представляют собой десятичные целые числа 17 и 19 соответственно. И если вы подсчитаете присутствующие байты, вы увидите, что эти значения являются правильными длинами байтов этих сообщений. Таким образом, здесь нет никаких BCD.

Это отличается от вашего примера. Байты x00 x84 в сетевом порядке байтов представляют собой десятичное целое число 132. Но ваше сообщение имеет размер 84 байта, а не 132 байта. Таким образом, очевидно, что байты x00 x84 НЕ представляют 16-битное десятичное значение, поэтому ReadSmallInt() — это неправильный метод для использования в первую очередь.

В вашем коде «клейкой ленты» вы берете десятичное значение, которое возвращает ReadSmallInt() (132), преобразуете его в шестнадцатеричную строку ('0084'), а затем анализируете его в десятичное значение (84). В Indy нет метода, который сделает за вас такое преобразование.

Это «работает» в вашем случае, но является ли это правильным преобразованием для выполнения, я не могу сказать наверняка, поскольку вы не предоставили никаких подробностей о протоколе, с которым имеете дело. Но если вы думаете, что байты представляют собой BCD, вам следует интерпретировать байты с точки зрения фактического BCD.

В упакованном BCD байт может представлять собой двузначное число. В данном случае байт x84 (10000100b) содержит два полубайта 1000b (8) и 0100b (4), поэтому вместе они образуют десятичное число 84, которое вычисляется следующим образом:

BYTE b = 0x84;
int len = (int((b >> 4) & 0x0F) * 10) + int(b & 0x0F);

Теперь, как это распространяется на несколько байтов в BCD, я не уверен, так как мой опыт работы с BCD очень ограничен. Но вам придется выяснить это, если вам нужно обрабатывать сообщения длиной более 99 байтов, что является наибольшим десятичным числом, которое может представлять один байт BCD.

Мне не понравилось мое решение, но, похоже, оно должно быть таким. Поскольку ReadSmallInt() читает два байта, максимальная длина, которую я могу обработать таким образом, будет 9999, что более чем достаточно для того, что я делаю. Спасибо за объяснение.

Beto 16.11.2022 21:17

Другие вопросы по теме