LexHex.cpp 28 KB

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