1 // Scintilla source code edit control
2 /** @file LexHex.cxx
3 ** Lexers for Motorola S-Record, Intel HEX and Tektronix extended HEX.
4 **
5 ** Written by Markus Heidelberg
6 **/
7 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
9
10 /*
11 * Motorola S-Record
12 * ===============================
13 *
14 * Each record (line) is built as follows:
15 *
16 * field digits states
17 *
18 * +----------+
19 * | start | 1 ('S') SCE_HEX_RECSTART
20 * +----------+
21 * | type | 1 SCE_HEX_RECTYPE, (SCE_HEX_RECTYPE_UNKNOWN)
22 * +----------+
23 * | count | 2 SCE_HEX_BYTECOUNT, SCE_HEX_BYTECOUNT_WRONG
24 * +----------+
25 * | address | 4/6/8 SCE_HEX_NOADDRESS, SCE_HEX_DATAADDRESS, SCE_HEX_RECCOUNT, SCE_HEX_STARTADDRESS, (SCE_HEX_ADDRESSFIELD_UNKNOWN)
26 * +----------+
27 * | data | 0..504/502/500 SCE_HEX_DATA_ODD, SCE_HEX_DATA_EVEN, SCE_HEX_DATA_EMPTY, (SCE_HEX_DATA_UNKNOWN)
28 * +----------+
29 * | checksum | 2 SCE_HEX_CHECKSUM, SCE_HEX_CHECKSUM_WRONG
30 * +----------+
31 *
32 *
33 * Intel HEX
34 * ===============================
35 *
36 * Each record (line) is built as follows:
37 *
38 * field digits states
39 *
40 * +----------+
41 * | start | 1 (':') SCE_HEX_RECSTART
42 * +----------+
43 * | count | 2 SCE_HEX_BYTECOUNT, SCE_HEX_BYTECOUNT_WRONG
44 * +----------+
45 * | address | 4 SCE_HEX_NOADDRESS, SCE_HEX_DATAADDRESS, (SCE_HEX_ADDRESSFIELD_UNKNOWN)
46 * +----------+
47 * | type | 2 SCE_HEX_RECTYPE, (SCE_HEX_RECTYPE_UNKNOWN)
48 * +----------+
49 * | data | 0..510 SCE_HEX_DATA_ODD, SCE_HEX_DATA_EVEN, SCE_HEX_DATA_EMPTY, SCE_HEX_EXTENDEDADDRESS, SCE_HEX_STARTADDRESS, (SCE_HEX_DATA_UNKNOWN)
50 * +----------+
51 * | checksum | 2 SCE_HEX_CHECKSUM, SCE_HEX_CHECKSUM_WRONG
52 * +----------+
53 *
54 *
55 * Folding:
56 *
57 * Data records (type 0x00), which follow an extended address record (type
58 * 0x02 or 0x04), can be folded. The extended address record is the fold
59 * point at fold level 0, the corresponding data records are set to level 1.
60 *
61 * Any record, which is not a data record, sets the fold level back to 0.
62 * Any line, which is not a record (blank lines and lines starting with a
63 * character other than ':'), leaves the fold level unchanged.
64 *
65 *
66 * Tektronix extended HEX
67 * ===============================
68 *
69 * Each record (line) is built as follows:
70 *
71 * field digits states
72 *
73 * +----------+
74 * | start | 1 ('%') SCE_HEX_RECSTART
75 * +----------+
76 * | length | 2 SCE_HEX_BYTECOUNT, SCE_HEX_BYTECOUNT_WRONG
77 * +----------+
78 * | type | 1 SCE_HEX_RECTYPE, (SCE_HEX_RECTYPE_UNKNOWN)
79 * +----------+
80 * | checksum | 2 SCE_HEX_CHECKSUM, SCE_HEX_CHECKSUM_WRONG
81 * +----------+
82 * | address | 9 SCE_HEX_DATAADDRESS, SCE_HEX_STARTADDRESS, (SCE_HEX_ADDRESSFIELD_UNKNOWN)
83 * +----------+
84 * | data | 0..241 SCE_HEX_DATA_ODD, SCE_HEX_DATA_EVEN
85 * +----------+
86 *
87 *
88 * General notes for all lexers
89 * ===============================
90 *
91 * - Depending on where the helper functions are invoked, some of them have to
92 * read beyond the current position. In case of malformed data (record too
93 * short), it has to be ensured that this either does not have bad influence
94 * or will be captured deliberately.
95 *
96 * - States in parentheses in the upper format descriptions indicate that they
97 * should not appear in a valid hex file.
98 *
99 * - State SCE_HEX_GARBAGE means garbage data after the intended end of the
100 * record, the line is too long then. This state is used in all lexers.
101 */
102
103 #include <stdlib.h>
104 #include <string.h>
105 #include <stdio.h>
106 #include <stdarg.h>
107 #include <assert.h>
108 #include <ctype.h>
109
110 #include "ILexer.h"
111 #include "Scintilla.h"
112 #include "SciLexer.h"
113
114 #include "WordList.h"
115 #include "LexAccessor.h"
116 #include "Accessor.h"
117 #include "StyleContext.h"
118 #include "CharacterSet.h"
119 #include "LexerModule.h"
120
121 using namespace Scintilla;
122
123 // prototypes for general helper functions
124 static inline bool IsNewline(const int ch);
125 static int GetHexaNibble(char hd);
126 static int GetHexaChar(char hd1, char hd2);
127 static int GetHexaChar(Sci_PositionU pos, Accessor &styler);
128 static bool ForwardWithinLine(StyleContext &sc, Sci_Position nb = 1);
129 static bool PosInSameRecord(Sci_PositionU pos1, Sci_PositionU pos2, Accessor &styler);
130 static Sci_Position CountByteCount(Sci_PositionU startPos, Sci_Position uncountedDigits, Accessor &styler);
131 static int CalcChecksum(Sci_PositionU startPos, Sci_Position cnt, bool twosCompl, Accessor &styler);
132
133 // prototypes for file format specific helper functions
134 static Sci_PositionU GetSrecRecStartPosition(Sci_PositionU pos, Accessor &styler);
135 static int GetSrecByteCount(Sci_PositionU recStartPos, Accessor &styler);
136 static Sci_Position CountSrecByteCount(Sci_PositionU recStartPos, Accessor &styler);
137 static int GetSrecAddressFieldSize(Sci_PositionU recStartPos, Accessor &styler);
138 static int GetSrecAddressFieldType(Sci_PositionU recStartPos, Accessor &styler);
139 static int GetSrecDataFieldType(Sci_PositionU recStartPos, Accessor &styler);
140 static Sci_Position GetSrecRequiredDataFieldSize(Sci_PositionU recStartPos, Accessor &styler);
141 static int GetSrecChecksum(Sci_PositionU recStartPos, Accessor &styler);
142 static int CalcSrecChecksum(Sci_PositionU recStartPos, Accessor &styler);
143
144 static Sci_PositionU GetIHexRecStartPosition(Sci_PositionU pos, Accessor &styler);
145 static int GetIHexByteCount(Sci_PositionU recStartPos, Accessor &styler);
146 static Sci_Position CountIHexByteCount(Sci_PositionU recStartPos, Accessor &styler);
147 static int GetIHexAddressFieldType(Sci_PositionU recStartPos, Accessor &styler);
148 static int GetIHexDataFieldType(Sci_PositionU recStartPos, Accessor &styler);
149 static int GetIHexRequiredDataFieldSize(Sci_PositionU recStartPos, Accessor &styler);
150 static int GetIHexChecksum(Sci_PositionU recStartPos, Accessor &styler);
151 static int CalcIHexChecksum(Sci_PositionU recStartPos, Accessor &styler);
152
153 static int GetTEHexDigitCount(Sci_PositionU recStartPos, Accessor &styler);
154 static Sci_Position CountTEHexDigitCount(Sci_PositionU recStartPos, Accessor &styler);
155 static int GetTEHexAddressFieldType(Sci_PositionU recStartPos, Accessor &styler);
156 static int GetTEHexChecksum(Sci_PositionU recStartPos, Accessor &styler);
157 static int CalcTEHexChecksum(Sci_PositionU recStartPos, Accessor &styler);
158
IsNewline(const int ch)159 static inline bool IsNewline(const int ch)
160 {
161 return (ch == '\n' || ch == '\r');
162 }
163
GetHexaNibble(char hd)164 static int GetHexaNibble(char hd)
165 {
166 int hexValue = 0;
167
168 if (hd >= '0' && hd <= '9') {
169 hexValue += hd - '0';
170 } else if (hd >= 'A' && hd <= 'F') {
171 hexValue += hd - 'A' + 10;
172 } else if (hd >= 'a' && hd <= 'f') {
173 hexValue += hd - 'a' + 10;
174 } else {
175 return -1;
176 }
177
178 return hexValue;
179 }
180
GetHexaChar(char hd1,char hd2)181 static int GetHexaChar(char hd1, char hd2)
182 {
183 int hexValue = 0;
184
185 if (hd1 >= '0' && hd1 <= '9') {
186 hexValue += 16 * (hd1 - '0');
187 } else if (hd1 >= 'A' && hd1 <= 'F') {
188 hexValue += 16 * (hd1 - 'A' + 10);
189 } else if (hd1 >= 'a' && hd1 <= 'f') {
190 hexValue += 16 * (hd1 - 'a' + 10);
191 } else {
192 return -1;
193 }
194
195 if (hd2 >= '0' && hd2 <= '9') {
196 hexValue += hd2 - '0';
197 } else if (hd2 >= 'A' && hd2 <= 'F') {
198 hexValue += hd2 - 'A' + 10;
199 } else if (hd2 >= 'a' && hd2 <= 'f') {
200 hexValue += hd2 - 'a' + 10;
201 } else {
202 return -1;
203 }
204
205 return hexValue;
206 }
207
GetHexaChar(Sci_PositionU pos,Accessor & styler)208 static int GetHexaChar(Sci_PositionU pos, Accessor &styler)
209 {
210 char highNibble, lowNibble;
211
212 highNibble = styler.SafeGetCharAt(pos);
213 lowNibble = styler.SafeGetCharAt(pos + 1);
214
215 return GetHexaChar(highNibble, lowNibble);
216 }
217
218 // Forward <nb> characters, but abort (and return false) if hitting the line
219 // end. Return true if forwarding within the line was possible.
220 // Avoids influence on highlighting of the subsequent line if the current line
221 // is malformed (too short).
ForwardWithinLine(StyleContext & sc,Sci_Position nb)222 static bool ForwardWithinLine(StyleContext &sc, Sci_Position nb)
223 {
224 for (Sci_Position i = 0; i < nb; i++) {
225 if (sc.atLineEnd) {
226 // line is too short
227 sc.SetState(SCE_HEX_DEFAULT);
228 sc.Forward();
229 return false;
230 } else {
231 sc.Forward();
232 }
233 }
234
235 return true;
236 }
237
238 // Checks whether the given positions are in the same record.
PosInSameRecord(Sci_PositionU pos1,Sci_PositionU pos2,Accessor & styler)239 static bool PosInSameRecord(Sci_PositionU pos1, Sci_PositionU pos2, Accessor &styler)
240 {
241 return styler.GetLine(pos1) == styler.GetLine(pos2);
242 }
243
244 // Count the number of digit pairs from <startPos> till end of record, ignoring
245 // <uncountedDigits> digits.
246 // If the record is too short, a negative count may be returned.
CountByteCount(Sci_PositionU startPos,Sci_Position uncountedDigits,Accessor & styler)247 static Sci_Position CountByteCount(Sci_PositionU startPos, Sci_Position uncountedDigits, Accessor &styler)
248 {
249 Sci_Position cnt;
250 Sci_PositionU pos;
251
252 pos = startPos;
253
254 while (!IsNewline(styler.SafeGetCharAt(pos, '\n'))) {
255 pos++;
256 }
257
258 // number of digits in this line minus number of digits of uncounted fields
259 cnt = static_cast<Sci_Position>(pos - startPos) - uncountedDigits;
260
261 // Prepare round up if odd (digit pair incomplete), this way the byte
262 // count is considered to be valid if the checksum is incomplete.
263 if (cnt >= 0) {
264 cnt++;
265 }
266
267 // digit pairs
268 cnt /= 2;
269
270 return cnt;
271 }
272
273 // Calculate the checksum of the record.
274 // <startPos> is the position of the first character of the starting digit
275 // pair, <cnt> is the number of digit pairs.
CalcChecksum(Sci_PositionU startPos,Sci_Position cnt,bool twosCompl,Accessor & styler)276 static int CalcChecksum(Sci_PositionU startPos, Sci_Position cnt, bool twosCompl, Accessor &styler)
277 {
278 int cs = 0;
279
280 for (Sci_PositionU pos = startPos; pos < startPos + cnt; pos += 2) {
281 int val = GetHexaChar(pos, styler);
282
283 if (val < 0) {
284 return val;
285 }
286
287 // overflow does not matter
288 cs += val;
289 }
290
291 if (twosCompl) {
292 // low byte of two's complement
293 return -cs & 0xFF;
294 } else {
295 // low byte of one's complement
296 return ~cs & 0xFF;
297 }
298 }
299
300 // Get the position of the record "start" field (first character in line) in
301 // the record around position <pos>.
GetSrecRecStartPosition(Sci_PositionU pos,Accessor & styler)302 static Sci_PositionU GetSrecRecStartPosition(Sci_PositionU pos, Accessor &styler)
303 {
304 while (styler.SafeGetCharAt(pos) != 'S') {
305 pos--;
306 }
307
308 return pos;
309 }
310
311 // Get the value of the "byte count" field, it counts the number of bytes in
312 // the subsequent fields ("address", "data" and "checksum" fields).
GetSrecByteCount(Sci_PositionU recStartPos,Accessor & styler)313 static int GetSrecByteCount(Sci_PositionU recStartPos, Accessor &styler)
314 {
315 int val;
316
317 val = GetHexaChar(recStartPos + 2, styler);
318 if (val < 0) {
319 val = 0;
320 }
321
322 return val;
323 }
324
325 // Count the number of digit pairs for the "address", "data" and "checksum"
326 // fields in this record. Has to be equal to the "byte count" field value.
327 // If the record is too short, a negative count may be returned.
CountSrecByteCount(Sci_PositionU recStartPos,Accessor & styler)328 static Sci_Position CountSrecByteCount(Sci_PositionU recStartPos, Accessor &styler)
329 {
330 return CountByteCount(recStartPos, 4, styler);
331 }
332
333 // Get the size of the "address" field.
GetSrecAddressFieldSize(Sci_PositionU recStartPos,Accessor & styler)334 static int GetSrecAddressFieldSize(Sci_PositionU recStartPos, Accessor &styler)
335 {
336 switch (styler.SafeGetCharAt(recStartPos + 1)) {
337 case '0':
338 case '1':
339 case '5':
340 case '9':
341 return 2; // 16 bit
342
343 case '2':
344 case '6':
345 case '8':
346 return 3; // 24 bit
347
348 case '3':
349 case '7':
350 return 4; // 32 bit
351
352 default:
353 return 0;
354 }
355 }
356
357 // Get the type of the "address" field content.
GetSrecAddressFieldType(Sci_PositionU recStartPos,Accessor & styler)358 static int GetSrecAddressFieldType(Sci_PositionU recStartPos, Accessor &styler)
359 {
360 switch (styler.SafeGetCharAt(recStartPos + 1)) {
361 case '0':
362 return SCE_HEX_NOADDRESS;
363
364 case '1':
365 case '2':
366 case '3':
367 return SCE_HEX_DATAADDRESS;
368
369 case '5':
370 case '6':
371 return SCE_HEX_RECCOUNT;
372
373 case '7':
374 case '8':
375 case '9':
376 return SCE_HEX_STARTADDRESS;
377
378 default: // handle possible format extension in the future
379 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
380 }
381 }
382
383 // Get the type of the "data" field content.
GetSrecDataFieldType(Sci_PositionU recStartPos,Accessor & styler)384 static int GetSrecDataFieldType(Sci_PositionU recStartPos, Accessor &styler)
385 {
386 switch (styler.SafeGetCharAt(recStartPos + 1)) {
387 case '0':
388 case '1':
389 case '2':
390 case '3':
391 return SCE_HEX_DATA_ODD;
392
393 case '5':
394 case '6':
395 case '7':
396 case '8':
397 case '9':
398 return SCE_HEX_DATA_EMPTY;
399
400 default: // handle possible format extension in the future
401 return SCE_HEX_DATA_UNKNOWN;
402 }
403 }
404
405 // Get the required size of the "data" field. Useless for block header and
406 // ordinary data records (type S0, S1, S2, S3), return the value calculated
407 // from the "byte count" and "address field" size in this case.
GetSrecRequiredDataFieldSize(Sci_PositionU recStartPos,Accessor & styler)408 static Sci_Position GetSrecRequiredDataFieldSize(Sci_PositionU recStartPos, Accessor &styler)
409 {
410 switch (styler.SafeGetCharAt(recStartPos + 1)) {
411 case '5':
412 case '6':
413 case '7':
414 case '8':
415 case '9':
416 return 0;
417
418 default:
419 return GetSrecByteCount(recStartPos, styler)
420 - GetSrecAddressFieldSize(recStartPos, styler)
421 - 1; // -1 for checksum field
422 }
423 }
424
425 // Get the value of the "checksum" field.
GetSrecChecksum(Sci_PositionU recStartPos,Accessor & styler)426 static int GetSrecChecksum(Sci_PositionU recStartPos, Accessor &styler)
427 {
428 int byteCount;
429
430 byteCount = GetSrecByteCount(recStartPos, styler);
431
432 return GetHexaChar(recStartPos + 2 + byteCount * 2, styler);
433 }
434
435 // Calculate the checksum of the record.
CalcSrecChecksum(Sci_PositionU recStartPos,Accessor & styler)436 static int CalcSrecChecksum(Sci_PositionU recStartPos, Accessor &styler)
437 {
438 Sci_Position byteCount;
439
440 byteCount = GetSrecByteCount(recStartPos, styler);
441
442 // sum over "byte count", "address" and "data" fields (6..510 digits)
443 return CalcChecksum(recStartPos + 2, byteCount * 2, false, styler);
444 }
445
446 // Get the position of the record "start" field (first character in line) in
447 // the record around position <pos>.
GetIHexRecStartPosition(Sci_PositionU pos,Accessor & styler)448 static Sci_PositionU GetIHexRecStartPosition(Sci_PositionU pos, Accessor &styler)
449 {
450 while (styler.SafeGetCharAt(pos) != ':') {
451 pos--;
452 }
453
454 return pos;
455 }
456
457 // Get the value of the "byte count" field, it counts the number of bytes in
458 // the "data" field.
GetIHexByteCount(Sci_PositionU recStartPos,Accessor & styler)459 static int GetIHexByteCount(Sci_PositionU recStartPos, Accessor &styler)
460 {
461 int val;
462
463 val = GetHexaChar(recStartPos + 1, styler);
464 if (val < 0) {
465 val = 0;
466 }
467
468 return val;
469 }
470
471 // Count the number of digit pairs for the "data" field in this record. Has to
472 // be equal to the "byte count" field value.
473 // If the record is too short, a negative count may be returned.
CountIHexByteCount(Sci_PositionU recStartPos,Accessor & styler)474 static Sci_Position CountIHexByteCount(Sci_PositionU recStartPos, Accessor &styler)
475 {
476 return CountByteCount(recStartPos, 11, styler);
477 }
478
479 // Get the type of the "address" field content.
GetIHexAddressFieldType(Sci_PositionU recStartPos,Accessor & styler)480 static int GetIHexAddressFieldType(Sci_PositionU recStartPos, Accessor &styler)
481 {
482 if (!PosInSameRecord(recStartPos, recStartPos + 7, styler)) {
483 // malformed (record too short)
484 // type cannot be determined
485 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
486 }
487
488 switch (GetHexaChar(recStartPos + 7, styler)) {
489 case 0x00:
490 return SCE_HEX_DATAADDRESS;
491
492 case 0x01:
493 case 0x02:
494 case 0x03:
495 case 0x04:
496 case 0x05:
497 return SCE_HEX_NOADDRESS;
498
499 default: // handle possible format extension in the future
500 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
501 }
502 }
503
504 // Get the type of the "data" field content.
GetIHexDataFieldType(Sci_PositionU recStartPos,Accessor & styler)505 static int GetIHexDataFieldType(Sci_PositionU recStartPos, Accessor &styler)
506 {
507 switch (GetHexaChar(recStartPos + 7, styler)) {
508 case 0x00:
509 return SCE_HEX_DATA_ODD;
510
511 case 0x01:
512 return SCE_HEX_DATA_EMPTY;
513
514 case 0x02:
515 case 0x04:
516 return SCE_HEX_EXTENDEDADDRESS;
517
518 case 0x03:
519 case 0x05:
520 return SCE_HEX_STARTADDRESS;
521
522 default: // handle possible format extension in the future
523 return SCE_HEX_DATA_UNKNOWN;
524 }
525 }
526
527 // Get the required size of the "data" field. Useless for an ordinary data
528 // record (type 00), return the "byte count" in this case.
GetIHexRequiredDataFieldSize(Sci_PositionU recStartPos,Accessor & styler)529 static int GetIHexRequiredDataFieldSize(Sci_PositionU recStartPos, Accessor &styler)
530 {
531 switch (GetHexaChar(recStartPos + 7, styler)) {
532 case 0x01:
533 return 0;
534
535 case 0x02:
536 case 0x04:
537 return 2;
538
539 case 0x03:
540 case 0x05:
541 return 4;
542
543 default:
544 return GetIHexByteCount(recStartPos, styler);
545 }
546 }
547
548 // Get the value of the "checksum" field.
GetIHexChecksum(Sci_PositionU recStartPos,Accessor & styler)549 static int GetIHexChecksum(Sci_PositionU recStartPos, Accessor &styler)
550 {
551 int byteCount;
552
553 byteCount = GetIHexByteCount(recStartPos, styler);
554
555 return GetHexaChar(recStartPos + 9 + byteCount * 2, styler);
556 }
557
558 // Calculate the checksum of the record.
CalcIHexChecksum(Sci_PositionU recStartPos,Accessor & styler)559 static int CalcIHexChecksum(Sci_PositionU recStartPos, Accessor &styler)
560 {
561 int byteCount;
562
563 byteCount = GetIHexByteCount(recStartPos, styler);
564
565 // sum over "byte count", "address", "type" and "data" fields (8..518 digits)
566 return CalcChecksum(recStartPos + 1, 8 + byteCount * 2, true, styler);
567 }
568
569
570 // Get the value of the "record length" field, it counts the number of digits in
571 // the record excluding the percent.
GetTEHexDigitCount(Sci_PositionU recStartPos,Accessor & styler)572 static int GetTEHexDigitCount(Sci_PositionU recStartPos, Accessor &styler)
573 {
574 int val = GetHexaChar(recStartPos + 1, styler);
575 if (val < 0)
576 val = 0;
577
578 return val;
579 }
580
581 // Count the number of digits in this record. Has to
582 // be equal to the "record length" field value.
CountTEHexDigitCount(Sci_PositionU recStartPos,Accessor & styler)583 static Sci_Position CountTEHexDigitCount(Sci_PositionU recStartPos, Accessor &styler)
584 {
585 Sci_PositionU pos;
586
587 pos = recStartPos+1;
588
589 while (!IsNewline(styler.SafeGetCharAt(pos, '\n'))) {
590 pos++;
591 }
592
593 return static_cast<Sci_Position>(pos - (recStartPos+1));
594 }
595
596 // Get the type of the "address" field content.
GetTEHexAddressFieldType(Sci_PositionU recStartPos,Accessor & styler)597 static int GetTEHexAddressFieldType(Sci_PositionU recStartPos, Accessor &styler)
598 {
599 switch (styler.SafeGetCharAt(recStartPos + 3)) {
600 case '6':
601 return SCE_HEX_DATAADDRESS;
602
603 case '8':
604 return SCE_HEX_STARTADDRESS;
605
606 default: // handle possible format extension in the future
607 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
608 }
609 }
610
611 // Get the value of the "checksum" field.
GetTEHexChecksum(Sci_PositionU recStartPos,Accessor & styler)612 static int GetTEHexChecksum(Sci_PositionU recStartPos, Accessor &styler)
613 {
614 return GetHexaChar(recStartPos+4, styler);
615 }
616
617 // Calculate the checksum of the record (excluding the checksum field).
CalcTEHexChecksum(Sci_PositionU recStartPos,Accessor & styler)618 static int CalcTEHexChecksum(Sci_PositionU recStartPos, Accessor &styler)
619 {
620 Sci_PositionU pos = recStartPos +1;
621 Sci_PositionU length = GetTEHexDigitCount(recStartPos, styler);
622
623 int cs = GetHexaNibble(styler.SafeGetCharAt(pos++));//length
624 cs += GetHexaNibble(styler.SafeGetCharAt(pos++));//length
625
626 cs += GetHexaNibble(styler.SafeGetCharAt(pos++));//type
627
628 pos += 2;// jump over CS field
629
630 for (; pos <= recStartPos + length; ++pos) {
631 int val = GetHexaNibble(styler.SafeGetCharAt(pos));
632
633 if (val < 0) {
634 return val;
635 }
636
637 // overflow does not matter
638 cs += val;
639 }
640
641 // low byte
642 return cs & 0xFF;
643
644 }
645
ColouriseSrecDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)646 static void ColouriseSrecDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler)
647 {
648 StyleContext sc(startPos, length, initStyle, styler);
649
650 while (sc.More()) {
651 Sci_PositionU recStartPos;
652 Sci_Position reqByteCount;
653 Sci_Position dataFieldSize;
654 int byteCount, addrFieldSize, addrFieldType, dataFieldType;
655 int cs1, cs2;
656
657 switch (sc.state) {
658 case SCE_HEX_DEFAULT:
659 if (sc.atLineStart && sc.Match('S')) {
660 sc.SetState(SCE_HEX_RECSTART);
661 }
662 ForwardWithinLine(sc);
663 break;
664
665 case SCE_HEX_RECSTART:
666 recStartPos = sc.currentPos - 1;
667 addrFieldType = GetSrecAddressFieldType(recStartPos, styler);
668
669 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
670 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
671 } else {
672 sc.SetState(SCE_HEX_RECTYPE);
673 }
674
675 ForwardWithinLine(sc);
676 break;
677
678 case SCE_HEX_RECTYPE:
679 case SCE_HEX_RECTYPE_UNKNOWN:
680 recStartPos = sc.currentPos - 2;
681 byteCount = GetSrecByteCount(recStartPos, styler);
682 reqByteCount = GetSrecAddressFieldSize(recStartPos, styler)
683 + GetSrecRequiredDataFieldSize(recStartPos, styler)
684 + 1; // +1 for checksum field
685
686 if (byteCount == CountSrecByteCount(recStartPos, styler)
687 && byteCount == reqByteCount) {
688 sc.SetState(SCE_HEX_BYTECOUNT);
689 } else {
690 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
691 }
692
693 ForwardWithinLine(sc, 2);
694 break;
695
696 case SCE_HEX_BYTECOUNT:
697 case SCE_HEX_BYTECOUNT_WRONG:
698 recStartPos = sc.currentPos - 4;
699 addrFieldSize = GetSrecAddressFieldSize(recStartPos, styler);
700 addrFieldType = GetSrecAddressFieldType(recStartPos, styler);
701
702 sc.SetState(addrFieldType);
703 ForwardWithinLine(sc, addrFieldSize * 2);
704 break;
705
706 case SCE_HEX_NOADDRESS:
707 case SCE_HEX_DATAADDRESS:
708 case SCE_HEX_RECCOUNT:
709 case SCE_HEX_STARTADDRESS:
710 case SCE_HEX_ADDRESSFIELD_UNKNOWN:
711 recStartPos = GetSrecRecStartPosition(sc.currentPos, styler);
712 dataFieldType = GetSrecDataFieldType(recStartPos, styler);
713
714 // Using the required size here if possible has the effect that the
715 // checksum is highlighted at a fixed position after this field for
716 // specific record types, independent on the "byte count" value.
717 dataFieldSize = GetSrecRequiredDataFieldSize(recStartPos, styler);
718
719 sc.SetState(dataFieldType);
720
721 if (dataFieldType == SCE_HEX_DATA_ODD) {
722 for (int i = 0; i < dataFieldSize * 2; i++) {
723 if ((i & 0x3) == 0) {
724 sc.SetState(SCE_HEX_DATA_ODD);
725 } else if ((i & 0x3) == 2) {
726 sc.SetState(SCE_HEX_DATA_EVEN);
727 }
728
729 if (!ForwardWithinLine(sc)) {
730 break;
731 }
732 }
733 } else {
734 ForwardWithinLine(sc, dataFieldSize * 2);
735 }
736 break;
737
738 case SCE_HEX_DATA_ODD:
739 case SCE_HEX_DATA_EVEN:
740 case SCE_HEX_DATA_EMPTY:
741 case SCE_HEX_DATA_UNKNOWN:
742 recStartPos = GetSrecRecStartPosition(sc.currentPos, styler);
743 cs1 = CalcSrecChecksum(recStartPos, styler);
744 cs2 = GetSrecChecksum(recStartPos, styler);
745
746 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
747 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
748 } else {
749 sc.SetState(SCE_HEX_CHECKSUM);
750 }
751
752 ForwardWithinLine(sc, 2);
753 break;
754
755 case SCE_HEX_CHECKSUM:
756 case SCE_HEX_CHECKSUM_WRONG:
757 case SCE_HEX_GARBAGE:
758 // record finished or line too long
759 sc.SetState(SCE_HEX_GARBAGE);
760 ForwardWithinLine(sc);
761 break;
762
763 default:
764 // prevent endless loop in faulty state
765 sc.SetState(SCE_HEX_DEFAULT);
766 break;
767 }
768 }
769 sc.Complete();
770 }
771
ColouriseIHexDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)772 static void ColouriseIHexDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler)
773 {
774 StyleContext sc(startPos, length, initStyle, styler);
775
776 while (sc.More()) {
777 Sci_PositionU recStartPos;
778 int byteCount, addrFieldType, dataFieldSize, dataFieldType;
779 int cs1, cs2;
780
781 switch (sc.state) {
782 case SCE_HEX_DEFAULT:
783 if (sc.atLineStart && sc.Match(':')) {
784 sc.SetState(SCE_HEX_RECSTART);
785 }
786 ForwardWithinLine(sc);
787 break;
788
789 case SCE_HEX_RECSTART:
790 recStartPos = sc.currentPos - 1;
791 byteCount = GetIHexByteCount(recStartPos, styler);
792 dataFieldSize = GetIHexRequiredDataFieldSize(recStartPos, styler);
793
794 if (byteCount == CountIHexByteCount(recStartPos, styler)
795 && byteCount == dataFieldSize) {
796 sc.SetState(SCE_HEX_BYTECOUNT);
797 } else {
798 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
799 }
800
801 ForwardWithinLine(sc, 2);
802 break;
803
804 case SCE_HEX_BYTECOUNT:
805 case SCE_HEX_BYTECOUNT_WRONG:
806 recStartPos = sc.currentPos - 3;
807 addrFieldType = GetIHexAddressFieldType(recStartPos, styler);
808
809 sc.SetState(addrFieldType);
810 ForwardWithinLine(sc, 4);
811 break;
812
813 case SCE_HEX_NOADDRESS:
814 case SCE_HEX_DATAADDRESS:
815 case SCE_HEX_ADDRESSFIELD_UNKNOWN:
816 recStartPos = sc.currentPos - 7;
817 addrFieldType = GetIHexAddressFieldType(recStartPos, styler);
818
819 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
820 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
821 } else {
822 sc.SetState(SCE_HEX_RECTYPE);
823 }
824
825 ForwardWithinLine(sc, 2);
826 break;
827
828 case SCE_HEX_RECTYPE:
829 case SCE_HEX_RECTYPE_UNKNOWN:
830 recStartPos = sc.currentPos - 9;
831 dataFieldType = GetIHexDataFieldType(recStartPos, styler);
832
833 // Using the required size here if possible has the effect that the
834 // checksum is highlighted at a fixed position after this field for
835 // specific record types, independent on the "byte count" value.
836 dataFieldSize = GetIHexRequiredDataFieldSize(recStartPos, styler);
837
838 sc.SetState(dataFieldType);
839
840 if (dataFieldType == SCE_HEX_DATA_ODD) {
841 for (int i = 0; i < dataFieldSize * 2; i++) {
842 if ((i & 0x3) == 0) {
843 sc.SetState(SCE_HEX_DATA_ODD);
844 } else if ((i & 0x3) == 2) {
845 sc.SetState(SCE_HEX_DATA_EVEN);
846 }
847
848 if (!ForwardWithinLine(sc)) {
849 break;
850 }
851 }
852 } else {
853 ForwardWithinLine(sc, dataFieldSize * 2);
854 }
855 break;
856
857 case SCE_HEX_DATA_ODD:
858 case SCE_HEX_DATA_EVEN:
859 case SCE_HEX_DATA_EMPTY:
860 case SCE_HEX_EXTENDEDADDRESS:
861 case SCE_HEX_STARTADDRESS:
862 case SCE_HEX_DATA_UNKNOWN:
863 recStartPos = GetIHexRecStartPosition(sc.currentPos, styler);
864 cs1 = CalcIHexChecksum(recStartPos, styler);
865 cs2 = GetIHexChecksum(recStartPos, styler);
866
867 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
868 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
869 } else {
870 sc.SetState(SCE_HEX_CHECKSUM);
871 }
872
873 ForwardWithinLine(sc, 2);
874 break;
875
876 case SCE_HEX_CHECKSUM:
877 case SCE_HEX_CHECKSUM_WRONG:
878 case SCE_HEX_GARBAGE:
879 // record finished or line too long
880 sc.SetState(SCE_HEX_GARBAGE);
881 ForwardWithinLine(sc);
882 break;
883
884 default:
885 // prevent endless loop in faulty state
886 sc.SetState(SCE_HEX_DEFAULT);
887 break;
888 }
889 }
890 sc.Complete();
891 }
892
FoldIHexDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)893 static void FoldIHexDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler)
894 {
895 Sci_PositionU endPos = startPos + length;
896
897 Sci_Position lineCurrent = styler.GetLine(startPos);
898 int levelCurrent = SC_FOLDLEVELBASE;
899 if (lineCurrent > 0)
900 levelCurrent = styler.LevelAt(lineCurrent - 1);
901
902 Sci_PositionU lineStartNext = styler.LineStart(lineCurrent + 1);
903 int levelNext = SC_FOLDLEVELBASE; // default if no specific line found
904
905 for (Sci_PositionU i = startPos; i < endPos; i++) {
906 bool atEOL = i == (lineStartNext - 1);
907 int style = styler.StyleAt(i);
908
909 // search for specific lines
910 if (style == SCE_HEX_EXTENDEDADDRESS) {
911 // extended addres record
912 levelNext = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
913 } else if (style == SCE_HEX_DATAADDRESS
914 || (style == SCE_HEX_DEFAULT
915 && i == (Sci_PositionU)styler.LineStart(lineCurrent))) {
916 // data record or no record start code at all
917 if (levelCurrent & SC_FOLDLEVELHEADERFLAG) {
918 levelNext = SC_FOLDLEVELBASE + 1;
919 } else {
920 // continue level 0 or 1, no fold point
921 levelNext = levelCurrent;
922 }
923 }
924
925 if (atEOL || (i == endPos - 1)) {
926 styler.SetLevel(lineCurrent, levelNext);
927
928 lineCurrent++;
929 lineStartNext = styler.LineStart(lineCurrent + 1);
930 levelCurrent = levelNext;
931 levelNext = SC_FOLDLEVELBASE;
932 }
933 }
934 }
935
ColouriseTEHexDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)936 static void ColouriseTEHexDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler)
937 {
938 StyleContext sc(startPos, length, initStyle, styler);
939
940 while (sc.More()) {
941 Sci_PositionU recStartPos;
942 int digitCount, addrFieldType;
943 int cs1, cs2;
944
945 switch (sc.state) {
946 case SCE_HEX_DEFAULT:
947 if (sc.atLineStart && sc.Match('%')) {
948 sc.SetState(SCE_HEX_RECSTART);
949 }
950 ForwardWithinLine(sc);
951 break;
952
953 case SCE_HEX_RECSTART:
954
955 recStartPos = sc.currentPos - 1;
956
957 if (GetTEHexDigitCount(recStartPos, styler) == CountTEHexDigitCount(recStartPos, styler)) {
958 sc.SetState(SCE_HEX_BYTECOUNT);
959 } else {
960 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
961 }
962
963 ForwardWithinLine(sc, 2);
964 break;
965
966 case SCE_HEX_BYTECOUNT:
967 case SCE_HEX_BYTECOUNT_WRONG:
968 recStartPos = sc.currentPos - 3;
969 addrFieldType = GetTEHexAddressFieldType(recStartPos, styler);
970
971 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
972 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
973 } else {
974 sc.SetState(SCE_HEX_RECTYPE);
975 }
976
977 ForwardWithinLine(sc);
978 break;
979
980 case SCE_HEX_RECTYPE:
981 case SCE_HEX_RECTYPE_UNKNOWN:
982 recStartPos = sc.currentPos - 4;
983 cs1 = CalcTEHexChecksum(recStartPos, styler);
984 cs2 = GetTEHexChecksum(recStartPos, styler);
985
986 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
987 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
988 } else {
989 sc.SetState(SCE_HEX_CHECKSUM);
990 }
991
992 ForwardWithinLine(sc, 2);
993 break;
994
995
996 case SCE_HEX_CHECKSUM:
997 case SCE_HEX_CHECKSUM_WRONG:
998 recStartPos = sc.currentPos - 6;
999 addrFieldType = GetTEHexAddressFieldType(recStartPos, styler);
1000
1001 sc.SetState(addrFieldType);
1002 ForwardWithinLine(sc, 9);
1003 break;
1004
1005 case SCE_HEX_DATAADDRESS:
1006 case SCE_HEX_STARTADDRESS:
1007 case SCE_HEX_ADDRESSFIELD_UNKNOWN:
1008 recStartPos = sc.currentPos - 15;
1009 digitCount = GetTEHexDigitCount(recStartPos, styler) - 14;
1010
1011 sc.SetState(SCE_HEX_DATA_ODD);
1012
1013 for (int i = 0; i < digitCount; i++) {
1014 if ((i & 0x3) == 0) {
1015 sc.SetState(SCE_HEX_DATA_ODD);
1016 } else if ((i & 0x3) == 2) {
1017 sc.SetState(SCE_HEX_DATA_EVEN);
1018 }
1019
1020 if (!ForwardWithinLine(sc)) {
1021 break;
1022 }
1023 }
1024 break;
1025
1026 case SCE_HEX_DATA_ODD:
1027 case SCE_HEX_DATA_EVEN:
1028 case SCE_HEX_GARBAGE:
1029 // record finished or line too long
1030 sc.SetState(SCE_HEX_GARBAGE);
1031 ForwardWithinLine(sc);
1032 break;
1033
1034 default:
1035 // prevent endless loop in faulty state
1036 sc.SetState(SCE_HEX_DEFAULT);
1037 break;
1038 }
1039 }
1040 sc.Complete();
1041 }
1042
1043 LexerModule lmSrec(SCLEX_SREC, ColouriseSrecDoc, "srec", 0, NULL);
1044 LexerModule lmIHex(SCLEX_IHEX, ColouriseIHexDoc, "ihex", FoldIHexDoc, NULL);
1045 LexerModule lmTEHex(SCLEX_TEHEX, ColouriseTEHexDoc, "tehex", 0, NULL);
1046