]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/common/StSRecordFile.cpp
Unified codebase for TX28, TX48, TX51, TX53
[karo-tx-uboot.git] / tools / elftosb / common / StSRecordFile.cpp
1 /*
2  * File:        StSRecordFile.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7
8 #include "stdafx.h"
9 #include "StSRecordFile.h"
10 #include "string.h"
11
12 StSRecordFile::StSRecordFile(std::istream & inStream)
13 :       m_stream(inStream)
14 {
15 }
16
17 //! Frees any data allocated as part of an S-record.
18 StSRecordFile::~StSRecordFile()
19 {
20         const_iterator it;
21         for (it = m_records.begin(); it != m_records.end(); it++)
22         {
23                 SRecord & theRecord = (SRecord &)*it;
24                 if (theRecord.m_data)
25                 {
26                         delete [] theRecord.m_data;
27                         theRecord.m_data = NULL;
28                 }
29         }
30 }
31
32 //! Just looks for "S[0-9]" as the first two characters of the file.
33 bool StSRecordFile::isSRecordFile()
34 {
35         int savePosition = m_stream.tellg();
36         m_stream.seekg(0, std::ios_base::beg);
37         
38         char buffer[2];
39         m_stream.read(buffer, 2);
40         bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
41         
42         m_stream.seekg(savePosition, std::ios_base::beg);
43         
44         return isSRecord;
45 }
46
47 //! Extract records one line at a time and hand them to the parseLine()
48 //! method. Either CR, LF, or CRLF line endings are supported. The input
49 //! stream is read until EOF.
50 //! The parse() method must be called after the object has been constructed
51 //! before any of the records will become accessible.
52 //! \exception StSRecordParseException will be thrown if any error occurs while
53 //!             parsing the input.
54 void StSRecordFile::parse()
55 {
56         // back to start of stream
57         m_stream.seekg(0, std::ios_base::beg);
58         
59         std::string thisLine;
60         
61         do {
62                 char thisChar;
63                 m_stream.get(thisChar);
64                 
65                 if (thisChar == '\r' || thisChar == '\n')
66                 {
67                         // skip the LF in a CRLF
68                         if (thisChar == '\r' && m_stream.peek() == '\n')
69                                 m_stream.ignore();
70                         
71                         // parse line if it's not empty
72                         if (!thisLine.empty())
73                         {
74                                 parseLine(thisLine);
75                         
76                                 // reset line
77                                 thisLine.clear();
78                         }
79                 }
80                 else
81                 {
82                         thisLine += thisChar;
83                 }
84         } while (!m_stream.eof());
85 }
86
87 bool StSRecordFile::isHexDigit(char c)
88 {
89         return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
90 }
91
92 int StSRecordFile::hexDigitToInt(char digit)
93 {
94         if (isdigit(digit))
95                 return digit - '0';
96         else if (digit >= 'a' && digit <= 'f')
97                 return 10 + digit - 'a';
98         else if (digit >= 'A' && digit <= 'F')
99                 return 10 + digit - 'A';
100         
101         // unknow char
102         return 0;
103 }
104
105 //! \exception StSRecordParseException is thrown if either of the nibble characters
106 //!             is not a valid hex digit.
107 int StSRecordFile::readHexByte(std::string & inString, int inIndex)
108 {
109         char nibbleCharHi= inString[inIndex];
110         char nibbleCharLo = inString[inIndex + 1];
111         
112         // must be hex digits
113         if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
114     {
115                 throw StSRecordParseException("invalid hex digit");
116     }
117         
118         return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
119 }
120
121 //! \brief Parses individual S-records.
122 //!
123 //! Takes a single S-record line as input and appends a new SRecord struct
124 //! to the m_records vector.
125 //! \exception StSRecordParseException will be thrown if any error occurs while
126 //!             parsing \a inLine.
127 void StSRecordFile::parseLine(std::string & inLine)
128 {
129         int checksum = 0;
130         SRecord newRecord;
131         memset(&newRecord, 0, sizeof(newRecord));
132         
133         // must start with "S" and be at least a certain length
134         if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
135     {
136         throw StSRecordParseException("invalid record length");
137     }
138
139         // parse type field
140         char typeChar = inLine[1];
141         if (!isdigit(typeChar))
142     {
143                 throw StSRecordParseException("invalid S-record type");
144     }
145         newRecord.m_type = typeChar - '0';
146         
147         // parse count field
148         newRecord.m_count = readHexByte(inLine, 2);
149         checksum += newRecord.m_count;
150         
151         // verify the record length now that we know the count
152         if (inLine.length() != 4 + newRecord.m_count * 2)
153     {
154                 throw StSRecordParseException("invalid record length");
155     }
156         
157         // get address length
158         int addressLength;      // len in bytes
159         bool hasData = false;
160         switch (newRecord.m_type)
161         {
162                 case 0:     // contains header information
163                         addressLength = 2;
164                         hasData = true;
165                         break;
166                 case 1:     // data record with 2-byte address
167                         addressLength = 2;
168                         hasData = true;
169                         break;
170                 case 2:     // data record with 3-byte address
171                         addressLength = 3;
172                         hasData = true;
173                         break;
174                 case 3:     // data record with 4-byte address
175                         addressLength = 4;
176                         hasData = true;
177                         break;
178                 case 5:     // the 2-byte address field contains a count of all prior S1, S2, and S3 records
179                         addressLength = 2;
180                         break;
181                 case 7:     // entry point record with 4-byte address
182                         addressLength = 4;
183                         break;
184                 case 8:     // entry point record with 3-byte address
185                         addressLength = 3;
186                         break;
187                 case 9:     // entry point record with 2-byte address
188                         addressLength = 2;
189                         break;
190                 default:
191                         // unrecognized type
192                         //throw StSRecordParseException("unknown S-record type");
193             break;
194         }
195         
196         // read address
197         int address = 0;
198         int i;
199         for (i=0; i < addressLength; ++i)
200         {
201                 int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
202                 address = (address << 8) | addressByte;
203                 checksum += addressByte;
204         }
205         newRecord.m_address = address;
206                 
207         // read data
208         if (hasData)
209         {
210                 int dataStartCharIndex = 4 + addressLength * 2;
211                 int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
212                 uint8_t * data = new uint8_t[dataLength];
213                 
214                 for (i=0; i < dataLength; ++i)
215                 {
216                         int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
217                         data[i] = dataByte;
218                         checksum += dataByte;
219                 }
220                 
221                 newRecord.m_data = data;
222                 newRecord.m_dataCount = dataLength;
223         }
224         
225         // read and compare checksum byte
226         checksum = (~checksum) & 0xff;  // low byte of one's complement of sum of other bytes
227         newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
228         if (checksum != newRecord.m_checksum)
229     {
230                 throw StSRecordParseException("invalid checksum");
231     }
232         
233         // now save the new S-record
234         m_records.push_back(newRecord);
235 }