QIP Infium, продолжение истории...

Как говорится: дело было!… И так, продолжая копаться в QIP Infium и его младшем(? старшем О_о) брате QIP 2010, добрел до истории. Хранится все это безобразие в бинарнике да еще и зашифровано от лишних глаз. Но как обычно все тайное интересно в двойне и поэтому будем разбираться чего тут у них и как.

Все числовые значения хранятся в big-endian порядке. Файл истории (qhf) представляет собой основной заголовок, в котором указан, ник, UIN, размер, количество сообщений и прочая техническая ересь:

Offset		Type			Comment
$00			char[3]			sign must be 'QHF'
$03			Byte			unknow, it's possible version=0x03
$04			DWORD			cdSize history
$08			Byte[10]		unknow
$12			Byte[16]		unknow
$22			DWORD			msg count
$26			DWORD			msg count
$2a			Word			reserved
$2c			Word			UIN string length (UinLen)
$2e			char[UinLen]	UIN in UTF-8
$2e+UinLen	Word			Nick string length (NickLen)
$30+UinLen	char[NickLen]	Nick in UTF-8

После всего этого последовательно идут сами сообщения со своими заголовками, структура которых следующего содержания:

Offset		Type				Comment
$00			Word				sign mast be 0x01
$02			DWORD				cdSizeBlock

$06 Word field type $08 Word cdSizeField $0A DWORD id msg
$0E Word field type $10 Word cdSizeField $12 DWORD UnixTime
$16 Word field type $18 Word unknow $1A Byte Bool my msg
$1B Word field type $1D Word cdSizeField $1F DWORD cdSizeMsg $23 Byte[cdSizeMsg] Msg

Осталось все это лишь разобрать и разложить по полочкам, что собственно и делает класс TInfiunHistoryReader:

  TInfiunHistoryReader = class(TMapReader)
  private
    FNick: String;
    FUIN: String;
    FCount: Cardinal;
    FMsgId: Cardinal;
    FSize: Cardinal;
    FType: Cardinal;
    function GetTextField(const cdLen: Cardinal): String;
    function GetNextBlock: Cardinal;
  public
    constructor Create(const fName: String);
    function GetNextMsg(var Msg: TMsgInfo): Boolean;
  published
    property Nick: String read FNick;
    property UIN: String read FUIN;
    property MsgCount: Cardinal read FCount;
    property MsgId: Cardinal read FMsgId;
    property Size: Cardinal read FSize;
  end;

Пример использования TInfiunHistoryReader:

procedure Parser(fName: String);
var
  Send, Time: String;
  pH: TInfiunHistoryReader;
  msgi: TMsgInfo;
begin
  ............
  pH:= TInfiunHistoryReader.Create(fName); try

AddText(Format('Size history: %d Bytes', [pH.Size])); AddText(Format('Message count: %d',[pH.MsgCount])); AddText('UIN: ' + pH.UIN); AddText('Nik: ' + pH.Nick); AddText('-----------------------------------------------'); while pH.GetNextMsg(msgi) do begin DateTimeToString(Time, 'dd/mm/yy hh:mm:ss', msgi.Time); if msgi.IsMy then Send:= 'Я' else Send:= Format('%s (%s)',[pH.Nick, pH.UIN]); AddText(Format('%s %s',[Send, Time])); AddText(msgi.MsgText); end; finally pH.Free; end; end;

Ко всему выше написанному прилагаю исходник и скомпилированный бинарник)

Скачать: Infium History Reader [src] [ 26,4 kB] загрузок: 2401


Комментарии

  1. =zeus= · 2 Июнь 2011, 21:17 · #

    Молодец, хорошую работу проделал!