2013-12-25 21:40:33 -08:00
|
|
|
/*
|
2014-03-04 06:07:13 -08:00
|
|
|
* Copyright (c) 2013-2014 Hugh Bailey <obs.jim@gmail.com>
|
2013-12-25 21:40:33 -08:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "c99defs.h"
|
|
|
|
#include "platform.h"
|
|
|
|
#include "bmem.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
#include "dstr.h"
|
|
|
|
|
|
|
|
FILE *os_wfopen(const wchar_t *path, const char *mode)
|
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
wchar_t *wcs_mode;
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
os_utf8_to_wcs_ptr(mode, 0, &wcs_mode);
|
2013-09-30 19:37:13 -07:00
|
|
|
file = _wfopen(path, wcs_mode);
|
|
|
|
bfree(wcs_mode);
|
|
|
|
#else
|
|
|
|
char *mbs_path;
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
os_wcs_to_utf8_ptr(path, 0, &mbs_path);
|
2013-09-30 19:37:13 -07:00
|
|
|
file = fopen(mbs_path, mode);
|
|
|
|
bfree(mbs_path);
|
|
|
|
#endif
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *os_fopen(const char *path, const char *mode)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
wchar_t *wpath = NULL;
|
|
|
|
FILE *file = NULL;
|
2014-03-04 06:07:13 -08:00
|
|
|
os_utf8_to_wcs_ptr(path, 0, &wpath);
|
2013-09-30 19:37:13 -07:00
|
|
|
file = os_wfopen(wpath, mode);
|
|
|
|
bfree(wpath);
|
|
|
|
|
|
|
|
return file;
|
|
|
|
#else
|
|
|
|
return fopen(path, mode);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
int64_t os_fgetsize(FILE *file)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-05-16 00:18:23 -07:00
|
|
|
int64_t cur_offset = os_ftelli64(file);
|
|
|
|
int64_t size;
|
2013-09-30 19:37:13 -07:00
|
|
|
int errval = 0;
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
if (fseek(file, 0, SEEK_END) == -1)
|
2013-09-30 19:37:13 -07:00
|
|
|
return -1;
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
size = os_ftelli64(file);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (size == -1)
|
|
|
|
errval = errno;
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
if (os_fseeki64(file, cur_offset, SEEK_SET) != 0 && errval != 0)
|
2013-09-30 19:37:13 -07:00
|
|
|
errno = errval;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
int os_fseeki64(FILE *file, int64_t offset, int origin)
|
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
return _fseeki64(file, offset, origin);
|
|
|
|
#else
|
|
|
|
return fseeko(file, offset, origin);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t os_ftelli64(FILE *file)
|
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
return _ftelli64(file);
|
|
|
|
#else
|
|
|
|
return ftello(file);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
size_t os_fread_mbs(FILE *file, char **pstr)
|
|
|
|
{
|
2013-10-17 17:21:42 -07:00
|
|
|
size_t size = 0;
|
2013-09-30 19:37:13 -07:00
|
|
|
size_t len = 0;
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
size = (size_t)os_ftelli64(file);
|
2014-02-14 14:56:01 -08:00
|
|
|
*pstr = NULL;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
char *mbstr = bmalloc(size+1);
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
fseek(file, 0, SEEK_SET);
|
2014-02-14 14:56:01 -08:00
|
|
|
size = fread(mbstr, 1, size, file);
|
|
|
|
if (size == 0) {
|
|
|
|
bfree(mbstr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
mbstr[size] = 0;
|
2014-03-04 06:07:13 -08:00
|
|
|
len = os_mbs_to_utf8_ptr(mbstr, size, pstr);
|
2013-09-30 19:37:13 -07:00
|
|
|
bfree(mbstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_fread_utf8(FILE *file, char **pstr)
|
|
|
|
{
|
2013-10-17 17:21:42 -07:00
|
|
|
size_t size = 0;
|
2014-02-14 14:56:01 -08:00
|
|
|
size_t size_read;
|
2013-09-30 19:37:13 -07:00
|
|
|
size_t len = 0;
|
|
|
|
|
2014-04-18 22:37:21 -07:00
|
|
|
*pstr = NULL;
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
size = (size_t)os_ftelli64(file);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
char bom[3];
|
2014-02-09 07:01:08 -08:00
|
|
|
char *utf8str;
|
2013-09-30 19:37:13 -07:00
|
|
|
off_t offset;
|
|
|
|
|
|
|
|
/* remove the ghastly BOM if present */
|
2014-05-16 00:18:23 -07:00
|
|
|
fseek(file, 0, SEEK_SET);
|
2014-02-14 14:56:01 -08:00
|
|
|
size_read = fread(bom, 1, 3, file);
|
|
|
|
if (size_read != 3)
|
|
|
|
return 0;
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
offset = (astrcmp_n(bom, "\xEF\xBB\xBF", 3) == 0) ? 3 : 0;
|
|
|
|
|
2014-02-09 07:01:08 -08:00
|
|
|
size -= offset;
|
2014-04-18 22:37:21 -07:00
|
|
|
if (size == 0)
|
|
|
|
return 0;
|
|
|
|
|
2014-02-09 07:01:08 -08:00
|
|
|
utf8str = bmalloc(size+1);
|
2014-05-16 00:18:23 -07:00
|
|
|
fseek(file, offset, SEEK_SET);
|
2014-02-14 14:56:01 -08:00
|
|
|
|
|
|
|
size = fread(utf8str, 1, size, file);
|
|
|
|
if (size == 0) {
|
|
|
|
bfree(utf8str);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
utf8str[size] = 0;
|
|
|
|
|
|
|
|
*pstr = utf8str;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *os_quick_read_mbs_file(const char *path)
|
|
|
|
{
|
|
|
|
FILE *f = os_fopen(path, "rb");
|
|
|
|
char *file_string = NULL;
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
os_fread_mbs(f, &file_string);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return file_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *os_quick_read_utf8_file(const char *path)
|
|
|
|
{
|
|
|
|
FILE *f = os_fopen(path, "rb");
|
|
|
|
char *file_string = NULL;
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
os_fread_utf8(f, &file_string);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return file_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool os_quick_write_mbs_file(const char *path, const char *str, size_t len)
|
|
|
|
{
|
|
|
|
FILE *f = os_fopen(path, "wb");
|
|
|
|
char *mbs = NULL;
|
|
|
|
size_t mbs_len = 0;
|
|
|
|
if (!f)
|
|
|
|
return false;
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
mbs_len = os_utf8_to_mbs_ptr(str, len, &mbs);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (mbs_len)
|
|
|
|
fwrite(mbs, 1, mbs_len, f);
|
|
|
|
bfree(mbs);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool os_quick_write_utf8_file(const char *path, const char *str, size_t len,
|
|
|
|
bool marker)
|
|
|
|
{
|
|
|
|
FILE *f = os_fopen(path, "wb");
|
|
|
|
if (!f)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (marker)
|
|
|
|
fwrite("\xEF\xBB\xBF", 1, 3, f);
|
|
|
|
if (len)
|
|
|
|
fwrite(str, 1, len, f);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_mbs_to_wcs(const char *str, size_t len, wchar_t *dst)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t out_len = dst ? len : mbstowcs(NULL, str, len);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
if (len && dst) {
|
2013-09-30 19:37:13 -07:00
|
|
|
mbstowcs(dst, str, out_len+1);
|
|
|
|
dst[out_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_utf8_to_wcs(const char *str, size_t len, wchar_t *dst)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
size_t in_len = len ? len : strlen(str);
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t out_len = dst ? len : utf8_to_wchar(str, in_len, NULL, 0, 0);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
if (out_len && dst) {
|
2013-09-30 19:37:13 -07:00
|
|
|
utf8_to_wchar(str, in_len, dst, out_len+1, 0);
|
|
|
|
dst[out_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_wcs_to_mbs(const wchar_t *str, size_t len, char *dst)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t out_len = dst ? len : wcstombs(NULL, str, len);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
if (len && dst) {
|
2013-09-30 19:37:13 -07:00
|
|
|
wcstombs(dst, str, out_len+1);
|
|
|
|
dst[out_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_wcs_to_utf8(const wchar_t *str, size_t len, char *dst)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2013-10-17 17:21:42 -07:00
|
|
|
size_t in_len = (len != 0) ? len : wcslen(str);
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t out_len = dst ? len : wchar_to_utf8(str, in_len, NULL, 0, 0);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
if (out_len && dst) {
|
2013-09-30 19:37:13 -07:00
|
|
|
wchar_to_utf8(str, in_len, dst, out_len+1, 0);
|
|
|
|
dst[out_len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_mbs_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr)
|
|
|
|
{
|
|
|
|
size_t out_len = os_mbs_to_wcs(str, len, NULL);
|
|
|
|
|
|
|
|
*pstr = bmalloc((out_len+1) * sizeof(wchar_t));
|
|
|
|
return os_mbs_to_wcs(str, out_len, *pstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_utf8_to_wcs_ptr(const char *str, size_t len, wchar_t **pstr)
|
|
|
|
{
|
|
|
|
size_t out_len = os_utf8_to_wcs(str, len, NULL);
|
|
|
|
*pstr = bmalloc((out_len+1) * sizeof(wchar_t));
|
|
|
|
return os_utf8_to_wcs(str, out_len, *pstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_wcs_to_mbs_ptr(const wchar_t *str, size_t len, char **pstr)
|
|
|
|
{
|
|
|
|
size_t out_len = os_wcs_to_mbs(str, len, NULL);
|
|
|
|
|
|
|
|
*pstr = bmalloc((out_len+1) * sizeof(char));
|
|
|
|
return os_wcs_to_mbs(str, out_len, *pstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_wcs_to_utf8_ptr(const wchar_t *str, size_t len, char **pstr)
|
|
|
|
{
|
|
|
|
size_t out_len = os_wcs_to_utf8(str, len, NULL);
|
|
|
|
|
|
|
|
*pstr = bmalloc((out_len+1) * sizeof(char));
|
|
|
|
return os_wcs_to_utf8(str, out_len, *pstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_utf8_to_mbs_ptr(const char *str, size_t len, char **pstr)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
wchar_t *wstr = NULL;
|
|
|
|
char *dst = NULL;
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t wlen = os_utf8_to_wcs_ptr(str, len, &wstr);
|
|
|
|
size_t out_len = os_wcs_to_mbs_ptr(wstr, wlen, &dst);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
bfree(wstr);
|
|
|
|
*pstr = dst;
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|
|
|
|
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t os_mbs_to_utf8_ptr(const char *str, size_t len, char **pstr)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
wchar_t *wstr = NULL;
|
|
|
|
char *dst = NULL;
|
2014-03-04 06:07:13 -08:00
|
|
|
size_t wlen = os_mbs_to_wcs_ptr(str, len, &wstr);
|
|
|
|
size_t out_len = os_wcs_to_utf8_ptr(wstr, wlen, &dst);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
bfree(wstr);
|
|
|
|
*pstr = dst;
|
|
|
|
|
|
|
|
return out_len;
|
|
|
|
}
|