- merged XScale branch back into trunk
[fw/openocd] / src / helper / fileio.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "types.h"
25 #include "replacements.h"
26 #include "log.h"
27
28 #include "fileio.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <ctype.h>
38
39 int fileio_close(fileio_t *fileio);
40 int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read);
41
42 int fileio_open_local(fileio_t *fileio)
43 {
44         fileio_local_t *fileio_local = malloc(sizeof(fileio_local_t));
45         char access[4];
46         
47         fileio->location_private = fileio_local;
48         
49         if ((fileio->access != FILEIO_WRITE) && (fileio->access != FILEIO_READWRITE))
50         {
51                 if (stat(fileio->url, &fileio_local->file_stat) == -1)
52                 {
53                         free(fileio_local);
54                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING,
55                                 "couldn't stat() %s: %s", fileio->url, strerror(errno));
56                         return ERROR_FILEIO_NOT_FOUND;
57                 }
58         
59                 if (S_ISDIR(fileio_local->file_stat.st_mode))
60                 {
61                         free(fileio_local);
62                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "%s is a directory", fileio->url);
63                         return ERROR_FILEIO_NOT_FOUND;
64                 }
65         }
66         
67         switch (fileio->access)
68         {
69                 case FILEIO_READ:
70                         strcpy(access, "r");
71                         break;
72                 case FILEIO_WRITE:
73                         strcpy(access, "w");
74                         break;
75                 case FILEIO_READWRITE:
76                         strcpy(access, "w+");
77                         break;
78                 case FILEIO_APPEND:
79                         strcpy(access, "a");    
80                         break;
81                 case FILEIO_APPENDREAD:
82                         strcpy(access, "a+");   
83                         break;
84                 default:
85                         free(fileio_local);
86                         ERROR("BUG: access neither read, write nor readwrite");
87                         return ERROR_INVALID_ARGUMENTS;
88         }
89         
90         if (fileio->access == FILEIO_READ)
91         {
92                 if (fileio_local->file_stat.st_size == 0)
93                 {
94                         /* tried to open an empty file for reading */
95                         free(fileio_local);
96                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "empty file %s", fileio->url);
97                         return ERROR_FILEIO_OPERATION_FAILED;
98                 }
99         }
100         
101         if (fileio->pri_type == FILEIO_IMAGE)
102                 strcat(access, "b");
103         
104         if (!(fileio_local->file = fopen(fileio->url, access)))
105         {
106                 free(fileio_local);
107                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't open %s", fileio->url);
108                 return ERROR_FILEIO_OPERATION_FAILED;
109         }
110         
111         if ((fileio->access != FILEIO_WRITE) || (fileio->access == FILEIO_READWRITE))
112         {
113                 fileio->size = fileio_local->file_stat.st_size;
114         }
115         else
116         {
117                 fileio->size = 0x0;
118         }
119         
120         return ERROR_OK;
121 }
122
123 //#ifdef FILEIO_BUFFER_COMPLETE_IHEX
124 int fileio_ihex_buffer_complete(fileio_t *fileio)
125 {
126         fileio_image_t *image = fileio->pri_type_private;
127         fileio_ihex_t *ihex = fileio->sec_type_private;
128         u32 raw_bytes_read, raw_bytes;
129         int retval;
130         u32 full_address = image->base_address;
131         char *buffer = malloc(ihex->raw_size);
132         u32 cooked_bytes = 0x0;
133         
134         ihex->raw_size = fileio->size;
135         ihex->buffer = malloc(ihex->raw_size >> 1);
136         
137         if ((retval = fileio_dispatch_read(fileio, ihex->raw_size, (u8*)buffer, &raw_bytes_read)) != ERROR_OK)
138         {
139                 free(buffer);
140                 ERROR("failed buffering IHEX file, read failed");
141                 return ERROR_FILEIO_OPERATION_FAILED;
142         }
143         
144         if (raw_bytes_read != ihex->raw_size)
145         {
146                 free(buffer);
147                 ERROR("failed buffering complete IHEX file, only partially read");
148                 return ERROR_FILEIO_OPERATION_FAILED;
149         }
150         
151         raw_bytes = 0x0;
152         while (raw_bytes < raw_bytes_read)
153         {
154                 u32 count;
155                 u32 address;
156                 u32 record_type;
157                 u32 checksum;
158                 
159                 if (sscanf(&buffer[raw_bytes], ":%2x%4x%2x", &count, &address, &record_type) != 3)
160                 {
161                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid IHEX record");
162                         return ERROR_FILEIO_OPERATION_FAILED;
163                 }
164                 raw_bytes += 9;
165                 
166                 if (record_type == 0)
167                 {
168                         if ((full_address & 0xffff) != address)
169                         {
170                                 free(buffer);
171                                 ERROR("can't handle non-linear IHEX file");
172                                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
173                                 return ERROR_FILEIO_OPERATION_FAILED;
174                         }
175                         
176                         while (count-- > 0)
177                         {
178                                 sscanf(&buffer[raw_bytes], "%2hhx", &ihex->buffer[cooked_bytes]);
179                                 raw_bytes += 2;
180                                 cooked_bytes += 1;
181                                 full_address++;
182                         }
183                 }
184                 else if (record_type == 1)
185                 {
186                         free(buffer);
187                         fileio->size = cooked_bytes;
188                         return ERROR_OK;
189                 }
190                 else if (record_type == 4)
191                 {
192                         u16 upper_address;
193                         
194                         sscanf(&buffer[raw_bytes], "%4hx", &upper_address);
195                         raw_bytes += 4;
196                         
197                         if ((full_address >> 16) != upper_address)
198                         {
199                                 free(buffer);
200                                 ERROR("can't handle non-linear IHEX file");
201                                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
202                                 return ERROR_FILEIO_OPERATION_FAILED;
203                         }
204                 }
205                 else if (record_type == 5)
206                 {
207                         u32 start_address;
208                         
209                         sscanf(&buffer[raw_bytes], "%8x", &start_address);
210                         raw_bytes += 8;
211                         
212                         image->has_start_address = 1;
213                         image->start_address = be_to_h_u32((u8*)&start_address);
214                 }
215                 else
216                 {
217                         free(buffer);
218                         ERROR("unhandled IHEX record type: %i", record_type);
219                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "unhandled IHEX record type: %i", record_type);
220                         return ERROR_FILEIO_OPERATION_FAILED;
221                 }
222                 
223                 sscanf(&buffer[raw_bytes], "%2x", &checksum);
224                 raw_bytes += 2;
225                 
226                 /* consume new-line character(s) */
227                 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
228                         raw_bytes++;
229
230                 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
231                         raw_bytes++;
232         }
233
234         free(buffer);
235         ERROR("premature end of IHEX file, no end-of-file record found");
236         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "premature end of IHEX file, no end-of-file record found");
237         return ERROR_FILEIO_OPERATION_FAILED;   
238 }
239 //#endif
240
241 int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
242         enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type)
243 {
244         int retval = ERROR_OK;
245         char *resource_identifier = NULL;
246
247         /* try to identify file location */
248         if ((resource_identifier = strstr(url, "bootp://")) && (resource_identifier == url))
249         {
250                 ERROR("bootp resource location isn't supported yet");
251                 return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
252         }
253         else if ((resource_identifier = strstr(url, "tftp://")) && (resource_identifier == url))
254         {
255                 ERROR("tftp resource location isn't supported yet");
256                 return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
257         }
258         else
259         {
260                 /* default to local files */
261                 fileio->location = FILEIO_LOCAL;
262         }
263         
264         fileio->access = access;
265         fileio->pri_type = pri_type;
266         fileio->sec_type = sec_type;
267         fileio->url = strdup(url);
268         
269         switch (fileio->location)
270         {
271                 case FILEIO_LOCAL:
272                         retval = fileio_open_local(fileio);
273                         break;
274                 default:
275                         ERROR("BUG: should never get here");
276                         exit(-1);
277         }
278         
279         if (retval != ERROR_OK)
280                 return retval;
281         
282         if (fileio->pri_type == FILEIO_TEXT)
283         {
284                 /* do nothing for now */
285                 return ERROR_OK;
286         }
287         else if (fileio->pri_type == FILEIO_IMAGE)
288         {
289                 fileio_image_t *image = malloc(sizeof(fileio_image_t));
290                 fileio_image_t *image_info = pri_info;
291                 
292                 fileio->pri_type_private = image;
293                 *image = *image_info; 
294                 
295                 if (fileio->sec_type == FILEIO_PLAIN)
296                 {
297                         fileio->sec_type_private = NULL;
298                 }
299                 else if (fileio->sec_type == FILEIO_IHEX)
300                 {
301                         fileio_ihex_t *fileio_ihex;
302                         
303                         if (fileio->access != FILEIO_READ)
304                         {
305                                 ERROR("can't write/append to a IHEX file");
306                                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't write/append to a IHEX file");
307                                 fileio_close(fileio);
308                                 return ERROR_FILEIO_OPERATION_FAILED;
309                         }
310                         
311                         fileio_ihex = malloc(sizeof(fileio_ihex_t));
312                         fileio->sec_type_private = fileio_ihex;
313                         
314                         fileio_ihex->position = 0;
315                         fileio_ihex->raw_size = fileio->size;
316 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
317                         if (fileio_ihex_buffer_complete(fileio) != ERROR_OK)
318                         {
319                                 fileio_close(fileio);
320                                 return ERROR_FILEIO_OPERATION_FAILED;
321                         }
322 #endif
323                 }
324         }
325         
326         return ERROR_OK;
327 }
328
329 int fileio_close_local(fileio_t *fileio)
330 {
331         int retval;
332         fileio_local_t *fileio_local = fileio->location_private;
333         
334         if ((retval = fclose(fileio_local->file)) != 0)
335         {
336                 if (retval == EBADF)
337                 {
338                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "BUG: fileio_local->file not a valid file descriptor");
339                 }
340                 else
341                 {
342                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't close %s: %s", fileio->url, strerror(errno));
343                 }
344
345                 return ERROR_FILEIO_OPERATION_FAILED;
346         }
347         
348         free(fileio->location_private);
349         
350         return ERROR_OK;
351 }
352
353 int fileio_close(fileio_t *fileio)
354 {
355         int retval;
356         
357         switch (fileio->location)
358         {
359                 case FILEIO_LOCAL:
360                         retval = fileio_close_local(fileio);
361                         break;
362                 default:
363                         ERROR("BUG: should never get here");
364                         retval = ERROR_FILEIO_OPERATION_FAILED;
365         }
366         
367         if (retval != ERROR_OK)
368                 return retval;
369         
370         free(fileio->url);
371         
372         if (fileio->pri_type == FILEIO_TEXT)
373         {
374                 /* do nothing for now */
375         }
376         else if (fileio->pri_type == FILEIO_IMAGE)
377         {
378                 if (fileio->sec_type == FILEIO_PLAIN)
379                 {
380                         /* nothing special to do for plain binary */
381                 }
382                 else if (fileio->sec_type == FILEIO_IHEX)
383                 {
384                         fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
385         
386                         if (fileio_ihex->buffer)
387                                 free(fileio_ihex->buffer);
388                         
389                         free(fileio->sec_type_private);
390                 }
391                 
392                 free(fileio->pri_type_private);
393         }
394         
395         return ERROR_OK;
396 }
397
398 int fileio_seek_local(fileio_t *fileio, u32 position)
399 {
400         int retval;
401         fileio_local_t *fileio_local = fileio->location_private;
402         
403         if ((retval = fseek(fileio_local->file, position, SEEK_SET)) != 0)
404         {
405                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't seek file %s: %s", fileio->url, strerror(errno));
406                 return ERROR_FILEIO_OPERATION_FAILED;
407         }
408         
409         return ERROR_OK;
410 }
411
412 int fileio_seek(fileio_t *fileio, u32 position)
413 {
414         switch (fileio->location)
415         {
416                 case FILEIO_LOCAL:
417                         return fileio_seek_local(fileio, position);
418                         break;
419                 default:
420                         ERROR("BUG: should never get here");
421         }
422         
423         return ERROR_OK;
424 }
425
426 int fileio_local_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
427 {
428         fileio_local_t *fileio_local = fileio->location_private;
429         
430         *size_read = fread(buffer, 1, size, fileio_local->file);
431         
432         return ERROR_OK;
433 }
434
435 int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
436 {
437         switch (fileio->location)
438         {
439                 case FILEIO_LOCAL:
440                         return fileio_local_read(fileio, size, buffer, size_read);
441                         break;
442                 default:
443                         ERROR("BUG: should never get here");
444                         exit(-1);
445         }
446 }
447
448 int fileio_read_ihex(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
449 {
450         fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
451
452         if ((fileio_ihex->position + size) > fileio->size)
453         {
454                 /* don't read past the end of the file */
455                 size = (fileio->size - fileio_ihex->position);
456         }
457         
458 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
459         memcpy(buffer, fileio_ihex->buffer + fileio_ihex->position, size);
460         *size_read = size;
461 #endif
462
463         return ERROR_OK;
464 }
465
466 int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
467 {
468         if (fileio->sec_type == FILEIO_PLAIN)
469         {
470                 return fileio_dispatch_read(fileio, size, buffer, size_read);
471         }
472         else if (fileio->sec_type == FILEIO_IHEX)
473         {
474                 return fileio_read_ihex(fileio, size, buffer, size_read);
475         }
476         
477         return ERROR_OK;
478 }
479
480 int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
481 {
482         fileio_local_t *fileio_local = fileio->location_private;
483         
484         *size_written = fwrite(buffer, 1, size, fileio_local->file);
485         
486         return ERROR_OK;
487 }
488
489 int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
490 {
491         switch (fileio->location)
492         {
493                 case FILEIO_LOCAL:
494                         return fileio_local_write(fileio, size, buffer, size_written);
495                         break;
496                 default:
497                         ERROR("BUG: should never get here");
498         }
499         
500         return ERROR_OK;
501 }
502
503 int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
504 {
505         int retval = ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
506         if (fileio->sec_type == FILEIO_PLAIN)
507         {
508                 retval = fileio_dispatch_write(fileio, size, buffer, size_written);
509         }
510         else if (fileio->sec_type == FILEIO_IHEX)
511         {
512                 return ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
513         }
514         
515         if (retval != ERROR_OK)
516                 return retval;
517                 
518         fileio->size += size;
519         
520         return ERROR_OK;
521 }
522
523 int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string)
524 {
525         if (type_string)
526         {
527                 if (!strcmp(type_string, "bin"))
528                 {
529                         *sec_type = FILEIO_PLAIN;
530                 }
531                 else if (!strcmp(type_string, "ihex"))
532                 {
533                         *sec_type = FILEIO_IHEX;
534                 }
535                 else
536                 {
537                         return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
538                 }
539         }
540         else
541         {
542                 *sec_type = FILEIO_PLAIN;
543         }
544         
545         return ERROR_OK;
546 }