unit uTokens;

////////////////////////////////////////////////////////////////////////////////
//
//                        Structure of Tokens
//
////////////////////////////////////////////////////////////////////////////////

{--------------------------------------------------------------------------------------
{      BB5 Flash-token:

Type 1
54  01 17  0E  00 00 00  0D BA  01  00 00 40 00  01 6E 00 00  62
TH  ST ST  HL   DEVICE   DC DC  UN  LL LL LL LL  SS SS SS SS  HC

Type 2
54  01 30  15  00 03 00  A2 72  00 00 00 08 FF FF FF FF 00 04 00 00 00 00 00 00 9A
TH  ST ST  HL  FI FI FI  DC DC  ?? ?? ?? ?? ?? ?? ?? ?? LL LL LL LL SS SS SS SS HC

TH - Token Header
ST - SubType (type of token)
HL - Header Length
FF - Flash ID
DC - Data Checksum
LL - Length of data between two tokens
SS - Start adress in flash
HC - Header Checksum

---------------------------------------------------------------------------------------
{      BB5 Cert-token

Type 1
5D 01 27 2D ............... .............. 00 00 00 23 0C 00 00 04 00 00 00 06 C0 AE
5D 01 27 2D ............... .............. 00 00 00 8D B6 00 00 04 00 00 00 06 C0 D6
5D 01 27 2D ............... .............. 01 01 00 C1 26 00 00 04 00 00 07 00 00 48

TH ST ST HL [20 byte SHA1?] [12 byte name] FF FF FF DC DC LL LL LL LL SS SS SS SS HC

Type 2
5D 01 28 43 ............... .............. 00 00 00 5A 5A 00 00 03 00 FF FF FF FF ................ 02 00 9D
5D 01 28 43 ............... .............. 01 01 00 BF 2B 00 00 04 00 FF FF FF FF ................ 02 00 48
5D 01 28 43 ............... .............. 00 00 00 8C 2E 00 00 02 80 FF FF FF FF ................ 01 00 25
5D 01 28 43 E9EFF4BFAA5393217CA6B17755FC3E1415658E9A 50415055424B455953000000000000 1D26 00000600 FFFFFFFF 64 3B2F33E3E6EEFC2D6F45213419C8E368FCB9960100 6D
TH ST ST HL [20 byte SHA1?] [12 byte name] FF FF FF DC DC LL LL LL LL SS SS SS SS [20 bytes SHA1?] ?? ?? HC

TH      HLEN                                        NAME/DESC                      DCHK BLKSZ             LAST_BYTE_IS_H_CHECKSUM

---------------------------------------------------------------------------------------

{      BB5 Image-token

allways applied in starting image-token
F0F0 0001 FF00 0000 FFF0 FFFF 00000000
[some identifier]   [ident?]  [ part ]

part is starting with 0

every 0x208 bytes (including this 8 bytes):
FFF0 FFFF [ part ]

every 0x20000 bytes this sequence is starting again but part is still continuing

letzter 0x20000 part:
F0F0 0001 FFC0 0000 FFF0 FFFF 0000 xxxx
            yy <- $C0 marks end

---------------------------------------------------------------------------------------}

interface

uses Classes, SysUtils, Hexutils;


procedure DeletePhoenixTokens(var ms:TMemoryStream; var res:Boolean; var FirstTokenType:Word; var SizeOfDataInToken: Cardinal);
procedure InsertPhoenixTokens(sc:TMemoryStream; var res:Boolean; var TokenType:Word; var Offset, SizeOfDataInToken: Cardinal);
function  FlashTokenChekSum(Buf:Pointer; BufLen: integer): Word;
function  FlashTokenCRC(Buf:Pointer; BufLen: integer): byte;

implementation

procedure DeletePhoenixTokens(var ms:TMemoryStream; var res:Boolean; var FirstTokenType:Word; var SizeOfDataInToken: Cardinal);
var
     i, HdrLen      : integer;
     TokenBuf       : array of byte;
     Data           : Byte;
     CurrTokenType  : Word;
     CurrTokenSize  : Cardinal;
     dest           : TMemoryStream;
begin
     i:=0; res:=false;
     dest:=TMemoryStream.Create;

     {ms.Read(i,1);
     if i<>$B2 then exit;
     SetLength(TokenBuf, 4);
     ms.ReadBuffer(TokenBuf[0], 4);//Длина Flash Header
     HdrLen := HexToInt(IntToHex(TokenBuf[0], 2)+IntToHex(TokenBuf[1], 2)+IntToHex(TokenBuf[2], 2)+IntToHex(TokenBuf[3], 2));
     ms.Seek(0,sofromBeginning);
     dest.CopyFrom(ms, HdrLen+5);}

     i:=0;
     while ms.Position<ms.Size do
     Begin
          ms.ReadBuffer(Data, 1);
          if Data=$54 then
          begin
               ms.ReadBuffer(CurrTokenType, 2);
               ms.ReadBuffer(Data, 1);
               SetLength(TokenBuf, Data+1);//length of header flash-token
               ms.ReadBuffer(TokenBuf[0],Data+1);// на единицу больше с учетом CRC
               case CurrTokenType of
               $1701:
                     begin
                          CurrTokenSize:=HexToInt(IntToHex(TokenBuf[6], 2)+IntToHex(TokenBuf[7], 2)+IntToHex(TokenBuf[8], 2)+IntToHex(TokenBuf[9], 2));
                          if i=0 then
                          begin
                               FirstTokentype:=CurrTokenType;//Копирование первого значения о типе применяемого токена для дальнейшей "переразметки"
                               SizeOfDataInToken:=CurrTokenSize;//Копирование первого значения размера токен блока для дальнейшей "переразметки"
                               inc(i);
                          end;
                     end;
               $3001:
                     begin
                          CurrTokenSize:=HexToInt(IntToHex(TokenBuf[17], 2)+IntToHex(TokenBuf[18], 2)+IntToHex(TokenBuf[19], 2)+IntToHex(TokenBuf[20], 2));
                          if i=0 then
                          begin
                               FirstTokentype:=CurrTokenType;//Копирование первого значения о типе применяемого токена для дальнейшей "переразметки"
                               SizeOfDataInToken:=CurrTokenSize;//Копирование первого значения размера токен блока для дальнейшей "переразметки"
                               inc(i);
                          end;
                     end else
                     begin
                          //Если текущее значение не равно $54, значит нарушена структурность разметки flash-token, либо новый тип разметки -> Error
                          dest.Free;
                          exit;
                     end;
               end;//end of case

               //Если имеются различия между данными о длине блока в токене и реальным значением -> Bad Image File
               if (ms.size-ms.position)<CurrTokenSize then
               begin
                    dest.Free;
                    exit;
               end;
               dest.CopyFrom(ms, CurrTokenSize);
          end;
     end;
     ms.Clear;
     dest.Seek(0,soFromBeginning);
     ms.CopyFrom(dest, dest.Size);
     dest.free;
     ms.Seek(0, soFromBeginning);
     res:=true;
end;

procedure InsertPhoenixTokens(sc:TMemoryStream; var res:Boolean; var TokenType:Word; var Offset, SizeOfDataInToken: Cardinal);
var
     i, HdrLen          : integer;
     b                  : boolean;
     TokenBuf           : array of byte;
     DataBuf            : array of byte;
     Data               : Byte;
     CurrTokenType,
     CurrTokenDataCheck : Word;
     CurrTokenSize      : Cardinal;
     dest               : TMemoryStream;
begin
     res:=false;
     dest:=TMemoryStream.Create;
     sc.Seek(0, sofromBeginning);
     i:=0;
     b:=true;//признак последнего блока данные меньшего по размерам, чем стандартный

     if TokenType=$1701 then SetLength(TokenBuf, $13) else
     if TokenType=$3001 then SetLength(TokenBuf, $19) else
     begin
          dest.Free;
          exit;
     end;
     SetLength(DataBuf, SizeOfDataInToken);

     while (sc.Position<sc.Size) and b do
     Begin
          //Возможно ли прочитать блок данных длиной SizeOfDataInToken
          //Необходимо для чтения остатка (для последнего блока данных)
          if (sc.size-sc.position)<SizeOfDataInToken then
               begin
                    SizeOfDataInToken:=sc.size-sc.position;
                    b:=false;
               end;

          sc.ReadBuffer(DataBuf[0], SizeOfDataInToken);
          CurrTokenDataCheck:=FlashTokenChekSum(@DataBuf[0], SizeOfDataInToken);
          case TokenType of
          $1701:
                begin
                     TokenBuf[0]:=$54;//TH - Token Header
                     //ST - SubType (type of token)
                     TokenBuf[1]:=$01;
                     TokenBuf[2]:=$17;
                     TokenBuf[3]:=$0E;//HL - Header Length
                     //May be Flash ID
                     TokenBuf[4]:=$00;
                     TokenBuf[5]:=$00;
                     TokenBuf[6]:=$00;
                     Word((@TokenBuf[7])^) :=CurrTokenDataCheck;//DC - Data Checksum
                     TokenBuf[9]:=$01;//Unknow
                     //LL - Length of data between two tokens
                     Word((@TokenBuf[10])^):=Swap((SizeOfDataInToken and $FFFF0000) shr 16);
                     Word((@TokenBuf[12])^):=Swap((SizeOfDataInToken and $0000FFFF));
                     //SS - Start adress in flash
                     Word((@TokenBuf[14])^):=Swap((Offset and $FFFF0000) shr 16);
                     Word((@TokenBuf[16])^):=Swap(Offset and $0000FFFF);
                     Byte((@TokenBuf[18])^):=FlashTokenCRC(@TokenBuf[1], Length(TokenBuf)-2);//HC - Header Checksum
                end;
          $3001:
                begin
                     TokenBuf[0] :=$54;//TH - Token Header
                     //ST - SubType (type of token)
                     TokenBuf[1] :=$01;
                     TokenBuf[2] :=$30;
                     TokenBuf[3] :=$15;//HL - Header Length
                     //May be Flash ID
                     TokenBuf[4] :=$00;
                     TokenBuf[5] :=$03;
                     TokenBuf[6] :=$00;
                     Word((@TokenBuf[7])^) :=CurrTokenDataCheck;//DC - Data Checksum
                     //Unknow
                     TokenBuf[9] :=$00;
                     TokenBuf[10]:=$00;
                     TokenBuf[11]:=$00;
                     TokenBuf[12]:=$08;
                     TokenBuf[13]:=$FF;
                     TokenBuf[14]:=$FF;
                     TokenBuf[15]:=$FF;
                     TokenBuf[16]:=$FF;
                     //LL - Length of data between two tokens
                     Word((@TokenBuf[17])^):=Swap((SizeOfDataInToken and $FFFF0000) shr 16);
                     Word((@TokenBuf[19])^):=Swap((SizeOfDataInToken and $0000FFFF));
                     //SS - Start adress in flash
                     Word((@TokenBuf[21])^):=Swap((Offset and $FFFF0000) shr 16);
                     Word((@TokenBuf[23])^):=Swap(Offset and $0000FFFF);
                     Byte((@TokenBuf[25])^):=FlashTokenCRC(@TokenBuf[1], Length(TokenBuf)-2);//HC - Header Checksum
                end;
          end;//end of case
          Offset:=Offset+SizeOfDataInToken;
          dest.WriteBuffer(TokenBuf[0], Length(TokenBuf));
          dest.WriteBuffer(DataBuf[0], SizeOfDataInToken);
    end;
    sc.clear;
    dest.Seek(0, sofrombeginning);
    sc.CopyFrom(dest, dest.Size);
    sc.Seek(0, sofrombeginning);
    dest.Free;
    res:=true;
end;

//Расчет контрольной суммы блока данных (DC - Data Checksum)
function  FlashTokenChekSum(Buf:Pointer; BufLen: integer): Word;
begin
     Result:=Word(Buf^);
     inc(Integer(Buf));dec(BufLen);
     inc(Integer(Buf));dec(BufLen);
     while BufLen > 0 do begin
     Result:=Result xor Word(Buf^);
     inc(Integer(Buf));dec(BufLen);
     inc(Integer(Buf));dec(BufLen);
     end;
end;

//Расчет контрольной суммы flash-tokens (последний байт - HC - Header Checksum)
function  FlashTokenCRC(Buf:Pointer; BufLen: integer): byte;
begin
     Result:=0;
     while BufLen > 0 do begin
     Result:=Result+Byte(Buf^);
     inc(Integer(Buf));
     dec(BufLen);
     end;
     Result:=Result xor $FF;
end;
end.
