[core] add INI file/portable support

* Application will start in portable mode if its name contains a 'p'
  eg. "rufus_portable.exe" or "prufus.exe"
* Closes #264
* Also fix a couple smaller issues
This commit is contained in:
Pete Batard 2015-01-25 00:56:38 +00:00
parent 7b0a5abab1
commit 17872dc1de
13 changed files with 369 additions and 79 deletions

View file

@ -37,6 +37,7 @@
static const char space[] = " \t";
static const wchar_t wspace[] = L" \t";
static const char* conversion_error = "Could not convert '%s' to UTF-16";
const struct {char c; int flag;} attr_parse[] = {
{ 'r', LOC_RIGHT_TO_LEFT },
@ -215,7 +216,7 @@ FILE* open_loc_file(const char* filename)
}
wfilename = utf8_to_wchar(filename);
if (wfilename == NULL) {
uprintf("localization: could not convert '%s' filename to UTF-16\n", filename);
uprintf(conversion_error, filename);
goto out;
}
fd = _wfopen(wfilename, L"rb");
@ -638,12 +639,12 @@ char* get_token_data_file(const char* token, const char* filename)
wfilename = utf8_to_wchar(filename);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", filename);
uprintf(conversion_error, filename);
goto out;
}
wtoken = utf8_to_wchar(token);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", token);
uprintf(conversion_error, token);
goto out;
}
fd = _wfopen(wfilename, L"r, ccs=UNICODE");
@ -667,6 +668,159 @@ out:
return ret;
}
/*
* replace or add 'data' for token 'token' in config file 'filename'
*/
char* set_token_data_file(const char* token, const char* data, const char* filename)
{
const wchar_t* outmode[] = { L"w", L"w, ccs=UTF-8", L"w, ccs=UTF-16LE" };
wchar_t *wtoken = NULL, *wfilename = NULL, *wtmpname = NULL, *wdata = NULL, bom = 0;
wchar_t buf[1024];
FILE *fd_in = NULL, *fd_out = NULL;
size_t i, size;
int mode = 0;
char *ret = NULL, tmp[2];
if ((filename == NULL) || (token == NULL) || (data == NULL))
return NULL;
if ((filename[0] == 0) || (token[0] == 0) || (data[0] == 0))
return NULL;
wfilename = utf8_to_wchar(filename);
if (wfilename == NULL) {
uprintf(conversion_error, filename);
goto out;
}
wtoken = utf8_to_wchar(token);
if (wfilename == NULL) {
uprintf(conversion_error, token);
goto out;
}
wdata = utf8_to_wchar(data);
if (wdata == NULL) {
uprintf(conversion_error, data);
goto out;
}
fd_in = _wfopen(wfilename, L"r, ccs=UNICODE");
if (fd_in == NULL) {
uprintf("Could not open file '%s'\n", filename);
goto out;
}
// Check the input file's BOM and create an output file with the same
if (fread(&bom, sizeof(bom), 1, fd_in) == 1) {
switch(bom) {
case 0xFEFF:
mode = 2; // UTF-16 (LE)
break;
case 0xBBEF: // Yeah, the UTF-8 BOM is really 0xEF,0xBB,0xBF, but
mode = 1; // find me a non UTF-8 file that actually begins with "ï»"
break;
default:
mode = 0; // ANSI
break;
}
fseek(fd_in, 0, SEEK_SET);
}
wtmpname = (wchar_t*)calloc(wcslen(wfilename)+2, sizeof(wchar_t));
if (wtmpname == NULL) {
uprintf("Could not allocate space for temporary output name\n");
goto out;
}
wcscpy(wtmpname, wfilename);
wtmpname[wcslen(wtmpname)] = '~';
fd_out = _wfopen(wtmpname, outmode[mode]);
if (fd_out == NULL) {
uprintf("Could not open temporary output file '%s~'\n", filename);
goto out;
}
// Process individual lines. NUL is always appended.
while (fgetws(buf, ARRAYSIZE(buf), fd_in) != NULL) {
i = 0;
// Skip leading spaces
i += wcsspn(&buf[i], wspace);
// Ignore comments or section headers
if ((buf[i] == ';') || (buf[i] == '[')) {
fputws(buf, fd_out);
continue;
}
// Our token should begin a line
if (_wcsnicmp(&buf[i], wtoken, wcslen(wtoken)) != 0) {
fputws(buf, fd_out);
continue;
}
// Token was found, move past token
i += wcslen(wtoken);
// Skip spaces
i += wcsspn(&buf[i], wspace);
// Check for an equal sign
if (buf[i] != L'=') {
fputws(buf, fd_out);
continue;
}
i++;
// Skip spaces after equal sign
i += wcsspn(&buf[i], wspace);
// Output the token
buf[i] = 0;
fputws(buf, fd_out);
// Now output the new data
fwprintf(fd_out, L"%s\n", wdata);
ret = (char*)data;
}
if (ret == NULL) {
// Didn't find an existing token => append it
fwprintf(fd_out, L"%s = %s\n", wtoken, wdata);
ret = (char*)data;
}
out:
if (fd_in != NULL) fclose(fd_in);
if (fd_out != NULL) fclose(fd_out);
// If an insertion occurred, delete existing file and use the new one
if (ret != NULL) {
// We're in Windows text mode => Remove CRs if requested
fd_in = _wfopen(wtmpname, L"rb");
fd_out = _wfopen(wfilename, L"wb");
// Don't check fds
if ((fd_in != NULL) && (fd_out != NULL)) {
size = (mode==2)?2:1;
while(fread(tmp, size, 1, fd_in) == 1)
fwrite(tmp, size, 1, fd_out);
fclose(fd_in);
fclose(fd_out);
} else {
uprintf("Could not write '%s' - original file has been left unmodified\n", filename);
ret = NULL;
if (fd_in != NULL) fclose(fd_in);
if (fd_out != NULL) fclose(fd_out);
}
}
if (wtmpname != NULL)
_wunlink(wtmpname);
safe_free(wfilename);
safe_free(wtmpname);
safe_free(wtoken);
safe_free(wdata);
return ret;
}
/*
* Parse a buffer (ANSI or UTF-8) and return the data for the 'n'th occurrence of 'token'
* The returned string is UTF-8 and MUST be freed by the caller
@ -806,17 +960,17 @@ char* insert_section_data(const char* filename, const char* section, const char*
wfilename = utf8_to_wchar(filename);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", filename);
uprintf(conversion_error, filename);
goto out;
}
wsection = utf8_to_wchar(section);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", section);
uprintf(conversion_error, section);
goto out;
}
wdata = utf8_to_wchar(data);
if (wdata == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", data);
uprintf(conversion_error, data);
goto out;
}
@ -842,9 +996,8 @@ char* insert_section_data(const char* filename, const char* section, const char*
break;
}
fseek(fd_in, 0, SEEK_SET);
duprintf("'%s' was detected as %s\n", filename,
(mode==0)?"ANSI/UTF8 (no BOM)":((mode==1)?"UTF8 (with BOM)":"UTF16 (with BOM"));
// duprintf("'%s' was detected as %s\n", filename,
// (mode==0)?"ANSI/UTF8 (no BOM)":((mode==1)?"UTF8 (with BOM)":"UTF16 (with BOM"));
wtmpname = (wchar_t*)calloc(wcslen(wfilename)+2, sizeof(wchar_t));
if (wtmpname == NULL) {
@ -941,22 +1094,22 @@ char* replace_in_token_data(const char* filename, const char* token, const char*
wfilename = utf8_to_wchar(filename);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", filename);
uprintf(conversion_error, filename);
goto out;
}
wtoken = utf8_to_wchar(token);
if (wfilename == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", token);
uprintf(conversion_error, token);
goto out;
}
wsrc = utf8_to_wchar(src);
if (wsrc == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", src);
uprintf(conversion_error, src);
goto out;
}
wrep = utf8_to_wchar(rep);
if (wsrc == NULL) {
uprintf("Could not convert '%s' to UTF-16\n", rep);
uprintf(conversion_error, rep);
goto out;
}
@ -1015,7 +1168,7 @@ char* replace_in_token_data(const char* filename, const char* token, const char*
}
// Token was found, move past token
i += strlen(token);
i += wcslen(wtoken);
// Skip spaces
i += wcsspn(&buf[i], wspace);