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