UNPKG

intel-hex

Version:

A JavaScript parser/writer for Intel HEX file format.

150 lines (143 loc) 5.03 kB
//Intel Hex record types const DATA = 0, END_OF_FILE = 1, EXT_SEGMENT_ADDR = 2, START_SEGMENT_ADDR = 3, EXT_LINEAR_ADDR = 4, START_LINEAR_ADDR = 5; const EMPTY_VALUE = 0xFF; /* intel_hex.parse(data) - `data` - Intel Hex file (string in ASCII format or Buffer Object) - `bufferSize` - the size of the Buffer containing the data (optional) The data exceeding the buffer size will be discarded - `addressOffset` - starting address offset (optional) The data before the starting address will be discarded returns an Object with the following properties: - `data` - data as a Buffer Object, **padded with 0xFF where data is empty**. - `startSegmentAddress` - the address provided by the last start segment address record; null, if not given - `startLinearAddress` - the address provided by the last start linear address record; null, if not given Special thanks to: http://en.wikipedia.org/wiki/Intel_HEX */ exports.parse = function parseIntelHex(data, bufferSize, addressOffset) { if(data instanceof Buffer) data = data.toString("ascii"); //Initialization var buf = Buffer.alloc(bufferSize || 8192), bufLength = 0, //Length of data in the buffer highAddress = 0, //upper address startSegmentAddress = null, startLinearAddress = null, addressOffset = addressOffset || 0, lineNum = 0, //Line number in the Intel Hex string pos = 0; //Current position in the Intel Hex string const SMALLEST_LINE = 11; while(pos + SMALLEST_LINE <= data.length) { //Parse an entire line if(data.charAt(pos++) != ":") throw new Error("Line " + (lineNum+1) + " does not start with a colon (:)."); else lineNum++; //Number of bytes (hex digit pairs) in the data field var dataLength = parseInt(data.substr(pos, 2), 16); pos += 2; //Get 16-bit address (big-endian) var lowAddress = parseInt(data.substr(pos, 4), 16); pos += 4; //Record type var recordType = parseInt(data.substr(pos, 2), 16); pos += 2; //Data field (hex-encoded string) var dataField = data.substr(pos, dataLength * 2), dataFieldBuf = Buffer.from(dataField, "hex"); pos += dataLength * 2; //Checksum var checksum = parseInt(data.substr(pos, 2), 16); pos += 2; //Validate checksum var calcChecksum = (dataLength + (lowAddress >> 8) + lowAddress + recordType) & 0xFF; for(var i = 0; i < dataLength; i++) calcChecksum = (calcChecksum + dataFieldBuf[i]) & 0xFF; calcChecksum = (0x100 - calcChecksum) & 0xFF; if(checksum != calcChecksum) throw new Error("Invalid checksum on line " + lineNum + ": got " + checksum + ", but expected " + calcChecksum); //Parse the record based on its recordType switch(recordType) { case DATA: var absoluteAddress = highAddress + lowAddress - addressOffset; //Expand buf, if necessary if(absoluteAddress + dataLength >= buf.length) { var tmp = Buffer.alloc((absoluteAddress + dataLength) * 2); buf.copy(tmp, 0, 0, bufLength); buf = tmp; } //Write over skipped bytes with EMPTY_VALUE if(absoluteAddress > bufLength) buf.fill(EMPTY_VALUE, bufLength, absoluteAddress); //Write the dataFieldBuf to buf dataFieldBuf.copy(buf, absoluteAddress); bufLength = Math.max(bufLength, absoluteAddress + dataLength); // Safely abort if the buffer length is already sufficient if(bufLength >= bufferSize) { return { "data": buf.slice(0, bufLength), "startSegmentAddress": startSegmentAddress, "startLinearAddress": startLinearAddress }; } break; case END_OF_FILE: if(dataLength != 0) throw new Error("Invalid EOF record on line " + lineNum + "."); return { "data": buf.slice(0, bufLength), "startSegmentAddress": startSegmentAddress, "startLinearAddress": startLinearAddress }; break; case EXT_SEGMENT_ADDR: if(dataLength != 2 || lowAddress != 0) throw new Error("Invalid extended segment address record on line " + lineNum + "."); highAddress = parseInt(dataField, 16) << 4; break; case START_SEGMENT_ADDR: if(dataLength != 4 || lowAddress != 0) throw new Error("Invalid start segment address record on line " + lineNum + "."); startSegmentAddress = parseInt(dataField, 16); break; case EXT_LINEAR_ADDR: if(dataLength != 2 || lowAddress != 0) throw new Error("Invalid extended linear address record on line " + lineNum + "."); highAddress = parseInt(dataField, 16) << 16; break; case START_LINEAR_ADDR: if(dataLength != 4 || lowAddress != 0) throw new Error("Invalid start linear address record on line " + lineNum + "."); startLinearAddress = parseInt(dataField, 16); break; default: throw new Error("Invalid record type (" + recordType + ") on line " + lineNum); break; } //Advance to the next line if(data.charAt(pos) == "\r") pos++; if(data.charAt(pos) == "\n") pos++; } throw new Error("Unexpected end of input: missing or invalid EOF record."); };