diff options
-rw-r--r-- | include/Scintilla.iface | 5 | ||||
-rw-r--r-- | lexers/LexHex.cxx | 283 |
2 files changed, 287 insertions, 1 deletions
diff --git a/include/Scintilla.iface b/include/Scintilla.iface index dcf170fcb..e35b16f16 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2720,6 +2720,7 @@ val SCLEX_DMIS=114 val SCLEX_REGISTRY=115 val SCLEX_BIBTEX=116 val SCLEX_SREC=117 +val SCLEX_IHEX=118 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -4560,11 +4561,15 @@ val SCE_HEX_DATAADDRESS=6 val SCE_HEX_RECCOUNT=7 val SCE_HEX_STARTADDRESS=8 val SCE_HEX_ADDRESSFIELD_UNKNOWN=9 +val SCE_HEX_EXTENDEDADDRESS=10 val SCE_HEX_DATA_ODD=11 val SCE_HEX_DATA_EVEN=12 val SCE_HEX_DATA_UNKNOWN=13 +val SCE_HEX_DATA_EMPTY=14 val SCE_HEX_CHECKSUM=15 val SCE_HEX_CHECKSUM_WRONG=16 +# Lexical state for SCLEX_IHEX (shared with Srec) +lex IHex=SCLEX_IHEX SCE_HEX_ # Events diff --git a/lexers/LexHex.cxx b/lexers/LexHex.cxx index 404b5d592..3604f7cb2 100644 --- a/lexers/LexHex.cxx +++ b/lexers/LexHex.cxx @@ -1,6 +1,6 @@ // Scintilla source code edit control /** @file LexHex.cxx - ** Lexer for Motorola S-Record. + ** Lexers for Motorola S-Record and Intel HEX. ** ** Written by Markus Heidelberg **/ @@ -28,6 +28,37 @@ * +----------+ * | checksum | 2 SCE_HEX_CHECKSUM, SCE_HEX_CHECKSUM_WRONG * +----------+ + * + * + * Intel HEX file format + * =============================== + * + * Each record (line) is built as follows: + * + * field digits states + * + * +----------+ + * | start | 1 (':') SCE_HEX_RECSTART + * +----------+ + * | count | 2 SCE_HEX_BYTECOUNT, SCE_HEX_BYTECOUNT_WRONG + * +----------+ + * | address | 4 SCE_HEX_NOADDRESS, SCE_HEX_DATAADDRESS, (SCE_HEX_ADDRESSFIELD_UNKNOWN) + * +----------+ + * | type | 2 SCE_HEX_RECTYPE + * +----------+ + * | 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) + * +----------+ + * | checksum | 2 SCE_HEX_CHECKSUM, SCE_HEX_CHECKSUM_WRONG + * +----------+ + * + * + * General notes for all lexers + * =============================== + * + * - Depending on where the helper functions are invoked, some of them have to + * read beyond the current position. In case of malformed data (record too + * short), it has to be ensured that this either does not have bad influence + * or will be captured deliberately. */ #include <stdlib.h> @@ -57,6 +88,7 @@ static inline bool IsNewline(const int ch); static int GetHexaChar(char hd1, char hd2); static int GetHexaChar(unsigned int pos, Accessor &styler); static bool ForwardWithinLine(StyleContext &sc, int nb = 1); +static bool PosInSameRecord(unsigned int pos1, unsigned int pos2, Accessor &styler); static int CountByteCount(unsigned int startPos, int uncountedDigits, Accessor &styler); static int CalcChecksum(unsigned int startPos, int cnt, bool twosCompl, Accessor &styler); @@ -69,6 +101,15 @@ static int GetSrecAddressFieldType(unsigned int recStartPos, Accessor &styler); static int GetSrecChecksum(unsigned int recStartPos, Accessor &styler); static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler); +static unsigned int GetIHexRecStartPosition(unsigned int pos, Accessor &styler); +static int GetIHexByteCount(unsigned int recStartPos, Accessor &styler); +static int CountIHexByteCount(unsigned int recStartPos, Accessor &styler); +static int GetIHexAddressFieldType(unsigned int recStartPos, Accessor &styler); +static int GetIHexDataFieldType(unsigned int recStartPos, Accessor &styler); +static int GetIHexRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler); +static int GetIHexChecksum(unsigned int recStartPos, Accessor &styler); +static int CalcIHexChecksum(unsigned int recStartPos, Accessor &styler); + static inline bool IsNewline(const int ch) { return (ch == '\n' || ch == '\r'); @@ -131,6 +172,12 @@ static bool ForwardWithinLine(StyleContext &sc, int nb) return true; } +// Checks whether the given positions are in the same record. +static bool PosInSameRecord(unsigned int pos1, unsigned int pos2, Accessor &styler) +{ + return styler.GetLine(pos1) == styler.GetLine(pos2); +} + // Count the number of digit pairs from <startPos> till end of record, ignoring // <uncountedDigits> digits. // If the record is too short, a negative count may be returned. @@ -291,6 +338,129 @@ static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler) return CalcChecksum(recStartPos + 2, byteCount * 2, false, styler); } +// Get the position of the record "start" field (first character in line) in +// the record around position <pos>. +static unsigned int GetIHexRecStartPosition(unsigned int pos, Accessor &styler) +{ + while (styler.SafeGetCharAt(pos) != ':') { + pos--; + } + + return pos; +} + +// Get the value of the "byte count" field, it counts the number of bytes in +// the "data" field. +static int GetIHexByteCount(unsigned int recStartPos, Accessor &styler) +{ + int val; + + val = GetHexaChar(recStartPos + 1, styler); + if (val < 0) { + val = 0; + } + + return val; +} + +// Count the number of digit pairs for the "data" field in this record. Has to +// be equal to the "byte count" field value. +// If the record is too short, a negative count may be returned. +static int CountIHexByteCount(unsigned int recStartPos, Accessor &styler) +{ + return CountByteCount(recStartPos, 11, styler); +} + +// Get the type of the "address" field content. +static int GetIHexAddressFieldType(unsigned int recStartPos, Accessor &styler) +{ + if (!PosInSameRecord(recStartPos, recStartPos + 7, styler)) { + // malformed (record too short) + // type cannot be determined + return SCE_HEX_ADDRESSFIELD_UNKNOWN; + } + + switch (GetHexaChar(recStartPos + 7, styler)) { + case 0x00: + return SCE_HEX_DATAADDRESS; + + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + return SCE_HEX_NOADDRESS; + + default: // handle possible format extension in the future + return SCE_HEX_ADDRESSFIELD_UNKNOWN; + } +} + +// Get the type of the "data" field content. +static int GetIHexDataFieldType(unsigned int recStartPos, Accessor &styler) +{ + switch (GetHexaChar(recStartPos + 7, styler)) { + case 0x00: + return SCE_HEX_DATA_ODD; + + case 0x01: + return SCE_HEX_DATA_EMPTY; + + case 0x02: + case 0x04: + return SCE_HEX_EXTENDEDADDRESS; + + case 0x03: + case 0x05: + return SCE_HEX_STARTADDRESS; + + default: // handle possible format extension in the future + return SCE_HEX_DATA_UNKNOWN; + } +} + +// Get the required size of the "data" field. Useless for an ordinary data +// record (type 00), return the "byte count" in this case. +static int GetIHexRequiredDataFieldSize(unsigned int recStartPos, Accessor &styler) +{ + switch (GetHexaChar(recStartPos + 7, styler)) { + case 0x01: + return 0; + + case 0x02: + case 0x04: + return 2; + + case 0x03: + case 0x05: + return 4; + + default: + return GetIHexByteCount(recStartPos, styler); + } +} + +// Get the value of the "checksum" field. +static int GetIHexChecksum(unsigned int recStartPos, Accessor &styler) +{ + int byteCount; + + byteCount = GetIHexByteCount(recStartPos, styler); + + return GetHexaChar(recStartPos + 9 + byteCount * 2, styler); +} + +// Calculate the checksum of the record. +static int CalcIHexChecksum(unsigned int recStartPos, Accessor &styler) +{ + int byteCount; + + byteCount = GetIHexByteCount(recStartPos, styler); + + // sum over "byte count", "address", "type" and "data" fields (8..518 digits) + return CalcChecksum(recStartPos + 1, 8 + byteCount * 2, true, styler); +} + static void ColouriseSrecDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); @@ -394,4 +564,115 @@ static void ColouriseSrecDoc(unsigned int startPos, int length, int initStyle, W sc.Complete(); } +static void ColouriseIHexDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) +{ + StyleContext sc(startPos, length, initStyle, styler); + + while (sc.More()) { + unsigned int recStartPos; + int byteCount, addrFieldType, dataFieldSize, dataFieldType; + int cs1, cs2; + + switch (sc.state) { + case SCE_HEX_DEFAULT: + if (sc.atLineStart && sc.Match(':')) { + sc.SetState(SCE_HEX_RECSTART); + } + ForwardWithinLine(sc); + break; + + case SCE_HEX_RECSTART: + recStartPos = sc.currentPos - 1; + byteCount = GetIHexByteCount(recStartPos, styler); + dataFieldSize = GetIHexRequiredDataFieldSize(recStartPos, styler); + + if (byteCount == CountIHexByteCount(recStartPos, styler) + && byteCount == dataFieldSize) { + sc.SetState(SCE_HEX_BYTECOUNT); + } else { + sc.SetState(SCE_HEX_BYTECOUNT_WRONG); + } + + ForwardWithinLine(sc, 2); + break; + + case SCE_HEX_BYTECOUNT: + case SCE_HEX_BYTECOUNT_WRONG: + recStartPos = sc.currentPos - 3; + addrFieldType = GetIHexAddressFieldType(recStartPos, styler); + + sc.SetState(addrFieldType); + ForwardWithinLine(sc, 4); + break; + + case SCE_HEX_NOADDRESS: + case SCE_HEX_DATAADDRESS: + case SCE_HEX_ADDRESSFIELD_UNKNOWN: + sc.SetState(SCE_HEX_RECTYPE); + ForwardWithinLine(sc, 2); + break; + + case SCE_HEX_RECTYPE: + recStartPos = sc.currentPos - 9; + dataFieldType = GetIHexDataFieldType(recStartPos, styler); + + sc.SetState(dataFieldType); + + if (dataFieldType == SCE_HEX_DATA_ODD) { + dataFieldSize = GetIHexByteCount(recStartPos, styler); + + for (int i = 0; i < dataFieldSize * 2; i++) { + if ((i & 0x3) == 0) { + sc.SetState(SCE_HEX_DATA_ODD); + } else if ((i & 0x3) == 2) { + sc.SetState(SCE_HEX_DATA_EVEN); + } + + if (!ForwardWithinLine(sc)) { + break; + } + } + } else if (dataFieldType == SCE_HEX_DATA_UNKNOWN) { + dataFieldSize = GetIHexByteCount(recStartPos, styler); + ForwardWithinLine(sc, dataFieldSize * 2); + } else { + // Using the required size here has the effect that the checksum is + // highlighted at a fixed position after this field, independent on + // the "byte count" value. + dataFieldSize = GetIHexRequiredDataFieldSize(recStartPos, styler); + ForwardWithinLine(sc, dataFieldSize * 2); + } + break; + + case SCE_HEX_DATA_ODD: + case SCE_HEX_DATA_EVEN: + case SCE_HEX_DATA_EMPTY: + case SCE_HEX_EXTENDEDADDRESS: + case SCE_HEX_STARTADDRESS: + case SCE_HEX_DATA_UNKNOWN: + recStartPos = GetIHexRecStartPosition(sc.currentPos, styler); + cs1 = CalcIHexChecksum(recStartPos, styler); + cs2 = GetIHexChecksum(recStartPos, styler); + + if (cs1 != cs2 || cs1 < 0 || cs2 < 0) { + sc.SetState(SCE_HEX_CHECKSUM_WRONG); + } else { + sc.SetState(SCE_HEX_CHECKSUM); + } + + ForwardWithinLine(sc, 2); + break; + + case SCE_HEX_CHECKSUM: + case SCE_HEX_CHECKSUM_WRONG: + // record finished + sc.SetState(SCE_HEX_DEFAULT); + ForwardWithinLine(sc); + break; + } + } + sc.Complete(); +} + LexerModule lmSrec(SCLEX_SREC, ColouriseSrecDoc, "srec", 0, NULL); +LexerModule lmIHex(SCLEX_IHEX, ColouriseIHexDoc, "ihex", 0, NULL); |