Как говорится: дело было!… И так, продолжая копаться в QIP Infium и его младшем(? старшем О_о) брате QIP 2010, добрел до истории. Хранится все это безобразие в бинарнике да еще и зашифровано от лишних глаз. Но как обычно все тайное интересно в двойне и поэтому будем разбираться чего тут у них и как.
Все числовые значения хранятся в
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;
Ко всему выше написанному прилагаю исходник и скомпилированный бинарник)
— =zeus= · 2 Июнь 2011, 21:17 · #
Молодец, хорошую работу проделал!