Compare commits

...

9 Commits

Author SHA1 Message Date
Syoyo Fujita
1a5046e06b Fix MSVC compile failure on AppVeyor CI. 2023-04-23 23:08:41 +09:00
Syoyo Fujita
877d856e71 Format error message.
Add regression test of issue-416.
2023-04-23 21:47:31 +09:00
Syoyo Fujita
b534b6b0d8 Fix syntax. 2023-04-23 21:40:23 +09:00
Syoyo Fujita
ecfd37dee2 - Add GetFileSizeInBytes Filesystem Callback
- Add feature to limit file size for external resources(images, buffers)
- Use strlen to correctly retrieve a string from a string which contains multiple null-characters.
- Return fail when opening a directory(Posix only). Fixes #416
2023-04-23 21:31:30 +09:00
Syoyo Fujita
5a6c55870e Deprecate ubuntu-18.04 image and update CI build configuration. 2023-04-10 18:51:29 +09:00
Syoyo Fujita
d71c6f61f3 Merge pull request #409 from NeilBickford-NV/nbickford/update-stb-image
Updates stb_image and stb_image_write
2023-03-30 18:13:12 +09:00
Neil Bickford
b5d27fd151 stb_image: Apply https://github.com/nothings/stb/pull/1443 2023-03-29 12:00:24 -07:00
Neil Bickford
af4456ba68 stb_image: Apply https://github.com/nothings/stb/pull/1454 2023-03-29 11:57:27 -07:00
Neil Bickford
344669ddf6 Update stb_image and stb_image_write to latest nothings/stb dev branch: 9f1776a36d 2023-03-29 11:56:13 -07:00
6 changed files with 1194 additions and 387 deletions

View File

