Разбор формата истории RnQ
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
Для плагина RnQHistoryToDB дошла очередь написать импорт истории RnQ в БД.
Нашел в инете программу "Синхронизатор историй", которая помогает объединить историю RnQ из неск. файлов в один. Взял часть информации о структуре истории из неё, часть из исходников R&Q 1105.
Набросал небольшую программку по чтению файла истории, прилагаю её в атаче.
Все бы хорошо, но самое главное поле - само сообщение, никак не удается прочитать, вроде оно и не шифровано если верить исходникам R&Q 1105, но выводится абра кадабра.
По формату:
Вся история идет блоками, насколько я понял структура блока такая:
What: Integer; // Тип блока (4 байта) - HI_event,HI_hashed или HI_cryptMode
Tipe: Byte; // Неизвестное поле (1 байт)
UIN: Integer; // UIN (4 байта)
Time: TDateTime; // Дата и время (8 байта)
ExInfoSize: Integer; // Размер поля расш. информации (4 байта), опытным путем выяснил что блок всегда одного размера - 21 байт
ExInfo: // Поле расш. информации (21 байт)
MsgSize: Integer; // Размер тела сообщения (4 байта)
Msg: AnsiString; // Само сообщение
Вроде как все поля читаются корректно, кроме поля самого сообщения, там абра кадабра.
Вопрос к Rapid D, само тело сообщения при типе блока HI_event = -1 как то кодируется? Или я структуру блока неправильно разложил?
Вложение RnQHistoryReader.rar не найдено
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Rapid D
- Не в сети
- Administrator
- Сообщений: 1995
- Спасибо получено: 35
сообщение всегда кодируется:
What: Integer; // Тип блока (4 байта) - HI_event,HI_hashed или HI_cryptMode
Tipe: Byte; // Неизвестное поле (1 байт)
UIN: Integer; // UIN (4 байта)
Time: TDateTime; // Дата и время (8 байта)
ExInfoSize: Integer; // Размер поля расш. информации (4 байта), опытным путем выяснил что блок всегда одного размера - 21 байт
ExInfo: // Поле расш. информации (21 байт)
MsgSize: Integer; // Размер тела сообщения (4 байта)
Msg: AnsiString; // Само сообщение
Вроде как все поля читаются корректно, кроме поля самого сообщения, там абра кадабра.
Вопрос к Rapid D, само тело сообщения при типе блока HI_event = -1 как то кодируется? Или я структуру блока неправильно разложил?Вложение RnQHistoryReader.rar не найдено
f_info:=critted(info_, StrToIntDef(who.uid, 0))
2-е поле наз-ся Kind. Вам лучше расшифровывать когда Kind=EK_msg
ExInfoSize совсем не всегда =21.
Msg - Совсем не AnsiString, а RawByteString.
И текст там не только зашифрован, но и может быть в разных кодировках. Последнее время в основном в UTF8.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
сообщение всегда кодируется:
f_info:=critted(info_, StrToIntDef(who.uid, 0))
2-е поле наз-ся Kind. Вам лучше расшифровывать когда Kind=EK_msg
ExInfoSize совсем не всегда =21.
Msg - Совсем не AnsiString, а RawByteString.
И текст там не только зашифрован, но и может быть в разных кодировках. Последнее время в основном в UTF8.
Все понятно, спасибо, все получилось. История успешно читается.
То что размер ExInfo = 21 байт - это я наврал, он может меняться и вовсе не 21 байт
Остался вопрос: А что содержит блок ExInfo ?
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
Единственный баг, это очень редко, но некоторые сообщения остаются все же абра-кадаброй.
Возможно дело в кодировке, хотя после расшифровки я проверяю строку, если она UTF8, то декодирую её.
Вложение RnQHistoryReader-c2dd6992266ed5721e5710a19b12c791.rar не найдено
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Rapid D
- Не в сети
- Administrator
- Сообщений: 1995
- Спасибо получено: 35
По поводу ExInfo - в исходниках 1105 всё и написано:
function extraInfo:string;
begin
result:=TLV2(EI_flags, int2str(flags));
if not isOnlyDigits(who.UID) then
result:= Result + TLV2(EI_UID, int2str(length(who.UID))+who.UID);
result:=int2str(length(result))+result;
end; // extrainfo
Т.е. если UIN=0, то туда пишется строка с, например, почтой (если это mail.ru контакт или AIM).
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
StrToIntDef(IntToStr(Res.UIN), 0) - странный код
Да это я так, на скору руку, так то просто Res.UIN и все
Rapid D писал(а):
По поводу ExInfo - в исходниках 1105 всё и написано:
function extraInfo:string;
begin
result:=TLV2(EI_flags, int2str(flags));
if not isOnlyDigits(who.UID) then
result:= Result + TLV2(EI_UID, int2str(length(who.UID))+who.UID);
result:=int2str(length(result))+result;
end; // extrainfo
Т.е. если UIN=0, то туда пишется строка с, например, почтой (если это mail.ru контакт или AIM).
С этим все ясно стало, спасибо.
Очень жаль, что в файл истории не пишется Никнейм собеседника, а только UIN. При импорте практически не реально понять кто же прячется за определенным номером
Может есть планы по доработке формата истории? Добавить пару полезных полей, такие как Никнейм и Количество сообщений. А то пока не прочитаешь весь файл, то не понятно сколько же всего в нем сообщений, накладно это очень. Про отсутствие Ника уже написал.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- cy6
- Не в сети
- Elite Member
- Сообщений: 273
- Спасибо получено: 0
Очень жаль, что в файл истории не пишется Никнейм собеседника, а только UIN. При импорте практически не реально понять кто же прячется за определенным номером
Может есть планы по доработке формата истории? Добавить пару полезных полей, такие как Никнейм и Количество сообщений. А то пока не прочитаешь весь файл, то не понятно сколько же всего в нем сообщений, накладно это очень. Про отсутствие Ника уже написал.
Поля переменной длинны, это не последние сюрпризы, которые вам могут встретится. Смотрим, например, в сторону протокола мыл-агента и плагинов, пихающих в историю картинки неприличных размеров.
Если любопытно, взгляните на исходники и историю создания RnQ_Repair. Могу также поделится не выложенными более свежими.
Никнеймы берутся элементарно из {%Root_RNQ%}\{%UIN%}\db5:db. Файлик db5 распаковываем любым алгоритмом с поддержкой Zip. Я пользуюсь zlib + minizip, последний в собственной адаптации.
Файлы истории уже достаточно перегружены "пестрым" составом данных, имхо.
А писать избыточные данные (которые могут быть получены путем вычисления или доступа к другим объектам), вообще плохой стиль. Дублирование информации используется для увеличения производительности (например поисковые ключи (индексы)), но у нас совсем не тот случай и не те объемы данных, имхо.
А количество сообщений все равно станет известно, так как файл все равно придется читать весь,
для конвертации. Это же связанный список, типа Next->Next. Хоть на стриммерную ленту пиши.
Sleuthhound писал(а):
А может не все варианты кодировки учли, или там вообще текста нет?Единственный баг, это очень редко, но некоторые сообщения остаются все же абра-кадаброй.
Возможно дело в кодировке, хотя после расшифровки я проверяю строку, если она UTF8, то декодирую её.
Я для декода написала вот такую функцию:
procedure FastDetectCharset(S: AnsiString; var CountUTF8, CountWin, CountUTF, CountUTFBE: Integer);
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
Поля переменной длинны, это не последние сюрпризы, которые вам могут встретится. Смотрим, например, в сторону протокола мыл-агента и плагинов, пихающих в историю картинки неприличных размеров.
С такими полями у меня вроде нет проблем. Удручает закрытость формата истории некоторыx меcсенждеров, к примеру QIP.
Если любопытно, взгляните на исходники и историю создания RnQ_Repair. Могу также поделится не выложенными более свежими.
Был бы очень благодарен, если поделитесь исходниками. Обещаю что никуда не уйдут.
Никнеймы берутся элементарно из {%Root_RNQ%}\{%UIN%}\db5:db. Файлик db5 распаковываем любым алгоритмом с поддержкой Zip. Я пользуюсь zlib + minizip, последний в собственной адаптации.
DB5 начал использоватся в сравнительно новых версиях RnQ, то есть по уму нужно еще и поддержку DB4 делать. Попробую брать данные оттуда. Спасибо за подсказку.
Файлы истории уже достаточно перегружены "пестрым" составом данных, имхо.
А писать избыточные данные (которые могут быть получены путем вычисления или доступа к другим объектам), вообще плохой стиль.
А если файл db5 не доступен? Собственно вот и приплыли. Избыточность не всегда отрицательна, иногда она очень даже полезна. Чем дергаться и разгребать 2 файла - файл истории + файл db5, проще добавить "избыточное поле" в файл истории и тем самым в разы упростить работу и себе и другим. Поле длиною 10-30 байт никак не повредит, ИМХО.
А количество сообщений все равно станет известно, так как файл все равно придется читать весь,
для конвертации. Это же связанный список, типа Next->Next. Хоть на стриммерную ленту пиши.
А если мне не нужно его весь читать? Нужно просто знать количество сообщений, как бы статистические данные. А тут приходится его весь читать. Ладно если там 1000 сообщений, а у меня допустим есть файлы истории в которых более 50 тыс. сообщений. На не быстром компьютере чтение таких файлов занимает несколько больше времени чем следовало бы. И это ради того чтобы узнать 1 цифру.
Sleuthhound писал(а):
А может не все варианты кодировки учли, или там вообще текста нет?Единственный баг, это очень редко, но некоторые сообщения остаются все же абра-кадаброй.
Возможно дело в кодировке, хотя после расшифровки я проверяю строку, если она UTF8, то декодирую её.
Я для декода написала вот такую функцию:
procedure FastDetectCharset(S: AnsiString; var CountUTF8, CountWin, CountUTF, CountUTFBE: Integer);
в WideStrUtils есть функция IsUTF8String, вот её я и использую для определения UTF8 строка или нет. Если UTF8, то делаем UTF8Decode. Конечно если строка в какой-нибудь другой кодировке, то получается абра-кадабра.
Не поделитесь своей процедуркой FastDetectCharset?
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- cy6
- Не в сети
- Elite Member
- Сообщений: 273
- Спасибо получено: 0
Смотрите файл Decode.pas в исходниках на предмет FastDetectCharset.Был бы очень благодарен, если поделитесь исходниками. Обещаю что никуда не уйдут.
...
в WideStrUtils есть функция IsUTF8String, вот её я и использую для определения UTF8 строка или нет. Если UTF8, то делаем UTF8Decode. Конечно если строка в какой-нибудь другой кодировке, то получается абра-кадабра.
Не поделитесь своей процедуркой FastDetectCharset?
Ссылка на исходники и пароль в теме утилиты/плагина RnQ_Repair.
Не выложенные более свежие, тоже кину, как только откопаю на диске.
Их содержимое касается некоторых хитро-мудростей нечасто встречающихся данных в истории, а также увеличения производительности класса файлового I/O.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
Смотрите файл Decode.pas в исходниках на предмет FastDetectCharset.
Ссылка на исходники и пароль в теме утилиты/плагина RnQ_Repair.
Взял процедуру FastDetectCharset, с ней абсолютно все сообщения нормально декодируются. Огромное спасибо!
cy6 писал(а):
Не выложенные более свежие, тоже кину, как только откопаю на диске.
Их содержимое касается некоторых хитро-мудростей нечасто встречающихся данных в истории, а также увеличения производительности класса файлового I/O.
Было бы любопытно посмотреть на предмет ускорения чтения и распарсивания файлов истории. Спасибо.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Sleuthhound
- Не в сети
- Premium Member
- Сообщений: 84
- Спасибо получено: 0
А какой у него формат? Какой-то общеизвестный или опять ковырять исходники нужно?
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- boulder
- Не в сети
- Senior Member
- Сообщений: 40
- Спасибо получено: 0
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- Mikanoshi
- Не в сети
- Platinum Member
- Сообщений: 1112
- Спасибо получено: 158
FF FF FF FF только в начале всех файлов истории, дальше другие байты, так что по этому их не найти
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- boulder
- Не в сети
- Senior Member
- Сообщений: 40
- Спасибо получено: 0
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.