Fix #6969: Account for BOM when reading script files

This commit is contained in:
Charles Pigott 2018-11-15 23:14:21 +00:00 committed by Niels Martin Hansen
parent 278a705bbb
commit 6accbf9afc
1 changed files with 69 additions and 60 deletions

View File

@ -432,13 +432,8 @@ static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger
SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror) SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror)
{ {
size_t size;
FILE *file; FILE *file;
SQInteger ret; size_t size;
unsigned short us;
unsigned char uc;
SQLEXREADFUNC func;
if (strncmp(this->GetAPIName(), "AI", 2) == 0) { if (strncmp(this->GetAPIName(), "AI", 2) == 0) {
file = FioFOpenFile(filename, "rb", AI_DIR, &size); file = FioFOpenFile(filename, "rb", AI_DIR, &size);
if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size); if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
@ -449,18 +444,23 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer
NOT_REACHED(); NOT_REACHED();
} }
if (file != NULL) { if (file == NULL) {
SQFile f(file, size); return sq_throwerror(vm, "cannot open the file");
ret = fread(&us, 1, sizeof(us), file); }
/* Most likely an empty file */ unsigned short bom = 0;
if (ret != 2) us = 0; if (size >= 2) {
fread(&bom, 1, sizeof(bom), file); // Inside tar, no point checking return value of fread
}
switch (us) { SQLEXREADFUNC func;
switch (bom) {
case SQ_BYTECODE_STREAM_TAG: { // BYTECODE case SQ_BYTECODE_STREAM_TAG: { // BYTECODE
if (fseek(file, -2, SEEK_CUR) < 0) { if (fseek(file, -2, SEEK_CUR) < 0) {
FioFCloseFile(file); FioFCloseFile(file);
return sq_throwerror(vm, "cannot seek the file"); return sq_throwerror(vm, "cannot seek the file");
} }
SQFile f(file, size);
if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) { if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) {
FioFCloseFile(file); FioFCloseFile(file);
return SQ_OK; return SQ_OK;
@ -473,37 +473,46 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer
* machine, or this file is encoded as little-endian and we're on a big-endian * machine, or this file is encoded as little-endian and we're on a big-endian
* machine. Either way, swap the bytes of every word we read. */ * machine. Either way, swap the bytes of every word we read. */
func = _io_file_lexfeed_UCS2_swap; func = _io_file_lexfeed_UCS2_swap;
size -= 2; // Skip BOM
break;
case 0xFEFF:
func = _io_file_lexfeed_UCS2_no_swap;
size -= 2; // Skip BOM
break; break;
case 0xFEFF: func = _io_file_lexfeed_UCS2_no_swap; break;
case 0xBBEF: // UTF-8 case 0xBBEF: // UTF-8
case 0xEFBB: // UTF-8 on big-endian machine case 0xEFBB: { // UTF-8 on big-endian machine
if (fread(&uc, 1, sizeof(uc), file) == 0) { /* Similarly, check the file is actually big enough to finish checking BOM */
if (size < 3) {
FioFCloseFile(file); FioFCloseFile(file);
return sq_throwerror(vm, "I/O error"); return sq_throwerror(vm, "I/O error");
} }
unsigned char uc;
fread(&uc, 1, sizeof(uc), file);
if (uc != 0xBF) { if (uc != 0xBF) {
FioFCloseFile(file); FioFCloseFile(file);
return sq_throwerror(vm, "Unrecognized encoding"); return sq_throwerror(vm, "Unrecognized encoding");
} }
func = _io_file_lexfeed_UTF8; func = _io_file_lexfeed_UTF8;
size -= 3; // Skip BOM
break; break;
}
default: // ASCII default: // ASCII
func = _io_file_lexfeed_ASCII; func = _io_file_lexfeed_ASCII;
if (fseek(file, -2, SEEK_CUR) < 0) { /* Account for when we might not have fread'd earlier */
if (size >= 2 && fseek(file, -2, SEEK_CUR) < 0) {
FioFCloseFile(file); FioFCloseFile(file);
return sq_throwerror(vm, "cannot seek the file"); return sq_throwerror(vm, "cannot seek the file");
} }
break; break;
} }
SQFile f(file, size);
if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) { if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) {
FioFCloseFile(file); FioFCloseFile(file);
return SQ_OK; return SQ_OK;
} }
FioFCloseFile(file); FioFCloseFile(file);
return SQ_ERROR; return SQ_ERROR;
}
return sq_throwerror(vm, "cannot open the file");
} }
bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root) bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)