Changeset 26 for IntelHexFile/UIntelHexFile.pas
- Timestamp:
- May 25, 2010, 1:51:46 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
IntelHexFile/UIntelHexFile.pas
r15 r26 4 4 5 5 uses 6 UTextFileStream, SysUtils; 6 Classes, UTextFileStream, SysUtils, Contnrs, UCommon, UMemoryStreamEx, 7 DateUtils; 7 8 8 9 type 9 TArrayofByte = array of Byte; 10 11 TIntelHexFile = class(TTextFileStream) 10 EFileCorrupted = class(Exception); 11 EChecksumError = class(Exception); 12 13 TIntelHexRecordType = (rtData, rtEndOfFile, rtSegmentAddress, rtExtendedAddress); 14 15 TMappedMemory = class(TMemoryStreamEx) 16 BaseAddress: Integer; 17 end; 18 19 { TIntelHexFile } 20 21 TIntelHexFile = class 22 private 23 function GetSize:Integer; 24 procedure WriteBlock(Block: TMappedMemory; StringList:TStringList); 25 function TwoComplement(Value: Byte): Byte; 12 26 public 13 function ReadContent: TArrayOfByte; 27 Blocks: TObjectList; // of TMappedMemory 28 BytePerLine: Byte; 29 procedure LoadFromFile(FileName: string); 30 procedure SaveToFile(FileName: string); 31 procedure LoadFromStringList(StringList:TStringList); 32 procedure SaveToStringList(StringList:TStringList); 33 procedure LoadFromBinFile(FileName: string); 34 procedure SaveToBinFile(FileName: string); 35 constructor Create; 36 destructor Destroy; override; 37 property Size: Integer read GetSize; 14 38 end; 15 39 … … 19 43 { TIntelHexFile } 20 44 21 function TIntelHexFile.ReadContent: TArrayOfByte; 45 function TIntelHexFile.GetSize:Integer; 46 var 47 I: Integer; 48 begin 49 Result := 0; 50 for I := 0 to Blocks.Count - 1 do 51 Result := Result + TMappedMemory(Blocks[I]).Size; 52 end; 53 54 procedure TIntelHexFile.WriteBlock(Block:TMappedMemory; StringList:TStringList) 55 ; 56 var 57 I: Integer; 58 L: Integer; 59 CheckSum: Byte; 60 OutputLine: string; 61 Count: Integer; 62 Line: TMemoryStreamEx; 63 begin 64 Line := TMemoryStreamEx.Create; 65 Block.Position := 0; 66 for L := 0 to (Block.Size div BytePerLine) do begin 67 Count := BytePerLine; 68 if Count > (Block.Size - Block.Position) then 69 Count := Block.Size - Block.Position; 70 if Count > 0 then begin 71 Line.Size := 4 + Count; 72 Line.Position := 0; 73 Line.WriteByte(Count); 74 Line.WriteByte(((Block.Position + Block.BaseAddress) shr 8) and $ff); 75 Line.WriteByte((Block.Position + Block.BaseAddress) and $ff); 76 Line.WriteByte(Integer(rtData)); 77 Line.WriteStreamPart(TStream(Block), Count); 78 79 CheckSum := TwoComplement(Line.Sum); 80 Line.WriteByte(CheckSum); 81 82 OutputLine := ':'; 83 Line.Position := 0; 84 for I := 0 to Line.Size - 1 do 85 OutputLine := OutputLine + IntToHex(Line.ReadByte, 2); 86 StringList.Add(OutputLine); 87 end; 88 end; 89 Line.Destroy; 90 end; 91 92 function TIntelHexFile.TwoComplement(Value:Byte):Byte; 93 begin 94 Result := (not Value + 1) and $ff; 95 end; 96 97 procedure TIntelHexFile.LoadFromFile(FileName: string); 98 var 99 StringList: TStringList; 100 begin 101 StringList := TStringList.Create; 102 StringList.LoadFromFile(UTF8Decode(FileName)); 103 LoadFromStringList(StringList); 104 StringList.Destroy; 105 end; 106 107 procedure TIntelHexFile.LoadFromStringList(StringList: TStringList); 22 108 var 23 109 Row: string; 24 110 DataCount: Byte; 25 RecordType: Byte;26 I: Integer; 27 C RC: Byte;28 ComputedCRC: Byte;29 Address: Word;111 RecordType: TIntelHexRecordType; 112 I: Integer; 113 CheckSum: Byte; 114 LastAddress: Integer; 115 Address: Integer; 30 116 SegmentAddress: Word; 31 117 ExtendedAddress: Word; 32 EndOfFile: Boolean; 33 34 function SplitString(var Text: string; Count: Word): string; 35 begin 36 Result := Copy(Text, 1, Count); 37 Delete(Text, 1, Count); 38 end; 39 40 begin 118 Block: TMappedMemory; 119 Line: TMemoryStreamEx; 120 begin 121 Line := TMemoryStreamEx.Create; 122 Blocks.Clear; 123 Block := nil; 124 LastAddress := -1; 41 125 ExtendedAddress := 0; 42 126 SegmentAddress := 0; 43 EndOfFile := False; 44 repeat 45 ComputedCRC := 0; 46 Row := ReadLn; 47 if SplitString(Row, 1) <> ':' then raise Exception.Create('File corrupted'); 48 for I := 0 to (Length(Row) div 2) - 2 do 49 ComputedCRC := ComputedCRC + StrToInt('$' + Row[I * 2 + 1] + Row[I * 2 + 2]); 50 ComputedCRC := not (ComputedCRC ) + 1; 51 52 DataCount := StrToInt('$' + SplitString(Row, 2)); 53 Address := StrToInt('$' + SplitString(Row, 4)) + (SegmentAddress shl 4) + 54 (ExtendedAddress shl 16); 55 RecordType := StrToInt('$' + SplitString(Row, 2)); 127 for I := 0 to StringList.Count - 1 do begin 128 Row := Trim(StringList[I]); 129 if SplitString(Row, 1) <> ':' then 130 raise EFileCorrupted.Create('File corrupted'); 131 132 Line.Position := 0; 133 Line.Size := Length(Row) div 2; 134 while Length(Row) > 0 do 135 Line.WriteByte(StrToInt('$' + SplitString(Row, 2))); 136 137 // Read CheckSum 138 Line.Position := Line.Size - 1; 139 CheckSum := Line.ReadByte; 140 Line.Size := Line.Size - 1; 141 if CheckSum <> TwoComplement(Line.Sum) then 142 raise EChecksumError.Create('Checksum error ' + Row); 143 144 Line.Position := 0; 145 DataCount := Line.ReadByte; 146 Address := ((Line.ReadByte shl 8) or Line.ReadByte) + 147 + (SegmentAddress shl 4) + (ExtendedAddress shl 16); 148 149 if LastAddress <> Address then begin 150 Block := TMappedMemory.Create; 151 Block.BaseAddress := Address; 152 Blocks.Add(Block); 153 end; 154 RecordType := TIntelHexRecordType(Line.ReadByte); 56 155 case RecordType of 57 0: begin // Data 58 if Length(Result) < (Address + DataCount) then 59 SetLength(Result, Address + DataCount); 60 for I := 0 to DataCount - 1 do begin 61 Result[Address + I] := StrToInt('$' + SplitString(Row, 2)); 62 end; 63 end; 64 1: begin // End-of-file 65 EndOfFile := True; 66 end; 67 2: begin // Segment address 68 SegmentAddress := StrToInt('$' + SplitString(Row, 4)); 156 rtData: begin 157 Block.WriteStreamPart(Line, Line.Size - Line.Position); 158 end; 159 rtEndOfFile: begin 160 Break; 161 end; 162 rtSegmentAddress: begin 163 SegmentAddress := (Line.ReadByte shl 8) or Line.ReadByte; 69 164 ExtendedAddress := 0; 70 165 end; 71 4: begin // Linear extended address72 ExtendedAddress := StrToInt('$' + SplitString(Row, 4));166 rtExtendedAddress: begin 167 ExtendedAddress := (Line.ReadByte shl 8) or Line.ReadByte; 73 168 SegmentAddress := 0; 74 169 end; 75 170 end; 76 CRC := StrToInt('$' + SplitString(Row, 2)); 77 if CRC <> ComputedCRC then raise Exception.Create('Checksum error'); 78 until Eof or EndOfFile; 171 LastAddress := Address + DataCount; 172 end; 173 Line.Destroy; 174 end; 175 176 procedure TIntelHexFile.SaveToFile(FileName: string); 177 var 178 StringList: TStringList; 179 begin 180 StringList := TStringList.Create; 181 SaveToStringList(StringList); 182 StringList.SaveToFile(UTF8Decode(FileName)); 183 StringList.Destroy; 184 end; 185 186 procedure TIntelHexFile.SaveToStringList(StringList: TStringList); 187 var 188 I: Integer; 189 Line: TMemoryStreamEx; 190 OutputLine: string; 191 CheckSum: Byte; 192 begin 193 StringList.Clear; 194 195 for I := 0 to Blocks.Count - 1 do 196 WriteBlock(TMappedMemory(Blocks[I]), StringList); 197 198 Line := TMemoryStreamEx.Create; 199 200 // Write EndOfFile 201 Line.Size := 4; 202 Line.WriteByte(0); 203 Line.WriteByte(0); 204 Line.WriteByte(0); 205 Line.WriteByte(Integer(rtEndOfFile)); 206 207 CheckSum := TwoComplement(Line.Sum); 208 209 Line.Position := 0; 210 OutputLine := ':'; 211 for I := 0 to Line.Size - 1 do 212 OutputLine := OutputLine + IntToHex(Line.ReadByte, 2); 213 OutputLine := OutputLine + IntToHex(CheckSum, 2); 214 StringList.Add(OutputLine); 215 216 Line.Destroy; 217 end; 218 219 procedure TIntelHexFile.LoadFromBinFile(FileName:string); 220 var 221 NewBlock: TMappedMemory; 222 begin 223 // TODO: analyze empty areas with FF bytes and split them to blocks 224 Blocks.Clear; 225 NewBlock := TMappedMemory.Create; 226 NewBlock.LoadFromFile(UTF8Decode(FileName)); 227 end; 228 229 procedure TIntelHexFile.SaveToBinFile(FileName:string); 230 var 231 MergedMemory: TMemoryStreamEx; 232 I: Integer; 233 begin 234 MergedMemory := TMemoryStreamEx.Create; 235 236 // Fill unused space by unused data (FF) 237 for I := 0 to Blocks.Count - 1 do 238 if MergedMemory.Size < (TMappedMemory(Blocks[I]).BaseAddress + TMappedMemory(Blocks[I]).Size) then 239 MergedMemory.Size := (TMappedMemory(Blocks[I]).BaseAddress + TMappedMemory(Blocks[I]).Size); 240 MergedMemory.FillByte($ff, MergedMemory.Size); 241 242 // Write all memory blocks 243 for I := 0 to Blocks.Count - 1 do begin 244 MergedMemory.Position := TMappedMemory(Blocks[I]).BaseAddress; 245 MergedMemory.WriteStream(TMappedMemory(Blocks[I]), TMappedMemory(Blocks[I]).Size); 246 end; 247 MergedMemory.SaveToFile(UTF8Decode(FileName)); 248 MergedMemory.Destroy; 249 end; 250 251 constructor TIntelHexFile.Create; 252 begin 253 Blocks := TObjectList.Create; 254 BytePerLine := 16; 255 end; 256 257 destructor TIntelHexFile.Destroy; 258 begin 259 Blocks.Destroy; 260 inherited Destroy; 79 261 end; 80 262
Note:
See TracChangeset
for help on using the changeset viewer.