Merge branch 'dev' of https://github.com/nothings/stb into dev

This commit is contained in:
Sean Barrett 2021-07-07 00:39:10 -07:00
commit 08e4b18650
18 changed files with 311 additions and 1507 deletions

23
.github/workflows/ci-fuzz.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'stb'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'stb'
fuzz-seconds: 900
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure()
with:
name: artifacts
path: ./out/artifacts

View File

@ -1,4 +1,7 @@
language: C language: C
arch:
- AMD64
- ppc64le
install: true install: true
script: script:
- cd tests - cd tests

View File

@ -20,7 +20,8 @@ by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
library | lastest version | category | LoC | description library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | -------------------------------- --------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.20 | audio | 5563 | decode ogg vorbis files from file/memory to float/16-bit signed output <<<<<<< HEAD
**[stb_vorbis.c](stb_vorbis.c)** | 1.21 | audio | 5569 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_image.h](stb_image.h)** | 2.26 | graphics | 7762 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM **[stb_image.h](stb_image.h)** | 2.26 | graphics | 7762 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC, PNM
**[stb_truetype.h](stb_truetype.h)** | 1.24 | graphics | 5011 | parse, decode, and rasterize characters from truetype fonts **[stb_truetype.h](stb_truetype.h)** | 1.24 | graphics | 5011 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.15 | graphics | 1690 | image writing to disk: PNG, TGA, BMP, JPG, HDR **[stb_image_write.h](stb_image_write.h)** | 1.15 | graphics | 1690 | image writing to disk: PNG, TGA, BMP, JPG, HDR
@ -43,7 +44,7 @@ library | lastest version | category | LoC | description
**[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL **[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
Total libraries: 21 Total libraries: 21
Total lines of C code: 56524 Total lines of C code: 56530
FAQ FAQ

File diff suppressed because it is too large Load Diff

View File

@ -104,7 +104,7 @@ DOCUMENTATION
moving the rest of the array over. Returns b. moving the rest of the array over. Returns b.
arrinsn: arrinsn:
void arrins(T* a, int p, int n); void arrinsn(T* a, int p, int n);
Inserts n uninitialized items into array a starting at a[p], Inserts n uninitialized items into array a starting at a[p],
moving the rest of the array over. moving the rest of the array over.
@ -123,7 +123,7 @@ DOCUMENTATION
Deletes the element at a[p], moving the rest of the array over. Deletes the element at a[p], moving the rest of the array over.
arrdeln: arrdeln:
void arrdel(T* a, int p, int n); void arrdeln(T* a, int p, int n);
Deletes n elements starting at a[p], moving the rest of the array over. Deletes n elements starting at a[p], moving the rest of the array over.
arrdelswap: arrdelswap:

View File

@ -111,7 +111,7 @@ RECENT REVISION HISTORY:
Josh Tobin Matthew Gregan github:poppolopoppo Josh Tobin Matthew Gregan github:poppolopoppo
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
Brad Weinberger Matvey Cherevko [reserved] Brad Weinberger Matvey Cherevko github:mosra
Luca Sas Alexander Veselov Zack Middleton [reserved] Luca Sas Alexander Veselov Zack Middleton [reserved]
Ryan C. Gordon [reserved] [reserved] Ryan C. Gordon [reserved] [reserved]
DO NOT ADD YOUR NAME HERE DO NOT ADD YOUR NAME HERE
@ -310,11 +310,10 @@ RECENT REVISION HISTORY:
// //
// iPhone PNG support: // iPhone PNG support:
// //
// By default we convert iphone-formatted PNGs back to RGB, even though // We optionally support converting iPhone-formatted PNGs (which store
// they are internally encoded differently. You can disable this conversion // premultiplied BGRA) back to RGB, even though they're internally encoded
// by calling stbi_convert_iphone_png_to_rgb(0), in which case // differently. To enable this conversion, call
// you will always just get the native iphone "format" through (which // stbi_convert_iphone_png_to_rgb(1).
// is BGR stored in RGB).
// //
// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
// pixel to remove any premultiplied alpha *only* if the image file explicitly // pixel to remove any premultiplied alpha *only* if the image file explicitly
@ -518,6 +517,8 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
// as above, but only applies to images loaded on the thread that calls the function // as above, but only applies to images loaded on the thread that calls the function
// this function is only available if your compiler supports thread-local variables; // this function is only available if your compiler supports thread-local variables;
// calling it will fail to link if your compiler doesn't // calling it will fail to link if your compiler doesn't
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
// ZLIB client - used by PNG, available for other purposes // ZLIB client - used by PNG, available for other purposes
@ -3821,6 +3822,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
else else
decode_n = z->s->img_n; decode_n = z->s->img_n;
// nothing to do if no components requested; check this now to avoid
// accessing uninitialized coutput[0] later
if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }
// resample and color-convert // resample and color-convert
{ {
int k; int k;
@ -4923,19 +4928,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
return 1; return 1;
} }
static int stbi__unpremultiply_on_load = 0; static int stbi__unpremultiply_on_load_global = 0;
static int stbi__de_iphone_flag = 0; static int stbi__de_iphone_flag_global = 0;
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
{ {
stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;
} }
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
{ {
stbi__de_iphone_flag = flag_true_if_should_convert; stbi__de_iphone_flag_global = flag_true_if_should_convert;
} }
#ifndef STBI_THREAD_LOCAL
#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global
#define stbi__de_iphone_flag stbi__de_iphone_flag_global
#else
static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
{
stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
stbi__unpremultiply_on_load_set = 1;
}
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)
{
stbi__de_iphone_flag_local = flag_true_if_should_convert;
stbi__de_iphone_flag_set = 1;
}
#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \
? stbi__unpremultiply_on_load_local \
: stbi__unpremultiply_on_load_global)
#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \
? stbi__de_iphone_flag_local \
: stbi__de_iphone_flag_global)
#endif // STBI_THREAD_LOCAL
static void stbi__de_iphone(stbi__png *z) static void stbi__de_iphone(stbi__png *z)
{ {
stbi__context *s = z->s; stbi__context *s = z->s;
@ -5316,6 +5348,32 @@ typedef struct
int extra_read; int extra_read;
} stbi__bmp_data; } stbi__bmp_data;
static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)
{
// BI_BITFIELDS specifies masks explicitly, don't override
if (compress == 3)
return 1;
if (compress == 0) {
if (info->bpp == 16) {
info->mr = 31u << 10;
info->mg = 31u << 5;
info->mb = 31u << 0;
} else if (info->bpp == 32) {
info->mr = 0xffu << 16;
info->mg = 0xffu << 8;
info->mb = 0xffu << 0;
info->ma = 0xffu << 24;
info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
} else {
// otherwise, use defaults, which is all-0
info->mr = info->mg = info->mb = info->ma = 0;
}
return 1;
}
return 0; // error
}
static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{ {
int hsz; int hsz;
@ -5343,6 +5401,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
if (hsz != 12) { if (hsz != 12) {
int compress = stbi__get32le(s); int compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes
if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard sizeof
stbi__get32le(s); // discard hres stbi__get32le(s); // discard hres
stbi__get32le(s); // discard vres stbi__get32le(s); // discard vres
@ -5357,17 +5417,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
} }
if (info->bpp == 16 || info->bpp == 32) { if (info->bpp == 16 || info->bpp == 32) {
if (compress == 0) { if (compress == 0) {
if (info->bpp == 32) { stbi__bmp_set_mask_defaults(info, compress);
info->mr = 0xffu << 16;
info->mg = 0xffu << 8;
info->mb = 0xffu << 0;
info->ma = 0xffu << 24;
info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
} else {
info->mr = 31u << 10;
info->mg = 31u << 5;
info->mb = 31u << 0;
}
} else if (compress == 3) { } else if (compress == 3) {
info->mr = stbi__get32le(s); info->mr = stbi__get32le(s);
info->mg = stbi__get32le(s); info->mg = stbi__get32le(s);
@ -5382,6 +5432,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
} else { } else {
// V4/V5 header
int i; int i;
if (hsz != 108 && hsz != 124) if (hsz != 108 && hsz != 124)
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
@ -5389,6 +5440,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->mg = stbi__get32le(s); info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s); info->mb = stbi__get32le(s);
info->ma = stbi__get32le(s); info->ma = stbi__get32le(s);
if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs
stbi__bmp_set_mask_defaults(info, compress);
stbi__get32le(s); // discard color space stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i) for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters stbi__get32le(s); // discard color space parameters
@ -6862,9 +6915,10 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
} }
if (delays) { if (delays) {
*delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
if (!*delays) if (!new_delays)
return stbi__load_gif_main_outofmem(&g, out, delays); return stbi__load_gif_main_outofmem(&g, out, delays);
*delays = new_delays;
delays_size = layers * sizeof(int); delays_size = layers * sizeof(int);
} }
} else { } else {
@ -7200,9 +7254,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
info.all_a = 255; info.all_a = 255;
p = stbi__bmp_parse_header(s, &info); p = stbi__bmp_parse_header(s, &info);
stbi__rewind( s ); if (p == NULL) {
if (p == NULL) stbi__rewind( s );
return 0; return 0;
}
if (x) *x = s->img_x; if (x) *x = s->img_x;
if (y) *y = s->img_y; if (y) *y = s->img_y;
if (comp) { if (comp) {
@ -7474,7 +7529,6 @@ static int stbi__pnm_is16(stbi__context *s)
return 1; return 1;
return 0; return 0;
} }
#endif #endif
static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)

View File

@ -178,7 +178,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_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); 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); STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif #endif
#endif #endif
@ -285,7 +285,7 @@ static void stbi__stdio_write(void *context, void *data, int size)
fwrite(data,1,size,(FILE*) context); fwrite(data,1,size,(FILE*) context);
} }
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
#ifdef __cplusplus #ifdef __cplusplus
#define STBIW_EXTERN extern "C" #define STBIW_EXTERN extern "C"
#else #else
@ -296,25 +296,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) STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{ {
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
} }
#endif #endif
static FILE *stbiw__fopen(char const *filename, char const *mode) static FILE *stbiw__fopen(char const *filename, char const *mode)
{ {
FILE *f; FILE *f;
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
wchar_t wMode[64]; wchar_t wMode[64];
wchar_t wFilename[1024]; wchar_t wFilename[1024];
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0; return 0;
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0; return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != _wfopen_s(&f, wFilename, wMode)) if (0 != _wfopen_s(&f, wFilename, wMode))
f = 0; f = 0;
#else #else
f = _wfopen(wFilename, wMode); f = _wfopen(wFilename, wMode);
#endif #endif
@ -622,6 +622,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)) #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) static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{ {
int exponent; int exponent;
@ -756,7 +758,7 @@ 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"; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
s->func(s->context, header, sizeof(header)-1); s->func(s->context, header, sizeof(header)-1);
#ifdef __STDC_WANT_SECURE_LIB__ #ifdef __STDC_LIB_EXT1__
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
#else #else
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
@ -777,7 +779,6 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x,
return stbi_write_hdr_core(&s, x, y, comp, (float *) data); 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) STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{ {
stbi__write_context s = { 0 }; stbi__write_context s = { 0 };
@ -1635,7 +1636,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
add HDR output add HDR output
fix monochrome BMP fix monochrome BMP
0.95 (2014-08-17) 0.95 (2014-08-17)
add monochrome TGA output add monochrome TGA output
0.94 (2014-05-31) 0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27) 0.93 (2014-05-27)

View File

@ -1,4 +1,4 @@
// stb_textedit.h - v1.13 - public domain - Sean Barrett // stb_textedit.h - v1.14 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools // Development of this library was sponsored by RAD Game Tools
// //
// This C header file implements the guts of a multi-line text-editing // This C header file implements the guts of a multi-line text-editing
@ -29,6 +29,7 @@
// //
// VERSION HISTORY // VERSION HISTORY
// //
// 1.14 ( ) page up/down, various fixes
// 1.13 (2019-02-07) fix bug in undo size management // 1.13 (2019-02-07) fix bug in undo size management
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
@ -52,6 +53,7 @@
// Ulf Winklemann: move-by-word in 1.1 // Ulf Winklemann: move-by-word in 1.1
// Fabian Giesen: secondary key inputs in 1.5 // Fabian Giesen: secondary key inputs in 1.5
// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
// Louis Schnellbach: page up/down in 1.14
// //
// Bugfixes: // Bugfixes:
// Scott Graham // Scott Graham
@ -142,6 +144,8 @@
// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right
// STB_TEXTEDIT_K_UP keyboard input to move cursor up // STB_TEXTEDIT_K_UP keyboard input to move cursor up
// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME
// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END
// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME
@ -164,10 +168,6 @@
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
// //
// Todo:
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
//
// Keyboard input must be encoded as a single integer value; e.g. a character code // Keyboard input must be encoded as a single integer value; e.g. a character code
// and some bitflags that represent shift states. to simplify the interface, SHIFT must // and some bitflags that represent shift states. to simplify the interface, SHIFT must
// be a bitflag, so we can test the shifted state of cursor movements to allow selection, // be a bitflag, so we can test the shifted state of cursor movements to allow selection,
@ -331,6 +331,10 @@ typedef struct
// each textfield keeps its own insert mode state. to keep an app-wide // each textfield keeps its own insert mode state. to keep an app-wide
// insert mode, copy this value in/out of the app state // insert mode, copy this value in/out of the app state
int row_count_per_page;
// page size in number of row.
// this value MUST be set to >0 for pageup or pagedown in multilines documents.
///////////////////// /////////////////////
// //
// private data // private data
@ -708,9 +712,7 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
state->has_preferred_x = 0; state->has_preferred_x = 0;
return 1; return 1;
} }
// remove the undo since we didn't actually insert the characters // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details)
if (state->undostate.undo_point)
--state->undostate.undo_point;
return 0; return 0;
} }
@ -849,12 +851,16 @@ retry:
break; break;
case STB_TEXTEDIT_K_DOWN: case STB_TEXTEDIT_K_DOWN:
case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
case STB_TEXTEDIT_K_PGDOWN:
case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
StbFindState find; StbFindState find;
StbTexteditRow row; StbTexteditRow row;
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
int row_count = is_page ? state->row_count_per_page : 1;
if (state->single_line) { if (!is_page && state->single_line) {
// on windows, up&down in single-line behave like left&right // on windows, up&down in single-line behave like left&right
key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
goto retry; goto retry;
@ -863,17 +869,20 @@ retry:
if (sel) if (sel)
stb_textedit_prep_selection_at_cursor(state); stb_textedit_prep_selection_at_cursor(state);
else if (STB_TEXT_HAS_SELECTION(state)) else if (STB_TEXT_HAS_SELECTION(state))
stb_textedit_move_to_last(str,state); stb_textedit_move_to_last(str, state);
// compute current position of cursor point // compute current position of cursor point
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
// now find character position down a row for (j = 0; j < row_count; ++j) {
if (find.length) { float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
int start = find.first_char + find.length; int start = find.first_char + find.length;
if (find.length == 0)
break;
// now find character position down a row
state->cursor = start; state->cursor = start;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0; x = row.x0;
@ -895,17 +904,25 @@ retry:
if (sel) if (sel)
state->select_end = state->cursor; state->select_end = state->cursor;
// go to next line
find.first_char = find.first_char + find.length;
find.length = row.num_chars;
} }
break; break;
} }
case STB_TEXTEDIT_K_UP: case STB_TEXTEDIT_K_UP:
case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
case STB_TEXTEDIT_K_PGUP:
case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
StbFindState find; StbFindState find;
StbTexteditRow row; StbTexteditRow row;
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
int row_count = is_page ? state->row_count_per_page : 1;
if (state->single_line) { if (!is_page && state->single_line) {
// on windows, up&down become left&right // on windows, up&down become left&right
key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
goto retry; goto retry;
@ -920,11 +937,14 @@ retry:
stb_textedit_clamp(str, state); stb_textedit_clamp(str, state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
// can only go up if there's a previous row for (j = 0; j < row_count; ++j) {
if (find.prev_first != find.first_char) { float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
// can only go up if there's a previous row
if (find.prev_first == find.first_char)
break;
// now find character position up a row // now find character position up a row
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
state->cursor = find.prev_first; state->cursor = find.prev_first;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0; x = row.x0;
@ -946,6 +966,14 @@ retry:
if (sel) if (sel)
state->select_end = state->cursor; state->select_end = state->cursor;
// go to previous line
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
--prev_scan;
find.first_char = find.prev_first;
find.prev_first = prev_scan;
} }
break; break;
} }
@ -1069,10 +1097,6 @@ retry:
state->has_preferred_x = 0; state->has_preferred_x = 0;
break; break;
} }
// @TODO:
// STB_TEXTEDIT_K_PGUP - move cursor up a page
// STB_TEXTEDIT_K_PGDOWN - move cursor down a page
} }
} }
@ -1337,6 +1361,7 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
state->initialized = 1; state->initialized = 1;
state->single_line = (unsigned char) is_single_line; state->single_line = (unsigned char) is_single_line;
state->insert_mode = 0; state->insert_mode = 0;
state->row_count_per_page = 0;
} }
// API initialize // API initialize

