- added missing files for last commit
[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         
246         if ((!url) || (strlen(url) < 3))
247         {
248                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid file url");
249                 return ERROR_INVALID_ARGUMENTS;
250         }
251         
252         if ((url[0] == '/') || (isalpha(url[0])) || ((url[1] == ':') && (url[2] == '\\')))
253         {
254                 fileio->location = FILEIO_LOCAL;
255         }
256         else
257         {
258                 ERROR("couldn't identify resource location from URL '%s'", url);
259                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't identify resource location from URL '%s'", url);
260                 return ERROR_FILEIO_LOCATION_UNKNOWN;
261         }
262         
263         fileio->access = access;
264         fileio->pri_type = pri_type;
265         fileio->sec_type = sec_type;
266         fileio->url = strdup(url);
267         
268         switch (fileio->location)
269         {
270                 case FILEIO_LOCAL:
271                         retval = fileio_open_local(fileio);
272                         break;
273                 default:
274                         ERROR("BUG: should never get here");
275                         exit(-1);
276         }
277         
278         if (retval != ERROR_OK)
279                 return retval;
280         
281         if (fileio->pri_type == FILEIO_TEXT)
282         {
283                 /* do nothing for now */
284                 return ERROR_OK;
285         }
286         else if (fileio->pri_type == FILEIO_IMAGE)
287         {
288                 fileio_image_t *image = malloc(sizeof(fileio_image_t));
289                 fileio_image_t *image_info = pri_info;
290                 
291                 fileio->pri_type_private = image;
292                 *image = *image_info; 
293                 
294                 if (fileio->sec_type == FILEIO_PLAIN)
295                 {
296                         fileio->sec_type_private = NULL;
297                 }
298                 else if (fileio->sec_type == FILEIO_IHEX)
299                 {
300                         fileio_ihex_t *fileio_ihex;
301                         
302                         if (fileio->access != FILEIO_READ)
303                         {
304                                 ERROR("can't write/append to a IHEX file");
305                                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't write/append to a IHEX file");
306                                 fileio_close(fileio);
307                                 return ERROR_FILEIO_OPERATION_FAILED;
308                         }
309                         
310                         fileio_ihex = malloc(sizeof(fileio_ihex_t));
311                         fileio->sec_type_private = fileio_ihex;
312                         
313                         fileio_ihex->position = 0;
314                         fileio_ihex->raw_size = fileio->size;
315 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
316                         if (fileio_ihex_buffer_complete(fileio) != ERROR_OK)
317                         {
318                                 fileio_close(fileio);
319                                 return ERROR_FILEIO_OPERATION_FAILED;
320                         }
321 #endif
322                 }
323         }
324         
325         return ERROR_OK;
326 }
327
328 int fileio_close_local(fileio_t *fileio)
329 {
330         int retval;
331         fileio_local_t *fileio_local = fileio->location_private;
332         
333         if ((retval = fclose(fileio_local->file)) != 0)
334         {
335                 if (retval == EBADF)
336                 {
337                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "BUG: fileio_local->file not a valid file descriptor");
338                 }
339                 else
340                 {
341                         snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't close %s: %s", fileio->url, strerror(errno));
342                 }
343
344                 return ERROR_FILEIO_OPERATION_FAILED;
345         }
346         
347         free(fileio->location_private);
348         
349         return ERROR_OK;
350 }
351
352 int fileio_close(fileio_t *fileio)
353 {
354         int retval;
355         
356         switch (fileio->location)
357         {
358                 case FILEIO_LOCAL:
359                         retval = fileio_close_local(fileio);
360                         break;
361                 default:
362                         ERROR("BUG: should never get here");
363         }
364         
365         if (retval != ERROR_OK)
366                 return retval;
367         
368         free(fileio->url);
369         
370         if (fileio->pri_type == FILEIO_TEXT)
371         {
372                 /* do nothing for now */
373         }
374         else if (fileio->pri_type == FILEIO_IMAGE)
375         {
376                 if (fileio->sec_type == FILEIO_PLAIN)
377                 {
378                         /* nothing special to do for plain binary */
379                 }
380                 else if (fileio->sec_type == FILEIO_IHEX)
381                 {
382                         fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
383         
384                         if (fileio_ihex->buffer)
385                                 free(fileio_ihex->buffer);
386                         
387                         free(fileio->sec_type_private);
388                 }
389                 
390                 free(fileio->pri_type_private);
391         }
392         
393         return ERROR_OK;
394 }
395
396 int fileio_seek_local(fileio_t *fileio, u32 position)
397 {
398         int retval;
399         fileio_local_t *fileio_local = fileio->location_private;
400         
401         if ((retval = fseek(fileio_local->file, position, SEEK_SET)) != 0)
402         {
403                 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't seek file %s: %s", fileio->url, strerror(errno));
404                 return ERROR_FILEIO_OPERATION_FAILED;
405         }
406         
407         return ERROR_OK;
408 }
409
410 int fileio_seek(fileio_t *fileio, u32 position)
411 {
412         switch (fileio->location)
413         {
414                 case FILEIO_LOCAL:
415                         return fileio_seek_local(fileio, position);
416                         break;
417                 default:
418                         ERROR("BUG: should never get here");
419         }
420         
421         return ERROR_OK;
422 }
423
424 int fileio_local_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
425 {
426         fileio_local_t *fileio_local = fileio->location_private;
427         
428         *size_read = fread(buffer, 1, size, fileio_local->file);
429         
430         return ERROR_OK;
431 }
432
433 int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
434 {
435         switch (fileio->location)
436         {
437                 case FILEIO_LOCAL:
438                         return fileio_local_read(fileio, size, buffer, size_read);
439                         break;
440                 default:
441                         ERROR("BUG: should never get here");
442                         exit(-1);
443         }
444 }
445
446 int fileio_read_ihex(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
447 {
448         fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
449
450         if ((fileio_ihex->position + size) > fileio->size)
451         {
452                 /* don't read past the end of the file */
453                 size = (fileio->size - fileio_ihex->position);
454         }
455         
456 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
457         memcpy(buffer, fileio_ihex->buffer + fileio_ihex->position, size);
458         *size_read = size;
459 #endif
460
461         return ERROR_OK;
462 }
463
464 int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
465 {
466         if (fileio->sec_type == FILEIO_PLAIN)
467         {
468                 return fileio_dispatch_read(fileio, size, buffer, size_read);
469         }
470         else if (fileio->sec_type == FILEIO_IHEX)
471         {
472                 return fileio_read_ihex(fileio, size, buffer, size_read);
473         }
474         
475         return ERROR_OK;
476 }
477
478 int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
479 {
480         fileio_local_t *fileio_local = fileio->location_private;
481         
482         *size_written = fwrite(buffer, 1, size, fileio_local->file);
483         
484         return ERROR_OK;
485 }
486
487 int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
488 {
489         switch (fileio->location)
490         {
491                 case FILEIO_LOCAL:
492                         return fileio_local_write(fileio, size, buffer, size_written);
493                         break;
494                 default:
495                         ERROR("BUG: should never get here");
496         }
497         
498         return ERROR_OK;
499 }
500
501 int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
502 {
503         int retval;
504         if (fileio->sec_type == FILEIO_PLAIN)
505         {
506                 retval = fileio_dispatch_write(fileio, size, buffer, size_written);
507         }
508         else if (fileio->sec_type == FILEIO_IHEX)
509         {
510                 return ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
511         }
512         
513         if (retval != ERROR_OK)
514                 return retval;
515                 
516         fileio->size += size;
517         
518         return ERROR_OK;
519 }
520
521 int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string)
522 {
523         if (type_string)
524         {
525                 if (!strcmp(type_string, "bin"))
526                 {
527                         *sec_type = FILEIO_PLAIN;
528                 }
529                 else if (!strcmp(type_string, "ihex"))
530                 {
531                         *sec_type = FILEIO_IHEX;
532                 }
533                 else
534                 {
535                         return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
536                 }
537         }
538         else
539         {
540                 *sec_type = FILEIO_PLAIN;
541         }
542         
543         return ERROR_OK;
544 }