+ u32 count;
+ u32 address;
+ u32 record_type;
+ u32 checksum;
+ uint8_t cal_checksum = 0;
+ u32 bytes_read = 0;
+
+ /* get record type and record length */
+ if (sscanf(&lpszLine[bytes_read], "S%1x%2x", &record_type, &count) != 2)
+ {
+ return ERROR_IMAGE_FORMAT_ERROR;
+ }
+
+ bytes_read += 4;
+ cal_checksum += (uint8_t)count;
+
+ /* skip checksum byte */
+ count -=1;
+
+ if (record_type == 0)
+ {
+ /* S0 - starting record (optional) */
+ int iValue;
+
+ while (count-- > 0) {
+ sscanf(&lpszLine[bytes_read], "%2x", &iValue);
+ cal_checksum += (uint8_t)iValue;
+ bytes_read += 2;
+ }
+ }
+ else if (record_type >= 1 && record_type <= 3)
+ {
+ switch( record_type )
+ {
+ case 1:
+ /* S1 - 16 bit address data record */
+ sscanf(&lpszLine[bytes_read], "%4x", &address);
+ cal_checksum += (uint8_t)(address >> 8);
+ cal_checksum += (uint8_t)address;
+ bytes_read += 4;
+ count -=2;
+ break;
+
+ case 2:
+ /* S2 - 24 bit address data record */
+ sscanf(&lpszLine[bytes_read], "%6x", &address);
+ cal_checksum += (uint8_t)(address >> 16);
+ cal_checksum += (uint8_t)(address >> 8);
+ cal_checksum += (uint8_t)address;
+ bytes_read += 6;
+ count -=3;
+ break;
+
+ case 3:
+ /* S3 - 32 bit address data record */
+ sscanf(&lpszLine[bytes_read], "%8x", &address);
+ cal_checksum += (uint8_t)(address >> 24);
+ cal_checksum += (uint8_t)(address >> 16);
+ cal_checksum += (uint8_t)(address >> 8);
+ cal_checksum += (uint8_t)address;
+ bytes_read += 8;
+ count -=4;
+ break;
+
+ }
+
+ if (full_address != address)
+ {
+ /* we encountered a nonconsecutive location, create a new section,
+ * unless the current section has zero size, in which case this specifies
+ * the current section's base address
+ */
+ if (section[image->num_sections].size != 0)
+ {
+ image->num_sections++;
+ section[image->num_sections].size = 0x0;
+ section[image->num_sections].flags = 0;
+ section[image->num_sections].private = &mot->buffer[cooked_bytes];
+ }
+ section[image->num_sections].base_address = address;
+ full_address = address;
+ }
+
+ while (count-- > 0)
+ {
+ unsigned value;
+ sscanf(&lpszLine[bytes_read], "%2x", &value);
+ mot->buffer[cooked_bytes] = (uint8_t)value;
+ cal_checksum += (uint8_t)mot->buffer[cooked_bytes];
+ bytes_read += 2;
+ cooked_bytes += 1;
+ section[image->num_sections].size += 1;
+ full_address++;
+ }
+ }
+ else if (record_type == 5)
+ {
+ /* S5 is the data count record, we ignore it */
+ u32 dummy;
+
+ while (count-- > 0)
+ {
+ sscanf(&lpszLine[bytes_read], "%2x", &dummy);
+ cal_checksum += (uint8_t)dummy;
+ bytes_read += 2;
+ }
+ }
+ else if (record_type >= 7 && record_type <= 9)
+ {
+ /* S7, S8, S9 - ending records for 32, 24 and 16bit */
+ image->num_sections++;
+
+ /* copy section information */
+ image->sections = malloc(sizeof(image_section_t) * image->num_sections);
+ for (i = 0; i < image->num_sections; i++)
+ {
+ image->sections[i].private = section[i].private;
+ image->sections[i].base_address = section[i].base_address;
+ image->sections[i].size = section[i].size;
+ image->sections[i].flags = section[i].flags;
+ }
+
+ return ERROR_OK;
+ }
+ else
+ {
+ LOG_ERROR("unhandled S19 record type: %i", record_type);
+ return ERROR_IMAGE_FORMAT_ERROR;
+ }
+
+ /* account for checksum, will always be 0xFF */
+ sscanf(&lpszLine[bytes_read], "%2x", &checksum);
+ cal_checksum += (uint8_t)checksum;
+ bytes_read += 2;
+
+ if( cal_checksum != 0xFF )
+ {
+ /* checksum failed */
+ LOG_ERROR("incorrect record checksum found in S19 file");
+ return ERROR_IMAGE_CHECKSUM;
+ }