@@ -4,41 +4,43 @@ on: [push, pull_request]
jobs:
# compile with older gcc4.8
build-gcc48:
# gcc4.8 is too old and ubuntu-18.04 image is not supported in GitHub Actions anymore,
# so disable this build.
## compile with older gcc4.8
#build-gcc48:
runs-on: ubuntu-18.04
name: Build with gcc 4.8
# runs-on: ubuntu-18.04
# name: Build with gcc 4.8
steps:
- name: Checkout
uses: actions/checkout@v1
# steps:
# - name: Checkout
# uses: actions/checkout@v1
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-4.8 g++-4.8
g++-4.8 -std=c++11 -o loader_example loader_example.cc
# - name: Build
# run: |
# sudo apt-get update
# sudo apt-get install -y build-essential
# sudo apt-get install -y gcc-4.8 g++-4.8
# g++-4.8 -std=c++11 -o loader_example loader_example.cc
- name: NoexceptBuild
run: |
g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
# - name: NoexceptBuild
# run: |
# g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
- name: RapidjsonBuild
run: |
git clone https://github.com/Tencent/rapidjson
g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
# - name: RapidjsonBuild
# run: |
# git clone https://github.com/Tencent/rapidjson
# g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
# compile with mingw gcc cross
build-mingw-cross:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
name: Build with MinGW gcc cross
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- name: Build
run: |
@@ -133,20 +135,20 @@ jobs:
# Cross-compile for aarch64 linux target
build-cross-aarch64:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
name: Build on cross aarch64
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
git clone https://github.com/Tencent/rapidjson
aarch64-linux-gnu-g++-8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
aarch64-linux-gnu-g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
# macOS clang
build-macos:

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* stb_image_write - v1.11 - public domain - http://nothings.org/stb/stb_image_write.h
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@@ -10,11 +10,6 @@
Will probably not work correctly with strict-aliasing optimizations.
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
compilation warnings or even errors. To avoid this, also before #including,
#define STBI_MSC_SECURE_CRT
ABOUT:
This header file is a library for writing images to C stdio or a callback.
@@ -110,7 +105,7 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
@@ -118,7 +113,7 @@ USAGE:
CREDITS:
Sean Barrett - PNG/BMP/TGA
Sean Barrett - PNG/BMP/TGA
Baldur Karlsson - HDR
Jean-Sebastien Guay - TGA monochrome
Tim Kelsey - misc enhancements
@@ -145,6 +140,7 @@ CREDITS:
Ivan Tikhonov
github:ignotion
Adam Schackart
Andrew Kensler
LICENSE
@@ -171,9 +167,9 @@ LICENSE
#endif
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
extern int stbi_write_tga_with_rle;
extern int stbi_write_png_compression_level;
extern int stbi_write_force_png_filter;
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_compression_level;
STBIWDEF int stbi_write_force_png_filter;
#endif
#ifndef STBI_WRITE_NO_STDIO
@@ -183,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
#ifdef STBI_WINDOWS_UTF8
#ifdef STBIW_WINDOWS_UTF8
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
#endif
@@ -252,17 +248,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi__flip_vertically_on_write=0;
static int stbi_write_png_compression_level = 8;
static int stbi_write_tga_with_rle = 1;
static int stbi_write_force_png_filter = -1;
#else
int stbi_write_png_compression_level = 8;
int stbi__flip_vertically_on_write=0;
int stbi_write_tga_with_rle = 1;
int stbi_write_force_png_filter = -1;
#endif
static int stbi__flip_vertically_on_write = 0;
STBIWDEF void stbi_flip_vertically_on_write(int flag)
{
stbi__flip_vertically_on_write = flag;
@@ -272,6 +268,8 @@ typedef struct
{
stbi_write_func *func;
void *context;
unsigned char buffer[64];
int buf_used;
} stbi__write_context;
// initialize a callback-based context
@@ -288,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size)
fwrite(data,1,size,(FILE*) context);
}
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
#ifdef __cplusplus
#define STBIW_EXTERN extern "C"
#else
@@ -299,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, bufferlen, NULL, NULL);
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
}
#endif
static FILE *stbiw__fopen(char const *filename, char const *mode)
{
FILE *f;
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
wchar_t wMode[64];
wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0;
#if _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0;
#else
f = _wfopen(wFilename, wMode);
#endif
@@ -385,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
va_end(v);
}
static void stbiw__write_flush(stbi__write_context *s)
{
if (s->buf_used) {
s->func(s->context, &s->buffer, s->buf_used);
s->buf_used = 0;
}
}
static void stbiw__putc(stbi__write_context *s, unsigned char c)
{
s->func(s->context, &c, 1);
}
static void stbiw__write1(stbi__write_context *s, unsigned char a)
{
if ((size_t)s->buf_used + 1 > sizeof(s->buffer))
stbiw__write_flush(s);
s->buffer[s->buf_used++] = a;
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
s->func(s->context, arr, 3);
int n;
if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
stbiw__write_flush(s);
n = s->buf_used;
s->buf_used = n+3;
s->buffer[n+0] = a;
s->buffer[n+1] = b;
s->buffer[n+2] = c;
}
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
@@ -403,7 +421,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
int k;
if (write_alpha < 0)
s->func(s->context, &d[comp - 1], 1);
stbiw__write1(s, d[comp - 1]);
switch (comp) {
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
@@ -411,7 +429,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
if (expand_mono)
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
else
s->func(s->context, d, 1); // monochrome TGA
stbiw__write1(s, d[0]); // monochrome TGA
break;
case 4:
if (!write_alpha) {
@@ -427,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
break;
}
if (write_alpha > 0)
s->func(s->context, &d[comp - 1], 1);
stbiw__write1(s, d[comp - 1]);
}
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
@@ -441,16 +459,18 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
if (stbi__flip_vertically_on_write)
vdir *= -1;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
if (vdir < 0) {
j_end = -1; j = y-1;
} else {
j_end = y; j = 0;
}
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
}
stbiw__write_flush(s);
s->func(s->context, &zero, scanline_pad);
}
}
@@ -471,16 +491,27 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x,
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
if (comp != 4) {
// write RGB bitmap
int pad = (-x*3) & 3;
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
} else {
// RGBA bitmaps need a v4 header
// use BI_BITFIELDS mode with 32bpp and alpha mask
// (straight BI_RGB with alpha mask doesn't work in most readers)
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header
108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header
}
}
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_bmp_core(&s, x, y, comp, data);
}
@@ -488,7 +519,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_bmp_core(&s, x, y, comp, data);
stbi__end_write_file(&s);
@@ -561,24 +592,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
if (diff) {
unsigned char header = STBIW_UCHAR(len - 1);
s->func(s->context, &header, 1);
stbiw__write1(s, header);
for (k = 0; k < len; ++k) {
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
}
} else {
unsigned char header = STBIW_UCHAR(len - 129);
s->func(s->context, &header, 1);
stbiw__write1(s, header);
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
}
}
}
stbiw__write_flush(s);
}
return 1;
}
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_tga_core(&s, x, y, comp, (void *) data);
}
@@ -586,7 +618,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
stbi__end_write_file(&s);
@@ -602,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
#ifndef STBI_WRITE_NO_STDIO
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
int exponent;
@@ -736,8 +770,8 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1);
#ifdef STBI_MSC_SECURE_CRT
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#ifdef __STDC_LIB_EXT1__
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#endif
@@ -752,15 +786,14 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
stbi__end_write_file(&s);
@@ -778,7 +811,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
#ifndef STBIW_ZLIB_COMPRESS
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
@@ -872,7 +905,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));
if (hash_table == NULL)
return NULL;
if (quality < 5) quality = 5;
@@ -895,7 +928,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
if (d >= best) { best=d; bestloc=hlist[j]; }
}
}
// when hash table entry is too long, delete half the entries
@@ -948,14 +981,31 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
(void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
// store uncompressed instead if compression was worse
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1
for (j = 0; j < data_len;) {
int blocklen = data_len - j;
if (blocklen > 32767) blocklen = 32767;
stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression
stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
memcpy(out+stbiw__sbn(out), data+j, blocklen);
stbiw__sbn(out) += blocklen;
j += blocklen;
}
}
{
// compute adler32 on input
unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552);
j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }
s1 %= 65521; s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
@@ -1048,13 +1098,13 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int
int type = mymap[filter_type];
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
if (type==0) {
memcpy(line_buffer, z, width*n);
return;
}
// first loop isn't optimized since it's just one pixel
// first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) {
switch (type) {
case 1: line_buffer[i] = z[i]; break;
@@ -1275,26 +1325,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
bits[0] = val & ((1<<bits[1])-1);
}
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos;
int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64];
// DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) {
for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
// DCT columns
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
}
// Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) {
float v = CDU[i]*fdtbl[i];
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
for(y = 0, j=0; y < 8; ++y) {
for(x = 0; x < 8; ++x,++j) {
float v;
i = y*du_stride+x;
v = CDU[i]*fdtbl[j];
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
}
// Encode DC
@@ -1409,10 +1464,10 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k;
int row, col, i, k, subsample;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
@@ -1421,6 +1476,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
}
quality = quality ? quality : 90;
subsample = quality <= 90 ? 1 : 0;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
@@ -1443,7 +1499,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1);
@@ -1466,36 +1522,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *)data;
const unsigned char *dataG = dataR + ofsG;
const unsigned char *dataB = dataR + ofsB;
int x, y, pos;
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
float r, g, b;
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
if(subsample) {
for(y = 0; y < height; y += 16) {
for(x = 0; x < width; x += 16) {
float Y[256], U[256], V[256];
for(row = y, pos = 0; row < y+16; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+16; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
r = imageData[p+0];
g = imageData[p+ofsG];
b = imageData[p+ofsB];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
// subsample U,V
{
float subU[64], subV[64];
int yy, xx;
for(yy = 0, pos = 0; yy < 8; ++yy) {
for(xx = 0; xx < 8; ++xx, ++pos) {
int j = yy*32+xx*2;
subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;
subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;
}
}
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
} else {
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for(row = y, pos = 0; row < y+8; ++row) {
// row >= height => use last input row
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
// if col >= width => use pixel from last input column
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
}
@@ -1512,7 +1606,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__write_context s = { 0 };
stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
@@ -1521,7 +1615,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__write_context s = { 0 };
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s);
@@ -1534,8 +1628,17 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.16 (2021-07-11)
make Deflate code emit uncompressed blocks when it would otherwise expand
support writing BMPs with alpha channel
1.15 (2020-07-13) unknown
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1.13
1.12
1.11 (2019-08-11)
1.10 (2019-02-07)
support utf8 filenames in Windows; fix warnings and platform ifdefs
support utf8 filenames in Windows; fix warnings and platform ifdefs
1.09 (2018-02-11)
fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1.08 (2018-01-29)
@@ -1566,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
@@ -1584,38 +1687,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

1
tests/issue-416.gltf Normal file
View File

@@ -0,0 +1 @@
{"images":[{"uri":"%!QAAAQAAA5"}],"asset":{"version":""}}

View File

@@ -721,3 +721,39 @@ TEST_CASE("serialize-image-failure", "[issue-394]") {
REQUIRE(false == result);
REQUIRE(os.str().size() == 0);
}
TEST_CASE("filesize-check", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
ctx.SetMaxExternalFileSize(10); // 10 bytes. will fail to load texture image.
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Cube/Cube.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(false == ret);
}
TEST_CASE("load-issue-416-model", "[issue-416]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "issue-416.gltf");
if (!warn.empty()) {
std::cout << "WARN:" << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "ERR:" << err << std::endl;
}
// external file load fails, but reading glTF itself is ok.
REQUIRE(true == ret);
}

View File

@@ -1301,6 +1301,12 @@ typedef bool (*WriteWholeFileFunction)(std::string *, const std::string &,
const std::vector<unsigned char> &,
void *);
///
/// GetFileSizeFunction type. Signature for custom filesystem callbacks.
///
typedef bool (*GetFileSizeFunction)(size_t *filesize_out, std::string *err, const std::string &abs_filename,
void *userdata);
///
/// A structure containing all required filesystem callbacks and a pointer to
/// their user data.
@@ -1310,6 +1316,7 @@ struct FsCallbacks {
ExpandFilePathFunction ExpandFilePath;
ReadWholeFileFunction ReadWholeFile;
WriteWholeFileFunction WriteWholeFile;
GetFileSizeFunction GetFileSizeInBytes; // To avoid GetFileSize Win32 API, add `InBytes` suffix.
void *user_data; // An argument that is passed to all fs callbacks
};
@@ -1333,6 +1340,9 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
bool WriteWholeFile(std::string *err, const std::string &filepath,
const std::vector<unsigned char> &contents, void *);
bool GetFileSizeInBytes(size_t *filesize_out, std::string *err, const std::string &filepath,
void *);
#endif
///
@@ -1472,6 +1482,19 @@ class TinyGLTF {
preserve_image_channels_ = onoff;
}
///
/// Set maximum allowed external file size in bytes.
/// Default: 2GB
/// Only effective for built-in ReadWholeFileFunction FS function.
///
void SetMaxExternalFileSize(size_t max_bytes) {
max_external_file_size_ = max_bytes;
}
size_t GetMaxExternalFileSize() const {
return max_external_file_size_;
}
bool GetPreserveImageChannels() const { return preserve_image_channels_; }
private:
@@ -1496,6 +1519,8 @@ class TinyGLTF {
bool preserve_image_channels_ = false; /// Default false(expand channels to
/// RGBA) for backward compatibility.
size_t max_external_file_size_{size_t((std::numeric_limits<int32_t>::max)())}; // Default 2GB
// Warning & error messages
std::string warn_;
std::string err_;
@@ -1503,11 +1528,11 @@ class TinyGLTF {
FsCallbacks fs = {
#ifndef TINYGLTF_NO_FS
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
&tinygltf::ReadWholeFile, &tinygltf::WriteWholeFile,
&tinygltf::ReadWholeFile, &tinygltf::WriteWholeFile, &tinygltf::GetFileSizeInBytes,
nullptr // Fs callback user data
#else
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr // Fs callback user data
#endif
@@ -1554,6 +1579,7 @@ class TinyGLTF {
#ifndef TINYGLTF_NO_FS
#include <cstdio>
#include <fstream>
#include <sys/stat.h> // for is_directory check
#endif
#include <sstream>
@@ -2107,9 +2133,19 @@ static std::string FindFile(const std::vector<std::string> &paths,
return std::string();
}
// https://github.com/syoyo/tinygltf/issues/416
// Use strlen() since std::string's size/length reports the number of elements in the buffer, not the length of string(null-terminated)
// strip null-character in the middle of string.
size_t slength = strlen(filepath.c_str());
if (slength == 0) {
return std::string();
}
std::string cleaned_filepath = std::string(filepath.c_str());
for (size_t i = 0; i < paths.size(); i++) {
std::string absPath =
fs->ExpandFilePath(JoinPath(paths[i], filepath), fs->user_data);
fs->ExpandFilePath(JoinPath(paths[i], cleaned_filepath), fs->user_data);
if (fs->FileExists(absPath, fs->user_data)) {
return absPath;
}
@@ -2355,7 +2391,7 @@ bool URIDecode(const std::string &in_uri, std::string *out_uri,
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
std::string *warn, const std::string &filename,
const std::string &basedir, bool required,
size_t reqBytes, bool checkSize, FsCallbacks *fs) {
size_t reqBytes, bool checkSize, size_t maxFileSize, FsCallbacks *fs) {
if (fs == nullptr || fs->FileExists == nullptr ||
fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) {
// This is a developer error, assert() ?
@@ -2381,6 +2417,29 @@ static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
return false;
}
// Check file size
if (fs->GetFileSizeInBytes) {
size_t file_size{0};
std::string _err;
bool ok = fs-GetFileSizeInBytes(&file_size, &_err, filepath, fs->user_data);
if (!ok) {
if (_err.size()) {
if (failMsgOut) {
(*failMsgOut) += "Getting file size failed : " + filename + ", err = " + _err + "\n";
}
}
return false;
}
if (file_size > maxFileSize) {
if (failMsgOut) {
(*failMsgOut) += "File size " + std::to_string(file_size) + " exceeds maximum allowed file size " + std::to_string(maxFileSize) + " : " + filepath + "\n";
}
return false;
}
}
std::vector<unsigned char> buf;
std::string fileReadErr;
bool fileRead =
@@ -2687,12 +2746,23 @@ bool FileExists(const std::string &abs_filename, void *) {
#else
#ifdef _WIN32
#if defined(_MSC_VER) || defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
// First check if a file is a directory.
DWORD result = GetFileAttributesW(UTF8ToWchar(abs_filename).c_str());
if (result == INVALID_FILE_ATTRIBUTES) {
return false;
}
if (result & FILE_ATTRIBUTE_DIRECTORY) {
return false;
}
FILE *fp = nullptr;
errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb");
if (err != 0) {
return false;
}
#else
// TODO: is_directory check
FILE *fp = nullptr;
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
if (err != 0) {
@@ -2701,6 +2771,14 @@ bool FileExists(const std::string &abs_filename, void *) {
#endif
#else
struct stat sb;
if (stat(abs_filename.c_str(), &sb)) {
return false;
}
if (S_ISDIR(sb.st_mode)) {
return false;
}
FILE *fp = fopen(abs_filename.c_str(), "rb");
#endif
if (fp) {
@@ -2777,6 +2855,100 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
#endif
}
bool GetFileSizeInBytes(size_t *filesize_out, std::string *err,
const std::string &filepath, void *userdata) {
(void)userdata;
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(),
AASSET_MODE_STREAMING);
if (!asset) {
if (err) {
(*err) += "File open error : " + filepath + "\n";
}
return false;
}
size_t size = AAsset_getLength(asset);
if (size == 0) {
if (err) {
(*err) += "Invalid file size : " + filepath +
" (does the path point to a directory?)";
}
return false;
}
return true;
} else {
if (err) {
(*err) += "No asset manager specified : " + filepath + "\n";
}
return false;
}
#else
#ifdef _WIN32
#if defined(__GLIBCXX__) // mingw
int file_descriptor =
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
std::istream f(&wfile_buf);
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
// For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
// `wchar_t *`
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
#else
// Unknown compiler/runtime
std::ifstream f(filepath.c_str(), std::ifstream::binary);
#endif
#else
std::ifstream f(filepath.c_str(), std::ifstream::binary);
#endif
if (!f) {
if (err) {
(*err) += "File open error : " + filepath + "\n";
}
return false;
}
// For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only)
int buf = f.peek();
if (!f) {
if (err) {
(*err) += "File read error. Maybe empty file or invalid file : " + filepath + "\n";
}
return false;
}
f.seekg(0, f.end);
size_t sz = static_cast<size_t>(f.tellg());
//std::cout << "sz = " << sz << "\n";
f.seekg(0, f.beg);
if (int64_t(sz) < 0) {
if (err) {
(*err) += "Invalid file size : " + filepath +
" (does the path point to a directory?)";
}
return false;
} else if (sz == 0) {
if (err) {
(*err) += "File is empty : " + filepath + "\n";
}
return false;
} else if (sz >= (std::numeric_limits<std::streamoff>::max)()) {
if (err) {
(*err) += "Invalid file size : " + filepath + "\n";
}
return false;
}
(*filesize_out) = sz;
return true;
#endif
}
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
const std::string &filepath, void *) {
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
@@ -2832,8 +3004,19 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
return false;
}
// For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only)
int buf = f.peek();
if (!f) {
if (err) {
(*err) += "File read error. Maybe empty file or invalid file : " + filepath + "\n";
}
return false;
}
f.seekg(0, f.end);
size_t sz = static_cast<size_t>(f.tellg());
//std::cout << "sz = " << sz << "\n";
f.seekg(0, f.beg);
if (int64_t(sz) < 0) {
@@ -2847,6 +3030,11 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
(*err) += "File is empty : " + filepath + "\n";
}
return false;
} else if (sz >= (std::numeric_limits<std::streamoff>::max)()) {
if (err) {
(*err) += "Invalid file size : " + filepath + "\n";
}
return false;
}
out->resize(sz);
@@ -3873,7 +4061,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const detail::json &o,
static bool ParseImage(Image *image, const int image_idx, std::string *err,
std::string *warn, const detail::json &o,
bool store_original_json_for_extras_and_extensions,
const std::string &basedir, FsCallbacks *fs,
const std::string &basedir, const size_t max_file_size, FsCallbacks *fs,
const URICallbacks *uri_cb,
LoadImageDataFunction *LoadImageData = nullptr,
void *load_image_user_data = nullptr) {
@@ -3973,8 +4161,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
if (err) {
(*err) += "Failed to decode 'uri' for image[" +
std::to_string(image_idx) + "] name = [" + image->name +
"]\n";
std::to_string(image_idx) + "] name = \"" + image->name +
"\"\n";
}
return false;
}
@@ -3989,8 +4177,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) {
if (warn) {
(*warn) += "Failed to decode 'uri' for image[" +
std::to_string(image_idx) + "] name = [" + image->name +
"]\n";
std::to_string(image_idx) + "] name = \"" + image->name +
"\"\n";
}
// Image loading failure is not critical to overall gltf loading.
@@ -3999,11 +4187,11 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
/* required */ false, /* required bytes */ 0,
/* checksize */ false, fs)) {
/* checksize */ false, /* max file size */ max_file_size, fs)) {
if (warn) {
(*warn) += "Failed to load external 'uri' for image[" +
std::to_string(image_idx) + "] name = [" + image->name +
"]\n";
std::to_string(image_idx) + "] name = \"" + decoded_uri +
"\"\n";
}
// If the image cannot be loaded, keep uri as image->uri.
return true;
@@ -4012,8 +4200,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
if (img.empty()) {
if (warn) {
(*warn) += "Image data is empty for image[" +
std::to_string(image_idx) + "] name = [" + image->name +
"] \n";
std::to_string(image_idx) + "] name = \"" + image->name +
"\" \n";
}
return false;
}
@@ -4176,7 +4364,7 @@ static bool ParseOcclusionTextureInfo(
static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
bool store_original_json_for_extras_and_extensions,
FsCallbacks *fs, const URICallbacks *uri_cb,
const std::string &basedir, bool is_binary = false,
const std::string &basedir, const size_t max_buffer_size, bool is_binary = false,
const unsigned char *bin_data = nullptr,
size_t bin_size = 0) {
size_t byteLength;
@@ -4228,7 +4416,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
}
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
decoded_uri, basedir, /* required */ true,
byteLength, /* checkSize */ true, fs)) {
byteLength, /* checkSize */ true, /* max_file_size */max_buffer_size, fs)) {
return false;
}
}
@@ -4276,7 +4464,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
}
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri,
basedir, /* required */ true, byteLength,
/* checkSize */ true, fs)) {
/* checkSize */ true, /* max file size */max_buffer_size, fs)) {
return false;
}
}
@@ -5811,7 +5999,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
Buffer buffer;
if (!ParseBuffer(&buffer, err, o,
store_original_json_for_extras_and_extensions_, &fs,
&uri_cb, base_dir, is_binary_, bin_data_, bin_size_)) {
&uri_cb, base_dir, max_external_file_size_, is_binary_, bin_data_, bin_size_)) {
return false;
}
@@ -6082,7 +6270,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
Image image;
if (!ParseImage(&image, idx, err, warn, o,
store_original_json_for_extras_and_extensions_, base_dir,
&fs, &uri_cb, &this->LoadImageData,
max_external_file_size_, &fs, &uri_cb, &this->LoadImageData,
load_image_user_data)) {
return false;
}