+ buffer += read_size;
+ size -= read_size;
+ offset += read_size;
+ *size_read += read_size;
+ /* need more data ? */
+ if (!size)
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+static int image_mot_buffer_complete(struct image *image)
+{
+ struct image_mot *mot = image->type_private;
+ struct fileio *fileio = &mot->fileio;
+ uint32_t full_address = 0x0;
+ uint32_t cooked_bytes;
+ int i;
+ char lpszLine[1023];
+
+ /* we can't determine the number of sections that we'll have to create ahead of time,
+ * so we locally hold them until parsing is finished */
+ struct imageection section[IMAGE_MAX_SECTIONS];
+
+ mot->buffer = malloc(fileio->size >> 1);
+ cooked_bytes = 0x0;
+ image->num_sections = 0;
+ section[image->num_sections].private = &mot->buffer[cooked_bytes];
+ section[image->num_sections].base_address = 0x0;
+ section[image->num_sections].size = 0x0;
+ section[image->num_sections].flags = 0;
+
+ while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK)
+ {
+ uint32_t count;
+ uint32_t address;
+ uint32_t record_type;
+ uint32_t checksum;
+ uint8_t cal_checksum = 0;
+ uint32_t bytes_read = 0;
+
+ /* get record type and record length */
+ if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32 , &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], "%4" SCNx32, &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], "%6" SCNx32 , &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], "%8" SCNx32 , &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 */
+ uint32_t dummy;
+
+ while (count-- > 0)
+ {
+ sscanf(&lpszLine[bytes_read], "%2" SCNx32 , &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(struct imageection) * 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;
+ }