From cdabc057a0a1e307a13f78181c782a3194362fb5 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Sun, 9 Feb 2020 17:05:29 +0100 Subject: [PATCH] Allow unseekable files with `INCBIN` Go figure the use case, but the feature is there now --- src/asm/section.c | 122 ++++++++++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 42 deletions(-) diff --git a/src/asm/section.c b/src/asm/section.c index 0029c7ab..8cb67ba7 100644 --- a/src/asm/section.c +++ b/src/asm/section.c @@ -1,4 +1,5 @@ +#include #include #include #include @@ -404,80 +405,117 @@ void out_PCRelByte(struct Expression *expr) */ void out_BinaryFile(char const *s) { - FILE *f; + FILE *f = fstk_FindFile(s, NULL); - f = fstk_FindFile(s, NULL); - if (f == NULL) { + if (!f) { if (oGeneratedMissingIncludes) { oFailedOnMissingInclude = true; return; } - err(1, "Unable to open incbin file '%s'", s); + fatalerror("Error opening INCBIN file '%s': %s", s, + strerror(errno)); } - int32_t fsize; - - fseek(f, 0, SEEK_END); - fsize = ftell(f); - fseek(f, 0, SEEK_SET); + int32_t fsize = -1; + int byte; checkcodesection(); - checksectionoverflow(fsize); + if (fseek(f, 0, SEEK_END) != -1) { + fsize = ftell(f); + rewind(f); - int32_t todo = fsize; + checksectionoverflow(fsize); + } else if (errno != ESPIPE) { + yyerror("Error determining size of INCBIN file '%s': %s", s, + strerror(errno)); + } - while (todo--) - pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f); + while ((byte = fgetc(f)) != EOF) { + if (fsize == -1) + checksectionoverflow(1); + pCurrentSection->tData[pCurrentSection->nPC++] = byte; + if (currentLoadSection) + currentLoadSection->nPC++; + nPC++; + } + + if (ferror(f)) + yyerror("Error reading INCBIN file '%s': %s", s, + strerror(errno)); - if (currentLoadSection) - currentLoadSection->nPC += fsize; - nPC += fsize; fclose(f); } void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) { - FILE *f; + if (start_pos < 0) { + yyerror("Start position cannot be negative (%d)", start_pos); + start_pos = 0; + } - if (start_pos < 0) - fatalerror("Start position cannot be negative"); + if (length < 0) { + yyerror("Number of bytes to read cannot be negative (%d)", + length); + length = 0; + } + if (length == 0) /* Don't even bother with 0-byte slices */ + return; - if (length < 0) - fatalerror("Number of bytes to read must be greater than zero"); + FILE *f = fstk_FindFile(s, NULL); - f = fstk_FindFile(s, NULL); - if (f == NULL) { + if (!f) { if (oGeneratedMissingIncludes) { oFailedOnMissingInclude = true; return; } - err(1, "Unable to open included file '%s'", s); + fatalerror("Error opening INCBIN file '%s': %s", s, + strerror(errno)); } - int32_t fsize; - - fseek(f, 0, SEEK_END); - fsize = ftell(f); - - if (start_pos >= fsize) - fatalerror("Specified start position is greater than length of file"); - - if ((start_pos + length) > fsize) - fatalerror("Specified range in INCBIN is out of bounds"); - - fseek(f, start_pos, SEEK_SET); - checkcodesection(); checksectionoverflow(length); + int32_t fsize; + + if (fseek(f, 0, SEEK_END) != -1) { + fsize = ftell(f); + + if (start_pos >= fsize) { + yyerror("Specified start position is greater than length of file"); + return; + } + + if ((start_pos + length) > fsize) + fatalerror("Specified range in INCBIN is out of bounds"); + + fseek(f, start_pos, SEEK_SET); + } else { + if (errno != ESPIPE) + yyerror("Error determining size of INCBIN file '%s': %s", + s, strerror(errno)); + /* The file isn't seekable, so we'll just skip bytes */ + while (start_pos--) + (void)fgetc(f); + } + int32_t todo = length; - while (todo--) - pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f); + while (todo--) { + int byte = fgetc(f); - if (currentLoadSection) - currentLoadSection->nPC += length; - nPC += length; + if (byte != EOF) { + pCurrentSection->tData[pCurrentSection->nPC++] = byte; + if (currentLoadSection) + currentLoadSection->nPC++; + nPC++; + } else if (ferror(f)) { + yyerror("Error reading INCBIN file '%s': %s", s, + strerror(errno)); + } else { + yyerror("Premature end of file (%d bytes left to read)", + todo + 1); + } + } fclose(f); }