View File

@ -1,4 +1,4 @@
// stb_tilemap_editor.h - v0.41 - Sean Barrett - http://nothings.org/stb // stb_tilemap_editor.h - v0.42 - Sean Barrett - http://nothings.org/stb
// placed in the public domain - not copyrighted - first released 2014-09 // placed in the public domain - not copyrighted - first released 2014-09
// //
// Embeddable tilemap editor for C/C++ // Embeddable tilemap editor for C/C++
@ -275,6 +275,7 @@
// either approach allows cut&pasting between levels.) // either approach allows cut&pasting between levels.)
// //
// REVISION HISTORY // REVISION HISTORY
// 0.42 fix compilation errors
// 0.41 fix warnings // 0.41 fix warnings
// 0.40 fix warning // 0.40 fix warning
// 0.39 fix warning // 0.39 fix warning
@ -317,6 +318,8 @@
// Bugfixes: // Bugfixes:
// Ryan Whitworth // Ryan Whitworth
// Eugene Opalev // Eugene Opalev
// Rob Loach
// github:wernsey
// //
// LICENSE // LICENSE
// //
@ -1821,6 +1824,8 @@ static int stbte__button(int colormode, const char *label, int x, int y, int tex
int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT; int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
int s = STBTE__BUTTON_INTERNAL_SPACING; int s = STBTE__BUTTON_INTERNAL_SPACING;
if(!disabled) stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) if (stbte__ui.event == STBTE__paint)
stbte__draw_textbox(x0,y0,x1,y1, (char*) label,s+textoff,s, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled)); stbte__draw_textbox(x0,y0,x1,y1, (char*) label,s+textoff,s, colormode, STBTE__INDEX_FOR_ID(id,disabled,toggled));
if (disabled) if (disabled)
@ -1833,6 +1838,8 @@ static int stbte__button_icon(int colormode, char ch, int x, int y, int width, i
int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT; int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
int s = STBTE__BUTTON_INTERNAL_SPACING; int s = STBTE__BUTTON_INTERNAL_SPACING;
stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
char label[2] = { ch, 0 }; char label[2] = { ch, 0 };
int pad = (9 - stbte__get_char_width(ch))/2; int pad = (9 - stbte__get_char_width(ch))/2;
@ -1846,6 +1853,7 @@ static int stbte__button_icon(int colormode, char ch, int x, int y, int width, i
static int stbte__minibutton(int colormode, int x, int y, int ch, int id) static int stbte__minibutton(int colormode, int x, int y, int ch, int id)
{ {
int x0 = x, y0 = y, x1 = x+8, y1 = y+7; int x0 = x, y0 = y, x1 = x+8, y1 = y+7;
stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
char str[2] = { (char)ch, 0 }; char str[2] = { (char)ch, 0 };
stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0)); stbte__draw_textbox(x0,y0,x1,y1, str,1,0,colormode, STBTE__INDEX_FOR_ID(id,0,0));
@ -1856,6 +1864,7 @@ static int stbte__minibutton(int colormode, int x, int y, int ch, int id)
static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int disabled, int colormode) static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int disabled, int colormode)
{ {
int x0 = x, y0 = y, x1 = x+10, y1 = y+11; int x0 = x, y0 = y, x1 = x+10, y1 = y+11;
if(!disabled) stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
char str[2] = { (char)ch, 0 }; char str[2] = { (char)ch, 0 };
int off = (9-stbte__get_char_width(ch))/2; int off = (9-stbte__get_char_width(ch))/2;
@ -1869,6 +1878,7 @@ static int stbte__layerbutton(int x, int y, int ch, int id, int toggled, int dis
static int stbte__microbutton(int x, int y, int size, int id, int colormode) static int stbte__microbutton(int x, int y, int size, int id, int colormode)
{ {
int x0 = x, y0 = y, x1 = x+size, y1 = y+size; int x0 = x, y0 = y, x1 = x+size, y1 = y+size;
stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) { if (stbte__ui.event == STBTE__paint) {
stbte__draw_box(x0,y0,x1,y1, colormode, STBTE__INDEX_FOR_ID(id,0,0)); stbte__draw_box(x0,y0,x1,y1, colormode, STBTE__INDEX_FOR_ID(id,0,0));
} }
@ -1878,6 +1888,7 @@ static int stbte__microbutton(int x, int y, int size, int id, int colormode)
static int stbte__microbutton_dragger(int x, int y, int size, int id, int *pos) static int stbte__microbutton_dragger(int x, int y, int size, int id, int *pos)
{ {
int x0 = x, y0 = y, x1 = x+size, y1 = y+size; int x0 = x, y0 = y, x1 = x+size, y1 = y+size;
stbte__hittest(x0,y0,x1,y1,id);
switch (stbte__ui.event) { switch (stbte__ui.event) {
case STBTE__paint: case STBTE__paint:
stbte__draw_box(x0,y0,x1,y1, STBTE__cexpander, STBTE__INDEX_FOR_ID(id,0,0)); stbte__draw_box(x0,y0,x1,y1, STBTE__cexpander, STBTE__INDEX_FOR_ID(id,0,0));
@ -1908,6 +1919,8 @@ static int stbte__category_button(const char *label, int x, int y, int width, in
int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT; int x0=x,y0=y, x1=x+width,y1=y+STBTE__BUTTON_HEIGHT;
int s = STBTE__BUTTON_INTERNAL_SPACING; int s = STBTE__BUTTON_INTERNAL_SPACING;
stbte__hittest(x0,y0,x1,y1,id);
if (stbte__ui.event == STBTE__paint) if (stbte__ui.event == STBTE__paint)
stbte__draw_textbox(x0,y0,x1,y1, (char*) label, s,s, STBTE__ccategory_button, STBTE__INDEX_FOR_ID(id,0,toggled)); stbte__draw_textbox(x0,y0,x1,y1, (char*) label, s,s, STBTE__ccategory_button, STBTE__INDEX_FOR_ID(id,0,toggled));
@ -1927,6 +1940,7 @@ static int stbte__slider(int x0, int w, int y, int range, int *value, int id)
{ {
int x1 = x0+w; int x1 = x0+w;
int pos = *value * w / (range+1); int pos = *value * w / (range+1);
stbte__hittest(x0,y-2,x1,y+3,id);
int event_mouse_move = STBTE__change; int event_mouse_move = STBTE__change;
switch (stbte__ui.event) { switch (stbte__ui.event) {
case STBTE__paint: case STBTE__paint:
@ -1969,6 +1983,7 @@ static int stbte__float_control(int x0, int y0, int w, float minv, float maxv, f
{ {
int x1 = x0+w; int x1 = x0+w;
int y1 = y0+11; int y1 = y0+11;
stbte__hittest(x0,y0,x1,y1,id);
switch (stbte__ui.event) { switch (stbte__ui.event) {
case STBTE__paint: { case STBTE__paint: {
char text[32]; char text[32];
@ -1980,7 +1995,7 @@ static int stbte__float_control(int x0, int y0, int w, float minv, float maxv, f
case STBTE__rightdown: case STBTE__rightdown:
if (STBTE__IS_HOT(id) && STBTE__INACTIVE()) if (STBTE__IS_HOT(id) && STBTE__INACTIVE())
stbte__activate(id); stbte__activate(id);
return STBTE__begin; return STBTE__begin;
break; break;
case STBTE__leftup: case STBTE__leftup:
case STBTE__rightup: case STBTE__rightup:
@ -2020,7 +2035,6 @@ static int stbte__float_control(int x0, int y0, int w, float minv, float maxv, f
static void stbte__scrollbar(int x, int y0, int y1, int *val, int v0, int v1, int num_vis, int id) static void stbte__scrollbar(int x, int y0, int y1, int *val, int v0, int v1, int num_vis, int id)
{ {
int over;
int thumbpos; int thumbpos;
if (v1 - v0 <= num_vis) if (v1 - v0 <= num_vis)
return; return;
@ -2029,7 +2043,7 @@ static void stbte__scrollbar(int x, int y0, int y1, int *val, int v0, int v1, in
thumbpos = y0+2 + (y1-y0-4) * *val / (v1 - v0 - num_vis); thumbpos = y0+2 + (y1-y0-4) * *val / (v1 - v0 - num_vis);
if (thumbpos < y0) thumbpos = y0; if (thumbpos < y0) thumbpos = y0;
if (thumbpos >= y1) thumbpos = y1; if (thumbpos >= y1) thumbpos = y1;
over = stbte__hittest(x-1,y0,x+2,y1,id); stbte__hittest(x-1,y0,x+2,y1,id);
switch (stbte__ui.event) { switch (stbte__ui.event) {
case STBTE__paint: case STBTE__paint:
stbte__draw_rect(x,y0,x+1,y1, stbte__color_table[STBTE__cscrollbar][STBTE__text][STBTE__idle]); stbte__draw_rect(x,y0,x+1,y1, stbte__color_table[STBTE__cscrollbar][STBTE__text][STBTE__idle]);
@ -2807,6 +2821,10 @@ static void stbte__drag_update(stbte_tilemap *tm, int mapx, int mapy, int copy_p
int ox,oy,i,deleted=0,written=0; int ox,oy,i,deleted=0,written=0;
short temp[STBTE_MAX_LAYERS]; short temp[STBTE_MAX_LAYERS];
short *data = NULL; short *data = NULL;
STBTE__NOTUSED(deleted);
STBTE__NOTUSED(written);
if (!stbte__ui.shift) { if (!stbte__ui.shift) {
ox = mapx - stbte__ui.drag_x; ox = mapx - stbte__ui.drag_x;
oy = mapy - stbte__ui.drag_y; oy = mapy - stbte__ui.drag_y;
@ -2928,6 +2946,9 @@ static void stbte__tile_paint(stbte_tilemap *tm, int sx, int sy, int mapx, int m
{ {
int i; int i;
int id = STBTE__IDMAP(mapx,mapy); int id = STBTE__IDMAP(mapx,mapy);
int x0=sx, y0=sy;
int x1=sx+tm->spacing_x, y1=sy+tm->spacing_y;
stbte__hittest(x0,y0,x1,y1, id);
short *data = tm->data[mapy][mapx]; short *data = tm->data[mapy][mapx];
short temp[STBTE_MAX_LAYERS]; short temp[STBTE_MAX_LAYERS];
@ -2996,7 +3017,7 @@ static void stbte__tile_paint(stbte_tilemap *tm, int sx, int sy, int mapx, int m
i = layer; i = layer;
if (i == tm->solo_layer || (!tm->layerinfo[i].hidden && tm->solo_layer < 0)) if (i == tm->solo_layer || (!tm->layerinfo[i].hidden && tm->solo_layer < 0))
if (data[i] >= 0) if (data[i] >= 0)
STBTE_DRAW_TILE(x0,y0, (unsigned short) data[i], 0, tm->props[mapy][mapx]); STBTE_DRAW_TILE(sx,sy, (unsigned short) data[i], 0, tm->props[mapy][mapx]);
} }
} }
@ -3492,11 +3513,14 @@ static void stbte__categories(stbte_tilemap *tm, int x0, int y0, int w, int h)
static void stbte__tile_in_palette(stbte_tilemap *tm, int x, int y, int slot) static void stbte__tile_in_palette(stbte_tilemap *tm, int x, int y, int slot)
{ {
stbte__tileinfo *t = &tm->tiles[slot];
int x0=x, y0=y, x1 = x+tm->palette_spacing_x - 1, y1 = y+tm->palette_spacing_y;
int id = STBTE__ID(STBTE__palette, slot); int id = STBTE__ID(STBTE__palette, slot);
stbte__hittest(x0,y0,x1,y1, id);
switch (stbte__ui.event) { switch (stbte__ui.event) {
case STBTE__paint: case STBTE__paint:
stbte__draw_rect(x,y,x+tm->palette_spacing_x-1,y+tm->palette_spacing_x-1, STBTE_COLOR_TILEPALETTE_BACKGROUND); stbte__draw_rect(x,y,x+tm->palette_spacing_x-1,y+tm->palette_spacing_x-1, STBTE_COLOR_TILEPALETTE_BACKGROUND);
STBTE_DRAW_TILE(x,y,t->id, slot == tm->cur_tile,0); STBTE_DRAW_TILE(x,y,id, slot == tm->cur_tile,0);
if (slot == tm->cur_tile) if (slot == tm->cur_tile)
stbte__draw_frame_delayed(x-1,y-1,x+tm->palette_spacing_x,y+tm->palette_spacing_y, STBTE_COLOR_TILEPALETTE_OUTLINE); stbte__draw_frame_delayed(x-1,y-1,x+tm->palette_spacing_x,y+tm->palette_spacing_y, STBTE_COLOR_TILEPALETTE_OUTLINE);
break; break;
@ -3565,6 +3589,7 @@ static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h)
my = stbte__ui.select_y0; my = stbte__ui.select_y0;
p = tm->props[my][mx]; p = tm->props[my][mx];
data = tm->data[my][mx]; data = tm->data[my][mx];
STBTE__NOTUSED(data);
for (i=0; i < STBTE_MAX_PROPERTIES; ++i) { for (i=0; i < STBTE_MAX_PROPERTIES; ++i) {
unsigned int n = STBTE_PROP_TYPE(i, data, p); unsigned int n = STBTE_PROP_TYPE(i, data, p);
if (n) { if (n) {
@ -3644,8 +3669,9 @@ static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h)
} }
} }
static int stbte__cp_mode, stbte__cp_aspect, stbte__cp_state, stbte__cp_index, stbte__save, stbte__cp_altered, stbte__color_copy; static int stbte__cp_mode, stbte__cp_aspect, stbte__save, stbte__cp_altered;
#ifdef STBTE__COLORPICKER #ifdef STBTE__COLORPICKER
static int stbte__cp_state, stbte__cp_index, stbte__color_copy;
static void stbte__dump_colorstate(void) static void stbte__dump_colorstate(void)
{ {
int i,j,k; int i,j,k;

View File

@ -2454,8 +2454,6 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
classDefTable = classDef1ValueArray + 2 * glyphCount;
} break; } break;
case 2: { case 2: {
@ -2478,8 +2476,6 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
else else
return (stbtt_int32)ttUSHORT(classRangeRecord + 4); return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
} }
classDefTable = classRangeRecords + 6 * classRangeCount;
} break; } break;
default: { default: {
@ -4486,35 +4482,35 @@ static float stbtt__cuberoot( float x )
return (float) STBTT_pow( x,1.0f/3.0f); return (float) STBTT_pow( x,1.0f/3.0f);
} }
// x^3 + c*x^2 + b*x + a = 0 // x^3 + a*x^2 + b*x + c = 0
static int stbtt__solve_cubic(float a, float b, float c, float* r) static int stbtt__solve_cubic(float a, float b, float c, float* r)
{ {
float s = -a / 3; float s = -a / 3;
float p = b - a*a / 3; float p = b - a*a / 3;
float q = a * (2*a*a - 9*b) / 27 + c; float q = a * (2*a*a - 9*b) / 27 + c;
float p3 = p*p*p; float p3 = p*p*p;
float d = q*q + 4*p3 / 27; float d = q*q + 4*p3 / 27;
if (d >= 0) { if (d >= 0) {
float z = (float) STBTT_sqrt(d); float z = (float) STBTT_sqrt(d);
float u = (-q + z) / 2; float u = (-q + z) / 2;
float v = (-q - z) / 2; float v = (-q - z) / 2;
u = stbtt__cuberoot(u); u = stbtt__cuberoot(u);
v = stbtt__cuberoot(v); v = stbtt__cuberoot(v);
r[0] = s + u + v; r[0] = s + u + v;
return 1; return 1;
} else { } else {
float u = (float) STBTT_sqrt(-p/3); float u = (float) STBTT_sqrt(-p/3);
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
float m = (float) STBTT_cos(v); float m = (float) STBTT_cos(v);
float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
r[0] = s + u * 2 * m; r[0] = s + u * 2 * m;
r[1] = s - u * (m + n); r[1] = s - u * (m + n);
r[2] = s - u * (m - n); r[2] = s - u * (m - n);
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
return 3; return 3;
} }
} }

View File

@ -1,4 +1,4 @@
// Ogg Vorbis audio decoder - v1.20 - public domain // Ogg Vorbis audio decoder - v1.22 - public domain
// http://nothings.org/stb_vorbis/ // http://nothings.org/stb_vorbis/
// //
// Original version written by Sean Barrett in 2007. // Original version written by Sean Barrett in 2007.
@ -29,12 +29,15 @@
// Bernhard Wodo Evan Balster github:alxprd // Bernhard Wodo Evan Balster github:alxprd
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot // Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart // Phillip Bennefall Rohit Thiago Goulart
// github:manxorist saga musix github:infatum // github:manxorist Saga Musix github:infatum
// Timur Gagiev Maxwell Koo Peter Waller // Timur Gagiev Maxwell Koo Peter Waller
// github:audinowho Dougall Johnson David Reid // github:audinowho Dougall Johnson David Reid
// github:Clownacy Pedro J. Estebanez Remi Verschelde // github:Clownacy Pedro J. Estebanez Remi Verschelde
// AnthoFoxo github:morlat Gabriel Ravier
// //
// Partial history: // Partial history:
// 1.22 - - various small fixes
// 1.21 - 2021-07-02 - fix bug for files with no comments
// 1.20 - 2020-07-11 - several small fixes // 1.20 - 2020-07-11 - several small fixes
// 1.19 - 2020-02-05 - warnings // 1.19 - 2020-02-05 - warnings
// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. // 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.
@ -220,6 +223,12 @@ extern int stb_vorbis_decode_frame_pushdata(
// channel. In other words, (*output)[0][0] contains the first sample from // channel. In other words, (*output)[0][0] contains the first sample from
// the first channel, and (*output)[1][0] contains the first sample from // the first channel, and (*output)[1][0] contains the first sample from
// the second channel. // the second channel.
//
// *output points into stb_vorbis's internal output buffer storage; these
// buffers are owned by stb_vorbis and application code should not free
// them or modify their contents. They are transient and will be overwritten
// once you ask for more data to get decoded, so be sure to grab any data
// you need before then.
extern void stb_vorbis_flush_pushdata(stb_vorbis *f); extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
// inform stb_vorbis that your next datablock will not be contiguous with // inform stb_vorbis that your next datablock will not be contiguous with
@ -579,7 +588,7 @@ enum STBVorbisError
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h> #include <malloc.h>
#endif #endif
#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__)
#include <alloca.h> #include <alloca.h>
#endif #endif
#else // STB_VORBIS_NO_CRT #else // STB_VORBIS_NO_CRT
@ -646,6 +655,12 @@ typedef signed int int32;
typedef float codetype; typedef float codetype;
#ifdef _MSC_VER
#define STBV_NOTUSED(v) (void)(v)
#else
#define STBV_NOTUSED(v) (void)sizeof(v)
#endif
// @NOTE // @NOTE
// //
// Some arrays below are tagged "//varies", which means it's actually // Some arrays below are tagged "//varies", which means it's actually
@ -1046,7 +1061,7 @@ static float float32_unpack(uint32 x)
uint32 sign = x & 0x80000000; uint32 sign = x & 0x80000000;
uint32 exp = (x & 0x7fe00000) >> 21; uint32 exp = (x & 0x7fe00000) >> 21;
double res = sign ? -(double)mantissa : (double)mantissa; double res = sign ? -(double)mantissa : (double)mantissa;
return (float) ldexp((float)res, exp-788); return (float) ldexp((float)res, (int)exp-788);
} }
@ -1077,6 +1092,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
// find the first entry // find the first entry
for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
if (k == n) { assert(c->sorted_entries == 0); return TRUE; } if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
assert(len[k] < 32); // no error return required, code reading lens checks this
// add to the list // add to the list
add_entry(c, 0, k, m++, len[k], values); add_entry(c, 0, k, m++, len[k], values);
// add all available leaves // add all available leaves
@ -1090,6 +1106,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
uint32 res; uint32 res;
int z = len[i], y; int z = len[i], y;
if (z == NO_CODE) continue; if (z == NO_CODE) continue;
assert(z < 32); // no error return required, code reading lens checks this
// find lowest available leaf (should always be earliest, // find lowest available leaf (should always be earliest,
// which is what the specification calls for) // which is what the specification calls for)
// note that this property, and the fact we can never have // note that this property, and the fact we can never have
@ -1099,12 +1116,10 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
while (z > 0 && !available[z]) --z; while (z > 0 && !available[z]) --z;
if (z == 0) { return FALSE; } if (z == 0) { return FALSE; }
res = available[z]; res = available[z];
assert(z >= 0 && z < 32);
available[z] = 0; available[z] = 0;
add_entry(c, bit_reverse(res), i, m++, len[i], values); add_entry(c, bit_reverse(res), i, m++, len[i], values);
// propagate availability up the tree // propagate availability up the tree
if (z != len[i]) { if (z != len[i]) {
assert(len[i] >= 0 && len[i] < 32);
for (y=len[i]; y > z; --y) { for (y=len[i]; y > z; --y) {
assert(available[y] == 0); assert(available[y] == 0);
available[y] = res + (1 << (32-y)); available[y] = res + (1 << (32-y));
@ -2577,34 +2592,33 @@ static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A,
while (z > base) { while (z > base) {
float k00,k11; float k00,k11;
float l00,l11;
k00 = z[-0] - z[-8]; k00 = z[-0] - z[ -8];
k11 = z[-1] - z[-9]; k11 = z[-1] - z[ -9];
z[-0] = z[-0] + z[-8]; l00 = z[-2] - z[-10];
z[-1] = z[-1] + z[-9]; l11 = z[-3] - z[-11];
z[-8] = k00; z[ -0] = z[-0] + z[ -8];
z[-9] = k11 ; z[ -1] = z[-1] + z[ -9];
z[ -2] = z[-2] + z[-10];
z[ -3] = z[-3] + z[-11];
z[ -8] = k00;
z[ -9] = k11;
z[-10] = (l00+l11) * A2;
z[-11] = (l11-l00) * A2;
k00 = z[ -2] - z[-10]; k00 = z[ -4] - z[-12];
k11 = z[ -3] - z[-11];
z[ -2] = z[ -2] + z[-10];
z[ -3] = z[ -3] + z[-11];
z[-10] = (k00+k11) * A2;
z[-11] = (k11-k00) * A2;
k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation
k11 = z[ -5] - z[-13]; k11 = z[ -5] - z[-13];
l00 = z[ -6] - z[-14];
l11 = z[ -7] - z[-15];
z[ -4] = z[ -4] + z[-12]; z[ -4] = z[ -4] + z[-12];
z[ -5] = z[ -5] + z[-13]; z[ -5] = z[ -5] + z[-13];
z[-12] = k11;
z[-13] = k00;
k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation
k11 = z[ -7] - z[-15];
z[ -6] = z[ -6] + z[-14]; z[ -6] = z[ -6] + z[-14];
z[ -7] = z[ -7] + z[-15]; z[ -7] = z[ -7] + z[-15];
z[-14] = (k00+k11) * A2; z[-12] = k11;
z[-15] = (k00-k11) * A2; z[-13] = -k00;
z[-14] = (l11-l00) * A2;
z[-15] = (l00+l11) * -A2;
iter_54(z); iter_54(z);
iter_54(z-8); iter_54(z-8);
@ -3069,6 +3083,7 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
for (q=1; q < g->values; ++q) { for (q=1; q < g->values; ++q) {
j = g->sorted_order[q]; j = g->sorted_order[q];
#ifndef STB_VORBIS_NO_DEFER_FLOOR #ifndef STB_VORBIS_NO_DEFER_FLOOR
STBV_NOTUSED(step2_flag);
if (finalY[j] >= 0) if (finalY[j] >= 0)
#else #else
if (step2_flag[j]) if (step2_flag[j])
@ -3171,6 +3186,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// WINDOWING // WINDOWING
STBV_NOTUSED(left_end);
n = f->blocksize[m->blockflag]; n = f->blocksize[m->blockflag];
map = &f->mapping[m->mapping]; map = &f->mapping[m->mapping];
@ -3368,7 +3384,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
// this isn't to spec, but spec would require us to read ahead // this isn't to spec, but spec would require us to read ahead
// and decode the size of all current frames--could be done, // and decode the size of all current frames--could be done,
// but presumably it's not a commonly used feature // but presumably it's not a commonly used feature
f->current_loc = -n2; // start of first frame is positioned for discard f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around)
// we might have to discard samples "from" the next frame too, // we might have to discard samples "from" the next frame too,
// if we're lapping a large block then a small at the start? // if we're lapping a large block then a small at the start?
f->discard_samples_deferred = n - right_end; f->discard_samples_deferred = n - right_end;
@ -3642,8 +3658,12 @@ static int start_decoder(vorb *f)
f->vendor[len] = (char)'\0'; f->vendor[len] = (char)'\0';
//user comments //user comments
f->comment_list_length = get32_packet(f); f->comment_list_length = get32_packet(f);
f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); f->comment_list = NULL;
if (f->comment_list == NULL) return error(f, VORBIS_outofmem); if (f->comment_list_length > 0)
{
f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length));
if (f->comment_list == NULL) return error(f, VORBIS_outofmem);
}
for(i=0; i < f->comment_list_length; ++i) { for(i=0; i < f->comment_list_length; ++i) {
len = get32_packet(f); len = get32_packet(f);
@ -3865,8 +3885,7 @@ static int start_decoder(vorb *f)
unsigned int div=1; unsigned int div=1;
for (k=0; k < c->dimensions; ++k) { for (k=0; k < c->dimensions; ++k) {
int off = (z / div) % c->lookup_values; int off = (z / div) % c->lookup_values;
float val = mults[off]; float val = mults[off]*c->delta_value + c->minimum_value + last;
val = mults[off]*c->delta_value + c->minimum_value + last;
c->multiplicands[j*c->dimensions + k] = val; c->multiplicands[j*c->dimensions + k] = val;
if (c->sequence_p) if (c->sequence_p)
last = val; last = val;
@ -3949,7 +3968,7 @@ static int start_decoder(vorb *f)
if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
} }
for (k=0; k < 1 << g->class_subclasses[j]; ++k) { for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
g->subclass_books[j][k] = get_bits(f,8)-1; g->subclass_books[j][k] = (int16)get_bits(f,8)-1;
if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
} }
} }
@ -4507,6 +4526,7 @@ stb_vorbis *stb_vorbis_open_pushdata(
*error = VORBIS_need_more_data; *error = VORBIS_need_more_data;
else else
*error = p.error; *error = p.error;
vorbis_deinit(&p);
return NULL; return NULL;
} }
f = vorbis_alloc(&p); f = vorbis_alloc(&p);
@ -4564,7 +4584,7 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
header[i] = get8(f); header[i] = get8(f);
if (f->eof) return 0; if (f->eof) return 0;
if (header[4] != 0) goto invalid; if (header[4] != 0) goto invalid;
goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24);
for (i=22; i < 26; ++i) for (i=22; i < 26; ++i)
header[i] = 0; header[i] = 0;
crc = 0; crc = 0;
@ -4968,7 +4988,7 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
// set. whoops! // set. whoops!
break; break;
} }
previous_safe = last_page_loc+1; //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging
last_page_loc = stb_vorbis_get_file_offset(f); last_page_loc = stb_vorbis_get_file_offset(f);
} }
@ -5079,7 +5099,10 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const st
stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
{ {
stb_vorbis *f, p; stb_vorbis *f, p;
if (data == NULL) return NULL; if (!data) {
if (error) *error = VORBIS_unexpected_eof;
return NULL;
}
vorbis_init(&p, alloc); vorbis_init(&p, alloc);
p.stream = (uint8 *) data; p.stream = (uint8 *) data;
p.stream_end = (uint8 *) data + len; p.stream_end = (uint8 *) data + len;
@ -5154,11 +5177,11 @@ static void copy_samples(short *dest, float *src, int len)
static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
{ {
#define BUFFER_SIZE 32 #define STB_BUFFER_SIZE 32
float buffer[BUFFER_SIZE]; float buffer[STB_BUFFER_SIZE];
int i,j,o,n = BUFFER_SIZE; int i,j,o,n = STB_BUFFER_SIZE;
check_endianness(); check_endianness();
for (o = 0; o < len; o += BUFFER_SIZE) { for (o = 0; o < len; o += STB_BUFFER_SIZE) {
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
if (o + n > len) n = len - o; if (o + n > len) n = len - o;
for (j=0; j < num_c; ++j) { for (j=0; j < num_c; ++j) {
@ -5175,16 +5198,17 @@ static void compute_samples(int mask, short *output, int num_c, float **data, in
output[o+i] = v; output[o+i] = v;
} }
} }
#undef STB_BUFFER_SIZE
} }
static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
{ {
#define BUFFER_SIZE 32 #define STB_BUFFER_SIZE 32
float buffer[BUFFER_SIZE]; float buffer[STB_BUFFER_SIZE];
int i,j,o,n = BUFFER_SIZE >> 1; int i,j,o,n = STB_BUFFER_SIZE >> 1;
// o is the offset in the source data // o is the offset in the source data
check_endianness(); check_endianness();
for (o = 0; o < len; o += BUFFER_SIZE >> 1) { for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) {
// o2 is the offset in the output data // o2 is the offset in the output data
int o2 = o << 1; int o2 = o << 1;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
@ -5214,6 +5238,7 @@ static void compute_stereo_samples(short *output, int num_c, float **data, int d
output[o2+i] = v; output[o2+i] = v;
} }
} }
#undef STB_BUFFER_SIZE
} }
static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
@ -5286,8 +5311,6 @@ int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short
float **outputs; float **outputs;
int len = num_shorts / channels; int len = num_shorts / channels;
int n=0; int n=0;
int z = f->channels;
if (z > channels) z = channels;
while (n < len) { while (n < len) {
int k = f->channel_buffer_end - f->channel_buffer_start; int k = f->channel_buffer_end - f->channel_buffer_start;
if (n+k >= len) k = len - n; if (n+k >= len) k = len - n;
@ -5306,8 +5329,6 @@ int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, in
{ {
float **outputs; float **outputs;
int n=0; int n=0;
int z = f->channels;
if (z > channels) z = channels;
while (n < len) { while (n < len) {
int k = f->channel_buffer_end - f->channel_buffer_start; int k = f->channel_buffer_end - f->channel_buffer_start;
if (n+k >= len) k = len - n; if (n+k >= len) k = len - n;

View File

@ -17,9 +17,13 @@ cp $SRC/stb/tests/stb_png.dict $OUT/stb_png_read_fuzzer.dict
tar xvzf $SRC/stb/jpg.tar.gz --directory $SRC/stb/tests tar xvzf $SRC/stb/jpg.tar.gz --directory $SRC/stb/tests
tar xvzf $SRC/stb/gif.tar.gz --directory $SRC/stb/tests tar xvzf $SRC/stb/gif.tar.gz --directory $SRC/stb/tests
unzip $SRC/stb/bmp.zip -d $SRC/stb/tests
unzip $SRC/stb/tga.zip -d $SRC/stb/tests
find $SRC/stb/tests -name "*.png" -o -name "*.jpg" -o -name ".gif" | \ find $SRC/stb/tests -name "*.png" -o -name "*.jpg" -o -name "*.gif" \
xargs zip $OUT/stbi_read_fuzzer_seed_corpus.zip -o -name "*.bmp" -o -name "*.tga" -o -name "*.TGA" \
-o -name "*.ppm" -o -name "*.pgm" \
| xargs zip $OUT/stbi_read_fuzzer_seed_corpus.zip
echo "" >> $SRC/stb/tests/gif.dict echo "" >> $SRC/stb/tests/gif.dict
cat $SRC/stb/tests/gif.dict $SRC/stb/tests/stb_png.dict > $OUT/stbi_read_fuzzer.dict cat $SRC/stb/tests/gif.dict $SRC/stb/tests/stb_png.dict > $OUT/stbi_read_fuzzer.dict

BIN
tests/pbm/basi0g16.pgm Normal file

Binary file not shown.

BIN
tests/pbm/basi2c16.ppm Normal file

Binary file not shown.

BIN
tests/pbm/cdfn2c08.ppm Normal file

Binary file not shown.

BIN
tests/pbm/cdun2c08.ppm Normal file

Binary file not shown.

BIN
tests/pbm/comment.pgm Normal file

Binary file not shown.

BIN
tests/pbm/ctfn0g04.pgm Normal file

Binary file not shown.