Update Scintilla to version 3.5.3
[TortoiseGit.git] / ext / scintilla / lexers / LexHex.cxx
blob2c43bdd4a84a57d10cef1d843e2b157bb6ad71e4
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.
11 * Motorola S-Record
12 * ===============================
14 * Each record (line) is built as follows:
16 * field digits states
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 * +----------+
33 * Intel HEX
34 * ===============================
36 * Each record (line) is built as follows:
38 * field digits states
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 * +----------+
55 * Folding:
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.
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.
66 * Tektronix extended HEX
67 * ===============================
69 * Each record (line) is built as follows:
71 * field digits states
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 * +----------+
88 * General notes for all lexers
89 * ===============================
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.
96 * - States in parentheses in the upper format descriptions indicate that they
97 * should not appear in a valid hex file.
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.
103 #include <stdlib.h>
104 #include <string.h>
105 #include <stdio.h>
106 #include <stdarg.h>
107 #include <assert.h>
108 #include <ctype.h>
110 #include "ILexer.h"
111 #include "Scintilla.h"
112 #include "SciLexer.h"
114 #include "WordList.h"
115 #include "LexAccessor.h"
116 #include "Accessor.h"
117 #include "StyleContext.h"
118 #include "CharacterSet.h"
119 #include "LexerModule.h"
121 #ifdef SCI_NAMESPACE
122 using namespace Scintilla;
123 #endif
125 // prototypes for general helper functions
126 static inline bool IsNewline(const int ch);
127 static int GetHexaNibble(char hd);
128 static int GetHexaChar(char hd1, char hd2);
129 static int GetHexaChar(unsigned int pos, Accessor &styler);
130 static bool ForwardWithinLine(StyleContext &sc, int nb = 1);
131 static bool PosInSameRecord(unsigned int pos1, unsigned int pos2, Accessor &styler);
132 static int CountByteCount(unsigned int startPos, int uncountedDigits, Accessor &styler);
133 static int CalcChecksum(unsigned int startPos, int cnt, bool twosCompl, Accessor &styler);
135 // prototypes for file format specific helper functions
136 static unsigned int GetSrecRecStartPosition(unsigned int pos, Accessor &styler);
137 static int GetSrecByteCount(unsigned int recStartPos, Accessor &styler);
138 static int CountSrecByteCount(unsigned int recStartPos, Accessor &styler);
139 static int GetSrecAddressFieldSize(unsigned int recStartPos, Accessor &styler);
140 static int GetSrecAddressFieldType(unsigned int recStartPos, Accessor &styler);
141 static int GetSrecDataFieldType(unsigned int recStartPos, Accessor &styler);
142 static int GetSrecRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler);
143 static int GetSrecChecksum(unsigned int recStartPos, Accessor &styler);
144 static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler);
146 static unsigned int GetIHexRecStartPosition(unsigned int pos, Accessor &styler);
147 static int GetIHexByteCount(unsigned int recStartPos, Accessor &styler);
148 static int CountIHexByteCount(unsigned int recStartPos, Accessor &styler);
149 static int GetIHexAddressFieldType(unsigned int recStartPos, Accessor &styler);
150 static int GetIHexDataFieldType(unsigned int recStartPos, Accessor &styler);
151 static int GetIHexRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler);
152 static int GetIHexChecksum(unsigned int recStartPos, Accessor &styler);
153 static int CalcIHexChecksum(unsigned int recStartPos, Accessor &styler);
155 static int GetTEHexDigitCount(unsigned int recStartPos, Accessor &styler);
156 static int CountTEHexDigitCount(unsigned int recStartPos, Accessor &styler);
157 static int GetTEHexAddressFieldType(unsigned int recStartPos, Accessor &styler);
158 static int GetTEHexChecksum(unsigned int recStartPos, Accessor &styler);
159 static int CalcTEHexChecksum(unsigned int recStartPos, Accessor &styler);
161 static inline bool IsNewline(const int ch)
163 return (ch == '\n' || ch == '\r');
166 static int GetHexaNibble(char hd)
168 int hexValue = 0;
170 if (hd >= '0' && hd <= '9') {
171 hexValue += hd - '0';
172 } else if (hd >= 'A' && hd <= 'F') {
173 hexValue += hd - 'A' + 10;
174 } else if (hd >= 'a' && hd <= 'f') {
175 hexValue += hd - 'a' + 10;
176 } else {
177 return -1;
180 return hexValue;
183 static int GetHexaChar(char hd1, char hd2)
185 int hexValue = 0;
187 if (hd1 >= '0' && hd1 <= '9') {
188 hexValue += 16 * (hd1 - '0');
189 } else if (hd1 >= 'A' && hd1 <= 'F') {
190 hexValue += 16 * (hd1 - 'A' + 10);
191 } else if (hd1 >= 'a' && hd1 <= 'f') {
192 hexValue += 16 * (hd1 - 'a' + 10);
193 } else {
194 return -1;
197 if (hd2 >= '0' && hd2 <= '9') {
198 hexValue += hd2 - '0';
199 } else if (hd2 >= 'A' && hd2 <= 'F') {
200 hexValue += hd2 - 'A' + 10;
201 } else if (hd2 >= 'a' && hd2 <= 'f') {
202 hexValue += hd2 - 'a' + 10;
203 } else {
204 return -1;
207 return hexValue;
210 static int GetHexaChar(unsigned int pos, Accessor &styler)
212 char highNibble, lowNibble;
214 highNibble = styler.SafeGetCharAt(pos);
215 lowNibble = styler.SafeGetCharAt(pos + 1);
217 return GetHexaChar(highNibble, lowNibble);
220 // Forward <nb> characters, but abort (and return false) if hitting the line
221 // end. Return true if forwarding within the line was possible.
222 // Avoids influence on highlighting of the subsequent line if the current line
223 // is malformed (too short).
224 static bool ForwardWithinLine(StyleContext &sc, int nb)
226 for (int i = 0; i < nb; i++) {
227 if (sc.atLineEnd) {
228 // line is too short
229 sc.SetState(SCE_HEX_DEFAULT);
230 sc.Forward();
231 return false;
232 } else {
233 sc.Forward();
237 return true;
240 // Checks whether the given positions are in the same record.
241 static bool PosInSameRecord(unsigned int pos1, unsigned int pos2, Accessor &styler)
243 return styler.GetLine(pos1) == styler.GetLine(pos2);
246 // Count the number of digit pairs from <startPos> till end of record, ignoring
247 // <uncountedDigits> digits.
248 // If the record is too short, a negative count may be returned.
249 static int CountByteCount(unsigned int startPos, int uncountedDigits, Accessor &styler)
251 int cnt;
252 unsigned int pos;
254 pos = startPos;
256 while (!IsNewline(styler.SafeGetCharAt(pos, '\n'))) {
257 pos++;
260 // number of digits in this line minus number of digits of uncounted fields
261 cnt = static_cast<int>(pos - startPos) - uncountedDigits;
263 // Prepare round up if odd (digit pair incomplete), this way the byte
264 // count is considered to be valid if the checksum is incomplete.
265 if (cnt >= 0) {
266 cnt++;
269 // digit pairs
270 cnt /= 2;
272 return cnt;
275 // Calculate the checksum of the record.
276 // <startPos> is the position of the first character of the starting digit
277 // pair, <cnt> is the number of digit pairs.
278 static int CalcChecksum(unsigned int startPos, int cnt, bool twosCompl, Accessor &styler)
280 int cs = 0;
282 for (unsigned int pos = startPos; pos < startPos + cnt; pos += 2) {
283 int val = GetHexaChar(pos, styler);
285 if (val < 0) {
286 return val;
289 // overflow does not matter
290 cs += val;
293 if (twosCompl) {
294 // low byte of two's complement
295 return -cs & 0xFF;
296 } else {
297 // low byte of one's complement
298 return ~cs & 0xFF;
302 // Get the position of the record "start" field (first character in line) in
303 // the record around position <pos>.
304 static unsigned int GetSrecRecStartPosition(unsigned int pos, Accessor &styler)
306 while (styler.SafeGetCharAt(pos) != 'S') {
307 pos--;
310 return pos;
313 // Get the value of the "byte count" field, it counts the number of bytes in
314 // the subsequent fields ("address", "data" and "checksum" fields).
315 static int GetSrecByteCount(unsigned int recStartPos, Accessor &styler)
317 int val;
319 val = GetHexaChar(recStartPos + 2, styler);
320 if (val < 0) {
321 val = 0;
324 return val;
327 // Count the number of digit pairs for the "address", "data" and "checksum"
328 // fields in this record. Has to be equal to the "byte count" field value.
329 // If the record is too short, a negative count may be returned.
330 static int CountSrecByteCount(unsigned int recStartPos, Accessor &styler)
332 return CountByteCount(recStartPos, 4, styler);
335 // Get the size of the "address" field.
336 static int GetSrecAddressFieldSize(unsigned int recStartPos, Accessor &styler)
338 switch (styler.SafeGetCharAt(recStartPos + 1)) {
339 case '0':
340 case '1':
341 case '5':
342 case '9':
343 return 2; // 16 bit
345 case '2':
346 case '6':
347 case '8':
348 return 3; // 24 bit
350 case '3':
351 case '7':
352 return 4; // 32 bit
354 default:
355 return 0;
359 // Get the type of the "address" field content.
360 static int GetSrecAddressFieldType(unsigned int recStartPos, Accessor &styler)
362 switch (styler.SafeGetCharAt(recStartPos + 1)) {
363 case '0':
364 return SCE_HEX_NOADDRESS;
366 case '1':
367 case '2':
368 case '3':
369 return SCE_HEX_DATAADDRESS;
371 case '5':
372 case '6':
373 return SCE_HEX_RECCOUNT;
375 case '7':
376 case '8':
377 case '9':
378 return SCE_HEX_STARTADDRESS;
380 default: // handle possible format extension in the future
381 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
385 // Get the type of the "data" field content.
386 static int GetSrecDataFieldType(unsigned int recStartPos, Accessor &styler)
388 switch (styler.SafeGetCharAt(recStartPos + 1)) {
389 case '0':
390 case '1':
391 case '2':
392 case '3':
393 return SCE_HEX_DATA_ODD;
395 case '5':
396 case '6':
397 case '7':
398 case '8':
399 case '9':
400 return SCE_HEX_DATA_EMPTY;
402 default: // handle possible format extension in the future
403 return SCE_HEX_DATA_UNKNOWN;
407 // Get the required size of the "data" field. Useless for block header and
408 // ordinary data records (type S0, S1, S2, S3), return the value calculated
409 // from the "byte count" and "address field" size in this case.
410 static int GetSrecRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler)
412 switch (styler.SafeGetCharAt(recStartPos + 1)) {
413 case '5':
414 case '6':
415 case '7':
416 case '8':
417 case '9':
418 return 0;
420 default:
421 return GetSrecByteCount(recStartPos, styler)
422 - GetSrecAddressFieldSize(recStartPos, styler)
423 - 1; // -1 for checksum field
427 // Get the value of the "checksum" field.
428 static int GetSrecChecksum(unsigned int recStartPos, Accessor &styler)
430 int byteCount;
432 byteCount = GetSrecByteCount(recStartPos, styler);
434 return GetHexaChar(recStartPos + 2 + byteCount * 2, styler);
437 // Calculate the checksum of the record.
438 static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler)
440 int byteCount;
442 byteCount = GetSrecByteCount(recStartPos, styler);
444 // sum over "byte count", "address" and "data" fields (6..510 digits)
445 return CalcChecksum(recStartPos + 2, byteCount * 2, false, styler);
448 // Get the position of the record "start" field (first character in line) in
449 // the record around position <pos>.
450 static unsigned int GetIHexRecStartPosition(unsigned int pos, Accessor &styler)
452 while (styler.SafeGetCharAt(pos) != ':') {
453 pos--;
456 return pos;
459 // Get the value of the "byte count" field, it counts the number of bytes in
460 // the "data" field.
461 static int GetIHexByteCount(unsigned int recStartPos, Accessor &styler)
463 int val;
465 val = GetHexaChar(recStartPos + 1, styler);
466 if (val < 0) {
467 val = 0;
470 return val;
473 // Count the number of digit pairs for the "data" field in this record. Has to
474 // be equal to the "byte count" field value.
475 // If the record is too short, a negative count may be returned.
476 static int CountIHexByteCount(unsigned int recStartPos, Accessor &styler)
478 return CountByteCount(recStartPos, 11, styler);
481 // Get the type of the "address" field content.
482 static int GetIHexAddressFieldType(unsigned int recStartPos, Accessor &styler)
484 if (!PosInSameRecord(recStartPos, recStartPos + 7, styler)) {
485 // malformed (record too short)
486 // type cannot be determined
487 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
490 switch (GetHexaChar(recStartPos + 7, styler)) {
491 case 0x00:
492 return SCE_HEX_DATAADDRESS;
494 case 0x01:
495 case 0x02:
496 case 0x03:
497 case 0x04:
498 case 0x05:
499 return SCE_HEX_NOADDRESS;
501 default: // handle possible format extension in the future
502 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
506 // Get the type of the "data" field content.
507 static int GetIHexDataFieldType(unsigned int recStartPos, Accessor &styler)
509 switch (GetHexaChar(recStartPos + 7, styler)) {
510 case 0x00:
511 return SCE_HEX_DATA_ODD;
513 case 0x01:
514 return SCE_HEX_DATA_EMPTY;
516 case 0x02:
517 case 0x04:
518 return SCE_HEX_EXTENDEDADDRESS;
520 case 0x03:
521 case 0x05:
522 return SCE_HEX_STARTADDRESS;
524 default: // handle possible format extension in the future
525 return SCE_HEX_DATA_UNKNOWN;
529 // Get the required size of the "data" field. Useless for an ordinary data
530 // record (type 00), return the "byte count" in this case.
531 static int GetIHexRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler)
533 switch (GetHexaChar(recStartPos + 7, styler)) {
534 case 0x01:
535 return 0;
537 case 0x02:
538 case 0x04:
539 return 2;
541 case 0x03:
542 case 0x05:
543 return 4;
545 default:
546 return GetIHexByteCount(recStartPos, styler);
550 // Get the value of the "checksum" field.
551 static int GetIHexChecksum(unsigned int recStartPos, Accessor &styler)
553 int byteCount;
555 byteCount = GetIHexByteCount(recStartPos, styler);
557 return GetHexaChar(recStartPos + 9 + byteCount * 2, styler);
560 // Calculate the checksum of the record.
561 static int CalcIHexChecksum(unsigned int recStartPos, Accessor &styler)
563 int byteCount;
565 byteCount = GetIHexByteCount(recStartPos, styler);
567 // sum over "byte count", "address", "type" and "data" fields (8..518 digits)
568 return CalcChecksum(recStartPos + 1, 8 + byteCount * 2, true, styler);
572 // Get the value of the "record length" field, it counts the number of digits in
573 // the record excluding the percent.
574 static int GetTEHexDigitCount(unsigned int recStartPos, Accessor &styler)
576 int val = GetHexaChar(recStartPos + 1, styler);
577 if (val < 0)
578 val = 0;
580 return val;
583 // Count the number of digits in this record. Has to
584 // be equal to the "record length" field value.
585 static int CountTEHexDigitCount(unsigned int recStartPos, Accessor &styler)
587 unsigned int pos;
589 pos = recStartPos+1;
591 while (!IsNewline(styler.SafeGetCharAt(pos, '\n'))) {
592 pos++;
595 return static_cast<int>(pos - (recStartPos+1));
598 // Get the type of the "address" field content.
599 static int GetTEHexAddressFieldType(unsigned int recStartPos, Accessor &styler)
601 switch (styler.SafeGetCharAt(recStartPos + 3)) {
602 case '6':
603 return SCE_HEX_DATAADDRESS;
605 case '8':
606 return SCE_HEX_STARTADDRESS;
608 default: // handle possible format extension in the future
609 return SCE_HEX_ADDRESSFIELD_UNKNOWN;
613 // Get the value of the "checksum" field.
614 static int GetTEHexChecksum(unsigned int recStartPos, Accessor &styler)
616 return GetHexaChar(recStartPos+4, styler);
619 // Calculate the checksum of the record (excluding the checksum field).
620 static int CalcTEHexChecksum(unsigned int recStartPos, Accessor &styler)
622 unsigned int pos = recStartPos +1;
623 unsigned int length = GetTEHexDigitCount(recStartPos, styler);
625 int cs = GetHexaNibble(styler.SafeGetCharAt(pos++));//length
626 cs += GetHexaNibble(styler.SafeGetCharAt(pos++));//length
628 cs += GetHexaNibble(styler.SafeGetCharAt(pos++));//type
630 pos += 2;// jump over CS field
632 for (; pos <= recStartPos + length; ++pos) {
633 int val = GetHexaNibble(styler.SafeGetCharAt(pos));
635 if (val < 0) {
636 return val;
639 // overflow does not matter
640 cs += val;
643 // low byte
644 return cs & 0xFF;
648 static void ColouriseSrecDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler)
650 StyleContext sc(startPos, length, initStyle, styler);
652 while (sc.More()) {
653 unsigned int recStartPos;
654 int byteCount, reqByteCount, addrFieldSize, addrFieldType, dataFieldSize, dataFieldType;
655 int cs1, cs2;
657 switch (sc.state) {
658 case SCE_HEX_DEFAULT:
659 if (sc.atLineStart && sc.Match('S')) {
660 sc.SetState(SCE_HEX_RECSTART);
662 ForwardWithinLine(sc);
663 break;
665 case SCE_HEX_RECSTART:
666 recStartPos = sc.currentPos - 1;
667 addrFieldType = GetSrecAddressFieldType(recStartPos, styler);
669 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
670 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
671 } else {
672 sc.SetState(SCE_HEX_RECTYPE);
675 ForwardWithinLine(sc);
676 break;
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
686 if (byteCount == CountSrecByteCount(recStartPos, styler)
687 && byteCount == reqByteCount) {
688 sc.SetState(SCE_HEX_BYTECOUNT);
689 } else {
690 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
693 ForwardWithinLine(sc, 2);
694 break;
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);
702 sc.SetState(addrFieldType);
703 ForwardWithinLine(sc, addrFieldSize * 2);
704 break;
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);
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);
719 sc.SetState(dataFieldType);
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);
729 if (!ForwardWithinLine(sc)) {
730 break;
733 } else {
734 ForwardWithinLine(sc, dataFieldSize * 2);
736 break;
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);
746 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
747 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
748 } else {
749 sc.SetState(SCE_HEX_CHECKSUM);
752 ForwardWithinLine(sc, 2);
753 break;
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;
763 default:
764 // prevent endless loop in faulty state
765 sc.SetState(SCE_HEX_DEFAULT);
766 break;
769 sc.Complete();
772 static void ColouriseIHexDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler)
774 StyleContext sc(startPos, length, initStyle, styler);
776 while (sc.More()) {
777 unsigned int recStartPos;
778 int byteCount, addrFieldType, dataFieldSize, dataFieldType;
779 int cs1, cs2;
781 switch (sc.state) {
782 case SCE_HEX_DEFAULT:
783 if (sc.atLineStart && sc.Match(':')) {
784 sc.SetState(SCE_HEX_RECSTART);
786 ForwardWithinLine(sc);
787 break;
789 case SCE_HEX_RECSTART:
790 recStartPos = sc.currentPos - 1;
791 byteCount = GetIHexByteCount(recStartPos, styler);
792 dataFieldSize = GetIHexRequiredDataFieldSize(recStartPos, styler);
794 if (byteCount == CountIHexByteCount(recStartPos, styler)
795 && byteCount == dataFieldSize) {
796 sc.SetState(SCE_HEX_BYTECOUNT);
797 } else {
798 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
801 ForwardWithinLine(sc, 2);
802 break;
804 case SCE_HEX_BYTECOUNT:
805 case SCE_HEX_BYTECOUNT_WRONG:
806 recStartPos = sc.currentPos - 3;
807 addrFieldType = GetIHexAddressFieldType(recStartPos, styler);
809 sc.SetState(addrFieldType);
810 ForwardWithinLine(sc, 4);
811 break;
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);
819 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
820 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
821 } else {
822 sc.SetState(SCE_HEX_RECTYPE);
825 ForwardWithinLine(sc, 2);
826 break;
828 case SCE_HEX_RECTYPE:
829 case SCE_HEX_RECTYPE_UNKNOWN:
830 recStartPos = sc.currentPos - 9;
831 dataFieldType = GetIHexDataFieldType(recStartPos, styler);
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);
838 sc.SetState(dataFieldType);
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);
848 if (!ForwardWithinLine(sc)) {
849 break;
852 } else {
853 ForwardWithinLine(sc, dataFieldSize * 2);
855 break;
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);
867 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
868 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
869 } else {
870 sc.SetState(SCE_HEX_CHECKSUM);
873 ForwardWithinLine(sc, 2);
874 break;
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;
884 default:
885 // prevent endless loop in faulty state
886 sc.SetState(SCE_HEX_DEFAULT);
887 break;
890 sc.Complete();
893 static void FoldIHexDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler)
895 unsigned int endPos = startPos + length;
897 int lineCurrent = styler.GetLine(startPos);
898 int levelCurrent = SC_FOLDLEVELBASE;
899 if (lineCurrent > 0)
900 levelCurrent = styler.LevelAt(lineCurrent - 1);
902 unsigned int lineStartNext = styler.LineStart(lineCurrent + 1);
903 int levelNext = SC_FOLDLEVELBASE; // default if no specific line found
905 for (unsigned int i = startPos; i < endPos; i++) {
906 bool atEOL = i == (lineStartNext - 1);
907 int style = styler.StyleAt(i);
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 == (unsigned int)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;
925 if (atEOL || (i == endPos - 1)) {
926 styler.SetLevel(lineCurrent, levelNext);
928 lineCurrent++;
929 lineStartNext = styler.LineStart(lineCurrent + 1);
930 levelCurrent = levelNext;
931 levelNext = SC_FOLDLEVELBASE;
936 static void ColouriseTEHexDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler)
938 StyleContext sc(startPos, length, initStyle, styler);
940 while (sc.More()) {
941 unsigned int recStartPos;
942 int digitCount, addrFieldType;
943 int cs1, cs2;
945 switch (sc.state) {
946 case SCE_HEX_DEFAULT:
947 if (sc.atLineStart && sc.Match('%')) {
948 sc.SetState(SCE_HEX_RECSTART);
950 ForwardWithinLine(sc);
951 break;
953 case SCE_HEX_RECSTART:
955 recStartPos = sc.currentPos - 1;
957 if (GetTEHexDigitCount(recStartPos, styler) == CountTEHexDigitCount(recStartPos, styler)) {
958 sc.SetState(SCE_HEX_BYTECOUNT);
959 } else {
960 sc.SetState(SCE_HEX_BYTECOUNT_WRONG);
963 ForwardWithinLine(sc, 2);
964 break;
966 case SCE_HEX_BYTECOUNT:
967 case SCE_HEX_BYTECOUNT_WRONG:
968 recStartPos = sc.currentPos - 3;
969 addrFieldType = GetTEHexAddressFieldType(recStartPos, styler);
971 if (addrFieldType == SCE_HEX_ADDRESSFIELD_UNKNOWN) {
972 sc.SetState(SCE_HEX_RECTYPE_UNKNOWN);
973 } else {
974 sc.SetState(SCE_HEX_RECTYPE);
977 ForwardWithinLine(sc);
978 break;
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);
986 if (cs1 != cs2 || cs1 < 0 || cs2 < 0) {
987 sc.SetState(SCE_HEX_CHECKSUM_WRONG);
988 } else {
989 sc.SetState(SCE_HEX_CHECKSUM);
992 ForwardWithinLine(sc, 2);
993 break;
996 case SCE_HEX_CHECKSUM:
997 case SCE_HEX_CHECKSUM_WRONG:
998 recStartPos = sc.currentPos - 6;
999 addrFieldType = GetTEHexAddressFieldType(recStartPos, styler);
1001 sc.SetState(addrFieldType);
1002 ForwardWithinLine(sc, 9);
1003 break;
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;
1011 sc.SetState(SCE_HEX_DATA_ODD);
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);
1020 if (!ForwardWithinLine(sc)) {
1021 break;
1024 break;
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;
1034 default:
1035 // prevent endless loop in faulty state
1036 sc.SetState(SCE_HEX_DEFAULT);
1037 break;
1040 sc.Complete();
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);