├── CMakeLists.txt ├── LICENSE ├── README.md ├── ok_csv.c ├── ok_csv.h ├── ok_fnt.c ├── ok_fnt.h ├── ok_jpg.c ├── ok_jpg.h ├── ok_mo.c ├── ok_mo.h ├── ok_png.c ├── ok_png.h ├── ok_png_write.c ├── ok_png_write.h ├── ok_wav.c ├── ok_wav.h └── test ├── .gitignore ├── CMakeLists.txt ├── PngSuite ├── PngSuite.LICENSE ├── PngSuite.README ├── PngSuite.png ├── basi0g01.png ├── basi0g02.png ├── basi0g04.png ├── basi0g08.png ├── basi0g16.png ├── basi2c08.png ├── basi2c16.png ├── basi3p01.png ├── basi3p02.png ├── basi3p04.png ├── basi3p08.png ├── basi4a08.png ├── basi4a16.png ├── basi6a08.png ├── basi6a16.png ├── basn0g01.png ├── basn0g02.png ├── basn0g04.png ├── basn0g08.png ├── basn0g16.png ├── basn2c08.png ├── basn2c16.png ├── basn3p01.png ├── basn3p02.png ├── basn3p04.png ├── basn3p08.png ├── basn4a08.png ├── basn4a16.png ├── basn6a08.png ├── basn6a16.png ├── bgai4a08.png ├── bgai4a16.png ├── bgan6a08.png ├── bgan6a16.png ├── bgbn4a08.png ├── bggn4a16.png ├── bgwn6a08.png ├── bgyn6a16.png ├── ccwn2c08.png ├── ccwn3p08.png ├── cdfn2c08.png ├── cdhn2c08.png ├── cdsn2c08.png ├── cdun2c08.png ├── ch1n3p04.png ├── ch2n3p08.png ├── cm0n0g04.png ├── cm7n0g04.png ├── cm9n0g04.png ├── cs3n2c16.png ├── cs3n3p08.png ├── cs5n2c08.png ├── cs5n3p08.png ├── cs8n2c08.png ├── cs8n3p08.png ├── ct0n0g04.png ├── ct1n0g04.png ├── cten0g04.png ├── ctfn0g04.png ├── ctgn0g04.png ├── cthn0g04.png ├── ctjn0g04.png ├── ctzn0g04.png ├── f00n0g08.png ├── f00n2c08.png ├── f01n0g08.png ├── f01n2c08.png ├── f02n0g08.png ├── f02n2c08.png ├── f03n0g08.png ├── f03n2c08.png ├── f04n0g08.png ├── f04n2c08.png ├── f99n0g04.png ├── g03n0g16.png ├── g03n2c08.png ├── g03n3p04.png ├── g04n0g16.png ├── g04n2c08.png ├── g04n3p04.png ├── g05n0g16.png ├── g05n2c08.png ├── g05n3p04.png ├── g07n0g16.png ├── g07n2c08.png ├── g07n3p04.png ├── g10n0g16.png ├── g10n2c08.png ├── g10n3p04.png ├── g25n0g16.png ├── g25n2c08.png ├── g25n3p04.png ├── oi1n0g16.png ├── oi1n2c16.png ├── oi2n0g16.png ├── oi2n2c16.png ├── oi4n0g16.png ├── oi4n2c16.png ├── oi9n0g16.png ├── oi9n2c16.png ├── pp0n2c16.png ├── pp0n6a08.png ├── ps1n0g08.png ├── ps1n2c16.png ├── ps2n0g08.png ├── ps2n2c16.png ├── s01i3p01.png ├── s01n3p01.png ├── s02i3p01.png ├── s02n3p01.png ├── s03i3p01.png ├── s03n3p01.png ├── s04i3p01.png ├── s04n3p01.png ├── s05i3p02.png ├── s05n3p02.png ├── s06i3p02.png ├── s06n3p02.png ├── s07i3p02.png ├── s07n3p02.png ├── s08i3p02.png ├── s08n3p02.png ├── s09i3p02.png ├── s09n3p02.png ├── s32i3p04.png ├── s32n3p04.png ├── s33i3p04.png ├── s33n3p04.png ├── s34i3p04.png ├── s34n3p04.png ├── s35i3p04.png ├── s35n3p04.png ├── s36i3p04.png ├── s36n3p04.png ├── s37i3p04.png ├── s37n3p04.png ├── s38i3p04.png ├── s38n3p04.png ├── s39i3p04.png ├── s39n3p04.png ├── s40i3p04.png ├── s40n3p04.png ├── tbbn0g04.png ├── tbbn2c16.png ├── tbbn3p08.png ├── tbgn2c16.png ├── tbgn3p08.png ├── tbrn2c08.png ├── tbwn0g16.png ├── tbwn3p08.png ├── tbyn3p08.png ├── tm3n3p02.png ├── tp0n0g08.png ├── tp0n2c08.png ├── tp0n3p08.png ├── tp1n3p08.png ├── xc1n0g08.png ├── xc9n2c08.png ├── xcrn0g04.png ├── xcsn0g01.png ├── xd0n2c08.png ├── xd3n2c08.png ├── xd9n2c08.png ├── xdtn0g01.png ├── xhdn0g08.png ├── xlfn0g04.png ├── xs1n0g01.png ├── xs2n0g01.png ├── xs4n0g01.png ├── xs7n0g01.png ├── z00n2c08.png ├── z03n2c08.png ├── z06n2c08.png └── z09n2c08.png ├── README.md ├── cmake ├── ConvertPNG.cmake ├── FileInformation.cmake ├── FileInformation.cmd ├── FileInformation.sh ├── FileInformation.vbs └── GenerateWAVs.cmake ├── csv └── test1.csv ├── csv_test.c ├── csv_test.h ├── file_compat.h ├── gettext ├── en.mo ├── en.po ├── es.mo ├── es.po ├── zh-Hans.mo └── zh-Hans.po ├── ios ├── .gitignore ├── OkFileFormatsTest.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── OkFileFormatsTest │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Info.plist │ ├── Launch Screen.storyboard │ └── main.m ├── jpg.dict ├── jpg ├── 2001-stargate.jpg ├── 2004.jpg ├── 65500h.jpg ├── 65500w.jpg ├── LEVEL76.jpg ├── applesauce.jpg ├── baby-camel.jpg ├── creek-after.jpg ├── einstein.jpg ├── ghost.jpg ├── gort.jpg ├── jpeg400jfif.jpg ├── jpeg444.jpg ├── jpg-gray.jpg ├── jpg-size-15x15.jpg ├── jpg-size-16x16.jpg ├── jpg-size-17x17.jpg ├── jpg-size-1x1.jpg ├── jpg-size-2x2.jpg ├── jpg-size-31x31.jpg ├── jpg-size-32x32.jpg ├── jpg-size-33x33.jpg ├── jpg-size-3x3.jpg ├── jpg-size-4x4.jpg ├── jpg-size-5x5.jpg ├── jpg-size-6x6.jpg ├── jpg-size-7x7.jpg ├── jpg-size-8x8.jpg ├── jpg-size-9x9.jpg ├── magritte.jpg ├── mandril_color.jpg ├── monkey_monkey.jpg ├── orientation_1.jpg ├── orientation_2.jpg ├── orientation_3.jpg ├── orientation_4.jpg ├── orientation_5.jpg ├── orientation_6.jpg ├── orientation_7.jpg ├── orientation_8.jpg ├── orientation_none.jpg ├── park.jpg ├── peace.jpg ├── peppers_color.jpg ├── pumpkins.jpg ├── robot.jpg ├── tomatoes.jpg └── zam.jpg ├── jpg_test.c ├── jpg_test.h ├── main.c ├── main_fuzzing.c ├── mo_test.c ├── mo_test.h ├── png.dict ├── png_suite_test.c ├── png_suite_test.h ├── png_write_test.c ├── png_write_test.h ├── test_common.c ├── test_common.h ├── wav ├── sound.wav └── sound2.wav ├── wav_test.c └── wav_test.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0) 2 | 3 | set(OK_FILE_FORMATS_VERSION "1.0") 4 | set(OK_FILE_FORMATS_API_VERSION "1") 5 | 6 | file(GLOB OK_FILE_FORMATS_SRC *.c *.h) 7 | add_library(ok-file-formats ${OK_FILE_FORMATS_SRC}) 8 | target_include_directories(ok-file-formats PUBLIC .) 9 | set_target_properties(ok-file-formats PROPERTIES 10 | OUTPUT_NAME "okfileformats" 11 | VERSION "${OK_FILE_FORMATS_VERSION}" 12 | SOVERSION "${OK_FILE_FORMATS_API_VERSION}" 13 | C_STANDARD 99) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-2017 David Brackeen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ok-file-formats 2 | 3 | C functions for reading a few different file formats. No external dependencies. Written in C99. 4 | 5 | | Library | Description 6 | |--------------------|--------------------------------------------------------------------------------------------------- 7 | | [ok_png](ok_png.h) | Reads PNG files. Supports Apple's proprietary `CgBI` chunk. Tested against the PngSuite. 8 | | [ok_jpg](ok_jpg.h) | Reads JPEG files. Baseline and progressive formats. Interprets EXIF orientation tags. No CMYK support. 9 | | [ok_wav](ok_wav.h) | Reads WAV and CAF files. PCM, u-law, a-law, and ADPCM formats. 10 | | [ok_fnt](ok_fnt.h) | Reads AngelCode BMFont files. Binary format from AngelCode Bitmap Font Generator v1.10 or newer. 11 | | [ok_csv](ok_csv.h) | Reads Comma-Separated Values files. 12 | | [ok_mo](ok_mo.h) | Reads gettext MO files. 13 | 14 | The source files do not depend on one another. If all you need is to read a PNG file, just 15 | use `ok_png.h` and `ok_png.c`. 16 | 17 | The `CMakeLists.txt` file can be used but is not required. 18 | 19 | The `ok_png`, `ok_jpg`, and `ok_wav` functions include: 20 | * Option to use a custom allocator (`ok_png_read_with_allocator`, etc.) 21 | * Fuzz tests. 22 | 23 | The `ok_png` and `ok_jpg` functions include these decode options: 24 | * Get the image dimensions without decoding image data. 25 | * Premultiply alpha. 26 | * Flip the image vertically. 27 | 28 | ## Example: Decode PNG 29 | 30 | ```C 31 | #include 32 | #include "ok_png.h" 33 | 34 | int main() { 35 | FILE *file = fopen("my_image.png", "rb"); 36 | ok_png image = ok_png_read(file, OK_PNG_COLOR_FORMAT_RGBA | OK_PNG_PREMULTIPLIED_ALPHA | OK_PNG_FLIP_Y); 37 | fclose(file); 38 | if (image.data) { 39 | printf("Got image! Size: %li x %li\n", (long)image.width, (long)image.height); 40 | free(image.data); 41 | } 42 | return 0; 43 | } 44 | ``` 45 | 46 | ## Recent breaking changes in `ok_png`, `ok_jpg`, and `ok_wav`: 47 | * The read functions now return the `ok_png`, `ok_jpg`, and `ok_wav` structs on the stack instead of the heap. (These structs are small, around 24-32 bytes). 48 | * Replaced `ok_png_read_to_buffer` with `ok_png_read_with_allocator`. 49 | * Replaced `ok_png_read_from_callbacks` with `ok_png_read_from_input`. 50 | * Replaced `error_message` with `error_code`. 51 | * Removed `ok_png_free`. Free `png.data` directly instead. 52 | 53 | -------------------------------------------------------------------------------- /ok_csv.h: -------------------------------------------------------------------------------- 1 | // ok-file-formats 2 | // https://github.com/brackeen/ok-file-formats 3 | 4 | #ifndef OK_CSV_H 5 | #define OK_CSV_H 6 | 7 | /** 8 | * @file 9 | * Functions to read CSV (Comma-Separated Values) files. 10 | * - Reads CSV files as defined by RFC 4180. 11 | * - Properly handles escaped fields. 12 | * 13 | * Example: 14 | * 15 | * #include 16 | * #include "ok_csv.h" 17 | * int main() { 18 | * FILE *file = fopen("my_data.csv", "rb"); 19 | * ok_csv *csv = ok_csv_read(file); 20 | * fclose(file); 21 | * if (csv->num_records > 0) { 22 | * printf("Got CSV! %i records\n", csv->num_records); 23 | * if (csv->num_fields[0] > 2) { 24 | * printf("Third field in first record: '%s'\n", csv->fields[0][2]); 25 | * } 26 | * } 27 | * ok_csv_free(csv); 28 | * return 0; 29 | * } 30 | */ 31 | 32 | #include 33 | #include 34 | #ifndef OK_NO_STDIO 35 | #include 36 | #endif 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /** 43 | * The data returned from #ok_csv_read(). 44 | */ 45 | typedef struct { 46 | /// Number of records (rows) 47 | size_t num_records; 48 | /// Number of fields (columns) for each record. 49 | size_t *num_fields; 50 | /// Fields. The value fields[record][field] is a NULL-terminated string. 51 | char ***fields; 52 | /// Error message (if num_records is 0) 53 | const char *error_message; 54 | } ok_csv; 55 | 56 | #ifndef OK_NO_STDIO 57 | 58 | /** 59 | * Reads a CSV file. 60 | * On failure, #ok_csv.num_records is zero and #ok_csv.error_message is set. 61 | * 62 | * @param file The file to read. 63 | * @return a new #ok_csv object. Never returns `NULL`. The object should be freed with 64 | * #ok_csv_free(). 65 | */ 66 | ok_csv *ok_csv_read(FILE *file); 67 | 68 | #endif 69 | 70 | /** 71 | * Frees the CSV data. This function should always be called when done with the CSV data, even if 72 | * reading failed. 73 | */ 74 | void ok_csv_free(ok_csv *csv); 75 | 76 | // MARK: Read from callbacks 77 | 78 | /** 79 | * Read function provided to the #ok_csv_read_from_callbacks() function. 80 | * 81 | * This function must read bytes from its source (typically `user_data`) and copy the data to 82 | * `buffer`. 83 | * 84 | * @param user_data The parameter that was passed to the #ok_csv_read_from_callbacks() function. 85 | * @param buffer The data buffer to copy bytes to. 86 | * @param count The number of bytes to read. 87 | * @return The number of bytes read. 88 | */ 89 | typedef size_t (*ok_csv_read_func)(void *user_data, uint8_t *buffer, size_t count); 90 | 91 | /** 92 | * Reads a CSV file. 93 | * On failure, #ok_csv.num_records is zero and #ok_csv.error_message is set. 94 | * 95 | * @param user_data The parameter to be passed to `read_func` and `seek_func`. 96 | * @param read_func The read function. 97 | * @return a new #ok_csv object. Never returns `NULL`. The object should be freed with 98 | * #ok_csv_free(). 99 | */ 100 | ok_csv *ok_csv_read_from_callbacks(void *user_data, ok_csv_read_func read_func); 101 | 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /ok_fnt.h: -------------------------------------------------------------------------------- 1 | /* 2 | ok-file-formats 3 | https://github.com/brackeen/ok-file-formats 4 | Copyright (c) 2014-2019 David Brackeen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 16 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 19 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef OK_FNT_H 23 | #define OK_FNT_H 24 | 25 | /** 26 | * @file 27 | * Functions to read AngelCode BMFont files. 28 | * Binary format, version 3, from AngelCode Bitmap Font Generator v1.10 or newer. 29 | * 30 | * Example: 31 | * 32 | * #include 33 | * #include "ok_fnt.h" 34 | * 35 | * int main() { 36 | * FILE *file = fopen("my_font.fnt", "rb"); 37 | * ok_fnt *fnt = ok_fnt_read(file); 38 | * fclose(file); 39 | * if (fnt->num_glyphs > 0) { 40 | * printf("Got FNT! %i glyphs\n", fnt->num_glyphs); 41 | * printf("First glyph is '%c' in page '%s'.\n", fnt->glyphs[0].ch, 42 | * fnt->page_names[fnt->glyphs[0].page]); 43 | * } 44 | * ok_fnt_free(fnt); 45 | * return 0; 46 | * } 47 | */ 48 | 49 | #include 50 | #include 51 | #ifndef OK_NO_STDIO 52 | #include 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | typedef struct { 60 | uint32_t ch; 61 | uint16_t x; 62 | uint16_t y; 63 | uint16_t width; 64 | uint16_t height; 65 | int16_t offset_x; 66 | int16_t offset_y; 67 | int16_t advance_x; 68 | uint8_t page; 69 | uint8_t channel; 70 | } ok_fnt_glyph; 71 | 72 | typedef struct { 73 | uint32_t first_char; 74 | uint32_t second_char; 75 | int16_t amount; 76 | } ok_fnt_kerning; 77 | 78 | /** 79 | * The data returned from #ok_fnt_read(). The `name` may be `NULL`. For details, see 80 | * http://www.angelcode.com/products/bmfont/doc/file_format.html 81 | */ 82 | typedef struct { 83 | char *name; 84 | int size; 85 | int line_height; 86 | int base; 87 | size_t num_pages; 88 | char **page_names; 89 | size_t num_glyphs; 90 | ok_fnt_glyph *glyphs; 91 | size_t num_kerning_pairs; 92 | ok_fnt_kerning *kerning_pairs; 93 | const char *error_message; 94 | } ok_fnt; 95 | 96 | #ifndef OK_NO_STDIO 97 | 98 | /** 99 | * Reads a FNT file. 100 | * On failure, #ok_fnt.num_glyphs is 0 and #ok_fnt.error_message is set. 101 | * 102 | * @param file The file to read. 103 | * @return a new #ok_fnt object. Never returns `NULL`. The object should be freed with 104 | * #ok_fnt_free(). 105 | */ 106 | ok_fnt *ok_fnt_read(FILE *file); 107 | 108 | #endif 109 | 110 | /** 111 | * Frees the font. This function should always be called when done with the font, even if reading 112 | * failed. 113 | */ 114 | void ok_fnt_free(ok_fnt *fnt); 115 | 116 | // MARK: Read from callbacks 117 | 118 | /** 119 | * Read function provided to the #ok_fnt_read_from_callbacks() function. 120 | * 121 | * This function must read bytes from its source (typically `user_data`) and copy the data to 122 | * `buffer`. 123 | * 124 | * @param user_data The parameter that was passed to the #ok_fnt_read_from_callbacks() function. 125 | * @param buffer The data buffer to copy bytes to. 126 | * @param count The number of bytes to read. 127 | * @return The number of bytes read. 128 | */ 129 | typedef size_t (*ok_fnt_read_func)(void *user_data, uint8_t *buffer, size_t count); 130 | 131 | /** 132 | * Reads a FNT file. 133 | * On failure, #ok_fnt.num_glyphs is 0 and #ok_fnt.error_message is set. 134 | * 135 | * @param user_data The parameter to be passed to `read_func` and `seek_func`. 136 | * @param read_func The read function. 137 | * @return a new #ok_fnt object. Never returns `NULL`. The object should be freed with 138 | * #ok_fnt_free(). 139 | */ 140 | ok_fnt *ok_fnt_read_from_callbacks(void *user_data, ok_fnt_read_func read_func); 141 | 142 | #ifdef __cplusplus 143 | } 144 | #endif 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /ok_jpg.h: -------------------------------------------------------------------------------- 1 | /* 2 | ok-file-formats 3 | https://github.com/brackeen/ok-file-formats 4 | Copyright (c) 2014-2020 David Brackeen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 16 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 19 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef OK_JPG_H 23 | #define OK_JPG_H 24 | 25 | /** 26 | * @file 27 | * Functions to read JPEG files. 28 | * 29 | * This JPEG decoder: 30 | * - Reads most JPEG files (baseline and progressive). 31 | * - Interprets EXIF orientation tags. 32 | * - Option to get the image dimensions without decoding. 33 | * - Option to flip the image vertically. 34 | * - Returns data in RGBA or BGRA format. 35 | * 36 | * Caveats: 37 | * - No CMYK or YCCK support. 38 | * 39 | * Example: 40 | * 41 | * #include 42 | * #include "ok_jpg.h" 43 | * 44 | * int main() { 45 | * FILE *file = fopen("my_image.jpg", "rb"); 46 | * ok_jpg image = ok_jpg_read(file, OK_JPG_COLOR_FORMAT_RGBA); 47 | * fclose(file); 48 | * if (image.data) { 49 | * printf("Got image! Size: %li x %li\n", (long)image.width, (long)image.height); 50 | * free(image.data); 51 | * } 52 | * return 0; 53 | * } 54 | */ 55 | 56 | #include 57 | #include 58 | #ifndef OK_NO_STDIO 59 | #include 60 | #endif 61 | 62 | #ifdef __cplusplus 63 | extern "C" { 64 | #endif 65 | 66 | typedef enum { 67 | OK_JPG_SUCCESS = 0, 68 | OK_JPG_ERROR_API, // Invalid argument sent to public API function 69 | OK_JPG_ERROR_INVALID, // Not a valid JPG file 70 | OK_JPG_ERROR_UNSUPPORTED, // Unsupported JPG file (CMYK) 71 | OK_JPG_ERROR_ALLOCATION, // Couldn't allocate memory 72 | OK_JPG_ERROR_IO, // Couldn't read or seek the file 73 | } ok_jpg_error; 74 | 75 | /** 76 | * The data returned from #ok_jpg_read() . 77 | */ 78 | typedef struct { 79 | uint32_t width; 80 | uint32_t height; 81 | uint32_t stride; 82 | uint8_t bpp; // Always 4 83 | ok_jpg_error error_code:24; 84 | uint8_t *data; 85 | } ok_jpg; 86 | 87 | /** 88 | * JPG decode flags. Use `OK_JPG_COLOR_FORMAT_RGBA` for the most cases. 89 | */ 90 | typedef enum { 91 | /// Set for RGBA color format. The alpha is always 255. 92 | OK_JPG_COLOR_FORMAT_RGBA = (0 << 0), 93 | /// Set for BGRA color format. The alpha is always 255. 94 | OK_JPG_COLOR_FORMAT_BGRA = (1 << 0), 95 | /// Set to flip the image data along the horizontal axis, so that the first row of data is 96 | /// the last row in the image. 97 | OK_JPG_FLIP_Y = (1 << 2), 98 | /// Set to read an image's dimensions and color format without reading the image data. 99 | OK_JPG_INFO_ONLY = (1 << 3) 100 | 101 | } ok_jpg_decode_flags; 102 | 103 | // MARK: Reading from a FILE 104 | 105 | #if !defined(OK_NO_STDIO) && !defined(OK_NO_DEFAULT_ALLOCATOR) 106 | 107 | /** 108 | * Reads a JPEG image using the default "stdlib" allocator. 109 | * On success, #ok_jpg.data contains the packed image data, with a size of 110 | * (`width * height * 4`). On failure, #ok_jpg.data is `NULL` and #ok_jpg.error_code is nonzero. 111 | * 112 | * The returned `data` must be freed by the caller (using stdlib's `free()`). 113 | * 114 | * @param file The file to read. 115 | * @param decode_flags The JPG decode flags. Use `OK_JPG_COLOR_FORMAT_RGBA` for the most cases. 116 | * @return a #ok_jpg object. 117 | */ 118 | ok_jpg ok_jpg_read(FILE *file, ok_jpg_decode_flags decode_flags); 119 | 120 | #endif 121 | 122 | // MARK: Reading from a FILE, using a custom allocator 123 | 124 | typedef struct { 125 | /** 126 | * Allocates uninitilized memory. 127 | * 128 | * @param user_data The pointer passed to #ok_jpg_read_with_allocator. 129 | * @param size The size of the memory to allocate. 130 | * @return the pointer to the newly allocated memory, or `NULL` if the memory could not be allocated. 131 | */ 132 | void *(*alloc)(void *user_data, size_t size); 133 | 134 | /** 135 | * Frees memory previously allocated with `alloc`. 136 | * 137 | * @param user_data The pointer passed to #ok_jpg_read_with_allocator. 138 | * @param memory The memory to free. 139 | */ 140 | void (*free)(void *user_data, void *memory); 141 | 142 | /** 143 | * Allocates memory for the decoded image. 144 | * This function may be `NULL`, in which case `alloc` is used instead. 145 | * 146 | * @param user_data The pointer passed to #ok_jpg_read_with_allocator. 147 | * @param width The image's width, in pixels. 148 | * @param height The image's height, in pixels. 149 | * @param bpp The image's number of bytes per pixel. 150 | * @param out_buffer The buffer to output data. The buffer must have a minimum size of 151 | * (`out_stride * height`) bytes. Set to `NULL` if the memory could not be allocated. 152 | * @param out_stride The stride of the buffer, in bytes. 153 | * By default, `out_stride` is `width * bpp`, but can be changed if needed. 154 | * The value must be greater than or equal to `width * bpp` or an error will occur. 155 | */ 156 | void (*image_alloc)(void *user_data, uint32_t width, uint32_t height, uint8_t bpp, 157 | uint8_t **out_buffer, uint32_t *out_stride); 158 | } ok_jpg_allocator; 159 | 160 | #if !defined(OK_NO_DEFAULT_ALLOCATOR) 161 | 162 | /// The default allocator using stdlib's `malloc` and `free`. 163 | extern const ok_jpg_allocator OK_JPG_DEFAULT_ALLOCATOR; 164 | 165 | #endif 166 | 167 | #if !defined(OK_NO_STDIO) 168 | 169 | /** 170 | * Reads a JPG image using a custom allocator. 171 | * On success, #ok_jpg.data contains the packed image data, with a size of 172 | * (`width * height * 4`). On failure, #ok_jpg.data is `NULL` and #ok_jpg.error_code is nonzero. 173 | * 174 | * The returned `data` must be freed by the caller. 175 | * 176 | * @param file The file to read. 177 | * @param decode_flags The JPG decode flags. Use `OK_JPG_COLOR_FORMAT_RGBA` for the most cases. 178 | * @param allocator The allocator to use. 179 | * @param allocator_user_data The pointer to pass to the allocator functions. 180 | * If using `OK_JPG_DEFAULT_ALLOCATOR`, this value should be `NULL`. 181 | * @return a #ok_jpg object. 182 | */ 183 | ok_jpg ok_jpg_read_with_allocator(FILE *file, ok_jpg_decode_flags decode_flags, 184 | ok_jpg_allocator allocator, void *allocator_user_data); 185 | 186 | #endif 187 | 188 | // MARK: Reading from custom input 189 | 190 | typedef struct { 191 | /** 192 | * Reads bytes from its source (typically `user_data`), copying the data to `buffer`. 193 | * 194 | * @param user_data The parameter that was passed to the #ok_jpg_read_from_input() 195 | * @param buffer The data buffer to copy bytes to. 196 | * @param count The number of bytes to read. 197 | * @return The number of bytes read. 198 | */ 199 | size_t (*read)(void *user_data, uint8_t *buffer, size_t count); 200 | 201 | /** 202 | * Skips bytes from its source (typically `user_data`). 203 | * 204 | * @param user_data The parameter that was passed to the #ok_jpg_read_from_input(). 205 | * @param count The number of bytes to skip. 206 | * @return `true` if success. 207 | */ 208 | bool (*seek)(void *user_data, long count); 209 | } ok_jpg_input; 210 | 211 | /** 212 | * Reads a JPG image. On success, #ok_jpg.data contains the packed image data, with a size of 213 | * (`width * height * 4`). On failure, #ok_jpg.data is `NULL` and #ok_jpg.error_code is nonzero. 214 | * 215 | * The returned `data` must be freed by the caller. 216 | * 217 | * @param decode_flags The JPG decode flags. Use `OK_JPG_COLOR_FORMAT_RGBA` for the most cases. 218 | * @param input_callbacks The custom input functions. 219 | * @param input_callbacks_user_data The parameter to be passed to the input's `read` and `seek` functions. 220 | * @param allocator The allocator to use. 221 | * @param allocator_user_data The pointer to pass to the allocator functions. 222 | * If using `OK_JPG_DEFAULT_ALLOCATOR`, this value should be `NULL`. 223 | * @return a #ok_jpg object. 224 | */ 225 | ok_jpg ok_jpg_read_from_input(ok_jpg_decode_flags decode_flags, 226 | ok_jpg_input input_callbacks, void *input_callbacks_user_data, 227 | ok_jpg_allocator allocator, void *allocator_user_data); 228 | 229 | #ifdef __cplusplus 230 | } 231 | #endif 232 | 233 | #endif 234 | -------------------------------------------------------------------------------- /ok_mo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ok-file-formats 3 | https://github.com/brackeen/ok-file-formats 4 | Copyright (c) 2014-2019 David Brackeen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 16 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 19 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef OK_MO_H 23 | #define OK_MO_H 24 | 25 | /** 26 | * @file 27 | * Functions to read GNU gettext MO files. Includes UTF-8 support. 28 | * 29 | * Example: 30 | * 31 | * #include 32 | * #include "ok_mo.h" 33 | 34 | * int main() { 35 | * FILE *file = fopen("my_strings.mo", "rb"); 36 | * ok_mo *mo = ok_mo_read(file); 37 | * fclose(file); 38 | * if (mo->num_strings > 0) { 39 | * printf("Got MO! %i strings\n", mo->num_strings); 40 | * printf("Value for 'Hello': '%s'\n", ok_mo_value(mo, "Hello")); 41 | * } 42 | * ok_mo_free(mo); 43 | * return 0; 44 | * } 45 | */ 46 | 47 | #include 48 | #include 49 | #ifndef OK_NO_STDIO 50 | #include 51 | #endif 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /// Internal storage of key-value data. 58 | struct ok_mo_string; 59 | 60 | /** 61 | * The data returned from #ok_mo_read(). 62 | */ 63 | typedef struct { 64 | uint32_t num_strings; 65 | struct ok_mo_string *strings; 66 | const char *error_message; 67 | } ok_mo; 68 | 69 | #ifndef OK_NO_STDIO 70 | 71 | /** 72 | * Reads a MO file. 73 | * On failure, #ok_mo.num_strings is 0 and #ok_mo.error_message is set. 74 | * 75 | * @param file The file to read. 76 | * @return A new #ok_mo object. Never returns `NULL`. The object should be freed with 77 | * #ok_mo_free(). 78 | */ 79 | ok_mo *ok_mo_read(FILE *file); 80 | 81 | #endif 82 | 83 | /** 84 | * Gets the value for the specified key. 85 | * @param mo The mo object. 86 | * @param key The key string to search for. 87 | * @return The value for the key. If there is no value for `key`, then `key` is returned. 88 | */ 89 | const char *ok_mo_value(ok_mo *mo, const char *key); 90 | 91 | /** 92 | * Gets the value for the specified key, with possible plural variants. 93 | * If there are plural variants, returns the plural variant for the specified n value. 94 | * @param mo The mo object. 95 | * @param key The key string to search for. 96 | * @param plural_key The value to return if the value for the key is not found, and `n` is not 1. 97 | * @param n The grammatical number. In English, the grammatical number categories are "singular" 98 | * (`n` is 1) and "plural" (`n` is not 1). 99 | * @return The value for the key. If there is no value for `key`, then either `key` or `plural_key` 100 | * is returned, depending on the value of `n`. 101 | */ 102 | const char *ok_mo_plural_value(ok_mo *mo, const char *key, const char *plural_key, int n); 103 | 104 | /** 105 | * Gets the value for the specified key in a context. 106 | * @param mo The mo object. 107 | * @param context The key context. For example, the context for "open" may be "file" or "window". 108 | * @param key The key string to search for. 109 | * @return The value for the key. If there is no value for `key`, then `key` is returned. 110 | */ 111 | const char *ok_mo_value_in_context(ok_mo *mo, const char *context, const char *key); 112 | 113 | /** 114 | * Gets the value for the specified key in a context, with possible plural variants. 115 | * @param mo The mo object. 116 | * @param context The key context. For example, the context for "open" may be "file" or "window". 117 | * @param key The key string to search for. 118 | * @param plural_key The value to return if the value for the key is not found, and `n` is not 1. 119 | * @param n The grammatical number. In English, the grammatical number categories are "singular" 120 | * (`n` is 1) and "plural" (`n` is not 1). 121 | * @return The value for the key. If there is no value for `key`, then either `key` or `plural_key` 122 | * is returned, depending on the value of `n`. 123 | */ 124 | const char *ok_mo_plural_value_in_context(ok_mo *mo, const char *context, const char *key, 125 | const char *plural_key, int n); 126 | 127 | /** 128 | * Frees the MO data. This function should always be called when finished with the MO data, even if 129 | * reading failed. 130 | */ 131 | void ok_mo_free(ok_mo *mo); 132 | 133 | /** 134 | * Gets the character length (as opposed to the byte length) of an UTF-8 string. 135 | * @param utf8 A UTF-8 encoded string, with a `NULL` terminator. 136 | */ 137 | unsigned int ok_utf8_strlen(const char *utf8); 138 | 139 | /** 140 | * Converts the first `n` characters of a UTF-8 string to a 32-bit Unicode (UCS-4) string. 141 | * @param utf8 A UTF-8 encoded string. 142 | * @param dest The destination buffer. The buffer must have a length of at least (n + 1) to 143 | * accommodate the `NULL` terminator. 144 | * @param n The number of Unicode characters to convert. 145 | * @return The number of characters copied, excluding the `NULL` termintor. The number may be 146 | * shorter than `n` if the end of the UTF-8 string was found. 147 | */ 148 | unsigned int ok_utf8_to_unicode(const char *utf8, uint32_t *dest, unsigned int n); 149 | 150 | // MARK: Read from callbacks 151 | 152 | /** 153 | * Read function provided to the #ok_mo_read_from_callbacks() function. 154 | * 155 | * This function must read bytes from its source (typically `user_data`) and copy the data to 156 | * `buffer`. 157 | * 158 | * @param user_data The parameter that was passed to the #ok_mo_read_from_callbacks() function. 159 | * @param buffer The data buffer to copy bytes to. 160 | * @param count The number of bytes to read. 161 | * @return The number of bytes read. 162 | */ 163 | typedef size_t (*ok_mo_read_func)(void *user_data, uint8_t *buffer, size_t count); 164 | 165 | /** 166 | * Seek function provided to the #ok_mo_read_from_callbacks() function. 167 | * 168 | * This function must skip bytes from its source (typically `user_data`). 169 | * 170 | * @param user_data The parameter that was passed to the #ok_mo_read_from_callbacks() function. 171 | * @param count The number of bytes to skip. 172 | * @return `true` if success. 173 | */ 174 | typedef bool (*ok_mo_seek_func)(void *user_data, long count); 175 | 176 | /** 177 | * Reads a MO file. 178 | * On failure, #ok_mo.num_strings is 0 and #ok_mo.error_message is set. 179 | * 180 | * @param user_data The parameter to be passed to `read_func` and `seek_func`. 181 | * @param read_func The read function. 182 | * @param seek_func The seek function. 183 | * @return A new #ok_mo object. Never returns `NULL`. The object should be freed with 184 | * #ok_mo_free(). 185 | */ 186 | ok_mo *ok_mo_read_from_callbacks(void *user_data, ok_mo_read_func read_func, 187 | ok_mo_seek_func seek_func); 188 | 189 | #ifdef __cplusplus 190 | } 191 | #endif 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /ok_png.h: -------------------------------------------------------------------------------- 1 | /* 2 | ok-file-formats 3 | https://github.com/brackeen/ok-file-formats 4 | Copyright (c) 2014-2020 David Brackeen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 16 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 19 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef OK_PNG_H 23 | #define OK_PNG_H 24 | 25 | /** 26 | * @file 27 | * Functions to read any PNG file. 28 | * 29 | * This PNG decoder: 30 | * - Supports all PNG color types and bit depths. 31 | * - Supports Apple's proprietary PNG extensions for iOS. 32 | * - Options to premultiply alpha and flip data vertically. 33 | * - Option to get image dimensions without decoding. 34 | * - Returns data in RGBA or BGRA format. 35 | * 36 | * Caveats: 37 | * - No gamma conversion. 38 | * - No CRC or ADLER32 checks. 39 | * - Ignores all chunks not related to the image. 40 | * 41 | * Example: 42 | * 43 | * #include 44 | * #include "ok_png.h" 45 | * 46 | * int main() { 47 | * FILE *file = fopen("my_image.png", "rb"); 48 | * ok_png image = ok_png_read(file, OK_PNG_COLOR_FORMAT_RGBA); 49 | * fclose(file); 50 | * if (image.data) { 51 | * printf("Got image! Size: %li x %li\n", (long)image.width, (long)image.height); 52 | * free(image.data); 53 | * } 54 | * return 0; 55 | * } 56 | */ 57 | 58 | #include 59 | #include 60 | #ifndef OK_NO_STDIO 61 | #include 62 | #endif 63 | 64 | #ifdef __cplusplus 65 | extern "C" { 66 | #endif 67 | 68 | typedef enum { 69 | OK_PNG_SUCCESS = 0, 70 | OK_PNG_ERROR_API, // Invalid argument sent to public API function 71 | OK_PNG_ERROR_INVALID, // Not a valid PNG file 72 | OK_PNG_ERROR_INFLATER, // Couldn't inflate data 73 | OK_PNG_ERROR_UNSUPPORTED, // Unsupported PNG file (width > 1073741824) 74 | OK_PNG_ERROR_ALLOCATION, // Couldn't allocate memory 75 | OK_PNG_ERROR_IO, // Couldn't read or seek the file 76 | } ok_png_error; 77 | 78 | /** 79 | * The data returned from #ok_png_read(). 80 | */ 81 | typedef struct { 82 | uint32_t width; 83 | uint32_t height; 84 | uint32_t stride; 85 | uint8_t bpp; // Always 4 86 | bool has_alpha; 87 | ok_png_error error_code:16; 88 | uint8_t *data; 89 | } ok_png; 90 | 91 | /** 92 | * PNG decode flags. Use `OK_PNG_COLOR_FORMAT_RGBA` for the most cases. 93 | */ 94 | typedef enum { 95 | /// Set for RGBA color format. This is the default format for standard PNG files. 96 | OK_PNG_COLOR_FORMAT_RGBA = (0 << 0), 97 | /// Set for BGRA color format. 98 | OK_PNG_COLOR_FORMAT_BGRA = (1 << 0), 99 | /// Set for premultiplied alpha. The default format on iOS devices is 100 | /// `(OK_PNG_COLOR_FORMAT_RGBA | OK_PNG_PREMULTIPLIED_ALPHA)` 101 | OK_PNG_PREMULTIPLIED_ALPHA = (1 << 1), 102 | /// Set to flip the image data along the horizontal axis, so that the first row of data is 103 | /// the last row in the image. 104 | OK_PNG_FLIP_Y = (1 << 2), 105 | /// Set to read an image's dimensions and color format without reading the image data. 106 | OK_PNG_INFO_ONLY = (1 << 3) 107 | } ok_png_decode_flags; 108 | 109 | // MARK: Reading from a FILE 110 | 111 | #if !defined(OK_NO_STDIO) && !defined(OK_NO_DEFAULT_ALLOCATOR) 112 | 113 | /** 114 | * Reads a PNG image using the default "stdlib" allocator. 115 | * On success, #ok_png.data contains the packed image data, with a size of 116 | * (`width * height * 4`). On failure, #ok_png.data is `NULL` and #ok_png.error_code is nonzero. 117 | * 118 | * The returned `data` must be freed by the caller (using stdlib's `free()`). 119 | * 120 | * @param file The file to read. 121 | * @param decode_flags The PNG decode flags. Use `OK_PNG_COLOR_FORMAT_RGBA` for the most cases. 122 | * @return a #ok_png object. 123 | */ 124 | ok_png ok_png_read(FILE *file, ok_png_decode_flags decode_flags); 125 | 126 | #endif 127 | 128 | // MARK: Reading from a FILE, using a custom allocator 129 | 130 | typedef struct { 131 | /** 132 | * Allocates uninitilized memory. 133 | * 134 | * @param user_data The pointer passed to #ok_png_read_with_allocator. 135 | * @param size The size of the memory to allocate. 136 | * @return the pointer to the newly allocated memory, or `NULL` if the memory could not be allocated. 137 | */ 138 | void *(*alloc)(void *user_data, size_t size); 139 | 140 | /** 141 | * Frees memory previously allocated with `alloc`. 142 | * 143 | * @param user_data The pointer passed to #ok_png_read_with_allocator. 144 | * @param memory The memory to free. 145 | */ 146 | void (*free)(void *user_data, void *memory); 147 | 148 | /** 149 | * Allocates memory for the decoded image. 150 | * This function may be `NULL`, in which case `alloc` is used instead. 151 | * 152 | * @param user_data The pointer passed to #ok_png_read_with_allocator. 153 | * @param width The image's width, in pixels. 154 | * @param height The image's height, in pixels. 155 | * @param bpp The image's number of bytes per pixel. 156 | * @param out_buffer The buffer to output data. The buffer must have a minimum size of 157 | * (`out_stride * height`) bytes. Set to `NULL` if the memory could not be allocated. 158 | * @param out_stride The stride of the buffer, in bytes. 159 | * By default, `out_stride` is `width * bpp`, but can be changed if needed. 160 | * The value must be greater than or equal to `width * bpp` or an error will occur. 161 | */ 162 | void (*image_alloc)(void *user_data, uint32_t width, uint32_t height, uint8_t bpp, 163 | uint8_t **out_buffer, uint32_t *out_stride); 164 | } ok_png_allocator; 165 | 166 | #if !defined(OK_NO_DEFAULT_ALLOCATOR) 167 | 168 | /// The default allocator using stdlib's `malloc` and `free`. 169 | extern const ok_png_allocator OK_PNG_DEFAULT_ALLOCATOR; 170 | 171 | #endif 172 | 173 | #if !defined(OK_NO_STDIO) 174 | 175 | /** 176 | * Reads a PNG image using a custom allocator. 177 | * On success, #ok_png.data contains the packed image data, with a size of 178 | * (`width * height * 4`). On failure, #ok_png.data is `NULL` and #ok_png.error_code is nonzero. 179 | * 180 | * The returned `data` must be freed by the caller. 181 | * 182 | * @param file The file to read. 183 | * @param decode_flags The PNG decode flags. Use `OK_PNG_COLOR_FORMAT_RGBA` for the most cases. 184 | * @param allocator The allocator to use. 185 | * @param allocator_user_data The pointer to pass to the allocator functions. 186 | * If using `OK_PNG_DEFAULT_ALLOCATOR`, this value should be `NULL`. 187 | * @return a #ok_png object. 188 | */ 189 | ok_png ok_png_read_with_allocator(FILE *file, ok_png_decode_flags decode_flags, 190 | ok_png_allocator allocator, void *allocator_user_data); 191 | 192 | #endif 193 | 194 | // MARK: Reading from custom input 195 | 196 | typedef struct { 197 | /** 198 | * Reads bytes from its source (typically `user_data`), copying the data to `buffer`. 199 | * 200 | * @param user_data The parameter that was passed to the #ok_png_read_from_input() 201 | * @param buffer The data buffer to copy bytes to. 202 | * @param count The number of bytes to read. 203 | * @return The number of bytes read. 204 | */ 205 | size_t (*read)(void *user_data, uint8_t *buffer, size_t count); 206 | 207 | /** 208 | * Skips bytes from its source (typically `user_data`). 209 | * 210 | * @param user_data The parameter that was passed to the #ok_png_read_from_input(). 211 | * @param count The number of bytes to skip. 212 | * @return `true` if success. 213 | */ 214 | bool (*seek)(void *user_data, long count); 215 | } ok_png_input; 216 | 217 | /** 218 | * Reads a PNG image. On success, #ok_png.data contains the packed image data, with a size of 219 | * (`width * height * 4`). On failure, #ok_png.data is `NULL` and #ok_png.error_code is nonzero. 220 | * 221 | * The returned `data` must be freed by the caller. 222 | * 223 | * @param decode_flags The PNG decode flags. Use `OK_PNG_COLOR_FORMAT_RGBA` for the most cases. 224 | * @param input_callbacks The custom input functions. 225 | * @param input_callbacks_user_data The parameter to be passed to the input's `read` and `seek` functions. 226 | * @param allocator The allocator to use. 227 | * @param allocator_user_data The pointer to pass to the allocator functions. 228 | * If using `OK_PNG_DEFAULT_ALLOCATOR`, this value should be `NULL`. 229 | * @return a #ok_png object. 230 | */ 231 | ok_png ok_png_read_from_input(ok_png_decode_flags decode_flags, 232 | ok_png_input input_callbacks, void *input_callbacks_user_data, 233 | ok_png_allocator allocator, void *allocator_user_data); 234 | 235 | // MARK: Inflater 236 | 237 | typedef struct ok_inflater ok_inflater; 238 | 239 | /** 240 | * Creates an inflater. Returns `NULL` on error. The inflater should be freed with 241 | * #ok_inflater_free(). 242 | * 243 | * @param nowrap If `true`, the inflater assumes there is no zlib wrapper around the data. 244 | */ 245 | ok_inflater *ok_inflater_init(bool nowrap, ok_png_allocator allocator, void *allocator_user_data); 246 | 247 | /** 248 | * Resets the inflater to work with a new stream. 249 | */ 250 | void ok_inflater_reset(ok_inflater *inflater); 251 | 252 | /** 253 | * Returns true if the inflater needs more input. 254 | */ 255 | bool ok_inflater_needs_input(const ok_inflater *inflater); 256 | 257 | /** 258 | * Sets the input for the inflater. Only call this function if #ok_inflater_needs_input() returns 259 | * `true`, otherwise, an error may occur. 260 | * 261 | * @param inflater The inflater. 262 | * @param buffer The input buffer. 263 | * @param buffer_length The length of the input buffer. 264 | */ 265 | void ok_inflater_set_input(ok_inflater *inflater, const uint8_t *buffer, size_t buffer_length); 266 | 267 | /** 268 | * Inflates at most `dst_length` bytes. Returns the number of bytes inflated, or `SIZE_MAX` 269 | * if an error occured. 270 | * 271 | * @param inflater The inflater. 272 | * @param dst The destination buffer to inflate bytes to. 273 | * @param dst_length The maximum number of bytes to inflate. 274 | */ 275 | size_t ok_inflater_inflate(ok_inflater *inflater, uint8_t *dst, size_t dst_length); 276 | 277 | /** 278 | * Frees the inflater. 279 | */ 280 | void ok_inflater_free(ok_inflater *inflater); 281 | 282 | #ifdef __cplusplus 283 | } 284 | #endif 285 | 286 | #endif 287 | -------------------------------------------------------------------------------- /ok_png_write.h: -------------------------------------------------------------------------------- 1 | // ok-file-formats 2 | // https://github.com/brackeen/ok-file-formats 3 | 4 | #ifndef OK_PNG_WRITE_H 5 | #define OK_PNG_WRITE_H 6 | 7 | /** 8 | @file 9 | Functions to write an uncompressed PNG file. 10 | 11 | Caveats: 12 | * PNGs are not compressed. 13 | * No support for interlaced output. 14 | 15 | Example: 16 | #include "ok_png_write.h" 17 | 18 | int main() { 19 | const uint8_t image_data[8] = { 0xff, 0xff, 0xbd, 0xff, 0xff, 0xbd, 0xc3, 0xff }; 20 | const uint8_t palette[6] = { 0x00, 0x00, 0x00, 0xd2, 0x32, 0x14 }; 21 | const uint8_t palette_alpha[2] = { 0x00, 0xff }; 22 | 23 | FILE *file = fopen("out_image.png", "wb"); 24 | bool success = ok_png_write_to_file(file, (ok_png_write_params){ 25 | .width = 8, 26 | .height = 8, 27 | .data = image_data, 28 | .bit_depth = 1, 29 | .color_type = OK_PNG_WRITE_COLOR_TYPE_PALETTE, 30 | .additional_chunks = (ok_png_write_chunk *[]){ 31 | &(ok_png_write_chunk){ 32 | .name = "PLTE", 33 | .data = palette, 34 | .length = sizeof(palette), 35 | }, 36 | &(ok_png_write_chunk){ 37 | .name = "tRNS", 38 | .data = palette_alpha, 39 | .length = sizeof(palette_alpha), 40 | }, 41 | NULL 42 | } 43 | }); 44 | printf("Success=%i\n", success); 45 | fclose(file); 46 | return 0; 47 | } 48 | */ 49 | 50 | #include 51 | #include 52 | #ifndef OK_NO_STDIO 53 | #include 54 | #endif 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | typedef enum { 61 | OK_PNG_WRITE_COLOR_TYPE_GRAY = 0, 62 | OK_PNG_WRITE_COLOR_TYPE_RGB = 2, 63 | OK_PNG_WRITE_COLOR_TYPE_PALETTE = 3, 64 | OK_PNG_WRITE_COLOR_TYPE_GRAY_ALPHA = 4, 65 | OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA = 6, 66 | } ok_png_write_color_type; 67 | 68 | /** 69 | @struct ok_png_write_chunk 70 | 71 | Defines a PNG chunk to write. 72 | 73 | @var name A 4-character chunk name. Typical chunk names are PLTE, tRNS, and gAMA. See the PNG spec for details. 74 | @var data The chunk data. If length is 0, data may be NULL. 75 | @var length The chunk data length, in bytes. 76 | */ 77 | typedef struct { 78 | const char *name; 79 | const uint8_t *data; 80 | uint32_t length; 81 | } ok_png_write_chunk; 82 | 83 | /** 84 | @struct ok_png_write_params 85 | 86 | Parameters for the #ok_png_write_to_file or #ok_png_write functions. 87 | 88 | @var width The width of the image, in pixels. 89 | 90 | @var height The height of the image, in pixels. 91 | 92 | @var data_stride The stride of the input image data, in bytes. If 0, the default "bytes per row" is assumed. 93 | 94 | @var data The input image data, which is written as-is without modification or verification. 95 | Note, even for 1, 2, and 4-bit images, rows must be byte-aligned. 96 | 97 | @var bit_depth The bit depth. If 0, the default is 8. 98 | 99 | The bit depth must be valid for the color type. The following bit depths are valid: 100 | 101 | Color type | Valid bit depths 102 | -----------------------------------+----------------- 103 | OK_PNG_WRITE_COLOR_TYPE_PALETTE | 1, 2, 4, 8 104 | OK_PNG_WRITE_COLOR_TYPE_GRAY | 1, 2, 4, 8, 16 105 | OK_PNG_WRITE_COLOR_TYPE_GRAY_ALPHA | 8, 16 106 | OK_PNG_WRITE_COLOR_TYPE_RGB | 8, 16 107 | OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA | 8, 16 108 | 109 | @var color_type The color type. 110 | 111 | @var flip_y If true, the image is written bottom-up instead of top-down. 112 | 113 | @var apple_cgbi_format If true, write PNGs in Apple's proprietary PNG format. 114 | This adds the CgBI chunk before the IHDR chunk and does not include zlib headers or checksums. 115 | Image data must be provided in premultiplied BGRA format (ok_png_write does not convert data). 116 | 117 | @var additional_chunks A NULL-terminated array of additional chunks to write. 118 | The chunks are written after the header chunk ("IHDR") and before the data chunk ("IDAT"). 119 | Images with a color type of OK_PNG_WRITE_COLOR_TYPE_PALETTE must include a "PLTE" chunk. 120 | See the PNG spec for details. 121 | 122 | @var buffer_size The size of the buffer for compressed IDAT chunks. If the compressed output 123 | is larger than the buffer, multiple IDAT chunks are written. 124 | If this value is 0, a default value of 65536 is used. This value must be 0x7fffffff or less. 125 | 126 | @var alloc The memory allocator, or NULL to use the stdlib's malloc. 127 | 128 | @var free The memory deallocator, or NULL to use the stdlib's free. 129 | 130 | @var allocator_context The context passed to the allocator. 131 | */ 132 | typedef struct { 133 | uint32_t width; 134 | uint32_t height; 135 | uint64_t data_stride; 136 | const uint8_t *data; 137 | uint8_t bit_depth; 138 | ok_png_write_color_type color_type; 139 | bool flip_y; 140 | bool apple_cgbi_format; 141 | ok_png_write_chunk **additional_chunks; 142 | 143 | // Compress options 144 | uint32_t buffer_size; 145 | void *(*alloc)(void *allocator_context, size_t length); 146 | void (*free)(void *allocator_context, void *memory); 147 | void *allocator_context; 148 | } ok_png_write_params; 149 | 150 | #ifndef OK_NO_STDIO 151 | 152 | /// Writes an image to a file and returns true on success. 153 | bool ok_png_write_to_file(FILE *file, ok_png_write_params params); 154 | 155 | #endif 156 | 157 | /// Write function for #ok_png_write. This function should return `true` on success 158 | typedef bool (*ok_png_write_function)(void *context, const uint8_t *buffer, size_t count); 159 | 160 | /// Writes an image and returns true on success. 161 | bool ok_png_write(ok_png_write_function write_function, void *write_function_context, ok_png_write_params params); 162 | 163 | // MARK: Deflate 164 | 165 | typedef struct ok_deflate ok_deflate; 166 | 167 | /** 168 | @var nowrap If `true`, no header or footer is written before or after the output. 169 | 170 | @var alloc The memory allocator, or NULL to use the stdlib's malloc. 171 | 172 | @var free The memory deallocator, or NULL to use the stdlib's free. 173 | 174 | @var allocator_context The context passed to the allocator. 175 | 176 | @var write The write function for output. Must not be NULL. 177 | This function should write the specified buffer and return true on success. 178 | 179 | @var write_context The context passed to the write function. 180 | */ 181 | typedef struct { 182 | bool nowrap; 183 | 184 | void *(*alloc)(void *allocator_context, size_t length); 185 | void (*free)(void *allocator_context, void *memory); 186 | void *allocator_context; 187 | 188 | bool (*write)(void *write_context, const uint8_t *data, size_t length); 189 | void *write_context; 190 | } ok_deflate_params; 191 | 192 | /// Create a deflater. The object must be freed with #ok_deflate_free 193 | ok_deflate *ok_deflate_init(ok_deflate_params params); 194 | 195 | /** 196 | Deflates data. 197 | 198 | This function may be called repeatedly. 199 | 200 | If `is_final` is true, this data represents the final data block in the stream. 201 | The footer is written (if nowrap is false) and the stream is reset. Another stream 202 | can be written using the same deflater. 203 | 204 | If `is_final` is false, some or all of the data may be buffered. 205 | 206 | @param data The data to deflate. 207 | @param length The data length. May be zero. 208 | @param is_final Flag indicating the data is the last in a stream. 209 | @return true on success, false on write error. 210 | */ 211 | bool ok_deflate_data(ok_deflate *deflate, const uint8_t *data, size_t length, bool is_final); 212 | 213 | /// Frees a deflater created with #ok_deflate_init 214 | void ok_deflate_free(ok_deflate *deflate); 215 | 216 | #ifdef __cplusplus 217 | } 218 | #endif 219 | 220 | #endif 221 | -------------------------------------------------------------------------------- /ok_wav.h: -------------------------------------------------------------------------------- 1 | /* 2 | ok-file-formats 3 | https://github.com/brackeen/ok-file-formats 4 | Copyright (c) 2014-2020 David Brackeen 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 16 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 19 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef OK_WAV_H 23 | #define OK_WAV_H 24 | 25 | /** 26 | * @file 27 | * Functions to read WAV and CAF files. 28 | * 29 | * Supported encodings: 30 | * * PCM (including floating-point). 31 | * * Both u-law and a-law. 32 | * * CAF: Apple's IMA ADPCM. 33 | * * WAV: Microsoft's IMA ADPCM. 34 | * * WAV: Microsoft's ADPCM. 35 | * 36 | * Example: 37 | * 38 | * #include 39 | * #include "ok_wav.h" 40 | * 41 | * int main() { 42 | * FILE *file = fopen("my_audio.wav", "rb"); 43 | * ok_wav audio = ok_wav_read(file, OK_WAV_DEFAULT_DECODE_FLAGS); 44 | * fclose(file); 45 | * if (audio.data) { 46 | * printf("Got audio! Length: %f seconds\n", (audio.num_frames / audio.sample_rate)); 47 | * free(audio.data); 48 | * } 49 | * return 0; 50 | * } 51 | */ 52 | 53 | #include 54 | #include 55 | #ifndef OK_NO_STDIO 56 | #include 57 | #endif 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | typedef enum { 64 | OK_WAV_SUCCESS = 0, 65 | OK_WAV_ERROR_API, // Invalid argument sent to public API function 66 | OK_WAV_ERROR_INVALID, // Not a valid WAV file 67 | OK_WAV_ERROR_UNSUPPORTED, // Unsupported WAV file (Not PCM, u-law, a-law, or ADPCM) 68 | OK_WAV_ERROR_ALLOCATION, // Couldn't allocate memory 69 | OK_WAV_ERROR_IO, // Couldn't read or seek the file 70 | } ok_wav_error; 71 | 72 | /** 73 | * The data returned from #ok_wav_read(). 74 | */ 75 | typedef struct { 76 | double sample_rate; 77 | uint64_t num_frames; 78 | uint8_t num_channels; 79 | uint8_t bit_depth; 80 | bool is_float; 81 | bool little_endian; 82 | ok_wav_error error_code; 83 | void *data; 84 | } ok_wav; 85 | 86 | /** 87 | * Decode flags. 88 | */ 89 | typedef enum { 90 | // Perform no endian conversion 91 | OK_WAV_ENDIAN_NO_CONVERSION = 0, 92 | /// Convert to native endian 93 | OK_WAV_ENDIAN_NATIVE = 1, 94 | /// Convert to little endian 95 | OK_WAV_ENDIAN_LITTLE = 2, 96 | /// Convert to big endian 97 | OK_WAV_ENDIAN_BIG = 3, 98 | } ok_wav_decode_flags; 99 | 100 | static const ok_wav_decode_flags OK_WAV_DEFAULT_DECODE_FLAGS = OK_WAV_ENDIAN_NATIVE; 101 | 102 | // MARK: Reading from a FILE 103 | 104 | #if !defined(OK_NO_STDIO) && !defined(OK_NO_DEFAULT_ALLOCATOR) 105 | 106 | /** 107 | * Reads a WAV (or CAF) audio file using the default "stdlib" allocator. 108 | * On success, #ok_wav.data has a length of `(num_channels * num_frames * (bit_depth/8))`. 109 | * On failure, #ok_wav.data is `NULL` and #ok_wav.error_code is nonzero. 110 | * 111 | * If the encoding of the file is u-law, a-law, or ADPCM, the data is converted to 16-bit 112 | * signed integer PCM data. 113 | * 114 | * The returned `data` must be freed by the caller (using stdlib's `free()`). 115 | * 116 | * @param file The file to read. 117 | * @param decode_flags The deocde flags. Use #OK_WAV_DEFAULT_DECODE_FLAGS in most cases. 118 | * @return a #ok_wav object. 119 | */ 120 | ok_wav ok_wav_read(FILE *file, ok_wav_decode_flags decode_flags); 121 | 122 | #endif 123 | 124 | // MARK: Reading from a FILE, using a custom allocator 125 | 126 | typedef struct { 127 | /** 128 | * Allocates uninitilized memory. 129 | * 130 | * @param user_data The pointer passed to #ok_wav_read_with_allocator. 131 | * @param size The size of the memory to allocate. 132 | * @return the pointer to the newly allocated memory, or `NULL` if the memory could not be allocated. 133 | */ 134 | void *(*alloc)(void *user_data, size_t size); 135 | 136 | /** 137 | * Frees memory previously allocated with `alloc`. 138 | * 139 | * @param user_data The pointer passed to #ok_wav_read_with_allocator. 140 | * @param memory The memory to free. 141 | */ 142 | void (*free)(void *user_data, void *memory); 143 | 144 | /** 145 | * Allocates memory for the decoded audio. 146 | * This function may be `NULL`, in which case `alloc` is used instead. 147 | * 148 | * @param user_data The pointer passed to #ok_wav_read_with_allocator. 149 | * @param num_frames The number of audio frames. This value may be slightly larger the the final audio's frame count. 150 | * @param num_channels The number of audio channels. Usually 1 or 2. 151 | * @param bit_depth The bit depth of each sample. 152 | * @return The buffer to output data. The buffer must have a minimum size of 153 | * (num_frames * num_channels * (bit_depth/8)) bytes. Return `NULL` if the memory could not be allocated. 154 | */ 155 | uint8_t *(*audio_alloc)(void *user_data, uint64_t num_frames, uint8_t num_channels, uint8_t bit_depth); 156 | } ok_wav_allocator; 157 | 158 | #if !defined(OK_NO_DEFAULT_ALLOCATOR) 159 | 160 | /// The default allocator using stdlib's `malloc` and `free`. 161 | extern const ok_wav_allocator OK_WAV_DEFAULT_ALLOCATOR; 162 | 163 | #endif 164 | 165 | #if !defined(OK_NO_STDIO) 166 | 167 | /** 168 | * Reads a WAV (or CAF) audio file using a custom allocator. 169 | * On success, #ok_wav.data has a length of `(num_channels * num_frames * (bit_depth/8))`. 170 | * On failure, #ok_wav.data is `NULL` and #ok_wav.error_code is nonzero. 171 | * 172 | * If the encoding of the file is u-law, a-law, or ADPCM, the data is converted to 16-bit 173 | * signed integer PCM data. 174 | * 175 | * The returned `data` must be freed by the caller. 176 | * 177 | * @param file The file to read. 178 | * @param decode_flags The WAV decode flags. Use #OK_WAV_DEFAULT_DECODE_FLAGS in most cases. 179 | * @param allocator The allocator to use. 180 | * @param allocator_user_data The pointer to pass to the allocator functions. 181 | * If using `OK_WAV_DEFAULT_ALLOCATOR`, this value should be `NULL`. 182 | * @return a #ok_wav object. 183 | */ 184 | ok_wav ok_wav_read_with_allocator(FILE *file, ok_wav_decode_flags decode_flags, 185 | ok_wav_allocator allocator, void *allocator_user_data); 186 | 187 | #endif 188 | 189 | // MARK: Reading from custom input 190 | 191 | typedef struct { 192 | /** 193 | * Reads bytes from its source (typically `user_data`), copying the data to `buffer`. 194 | * 195 | * @param user_data The parameter that was passed to the #ok_wav_read_from_input() 196 | * @param buffer The data buffer to copy bytes to. 197 | * @param count The number of bytes to read. 198 | * @return The number of bytes read. 199 | */ 200 | size_t (*read)(void *user_data, uint8_t *buffer, size_t count); 201 | 202 | /** 203 | * Skips bytes from its source (typically `user_data`). 204 | * 205 | * @param user_data The parameter that was passed to the #ok_wav_read_from_input(). 206 | * @param count The number of bytes to skip. 207 | * @return `true` if success. 208 | */ 209 | bool (*seek)(void *user_data, long count); 210 | } ok_wav_input; 211 | 212 | /** 213 | * Reads a WAV (or CAF) audio file. 214 | * On success, #ok_wav.data has a length of `(num_channels * num_frames * (bit_depth/8))`. 215 | * On failure, #ok_wav.data is `NULL` and #ok_wav.error_code is nonzero. 216 | * 217 | * If the encoding of the file is u-law, a-law, or ADPCM, the data is converted to 16-bit 218 | * signed integer PCM data. 219 | * 220 | * The returned `data` must be freed by the caller. 221 | * 222 | * @param decode_flags The WAV decode flags. Use #OK_WAV_DEFAULT_DECODE_FLAGS in most cases. 223 | * @param input_callbacks The custom input functions. 224 | * @param input_callbacks_user_data The parameter to be passed to the input's `read` and `seek` functions. 225 | * @param allocator The allocator to use. 226 | * @param allocator_user_data The pointer to pass to the allocator functions. 227 | * If using `OK_WAV_DEFAULT_ALLOCATOR`, this value should be `NULL`. 228 | * @return a #ok_wav object. 229 | */ 230 | ok_wav ok_wav_read_from_input(ok_wav_decode_flags decode_flags, 231 | ok_wav_input input_callbacks, void *input_callbacks_user_data, 232 | ok_wav_allocator allocator, void *allocator_user_data); 233 | 234 | #ifdef __cplusplus 235 | } 236 | #endif 237 | 238 | #endif 239 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF) 4 | option(FUZZ_TEST "Use afl-cc to build ok-file-formats-fuzz-test" OFF) 5 | option(FUZZ_WITH_ASAN "Use Address Sanitizer when building the fuzz test (Warning: slow)" OFF) 6 | 7 | # Dependencies 8 | if (FUZZ_TEST) 9 | # Fuzzing (Compiling for American Fuzzy Lop++) 10 | find_program(FUZZING_COMPILER afl-cc) 11 | if (NOT FUZZING_COMPILER) 12 | message(FATAL_ERROR "afl-cc not found. Cannot build with FUZZ_TEST=ON") 13 | endif() 14 | set(CMAKE_C_COMPILER ${FUZZING_COMPILER}) 15 | set(CMAKE_CXX_COMPILER ${FUZZING_COMPILER}) 16 | endif() 17 | 18 | find_program(IMAGEMAGICK_COMMAND magick) 19 | if (NOT IMAGEMAGICK_COMMAND) 20 | message(FATAL_ERROR "ImageMagick 7 not found") 21 | endif() 22 | 23 | find_program(SOX_COMMAND sox) 24 | if (NOT SOX_COMMAND) 25 | message(FATAL_ERROR "SoX not found. See http://sox.sourceforge.net/") 26 | endif() 27 | 28 | # Project setup 29 | project(OK_FILE_FORMATS_TESTS C) 30 | 31 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") 32 | include(FileInformation) 33 | 34 | if (TREAT_WARNINGS_AS_ERRORS) 35 | if (CMAKE_C_COMPILER_ID MATCHES "MSVC") 36 | set(TREAT_WARNINGS_AS_ERRORS_FLAG "/WX") 37 | else() 38 | set(TREAT_WARNINGS_AS_ERRORS_FLAG "-Werror") 39 | endif() 40 | else() 41 | set(TREAT_WARNINGS_AS_ERRORS_FLAG "") 42 | endif() 43 | 44 | include_directories(..) 45 | file(GLOB src_files "../*.h" "../*.c") 46 | source_group("" FILES ${src_files}) 47 | 48 | # Generated files 49 | file(GLOB test_png_files "PngSuite/*.png") 50 | file(GLOB test_jpg_files "jpg/*.jpg") 51 | 52 | add_custom_target(create_gen_directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/gen) 53 | set(GEN_FILES create_gen_directory) 54 | 55 | # Copy small files for fuzzing 56 | if (FUZZ_TEST) 57 | add_custom_target(create_fuzzing_results_directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/gen/fuzzing/afl_results) 58 | list(APPEND GEN_FILES create_fuzzing_results_directory) 59 | 60 | set(JPG_FUZZING_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/fuzzing/input/jpg") 61 | set(PNG_FUZZING_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/fuzzing/input/png") 62 | 63 | add_custom_target(create_jpg_fuzzing_directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${JPG_FUZZING_OUT_DIR}) 64 | add_custom_target(create_png_fuzzing_directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${PNG_FUZZING_OUT_DIR}) 65 | list(APPEND GEN_FILES create_jpg_fuzzing_directory) 66 | list(APPEND GEN_FILES create_png_fuzzing_directory) 67 | endif() 68 | 69 | # Convert png files to raw RGBA8888 format. 70 | # Requires ImageMagick. 71 | foreach(png_file ${test_png_files}) 72 | get_filename_component(file_name ${png_file} NAME_WE) 73 | if (FUZZ_TEST) 74 | add_custom_command( 75 | OUTPUT ${PNG_FUZZING_OUT_DIR}/${file_name}.png 76 | DEPENDS ${png_file} 77 | COMMAND ${CMAKE_COMMAND} -E copy ${png_file} ${PNG_FUZZING_OUT_DIR}/${file_name}.png 78 | COMMENT "Converting ${file_name}.png [for fuzzing]" 79 | VERBATIM 80 | ) 81 | list(APPEND GEN_FILES ${PNG_FUZZING_OUT_DIR}/${file_name}.png) 82 | else() 83 | set(gen_file "${CMAKE_CURRENT_BINARY_DIR}/gen/${file_name}.rgba") 84 | add_custom_command( 85 | OUTPUT ${gen_file} 86 | DEPENDS ${png_file} 87 | COMMAND ${CMAKE_COMMAND} -DIMAGEMAGICK_COMMAND=${IMAGEMAGICK_COMMAND} -DIN_FILE=${png_file} -DOUT_FILE=${gen_file} -P ${CMAKE_CURRENT_LIST_DIR}/cmake/ConvertPNG.cmake 88 | COMMENT "Converting ${file_name}.png" 89 | VERBATIM 90 | ) 91 | list(APPEND GEN_FILES ${gen_file}) 92 | endif() 93 | endforeach() 94 | 95 | # Convert jpg files to raw RGBA8888 format, applying exif orientation tags if found. 96 | # Tested against jpeg 8d via ImageMagick. 97 | set(FUZZING_JPG_LIST "jpg-gray" "jpeg444" "LEVEL76" "65500w" "park" "orientation_1" "jpg-size-1x1" "jpg-size-7x7" "jpg-size-33x33" "2004" "gort") 98 | foreach(jpg_file ${test_jpg_files}) 99 | get_filename_component(file_name ${jpg_file} NAME_WE) 100 | if (FUZZ_TEST) 101 | if (${file_name} IN_LIST FUZZING_JPG_LIST) 102 | add_custom_command( 103 | OUTPUT ${JPG_FUZZING_OUT_DIR}/${file_name}.jpg 104 | DEPENDS ${jpg_file} 105 | COMMAND ${CMAKE_COMMAND} -E copy ${jpg_file} ${JPG_FUZZING_OUT_DIR}/${file_name}.jpg 106 | COMMENT "Converting ${file_name}.jpg [for fuzzing]" 107 | VERBATIM 108 | ) 109 | list(APPEND GEN_FILES ${JPG_FUZZING_OUT_DIR}/${file_name}.jpg) 110 | endif() 111 | else() 112 | set(gen_file "${CMAKE_CURRENT_BINARY_DIR}/gen/${file_name}.rgba") 113 | 114 | # Disable fancy upsampling because it uses a different upsampling method that ok_jpg. 115 | # See also OK_JPG_IDCT_UPSAMPLING=0 below. 116 | add_custom_command( 117 | OUTPUT ${gen_file} 118 | DEPENDS ${jpg_file} 119 | COMMAND ${IMAGEMAGICK_COMMAND} -define jpeg:fancy-upsampling=off ${jpg_file} -auto-orient ${gen_file} 120 | COMMENT "Converting ${file_name}.jpg" 121 | VERBATIM 122 | ) 123 | list(APPEND GEN_FILES ${gen_file}) 124 | endif() 125 | endforeach() 126 | 127 | # Generate WAV files 128 | include(GenerateWAVs) 129 | add_custom_target(gen ALL DEPENDS ${GEN_FILES}) 130 | 131 | if (FUZZ_TEST) 132 | # Fuzz test 133 | add_executable(ok-file-formats-fuzz-test ${src_files} "main_fuzzing.c") 134 | add_dependencies(ok-file-formats-fuzz-test gen) 135 | if (FUZZ_WITH_ASAN) 136 | set_target_properties(ok-file-formats-fuzz-test PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -O3") 137 | set_target_properties(ok-file-formats-fuzz-test PROPERTIES LINK_FLAGS "-fsanitize=address") 138 | endif() 139 | else() 140 | # Correctness test 141 | file(GLOB test_src_files "*.h" "*.c") 142 | list(FILTER test_src_files EXCLUDE REGEX ".*main_fuzzing\\.c$") 143 | add_executable(ok-file-formats-test ${src_files} ${test_src_files}) 144 | add_dependencies(ok-file-formats-test gen) 145 | if (CMAKE_C_COMPILER_ID MATCHES "Clang") 146 | # Enable -Wwrite-strings because -Weverything doesn't enable it in all versions of Clang 147 | set_target_properties(ok-file-formats-test PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -g -Weverything -Wwrite-strings -Wno-padded -Wno-covered-switch-default -Wno-declaration-after-statement ${TREAT_WARNINGS_AS_ERRORS_FLAG}") 148 | set_target_properties(ok-file-formats-test PROPERTIES LINK_FLAGS "-fsanitize=address") 149 | elseif (CMAKE_C_COMPILER_ID MATCHES "GNU") 150 | set_target_properties(ok-file-formats-test PROPERTIES COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -g -Wall -Wextra -Wwrite-strings ${TREAT_WARNINGS_AS_ERRORS_FLAG}") 151 | set_target_properties(ok-file-formats-test PROPERTIES LINK_FLAGS "-fsanitize=address") 152 | elseif (CMAKE_C_COMPILER_ID MATCHES "MSVC") 153 | set_target_properties(ok-file-formats-test PROPERTIES COMPILE_FLAGS "/Wall ${TREAT_WARNINGS_AS_ERRORS_FLAG}") 154 | endif() 155 | 156 | # Disable ok_jpg's IDCT upsampling because it uses a different upsampling method that libjpeg-turbo. 157 | # See also "jpeg:fancy-upsampling=off" above. 158 | target_compile_definitions(ok-file-formats-test PUBLIC OK_JPG_IDCT_UPSAMPLING=0) 159 | 160 | # CTest setup 161 | enable_testing() 162 | add_test(NAME ok-file-formats-test 163 | COMMAND ok-file-formats-test 164 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} 165 | ) 166 | endif() 167 | -------------------------------------------------------------------------------- /test/PngSuite/PngSuite.LICENSE: -------------------------------------------------------------------------------- 1 | PngSuite 2 | -------- 3 | 4 | Permission to use, copy, modify and distribute these images for any 5 | purpose and without fee is hereby granted. 6 | 7 | 8 | (c) Willem van Schaik, 1996, 2011 9 | 10 | -------------------------------------------------------------------------------- /test/PngSuite/PngSuite.README: -------------------------------------------------------------------------------- 1 | PNGSUITE 2 | ---------------- 3 | 4 | testset for PNG-(de)coders 5 | created by Willem van Schaik 6 | ------------------------------------ 7 | 8 | This is a collection of graphics images created to test the png applications 9 | like viewers, converters and editors. All (as far as that is possible) 10 | formats supported by the PNG standard are represented. 11 | 12 | The suite consists of the following files: 13 | 14 | - PngSuite.README - this file 15 | - PngSuite.LICENSE - the PngSuite is freeware 16 | - PngSuite.png - image with PngSuite logo 17 | - PngSuite.tgz - archive of all PNG testfiles 18 | - PngSuite.zip - same in .zip format for PCs 19 | 20 | 21 | -------- 22 | (c) Willem van Schaik 23 | willem@schaik.com 24 | Calgary, April 2011 25 | 26 | -------------------------------------------------------------------------------- /test/PngSuite/PngSuite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/PngSuite.png -------------------------------------------------------------------------------- /test/PngSuite/basi0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi0g01.png -------------------------------------------------------------------------------- /test/PngSuite/basi0g02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi0g02.png -------------------------------------------------------------------------------- /test/PngSuite/basi0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi0g04.png -------------------------------------------------------------------------------- /test/PngSuite/basi0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi0g08.png -------------------------------------------------------------------------------- /test/PngSuite/basi0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi0g16.png -------------------------------------------------------------------------------- /test/PngSuite/basi2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi2c08.png -------------------------------------------------------------------------------- /test/PngSuite/basi2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi2c16.png -------------------------------------------------------------------------------- /test/PngSuite/basi3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi3p01.png -------------------------------------------------------------------------------- /test/PngSuite/basi3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi3p02.png -------------------------------------------------------------------------------- /test/PngSuite/basi3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi3p04.png -------------------------------------------------------------------------------- /test/PngSuite/basi3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi3p08.png -------------------------------------------------------------------------------- /test/PngSuite/basi4a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi4a08.png -------------------------------------------------------------------------------- /test/PngSuite/basi4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi4a16.png -------------------------------------------------------------------------------- /test/PngSuite/basi6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi6a08.png -------------------------------------------------------------------------------- /test/PngSuite/basi6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basi6a16.png -------------------------------------------------------------------------------- /test/PngSuite/basn0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn0g01.png -------------------------------------------------------------------------------- /test/PngSuite/basn0g02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn0g02.png -------------------------------------------------------------------------------- /test/PngSuite/basn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/basn0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn0g08.png -------------------------------------------------------------------------------- /test/PngSuite/basn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn0g16.png -------------------------------------------------------------------------------- /test/PngSuite/basn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/basn2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn2c16.png -------------------------------------------------------------------------------- /test/PngSuite/basn3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn3p01.png -------------------------------------------------------------------------------- /test/PngSuite/basn3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn3p02.png -------------------------------------------------------------------------------- /test/PngSuite/basn3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn3p04.png -------------------------------------------------------------------------------- /test/PngSuite/basn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/basn4a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn4a08.png -------------------------------------------------------------------------------- /test/PngSuite/basn4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn4a16.png -------------------------------------------------------------------------------- /test/PngSuite/basn6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn6a08.png -------------------------------------------------------------------------------- /test/PngSuite/basn6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/basn6a16.png -------------------------------------------------------------------------------- /test/PngSuite/bgai4a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgai4a08.png -------------------------------------------------------------------------------- /test/PngSuite/bgai4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgai4a16.png -------------------------------------------------------------------------------- /test/PngSuite/bgan6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgan6a08.png -------------------------------------------------------------------------------- /test/PngSuite/bgan6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgan6a16.png -------------------------------------------------------------------------------- /test/PngSuite/bgbn4a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgbn4a08.png -------------------------------------------------------------------------------- /test/PngSuite/bggn4a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bggn4a16.png -------------------------------------------------------------------------------- /test/PngSuite/bgwn6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgwn6a08.png -------------------------------------------------------------------------------- /test/PngSuite/bgyn6a16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/bgyn6a16.png -------------------------------------------------------------------------------- /test/PngSuite/ccwn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ccwn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/ccwn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ccwn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/cdfn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cdfn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/cdhn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cdhn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/cdsn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cdsn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/cdun2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cdun2c08.png -------------------------------------------------------------------------------- /test/PngSuite/ch1n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ch1n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/ch2n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ch2n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/cm0n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cm0n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/cm7n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cm7n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/cm9n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cm9n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/cs3n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs3n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/cs3n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs3n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/cs5n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs5n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/cs5n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs5n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/cs8n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs8n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/cs8n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cs8n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/ct0n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ct0n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/ct1n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ct1n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/cten0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cten0g04.png -------------------------------------------------------------------------------- /test/PngSuite/ctfn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ctfn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/ctgn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ctgn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/cthn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/cthn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/ctjn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ctjn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/ctzn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ctzn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/f00n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f00n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/f00n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f00n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/f01n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f01n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/f01n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f01n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/f02n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f02n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/f02n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f02n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/f03n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f03n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/f03n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f03n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/f04n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f04n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/f04n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f04n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/f99n0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/f99n0g04.png -------------------------------------------------------------------------------- /test/PngSuite/g03n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g03n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g03n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g03n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g03n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g03n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/g04n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g04n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g04n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g04n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g04n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g04n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/g05n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g05n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g05n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g05n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g05n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g05n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/g07n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g07n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g07n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g07n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g07n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g07n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/g10n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g10n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g10n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g10n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g10n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g10n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/g25n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g25n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/g25n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g25n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/g25n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/g25n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/oi1n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi1n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/oi1n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi1n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/oi2n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi2n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/oi2n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi2n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/oi4n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi4n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/oi4n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi4n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/oi9n0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi9n0g16.png -------------------------------------------------------------------------------- /test/PngSuite/oi9n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/oi9n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/pp0n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/pp0n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/pp0n6a08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/pp0n6a08.png -------------------------------------------------------------------------------- /test/PngSuite/ps1n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ps1n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/ps1n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ps1n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/ps2n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ps2n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/ps2n2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/ps2n2c16.png -------------------------------------------------------------------------------- /test/PngSuite/s01i3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s01i3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s01n3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s01n3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s02i3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s02i3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s02n3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s02n3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s03i3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s03i3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s03n3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s03n3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s04i3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s04i3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s04n3p01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s04n3p01.png -------------------------------------------------------------------------------- /test/PngSuite/s05i3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s05i3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s05n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s05n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s06i3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s06i3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s06n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s06n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s07i3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s07i3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s07n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s07n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s08i3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s08i3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s08n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s08n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s09i3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s09i3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s09n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s09n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/s32i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s32i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s32n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s32n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s33i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s33i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s33n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s33n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s34i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s34i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s34n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s34n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s35i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s35i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s35n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s35n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s36i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s36i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s36n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s36n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s37i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s37i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s37n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s37n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s38i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s38i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s38n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s38n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s39i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s39i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s39n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s39n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s40i3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s40i3p04.png -------------------------------------------------------------------------------- /test/PngSuite/s40n3p04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/s40n3p04.png -------------------------------------------------------------------------------- /test/PngSuite/tbbn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbbn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/tbbn2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbbn2c16.png -------------------------------------------------------------------------------- /test/PngSuite/tbbn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbbn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/tbgn2c16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbgn2c16.png -------------------------------------------------------------------------------- /test/PngSuite/tbgn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbgn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/tbrn2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbrn2c08.png -------------------------------------------------------------------------------- /test/PngSuite/tbwn0g16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbwn0g16.png -------------------------------------------------------------------------------- /test/PngSuite/tbwn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbwn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/tbyn3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tbyn3p08.png -------------------------------------------------------------------------------- /test/PngSuite/tm3n3p02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tm3n3p02.png -------------------------------------------------------------------------------- /test/PngSuite/tp0n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tp0n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/tp0n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tp0n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/tp0n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tp0n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/tp1n3p08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/tp1n3p08.png -------------------------------------------------------------------------------- /test/PngSuite/xc1n0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xc1n0g08.png -------------------------------------------------------------------------------- /test/PngSuite/xc9n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xc9n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/xcrn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xcrn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/xcsn0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xcsn0g01.png -------------------------------------------------------------------------------- /test/PngSuite/xd0n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xd0n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/xd3n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xd3n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/xd9n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xd9n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/xdtn0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xdtn0g01.png -------------------------------------------------------------------------------- /test/PngSuite/xhdn0g08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xhdn0g08.png -------------------------------------------------------------------------------- /test/PngSuite/xlfn0g04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xlfn0g04.png -------------------------------------------------------------------------------- /test/PngSuite/xs1n0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xs1n0g01.png -------------------------------------------------------------------------------- /test/PngSuite/xs2n0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xs2n0g01.png -------------------------------------------------------------------------------- /test/PngSuite/xs4n0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xs4n0g01.png -------------------------------------------------------------------------------- /test/PngSuite/xs7n0g01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/xs7n0g01.png -------------------------------------------------------------------------------- /test/PngSuite/z00n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/z00n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/z03n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/z03n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/z06n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/z06n2c08.png -------------------------------------------------------------------------------- /test/PngSuite/z09n2c08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/PngSuite/z09n2c08.png -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # ok-file-formats tests 2 | 3 | There are two tests here: A correctness test and a fuzz test. 4 | 5 | The correctness test checks the output of `ok_png`, `ok_jpg`, and `ok_wav` against the output of 6 | [ImageMagick 7](https://www.imagemagick.org/), [SoX 14](http://sox.sourceforge.net/)) and, on macOS, 7 | the pre-installed `afconvert`. 8 | 9 | The fuzz test uses American Fuzzy Lop++. 10 | 11 | ## Requirements 12 | 13 | On macOS, install ImageMagick 7 and SoX: 14 | 15 | brew install imagemagick sox 16 | 17 | For the fuzz test, install American Fuzzy Lop++: 18 | 19 | brew install afl++ 20 | 21 | ## Correctness test 22 | 23 | To run the correctness test: 24 | 25 | cmake -B build && cmake --build build && ctest --verbose --test-dir build 26 | 27 | Alternatively, to run the correctness test from an IDE: 28 | 29 | cmake -B build && cmake --build build -G Xcode 30 | 31 | ### PNG 32 | 33 | For PNG tests, the [PngSuite](http://www.schaik.com/pngsuite/pngsuite.html) images from Willem van 34 | Schaik are used. 35 | 36 | Tested against ImageMagick 7.0.8-23. Earlier versions of ImageMagick 7 may have incorrect output for 37 | some PNG files. 38 | 39 | To test Apple's proprietary PNG extensions, the tests must run on an actual iOS device, and not the 40 | simulator. 41 | 42 | ### JPEG 43 | 44 | The JPEG tests disable "fancy upsampling" because results will vary based on what version of the 45 | libjpeg library ImageMagick uses. The `ok_jpg` decoder uses a similar upsampling method than the 46 | libjpeg-8d library, but is different that libjpeg-turbo. 47 | 48 | Although there are only a few dozen JPEGs in the included tests, `ok_jpg` has been tested against 49 | thousands of images, some dated back to the 90's. 50 | 51 | ## Fuzz test 52 | 53 | To build `ok-file-formats-fuzz-test`: 54 | 55 | cmake -B build -DFUZZ_TEST=ON && cmake --build build 56 | 57 | Optionally, enable Address Sanitizer (warning, this is slow): 58 | 59 | cmake -B build -DFUZZ_TEST=ON -DFUZZ_WITH_ASAN=ON && cmake --build build 60 | 61 | Then run one of these commands: 62 | 63 | afl-fuzz -i build/gen/fuzzing/input/wav -o build/gen/fuzzing/afl_results/wav ./build/ok-file-formats-fuzz-test --wav 64 | afl-fuzz -i build/gen/fuzzing/input/caf -o build/gen/fuzzing/afl_results/caf ./build/ok-file-formats-fuzz-test --caf 65 | afl-fuzz -t 1000 -x png.dict -i build/gen/fuzzing/input/png -o build/gen/fuzzing/afl_results/png ./build/ok-file-formats-fuzz-test --png 66 | afl-fuzz -t 1000 -x jpg.dict -i build/gen/fuzzing/input/jpg -o build/gen/fuzzing/afl_results/jpg ./build/ok-file-formats-fuzz-test --jpg 67 | 68 | Fuzzing will take hours or even days to complete, depending on the input. `afl-fuzz` runs on one 69 | core, so if you have a multi-core machine you can run multiple tests at once. 70 | 71 | The generated input cases are imperfect. For more input cases, see 72 | [Mozilla's Fuzzdata samples](https://github.com/MozillaSecurity/fuzzdata/tree/master/samples) and 73 | [input cases provided by moonAgirl](https://github.com/moonAgirl/Bugs/tree/master/ok-file-formats). 74 | -------------------------------------------------------------------------------- /test/cmake/ConvertPNG.cmake: -------------------------------------------------------------------------------- 1 | # Converts the png file ${IN_FILE} to the RGBA8888 file ${OUT_FILE} 2 | # The gAMA chunk is ignored. 3 | # The "-intensity Average" setting prevents ImageMagick from color-converting grayscale files. 4 | # For invalid files, a zero-byte output file is created. 5 | execute_process( 6 | COMMAND ${IMAGEMAGICK_COMMAND} -define png:bit-depth=8 -define png:exclude-chunk=gAMA ${IN_FILE} ${CMAKE_CURRENT_LIST_DIR}/temp.png 7 | ERROR_QUIET 8 | ) 9 | if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/temp.png) 10 | execute_process(COMMAND ${IMAGEMAGICK_COMMAND} -intensity Average ${CMAKE_CURRENT_LIST_DIR}/temp.png ${OUT_FILE}) 11 | file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/temp.png) 12 | else() 13 | file(WRITE ${OUT_FILE} "") 14 | endif() 15 | -------------------------------------------------------------------------------- /test/cmake/FileInformation.cmake: -------------------------------------------------------------------------------- 1 | # - CMake module for getting file information such as size and modification date 2 | # 3 | # This module overrides the built-in CMake command file to provide two additional sub-commands 4 | # SIZE and TIMESTAMP on all platforms. Under UNIX the sub-commands USER_NAME, GROUP_NAME and 5 | # PERMISSIONS are also provided. 6 | # 7 | # file (SIZE filename var) 8 | # SIZE will store the size of the file in bytes into the variable. 9 | # 10 | # file (TIMESTAMP filename var) 11 | # TIMESTAMP will store the modification date of the file into the variable as an ISO 8601 12 | # formatted string (e.g., "2011-07-02T13:00:22"). The chronological order of two timestamps 13 | # can be determined with a STRLESS, STRGREATER or STREQUAL expression. 14 | # 15 | # get_timestamp_component (var timestamp TIMESTAMP|DATE|TIME|YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|TIMEZONE ...) 16 | # gets a specific component of a ISO 8601 formatted string. Multiple components can be 17 | # retrieved at the same time as a list. 18 | # 19 | # current_timestamp (var [ TIMESTAMP|DATE|TIME|YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|TIMEZONE ... ]) 20 | # will store the current date and time into the variable as an ISO 8601 formatted string. 21 | # Optionally components of the current date and time can be retrieved as a list instead. 22 | # 23 | # The following sub-commands are available on UNIX and Apple (Mac OS X) only: 24 | # 25 | # file (USER_NAME filename var) 26 | # USER_NAME will store the user name of the file owner into the variable. 27 | # 28 | # file (GROUP_NAME filename var) 29 | # GROUP_NAME will store the group name of the file owner into the variable. 30 | # 31 | # file (PERMISSIONS filename var) 32 | # PERMISSIONS will store the the permissions of the file into the variable as a list. 33 | # Valid permissions are OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, 34 | # GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, WORLD_EXECUTE, SETUID, and SETGID. 35 | # 36 | #============================================================================= 37 | # Copyright 2011-2013 Sascha Kratky 38 | # 39 | # Permission is hereby granted, free of charge, to any person 40 | # obtaining a copy of this software and associated documentation 41 | # files (the "Software"), to deal in the Software without 42 | # restriction, including without limitation the rights to use, 43 | # copy, modify, merge, publish, distribute, sublicense, and/or sell 44 | # copies of the Software, and to permit persons to whom the 45 | # Software is furnished to do so, subject to the following 46 | # conditions: 47 | # 48 | # The above copyright notice and this permission notice shall be 49 | # included in all copies or substantial portions of the Software. 50 | # 51 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 52 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 53 | # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 54 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 55 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 56 | # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 57 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 58 | # OTHER DEALINGS IN THE SOFTWARE. 59 | #============================================================================= 60 | 61 | get_filename_component(FileInformation_CMAKE_MODULE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 62 | set (FileInformation_CMAKE_MODULE_VERSION "1.2.0") 63 | find_program(BASH bash) 64 | 65 | # private function which invokes platform specific helper script 66 | function (_invoke_helper_script _command _filePath _outputVar _exitCodeVar) 67 | if (CMAKE_HOST_UNIX) 68 | set (_helperScript "${FileInformation_CMAKE_MODULE_DIR}/FileInformation.sh") 69 | # make sure helper script is executable 70 | execute_process(COMMAND chmod "-f" "+x" "${_helperScript}" TIMEOUT 5) 71 | elseif (CMAKE_HOST_WIN32) 72 | set (_helperScript "${FileInformation_CMAKE_MODULE_DIR}/FileInformation.cmd") 73 | # Windows requires native paths 74 | file (TO_NATIVE_PATH "${_helperScript}" _helperScript) 75 | if (_filePath) 76 | file (TO_NATIVE_PATH "${_filePath}" _filePath) 77 | endif() 78 | else() 79 | message (FATAL_ERROR "Unsupported host platform ${CMAKE_HOST_SYSTEM_NAME}.") 80 | endif() 81 | string (TOLOWER "${_command}" _cmd) 82 | execute_process( 83 | COMMAND "${BASH}" "${_helperScript}" "--${_cmd}" "${_filePath}" 84 | TIMEOUT 5 85 | RESULT_VARIABLE _result 86 | OUTPUT_VARIABLE _output 87 | OUTPUT_STRIP_TRAILING_WHITESPACE) 88 | set (${_exitCodeVar} ${_result} PARENT_SCOPE) 89 | set (${_outputVar} ${_output} PARENT_SCOPE) 90 | endfunction() 91 | 92 | if (NOT COMMAND get_timestamp_component) 93 | # do not override get_timestamp_component if it already exists 94 | function (get_timestamp_component _outputVar _timestamp) 95 | if (${ARGC} LESS 3) 96 | message (FATAL_ERROR "timestamp requires at least three arguments.") 97 | endif() 98 | string(STRIP "${_timestamp}" _timestamp) 99 | if ("${_timestamp}" MATCHES "([0-9-]+)T([0-9:Z+-]+)") 100 | set (_date "${CMAKE_MATCH_1}") 101 | set (_time "${CMAKE_MATCH_2}") 102 | if ("${_date}" MATCHES "([0-9][0-9][0-9][0-9])(-?([0-9][0-9])(-?([0-9][0-9]))?)?") 103 | set (_year "${CMAKE_MATCH_1}") 104 | set (_month "${CMAKE_MATCH_3}") 105 | set (_day "${CMAKE_MATCH_5}") 106 | else() 107 | unset(_year) 108 | unset(_month) 109 | unset(_day) 110 | endif() 111 | if ("${_time}" MATCHES "([0-9][0-9])(:?([0-9][0-9])(:?([0-9][0-9]))?)?(Z|([+-][0-9:]+))?") 112 | set (_hour "${CMAKE_MATCH_1}") 113 | set (_minute "${CMAKE_MATCH_3}") 114 | set (_second "${CMAKE_MATCH_5}") 115 | set (_timezone "${CMAKE_MATCH_6}") 116 | if (_timezone) 117 | # if time is UTC, use +00:00 118 | string (REPLACE "Z" "+0000" _timezone "${_timezone}") 119 | # use canonical representation of time zone 120 | string (REPLACE ":" "" _timezone "${_timezone}") 121 | string (REGEX REPLACE "^[0-9][0-9]$" "\\000" _timezone "${_timezone}") 122 | endif() 123 | else() 124 | unset(_hour) 125 | unset(_minute) 126 | unset(_second) 127 | endif() 128 | set (_result "") 129 | foreach (_component ${ARGN}) 130 | string (TOLOWER "_${_component}" _componentVar) 131 | if (DEFINED "${_componentVar}" AND 132 | "${${_componentVar}}" MATCHES ".+") 133 | set (_componentValue "${${_componentVar}}") 134 | else() 135 | message (WARNING 136 | "get_timestamp_component cannot extract component ${_component}.") 137 | set (_componentValue "${_component}-NOTFOUND") 138 | endif() 139 | list (APPEND _result ${_componentValue}) 140 | endforeach() 141 | else() 142 | message (SEND_ERROR 143 | "get_timestamp_component ${_timeStamp} is not an ISO 8601 string.") 144 | set (_result "TIMESTAMP-NOTFOUND") 145 | endif() 146 | set (${_outputVar} ${_result} PARENT_SCOPE) 147 | endfunction() 148 | endif() 149 | 150 | if (NOT COMMAND current_timestamp) 151 | # do not override current_timestamp if it already exists 152 | function (current_timestamp _outputVar) 153 | _invoke_helper_script("current_timestamp" "" _result _exitCode) 154 | if (NOT ${_exitCode} EQUAL 0) 155 | message (SEND_ERROR "current_timestamp failed.") 156 | set (_result "TIMESTAMP-NOTFOUND") 157 | elseif (${ARGC} GREATER 1) 158 | get_timestamp_component (_result "${_result}" ${ARGN}) 159 | endif() 160 | set (${_outputVar} ${_result} PARENT_SCOPE) 161 | endfunction() 162 | endif() 163 | 164 | macro (file) 165 | if ("${ARGV0}" MATCHES "SIZE|TIMESTAMP|PERMISSIONS|USER_NAME|GROUP_NAME") 166 | if (NOT ${ARGC} EQUAL 3) 167 | message (FATAL_ERROR "file sub-command ${ARGV0} requires two arguments.") 168 | endif() 169 | set (_filePath "${ARGV1}") 170 | set (_varName "${ARGV2}") 171 | get_filename_component(_filePath "${_filePath}" ABSOLUTE) 172 | if (NOT EXISTS "${_filePath}") 173 | message (FATAL_ERROR "file ${ARGV0} ${_filePath} does not exist.") 174 | endif() 175 | if ("${ARGV0}" STREQUAL "SIZE" AND IS_DIRECTORY "${_filePath}") 176 | message (FATAL_ERROR "file ${ARGV0} ${_filePath} is a directory.") 177 | endif() 178 | _invoke_helper_script("${ARGV0}" "${_filePath}" ${_varName} _exitCode) 179 | if (NOT ${_exitCode} EQUAL 0) 180 | message (SEND_ERROR "file ${ARGV0} failed for ${_filePath}.") 181 | set (${_varName} "${ARGV0}-NOTFOUND") 182 | endif() 183 | else() 184 | # pass call to original file function 185 | _file (${ARGV}) 186 | endif() 187 | endmacro() 188 | -------------------------------------------------------------------------------- /test/cmake/FileInformation.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem helper script for FileInformation CMake module 3 | 4 | setlocal enabledelayedexpansion 5 | 6 | set "INPUT_OPTION=%~1" 7 | 8 | if "!INPUT_OPTION!" == "--size" ( 9 | echo %~z2 10 | ) else if "!INPUT_OPTION!" == "--timestamp" ( 11 | rem do not use %~t2, its format depends on regional settings 12 | rem use Visual Basic to obtain ISO 8601 formatted time stamp 13 | cscript //Nologo "%~dpn0.vbs" "%~1" "%~f2" 14 | ) else if "!INPUT_OPTION!" == "--current_timestamp" ( 15 | rem do not use %DATE% and %TIME%, their format depends on regional settings 16 | rem use Visual Basic to obtain ISO 8601 formatted time stamp 17 | cscript //Nologo "%~dpn0.vbs" "%~1" 18 | ) else ( 19 | exit 1 20 | ) 21 | -------------------------------------------------------------------------------- /test/cmake/FileInformation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # helper script for FileInformation CMake module 3 | 4 | #logger $# "$@" 5 | 6 | function to_cmake_permission() { 7 | local symbolic_perm=$1 8 | local owner_group_world=$2 9 | local set_user_group=$3 10 | case "${symbolic_perm}" in 11 | "r" ) echo "${owner_group_world}_READ";; 12 | "w" ) echo "${owner_group_world}_WRITE";; 13 | "x" ) echo "${owner_group_world}_EXECUTE";; 14 | "s" ) echo "${owner_group_world}_EXECUTE;${set_user_group}";; 15 | "S" ) echo "${set_user_group}";; 16 | "t" ) echo "${owner_group_world}_EXECUTE";; 17 | * ) echo "";; 18 | esac 19 | } 20 | 21 | function to_cmake_permissions() { 22 | local symbolic_perms=$1 23 | local -a cmake_perms_array 24 | for i in 0 1 2 25 | do 26 | cmake_perms_array[((0+$i))]=$(to_cmake_permission ${symbolic_perms:((1+$i)):1} "OWNER" "SETUID") 27 | cmake_perms_array[((3+$i))]=$(to_cmake_permission ${symbolic_perms:((4+$i)):1} "GROUP" "SETGID") 28 | cmake_perms_array[((6+$i))]=$(to_cmake_permission ${symbolic_perms:((7+$i)):1} "WORLD") 29 | done 30 | local cmake_perms="" 31 | for cmake_perm in ${cmake_perms_array[*]} 32 | do 33 | if [ -z $cmake_perms ] 34 | then 35 | cmake_perms=$cmake_perm 36 | else 37 | cmake_perms="$cmake_perms;$cmake_perm" 38 | fi 39 | done 40 | echo $cmake_perms 41 | } 42 | 43 | INPUT_OPTION=$1 44 | 45 | # format timestamp according to ISO 8601 46 | TIMESTAMP_FORMAT=%Y-%m-%dT%H:%M:%S%z 47 | 48 | if [[ $OSTYPE == darwin* || $OSTYPE == freebsd* ]] 49 | then 50 | # Mac OS X or FreeBSD 51 | if [ "$INPUT_OPTION" = "--size" ] 52 | then 53 | stat -f "%z" "$2" 54 | elif [ "$INPUT_OPTION" = "--timestamp" ] 55 | then 56 | date -r $(stat -f "%m" "$2") "+$TIMESTAMP_FORMAT" 57 | elif [ "$INPUT_OPTION" = "--current_timestamp" ] 58 | then 59 | date "+$TIMESTAMP_FORMAT" 60 | elif [ "$INPUT_OPTION" = "--user_name" ] 61 | then 62 | stat -f "%Su" "$2" 63 | elif [ "$INPUT_OPTION" = "--group_name" ] 64 | then 65 | stat -f "%Sg" "$2" 66 | elif [ "$INPUT_OPTION" = "--permissions" ] 67 | then 68 | to_cmake_permissions $(stat -f "%Sp" "$2") 69 | else 70 | exit 1 71 | fi 72 | else 73 | # other Unices 74 | if [ "$INPUT_OPTION" = "--size" ] 75 | then 76 | stat -c "%s" "$2" 77 | elif [ "$INPUT_OPTION" = "--timestamp" ] 78 | then 79 | date -r "$2" "+$TIMESTAMP_FORMAT" 80 | elif [ "$INPUT_OPTION" = "--current_timestamp" ] 81 | then 82 | date "+$TIMESTAMP_FORMAT" 83 | elif [ "$INPUT_OPTION" = "--user_name" ] 84 | then 85 | stat -c "%U" "$2" 86 | elif [ "$INPUT_OPTION" = "--group_name" ] 87 | then 88 | stat -c "%G" "$2" 89 | elif [ "$INPUT_OPTION" = "--permissions" ] 90 | then 91 | to_cmake_permissions $(stat -c "%A" "$2") 92 | else 93 | exit 1 94 | fi 95 | fi 96 | -------------------------------------------------------------------------------- /test/cmake/FileInformation.vbs: -------------------------------------------------------------------------------- 1 | ' helper script for FileInformation CMake module 2 | 3 | Function ToISODateTime(ByVal dt) 4 | ToISODateTime = CStr(Year(dt)) & "-" & _ 5 | Right("00" & Month(dt), 2) & "-" & _ 6 | Right("00" & Day(dt), 2) & "T" & _ 7 | Right("00" & Hour(dt), 2) & ":" & _ 8 | Right("00" & Minute(dt), 2) & ":" & _ 9 | Right("00" & Second(dt), 2) 10 | End Function 11 | 12 | If WScript.Arguments.Count < 1 Then 13 | Wscript.Quit 1 14 | End If 15 | 16 | InputOption=WScript.Arguments.Item(0) 17 | 18 | If InputOption = "--current_timestamp" Then 19 | Wscript.Echo ToISODateTime(Now) 20 | Wscript.Quit 0 21 | End If 22 | 23 | If WScript.Arguments.Count < 2 Then 24 | Wscript.Quit 1 25 | End If 26 | 27 | Set FSO=CreateObject("Scripting.FileSystemObject") 28 | if FSO.FolderExists(WScript.Arguments.Item(1)) Then 29 | Set FSItem=FSO.GetFolder(WScript.Arguments.Item(1)) 30 | Else 31 | Set FSItem=FSO.GetFile(WScript.Arguments.Item(1)) 32 | End If 33 | 34 | If InputOption = "--size" Then 35 | Wscript.Echo CStr(FSItem.Size) 36 | Wscript.Quit 0 37 | ElseIf InputOption = "--timestamp" Then 38 | Wscript.Echo ToISODateTime(FSItem.DateLastModified) 39 | Wscript.Quit 0 40 | End If 41 | 42 | Wscript.Quit 1 43 | -------------------------------------------------------------------------------- /test/csv/test1.csv: -------------------------------------------------------------------------------- 1 | Name,Language,Value 2 | hello,en,Hello 3 | hello,zh-Hans,你好 4 | name,en,"Smith, Fred" 5 | nickname,en,"""The Prof""" 6 | ,, 7 | 8 | multiline,en,"This is 9 | two lines" 10 | multiline2,en," 11 | This is also two lines" 12 | long,latin,"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse fringilla, ipsum et vulputate dignissim, felis leo fermentum diam, ut vestibulum risus elit in odio. Duis at justo sit amet dui egestas tempor ut id justo. Pellentesque accumsan, nulla cursus rutrum auctor, turpis justo consectetur dui, id euismod metus sapien sed nunc. Nam id euismod velit, eget lobortis nunc. Suspendisse eleifend non nisl eu iaculis. Phasellus eu sapien in leo elementum venenatis. Etiam aliquam arcu lacinia ligula varius, nec vehicula erat bibendum. Curabitur nec est nisi. Quisque feugiat congue imperdiet. Maecenas ornare magna libero, id consectetur lectus lacinia sit amet. Aliquam libero sapien, facilisis non mollis ac, lobortis vel libero. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus iaculis eros sed libero pharetra, tristique lobortis quam malesuada. Quisque adipiscing id justo non semper. Maecenas porttitor ac mi sed ultricies. Nunc vel eleifend elit, a tristique nunc. 13 | Cras id porta ligula. Donec mollis, massa gravida dignissim pharetra, urna dolor vestibulum ipsum, ut accumsan neque mauris ut lectus. Sed nec facilisis libero. Integer auctor ornare purus. Mauris et pharetra diam. Etiam sagittis orci nisl, sed vehicula est gravida ut. Integer dapibus, tortor fringilla vehicula tincidunt, justo nibh vulputate odio, in consectetur mi est at nibh. Aenean facilisis elit diam, et commodo ligula posuere in. Donec ut elit eget nunc egestas egestas in eget erat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec lacinia commodo malesuada. Etiam eleifend elementum neque et sagittis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce augue nisi, gravida sit amet faucibus sit amet, euismod vitae ipsum. Ut gravida vehicula arcu a volutpat. 14 | Vivamus id commodo quam. Vivamus at porta tortor. Suspendisse fermentum magna justo. Etiam aliquam ligula vitae neque laoreet, ut sollicitudin felis fringilla. Aliquam pharetra sit amet ante nec malesuada. Fusce volutpat, orci at sodales consequat, sem sapien tincidunt ante, ac sollicitudin felis enim eu dui. Duis eget orci fringilla, porttitor libero pulvinar, luctus enim. Etiam molestie dapibus diam ut rutrum. 15 | Ut porta enim quis faucibus fermentum. Praesent ullamcorper dui et tellus tempus rutrum. In adipiscing arcu vel metus dictum, vel ornare massa placerat. Maecenas consectetur volutpat purus ac bibendum. Cras augue orci, ultrices sit amet lacinia vel, porta et velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam posuere, ante scelerisque tincidunt pretium, tellus neque vestibulum quam, non fringilla diam enim quis sem. Nullam mi sapien, venenatis eu turpis a, aliquam scelerisque diam. Sed ultricies dui non enim aliquam, quis bibendum tellus sollicitudin. Vestibulum at hendrerit neque. Suspendisse pretium neque in enim tempus volutpat. 16 | Aenean suscipit dolor quis tortor cursus tristique. Mauris ligula tellus, consectetur vitae nulla sit amet, bibendum pulvinar ligula. Pellentesque et volutpat ante. In mollis ullamcorper lorem, quis aliquam dui pulvinar sed. Morbi in arcu id tortor porta pretium at et quam. Morbi sollicitudin nunc ac diam imperdiet, sed luctus libero viverra. Suspendisse et tristique tortor. 17 | Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In vel turpis viverra, commodo risus sit amet, viverra diam. Fusce risus odio, varius non odio sit amet, vehicula malesuada odio. Nam vehicula at ante non fermentum. Nunc faucibus consequat mauris, vitae molestie purus posuere interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent eu mi orci. Quisque eu turpis faucibus dui suscipit placerat. Praesent massa turpis, adipiscing ac nisi sed, aliquam aliquam tortor. Aenean sagittis arcu ut urna malesuada, sed tempor arcu ultrices. Proin feugiat vehicula metus. Vestibulum malesuada, ante eu vulputate cursus, enim lacus sodales tortor, et dapibus nibh est a cras amet." 18 | -------------------------------------------------------------------------------- /test/csv_test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "csv_test.h" 3 | #include "ok_csv.h" 4 | #include "ok_mo.h" // for UTF-8 code 5 | #include "test_common.h" 6 | #include 7 | #include 8 | #include 9 | 10 | int csv_test(const char *path, bool verbose) { 11 | (void)verbose; 12 | 13 | char *test1_file = get_full_path(path, "test1", "csv"); 14 | 15 | FILE *file = fopen(test1_file, "rb"); 16 | ok_csv *csv = ok_csv_read(file); 17 | fclose(file); 18 | free(test1_file); 19 | 20 | if (!csv) { 21 | printf("Failure: ok_csv is NULL\n"); 22 | return 1; 23 | } 24 | if (csv->num_records == 0) { 25 | printf("Failure: Couldn't load CSV: %s\n", csv->error_message); 26 | return 1; 27 | } 28 | if (csv->num_records != 10) { 29 | printf("Failure: Didn't find 10 records\n"); 30 | return 1; 31 | } 32 | 33 | char hello_utf8[] = {(char)0xe4, (char)0xbd, (char)0xa0, (char)0xe5, (char)0xa5, (char)0xbd, 0}; 34 | unsigned int hello_len = ok_utf8_strlen(hello_utf8); 35 | uint32_t *hello = malloc(sizeof(uint32_t) * (hello_len + 1)); 36 | ok_utf8_to_unicode(hello_utf8, hello, hello_len); 37 | if (!hello || hello[0] != 0x4f60 || hello[1] != 0x597d || hello[2] != 0) { 38 | printf("Failure: Couldn't convert UTF-8 to unicode\n"); 39 | return 1; 40 | } 41 | free(hello); 42 | 43 | if (memcmp(hello_utf8, csv->fields[2][2], 7)) { 44 | printf("Failure: Couldn't read UTF-8 field\n"); 45 | return 1; 46 | } 47 | if (memcmp("Smith, Fred", csv->fields[3][2], 12)) { 48 | printf("Failure: Couldn't read field with comma\n"); 49 | return 1; 50 | } 51 | if (memcmp("\"The Prof\"", csv->fields[4][2], 11)) { 52 | printf("Failure: Couldn't read field with quotes\n"); 53 | return 1; 54 | } 55 | 56 | if (csv->num_fields[5] != 3 || csv->fields[5][0][0] != 0 || 57 | csv->fields[5][1][0] != 0 || csv->fields[5][1][0] != 0) { 58 | printf("Failure: Couldn't read three blank fields\n"); 59 | return 1; 60 | } 61 | if (csv->num_fields[6] != 1 || csv->fields[6][0][0] != 0) { 62 | printf("Failure: Couldn't read one blank line\n"); 63 | return 1; 64 | } 65 | if (memcmp("This is\ntwo lines", csv->fields[7][2], 18)) { 66 | printf("Failure: Couldn't read multiline\n"); 67 | return 1; 68 | } 69 | if (memcmp("\nThis is also two lines", csv->fields[8][2], 24)) { 70 | printf("Failure: Couldn't read multiline2\n"); 71 | return 1; 72 | } 73 | if (strlen(csv->fields[9][2]) != 4105) { 74 | printf("Failure: Couldn't read long line\n"); 75 | return 1; 76 | } 77 | 78 | ok_csv_free(csv); 79 | 80 | printf("Success: CSV\n"); 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /test/csv_test.h: -------------------------------------------------------------------------------- 1 | #ifndef CSV_TEST_H 2 | #define CSV_TEST_H 3 | 4 | #include 5 | 6 | int csv_test(const char *path_to_csv_files, bool verbose); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /test/gettext/en.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/gettext/en.mo -------------------------------------------------------------------------------- /test/gettext/en.po: -------------------------------------------------------------------------------- 1 | # Test strings 2 | # /usr/local/opt/gettext/bin/msgfmt en.po -o en.mo 3 | # 4 | #, fuzzy 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "Report-Msgid-Bugs-To: \n" 9 | "POT-Creation-Date: 2014-08-04 15:32-0700\n" 10 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 11 | "Last-Translator: FULL NAME \n" 12 | "Language-Team: LANGUAGE \n" 13 | "Language: en\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #, c-format 19 | msgid "Hello" 20 | msgstr "" 21 | 22 | #, c-format 23 | msgid "The {0} was {1}" 24 | msgstr "" 25 | 26 | #, c-format 27 | msgid "story_0" 28 | msgstr "" 29 | "hello, this is\n" 30 | "a very long string\n" 31 | "if you know what i mean" 32 | 33 | #, c-format 34 | msgctxt "Menu" 35 | msgid "File" 36 | msgstr "" 37 | 38 | #, c-format 39 | msgid "%d user likes this." 40 | msgid_plural "%d users like this." 41 | msgstr[0] "" 42 | msgstr[1] "" -------------------------------------------------------------------------------- /test/gettext/es.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/gettext/es.mo -------------------------------------------------------------------------------- /test/gettext/es.po: -------------------------------------------------------------------------------- 1 | # Test strings 2 | # /usr/local/opt/gettext/bin/msgfmt es.po -o es.mo 3 | # 4 | #, fuzzy 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "Report-Msgid-Bugs-To: \n" 9 | "POT-Creation-Date: 2014-08-04 15:32-0700\n" 10 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 11 | "Last-Translator: FULL NAME \n" 12 | "Language-Team: LANGUAGE \n" 13 | "Language: es\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #, c-format 19 | msgid "Hello" 20 | msgstr "Hola" 21 | 22 | #, c-format 23 | msgid "The {0} was {1}" 24 | msgstr "El {0} {1} era" 25 | 26 | #, c-format 27 | msgid "story_0" 28 | msgstr "" 29 | "hola, este es\n" 30 | "una muy larga cadena\n" 31 | "Si sabes a lo que me refiero" 32 | 33 | #, c-format 34 | msgctxt "Menu" 35 | msgid "File" 36 | msgstr "Archivo" 37 | 38 | #, c-format 39 | msgid "%d user likes this." 40 | msgid_plural "%d users like this." 41 | msgstr[0] "%d usuario le gusta esto." 42 | msgstr[1] "%d usuarios les gusta esto." -------------------------------------------------------------------------------- /test/gettext/zh-Hans.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/gettext/zh-Hans.mo -------------------------------------------------------------------------------- /test/gettext/zh-Hans.po: -------------------------------------------------------------------------------- 1 | # Test strings 2 | # /usr/local/opt/gettext/bin/msgfmt zh-Hans.po -o zh-Hans.mo 3 | # 4 | #, fuzzy 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "Report-Msgid-Bugs-To: \n" 9 | "POT-Creation-Date: 2014-08-04 15:32-0700\n" 10 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 11 | "Last-Translator: FULL NAME \n" 12 | "Language-Team: LANGUAGE \n" 13 | "Language: zh-Hans\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #, c-format 19 | msgid "Hello" 20 | msgstr "你好" 21 | 22 | #, c-format 23 | msgid "The {0} was {1}" 24 | msgstr "{0}是{1}" 25 | 26 | #, c-format 27 | msgid "story_0" 28 | msgstr "" 29 | "你好,这是\n" 30 | "一个很长的字符串\n" 31 | "如果你明白我的意思" 32 | 33 | #, c-format 34 | msgctxt "Menu" 35 | msgid "File" 36 | msgstr "文件" 37 | 38 | #, c-format 39 | msgid "%d user likes this." 40 | msgid_plural "%d users like this." 41 | msgstr[0] "%d 用户喜欢这个." 42 | -------------------------------------------------------------------------------- /test/ios/.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | xcshareddata 3 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest/AppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | @import UIKit; 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (strong, nonatomic) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest/AppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | #import "AppDelegate.h" 3 | #include "png_suite_test.h" 4 | #include "png_write_test.h" 5 | #include "jpg_test.h" 6 | #include "csv_test.h" 7 | #include "mo_test.h" 8 | #include "wav_test.h" 9 | 10 | #define LOCAL_TEST 0 11 | 12 | #if LOCAL_TEST 13 | #include "test_common.h" 14 | #include "ok_png.h" 15 | #include "ok_jpg.h" 16 | 17 | static void dataRelease(void *info, const void *data, size_t size) { 18 | free((void *)data); 19 | } 20 | 21 | #endif 22 | 23 | @interface AppDelegate () 24 | 25 | @end 26 | 27 | @implementation AppDelegate 28 | 29 | @synthesize window; 30 | 31 | - (BOOL)application:(__unused UIApplication *)application didFinishLaunchingWithOptions:(__unused NSDictionary *)launchOptions { 32 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 33 | self.window.rootViewController = [UIViewController new]; 34 | [self.window makeKeyAndVisible]; 35 | 36 | const char *path = [[NSBundle mainBundle].bundlePath UTF8String]; 37 | 38 | bool verbose = false; 39 | png_suite_test(path, path, verbose); 40 | png_write_test(verbose); 41 | wav_test(path, verbose); 42 | jpg_test(path, path, verbose); 43 | csv_test(path, verbose); 44 | gettext_test(path, verbose); 45 | 46 | #if LOCAL_TEST 47 | const ok_png_allocator png_allocator = { 48 | .alloc = custom_alloc, 49 | .free = custom_free, 50 | .image_alloc = custom_image_alloc 51 | }; 52 | char *src_path = get_full_path(path, "crash0", "png"); 53 | FILE *file = fopen(src_path, "rb"); 54 | if (!file) { 55 | printf("Test file not found.\n"); 56 | } else { 57 | ok_png result = ok_png_read_with_allocator(file, OK_PNG_COLOR_FORMAT_RGBA, png_allocator, NULL); 58 | fclose(file); 59 | if (result.error_code) { 60 | printf("PNG error code: %i\n", result.error_code); 61 | } 62 | free(result.data); 63 | } 64 | free(src_path); 65 | 66 | const ok_jpg_allocator jpg_allocator = { 67 | .alloc = custom_alloc, 68 | .free = custom_free, 69 | .image_alloc = custom_image_alloc 70 | }; 71 | char *in_filename = get_full_path(path, "2001-stargate", "jpg"); 72 | file = fopen(in_filename, "rb"); 73 | if (file) { 74 | ok_jpg jpg = ok_jpg_read_with_allocator(file, OK_JPG_COLOR_FORMAT_BGRA, jpg_allocator, NULL); 75 | fclose(file); 76 | if (jpg.error_code) { 77 | printf("JPG error code: %i\n", jpg.error_code); 78 | } 79 | if (jpg.data) { 80 | CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, jpg.data, jpg.stride * jpg.height, dataRelease); 81 | 82 | NSUInteger bytesPerRow = jpg.stride; 83 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 84 | CGBitmapInfo bitmapInfo = (CGBitmapInfo)(kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 85 | CGImageRef imageRef = CGImageCreate(jpg.width, jpg.height, 8, 32, bytesPerRow, colorSpace, bitmapInfo, dataProvider, NULL, NO, kCGRenderingIntentDefault); 86 | UIImage *image = [UIImage imageWithCGImage:imageRef scale:2.0 orientation:UIImageOrientationUp]; 87 | CGColorSpaceRelease(colorSpace); 88 | CGDataProviderRelease(dataProvider); 89 | 90 | UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 91 | imageView.frame = self.window.frame; 92 | imageView.contentMode = UIViewContentModeScaleAspectFit; 93 | imageView.backgroundColor = [UIColor grayColor]; 94 | [self.window.rootViewController.view addSubview:imageView]; 95 | } 96 | //free(jpg.data); Don't free, dataRelease() handles it 97 | } 98 | free(in_filename); 99 | #endif 100 | 101 | return YES; 102 | } 103 | 104 | - (void)applicationWillResignActive:(__unused UIApplication *)application { 105 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 106 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 107 | } 108 | 109 | - (void)applicationDidEnterBackground:(__unused UIApplication *)application { 110 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 111 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 112 | } 113 | 114 | - (void)applicationWillEnterForeground:(__unused UIApplication *)application { 115 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 116 | } 117 | 118 | - (void)applicationDidBecomeActive:(__unused UIApplication *)application { 119 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 120 | } 121 | 122 | - (void)applicationWillTerminate:(__unused UIApplication *)application { 123 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | Launch Screen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/ios/OkFileFormatsTest/main.m: -------------------------------------------------------------------------------- 1 | 2 | @import UIKit; 3 | 4 | #import "AppDelegate.h" 5 | 6 | int main(int argc, char * argv[]) { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/jpg.dict: -------------------------------------------------------------------------------- 1 | # AFL dictionary for JPEG images 2 | 3 | header_jpg="\xff\xd8" 4 | 5 | section_sof0="\xff\xc0" 6 | section_sof1="\xff\xc1" 7 | section_sof2="\xff\xc2" 8 | section_dht="\xff\xc4" 9 | section_rst0="\xff\xd0" 10 | section_rst1="\xff\xd1" 11 | section_rst2="\xff\xd2" 12 | section_rst3="\xff\xd3" 13 | section_rst4="\xff\xd4" 14 | section_rst5="\xff\xd5" 15 | section_rst6="\xff\xd6" 16 | section_rst7="\xff\xd7" 17 | section_eoi="\xff\xd9" 18 | section_sos="\xff\xda" 19 | section_dqt="\xff\xdb" 20 | section_dri="\xff\xdd" 21 | section_app0="\xff\xe0" 22 | section_app1="\xff\xe1" 23 | section_app2="\xff\xe2" 24 | section_app3="\xff\xe3" 25 | section_app4="\xff\xe4" 26 | section_app5="\xff\xe5" 27 | section_app6="\xff\xe6" 28 | section_app7="\xff\xe7" 29 | section_app8="\xff\xe8" 30 | section_app9="\xff\xe9" 31 | section_app10="\xff\xea" 32 | section_app11="\xff\xeb" 33 | section_app12="\xff\xec" 34 | section_app13="\xff\xed" 35 | section_app14="\xff\xee" 36 | section_app15="\xff\xef" 37 | section_com="\xff\xfe" 38 | -------------------------------------------------------------------------------- /test/jpg/2001-stargate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/2001-stargate.jpg -------------------------------------------------------------------------------- /test/jpg/2004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/2004.jpg -------------------------------------------------------------------------------- /test/jpg/65500h.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/65500h.jpg -------------------------------------------------------------------------------- /test/jpg/65500w.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/65500w.jpg -------------------------------------------------------------------------------- /test/jpg/LEVEL76.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/LEVEL76.jpg -------------------------------------------------------------------------------- /test/jpg/applesauce.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/applesauce.jpg -------------------------------------------------------------------------------- /test/jpg/baby-camel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/baby-camel.jpg -------------------------------------------------------------------------------- /test/jpg/creek-after.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/creek-after.jpg -------------------------------------------------------------------------------- /test/jpg/einstein.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/einstein.jpg -------------------------------------------------------------------------------- /test/jpg/ghost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/ghost.jpg -------------------------------------------------------------------------------- /test/jpg/gort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/gort.jpg -------------------------------------------------------------------------------- /test/jpg/jpeg400jfif.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpeg400jfif.jpg -------------------------------------------------------------------------------- /test/jpg/jpeg444.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpeg444.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-gray.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-15x15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-15x15.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-16x16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-16x16.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-17x17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-17x17.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-1x1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-1x1.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-2x2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-2x2.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-31x31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-31x31.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-32x32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-32x32.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-33x33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-33x33.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-3x3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-3x3.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-4x4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-4x4.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-5x5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-5x5.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-6x6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-6x6.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-7x7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-7x7.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-8x8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-8x8.jpg -------------------------------------------------------------------------------- /test/jpg/jpg-size-9x9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/jpg-size-9x9.jpg -------------------------------------------------------------------------------- /test/jpg/magritte.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/magritte.jpg -------------------------------------------------------------------------------- /test/jpg/mandril_color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/mandril_color.jpg -------------------------------------------------------------------------------- /test/jpg/monkey_monkey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/monkey_monkey.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_1.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_2.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_3.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_4.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_5.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_6.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_7.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_8.jpg -------------------------------------------------------------------------------- /test/jpg/orientation_none.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/orientation_none.jpg -------------------------------------------------------------------------------- /test/jpg/park.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/park.jpg -------------------------------------------------------------------------------- /test/jpg/peace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/peace.jpg -------------------------------------------------------------------------------- /test/jpg/peppers_color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/peppers_color.jpg -------------------------------------------------------------------------------- /test/jpg/pumpkins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/pumpkins.jpg -------------------------------------------------------------------------------- /test/jpg/robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/robot.jpg -------------------------------------------------------------------------------- /test/jpg/tomatoes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/tomatoes.jpg -------------------------------------------------------------------------------- /test/jpg/zam.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/jpg/zam.jpg -------------------------------------------------------------------------------- /test/jpg_test.c: -------------------------------------------------------------------------------- 1 | #include "jpg_test.h" 2 | #include "ok_jpg.h" 3 | #include "test_common.h" 4 | #include 5 | #include 6 | #include 7 | 8 | enum jpg_test_type { 9 | test_normal, 10 | test_info_only, 11 | test_allocator, 12 | }; 13 | 14 | static const char *filenames[] = { 15 | 16 | // Grayscale 17 | "jpg-gray", 18 | "jpeg400jfif", // With restart markers 19 | "peace", 20 | 21 | // No upsampling 22 | "creek-after", 23 | "jpeg444", 24 | "magritte", 25 | 26 | // 2x1 upsampling 27 | "baby-camel", 28 | "LEVEL76", 29 | 30 | // 1x2 upsampling 31 | "mandril_color", 32 | "peppers_color", 33 | 34 | // 2x2 upsampling 35 | "2001-stargate", 36 | "monkey_monkey", 37 | "tomatoes", 38 | "zam", 39 | 40 | // Strange markers 41 | "applesauce", // Extra 0xFF 42 | "park", // Extra 0x00 before 0xFF 43 | 44 | // Large images (max size handled by ImageMagick) 45 | "65500w", 46 | "65500h", 47 | 48 | // Progressive 49 | "pumpkins", // Color, 2x2 upsampling, no successive approximation 50 | "robot", // Color, 2x2 upsampling, successive approximation 51 | "2004", // Color, no upsampling, successive approximation 52 | "einstein", // Color, no upsampling, no successive approximation 53 | "gort", // Grayscale, no upsampling, no successive approximation 54 | "ghost", // Color, 2x2 upsampling, successive approximation, with restart markers 55 | 56 | // Various sizes (2x2 upsampling) 57 | "jpg-size-1x1", 58 | "jpg-size-2x2", 59 | "jpg-size-3x3", 60 | "jpg-size-4x4", 61 | "jpg-size-5x5", 62 | "jpg-size-6x6", 63 | "jpg-size-7x7", 64 | "jpg-size-8x8", 65 | "jpg-size-9x9", 66 | "jpg-size-15x15", 67 | "jpg-size-16x16", 68 | "jpg-size-17x17", 69 | "jpg-size-31x31", 70 | "jpg-size-32x32", 71 | "jpg-size-33x33", 72 | 73 | // EXIF orientation 74 | "orientation_none", 75 | "orientation_1", 76 | "orientation_2", 77 | "orientation_3", 78 | "orientation_4", 79 | "orientation_5", 80 | "orientation_6", 81 | "orientation_7", 82 | "orientation_8", 83 | }; 84 | 85 | static bool test_image(const char *path_to_jpgs, 86 | const char *path_to_rgba_files, 87 | const char *name, 88 | enum jpg_test_type test_type, bool verbose) { 89 | char *rgba_filename = get_full_path(path_to_rgba_files, name, "rgba"); 90 | unsigned long rgba_data_length; 91 | uint8_t *rgba_data = read_file(rgba_filename, &rgba_data_length); 92 | bool success = false; 93 | 94 | const ok_jpg_allocator allocator = { 95 | .alloc = custom_alloc, 96 | .free = custom_free, 97 | .image_alloc = custom_image_alloc 98 | }; 99 | 100 | // Load via ok_jpg 101 | char *in_filename = get_full_path(path_to_jpgs, name, "jpg"); 102 | FILE *file = fopen(in_filename, "rb"); 103 | if (file) { 104 | ok_jpg jpg = { 0 }; 105 | switch (test_type) { 106 | case test_normal: 107 | jpg = ok_jpg_read(file, OK_JPG_COLOR_FORMAT_RGBA); 108 | break; 109 | case test_info_only: 110 | jpg = ok_jpg_read(file, OK_JPG_INFO_ONLY); 111 | break; 112 | case test_allocator: 113 | jpg = ok_jpg_read_with_allocator(file, OK_JPG_COLOR_FORMAT_RGBA, allocator, NULL); 114 | break; 115 | } 116 | fclose(file); 117 | 118 | bool info_only = test_type == test_info_only; 119 | success = compare(name, "jpg", jpg.data, jpg.stride, jpg.width, jpg.height, 120 | rgba_data, rgba_data_length, info_only, 4, verbose); 121 | free(jpg.data); 122 | } else { 123 | printf("Warning: File not found: %s.jpg\n", name); 124 | success = true; 125 | } 126 | 127 | free(rgba_data); 128 | free(rgba_filename); 129 | free(in_filename); 130 | 131 | return success; 132 | } 133 | 134 | int jpg_test(const char *path_to_jpgs, const char *path_to_rgba_files, bool verbose) { 135 | const int num_files = sizeof(filenames) / sizeof(filenames[0]); 136 | if (verbose) { 137 | printf("Testing %i files in path \"%s\".\n", num_files, path_to_jpgs); 138 | } 139 | 140 | double startTime = clock() / (double)CLOCKS_PER_SEC; 141 | int num_failures = 0; 142 | for (int i = 0; i < num_files; i++) { 143 | bool success = test_image(path_to_jpgs, path_to_rgba_files, filenames[i], test_normal, 144 | verbose); 145 | if (!success) { 146 | num_failures++; 147 | continue; 148 | } 149 | success = test_image(path_to_jpgs, path_to_rgba_files, filenames[i], test_info_only, 150 | verbose); 151 | if (!success) { 152 | num_failures++; 153 | continue; 154 | } 155 | 156 | success = test_image(path_to_jpgs, path_to_rgba_files, filenames[i], test_allocator, 157 | verbose); 158 | if (!success) { 159 | num_failures++; 160 | } 161 | } 162 | double endTime = clock() / (double)CLOCKS_PER_SEC; 163 | double elapsedTime = endTime - startTime; 164 | printf("Success: JPEG %i of %i\n", (num_files - num_failures), num_files); 165 | if (verbose) { 166 | printf("Duration: %f seconds\n", elapsedTime); 167 | } 168 | return num_failures; 169 | } 170 | -------------------------------------------------------------------------------- /test/jpg_test.h: -------------------------------------------------------------------------------- 1 | #ifndef JPG_TEST_H 2 | #define JPG_TEST_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | int jpg_test(const char *path_to_jpgs, const char *path_to_rgba_files, bool verbose); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include "csv_test.h" 2 | #include "jpg_test.h" 3 | #include "mo_test.h" 4 | #include "png_suite_test.h" 5 | #include "png_write_test.h" 6 | #include "wav_test.h" 7 | #include "test_common.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef _WIN32 14 | #include 15 | # define getcwd _getcwd 16 | #else 17 | # include 18 | #endif 19 | 20 | int main(int argc, char *argv[]) { 21 | bool verbose = false; 22 | for (int i = 0; i < argc; i++) { 23 | if (strcmp("--verbose", argv[i]) == 0) { 24 | verbose = true; 25 | } 26 | } 27 | 28 | // Find parent of "PngSuite" directory 29 | char path[1024]; 30 | if (getcwd(path, sizeof(path)) == NULL) { 31 | perror("getcwd() error"); 32 | return 1; 33 | } 34 | char *path_png = NULL; 35 | while (true) { 36 | path_png = append_path(path, "PngSuite"); 37 | DIR *dir = opendir(path_png); 38 | if (dir) { 39 | // Found 40 | closedir(dir); 41 | break; 42 | } 43 | free(path_png); 44 | path_png = NULL; 45 | if (!parent_path(path)) { 46 | printf("Error: Couldn't find PngSuite\n"); 47 | return 1; 48 | } 49 | } 50 | 51 | // Run tests 52 | printf("Running from %s\n", path); 53 | 54 | int error_count = 0; 55 | char *path_jpg = append_path(path, "jpg"); 56 | char *path_csv = append_path(path, "csv"); 57 | char *path_gettext = append_path(path, "gettext"); 58 | 59 | #ifdef _WIN32 60 | strcat(path, "\\build"); 61 | #else 62 | strcat(path, "/build"); 63 | #endif 64 | char *path_gen = append_path(path, "gen"); 65 | 66 | error_count += png_suite_test(path_png, path_gen, verbose); 67 | error_count += png_write_test(verbose); 68 | error_count += wav_test(path_gen, verbose); 69 | error_count += jpg_test(path_jpg, path_gen, verbose); 70 | error_count += csv_test(path_csv, verbose); 71 | error_count += gettext_test(path_gettext, verbose); 72 | 73 | free(path_png); 74 | free(path_jpg); 75 | free(path_gen); 76 | free(path_csv); 77 | free(path_gettext); 78 | return error_count; 79 | } 80 | -------------------------------------------------------------------------------- /test/main_fuzzing.c: -------------------------------------------------------------------------------- 1 | #include "ok_jpg.h" 2 | #include "ok_png.h" 3 | #include "ok_wav.h" 4 | #include "ok_fnt.h" 5 | #include "ok_csv.h" 6 | #include "ok_mo.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 12 | 13 | // Prevent loading of images that require more than 1GB of memory (prevent hangs in AFL) 14 | static const size_t CUSTOM_MEMORY_MAX = 1024 * 1024 * 1024; 15 | 16 | static void *custom_alloc(void *user_data, size_t size) { 17 | (void)user_data; 18 | return malloc(size); 19 | } 20 | 21 | static void custom_free(void *user_data, void *memory) { 22 | (void)user_data; 23 | free(memory); 24 | } 25 | 26 | static void custom_image_alloc(void *user_data, uint32_t width, uint32_t height, uint8_t bpp, 27 | uint8_t **dst_buffer, uint32_t *dst_stride) { 28 | (void)user_data; 29 | (void)width; 30 | (void)bpp; 31 | uint64_t size = (uint64_t)*dst_stride * height; 32 | size_t platform_size = (size_t)size; 33 | 34 | if (platform_size == size && platform_size <= CUSTOM_MEMORY_MAX) { 35 | *dst_buffer = malloc(platform_size); 36 | } 37 | } 38 | 39 | static void printHelp() { 40 | fprintf(stderr, "Reads a png, jpg, wav, fnt, csv, or mo file from stdin. " 41 | "Useful for fuzzing.\n\n"); 42 | fprintf(stderr, "One of these arguments required: --png --jpg --wav --fnt --csv --mo\n"); 43 | fprintf(stderr, "Options for png and jpg: --format-bgra --format-pre --format-flip\n"); 44 | } 45 | 46 | int main(int argc, char *argv[]) { 47 | int test_png = 0; 48 | int test_jpg = 0; 49 | int test_wav = 0; 50 | int test_fnt = 0; 51 | int test_csv = 0; 52 | int test_mo = 0; 53 | ok_png_decode_flags png_flags = OK_PNG_COLOR_FORMAT_RGBA; 54 | ok_jpg_decode_flags jpg_flags = OK_JPG_COLOR_FORMAT_RGBA; 55 | 56 | for (int i = 1; i < argc; i++) { 57 | if (strcmp("--format-bgra", argv[i]) == 0) { 58 | png_flags |= OK_PNG_COLOR_FORMAT_BGRA; 59 | jpg_flags |= OK_PNG_COLOR_FORMAT_BGRA; 60 | } else if (strcmp("--format-pre", argv[i]) == 0) { 61 | png_flags |= OK_PNG_PREMULTIPLIED_ALPHA; 62 | } else if (strcmp("--format-flip", argv[i]) == 0) { 63 | png_flags |= OK_PNG_FLIP_Y; 64 | jpg_flags |= OK_JPG_FLIP_Y; 65 | } else if (strcmp("--png", argv[i]) == 0) { 66 | test_png = 1; 67 | } else if (strcmp("--jpg", argv[i]) == 0) { 68 | test_jpg = 1; 69 | } else if (strcmp("--wav", argv[i]) == 0 || strcmp("--caf", argv[i]) == 0) { 70 | test_wav = 1; 71 | } else if (strcmp("--fnt", argv[i]) == 0) { 72 | test_fnt = 1; 73 | } else if (strcmp("--csv", argv[i]) == 0) { 74 | test_csv = 1; 75 | } else if (strcmp("--mo", argv[i]) == 0) { 76 | test_mo = 1; 77 | } else { 78 | fprintf(stderr, "Unrecognized argument: %s\n\n", argv[i]); 79 | printHelp(); 80 | abort(); // Prevent fuzzer from continuing 81 | return 1; 82 | } 83 | } 84 | 85 | if (test_png + test_jpg + test_wav + test_fnt + test_csv + test_mo != 1) { 86 | printHelp(); 87 | abort(); // Prevent fuzzer from continuing 88 | return 1; 89 | } 90 | 91 | if (test_png) { 92 | const ok_png_allocator allocator = { 93 | .alloc = custom_alloc, 94 | .free = custom_free, 95 | .image_alloc = custom_image_alloc 96 | }; 97 | ok_png png = ok_png_read_with_allocator(stdin, png_flags, allocator, NULL); 98 | if (png.error_code) { 99 | fprintf(stderr, "Error code: %i\n", png.error_code); 100 | } 101 | free(png.data); 102 | } else if (test_jpg) { 103 | const ok_jpg_allocator allocator = { 104 | .alloc = custom_alloc, 105 | .free = custom_free, 106 | .image_alloc = custom_image_alloc 107 | }; 108 | ok_jpg jpg = ok_jpg_read_with_allocator(stdin, jpg_flags, allocator, NULL); 109 | if (jpg.error_code) { 110 | fprintf(stderr, "Error code: %i\n", jpg.error_code); 111 | } 112 | free(jpg.data); 113 | } else if (test_wav) { 114 | ok_wav wav = ok_wav_read(stdin, OK_WAV_DEFAULT_DECODE_FLAGS); 115 | if (wav.error_code) { 116 | fprintf(stderr, "Error code: %i\n", wav.error_code); 117 | } 118 | free(wav.data); 119 | } else if (test_fnt) { 120 | ok_fnt *fnt = ok_fnt_read(stdin); 121 | if (fnt->error_message) { 122 | fprintf(stderr, "%s\n", fnt->error_message); 123 | } 124 | ok_fnt_free(fnt); 125 | } else if (test_csv) { 126 | ok_csv *csv = ok_csv_read(stdin); 127 | if (csv->error_message) { 128 | fprintf(stderr, "%s\n", csv->error_message); 129 | } 130 | ok_csv_free(csv); 131 | } else if (test_mo) { 132 | ok_mo *mo = ok_mo_read(stdin); 133 | if (mo->error_message) { 134 | fprintf(stderr, "%s\n", mo->error_message); 135 | } 136 | ok_mo_free(mo); 137 | } 138 | 139 | return 0; 140 | } 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /test/mo_test.c: -------------------------------------------------------------------------------- 1 | #include "mo_test.h" 2 | #include "ok_mo.h" 3 | #include "test_common.h" 4 | #include 5 | #include 6 | #include 7 | 8 | static ok_mo *mo_read(const char *filename) { 9 | FILE *file = fopen(filename, "rb"); 10 | ok_mo *mo = ok_mo_read(file); 11 | fclose(file); 12 | return mo; 13 | } 14 | 15 | int gettext_test(const char *path, bool verbose) { 16 | (void)verbose; 17 | 18 | char *en_file = get_full_path(path, "en", "mo"); 19 | char *es_file = get_full_path(path, "es", "mo"); 20 | char *zh_file = get_full_path(path, "zh-Hans", "mo"); 21 | 22 | ok_mo *mo_en = mo_read(en_file); 23 | if (strcmp("Hello", ok_mo_value(mo_en, "Hello")) != 0) { 24 | printf("Failure: Hello\n"); 25 | return 1; 26 | } 27 | if (strcmp("N/A", ok_mo_value(mo_en, "N/A")) != 0) { 28 | printf("Failure: missing key\n"); 29 | return 1; 30 | } 31 | if (strcmp("%d user likes this.", ok_mo_plural_value(mo_en, "%d user likes this.", 32 | "%d users like this.", 1)) != 0) { 33 | printf("Failure: singular\n"); 34 | return 1; 35 | } 36 | if (strcmp("%d users like this.", ok_mo_plural_value(mo_en, "%d user likes this.", 37 | "%d users like this.", 2)) != 0) { 38 | printf("Failure: plural\n"); 39 | return 1; 40 | } 41 | ok_mo_free(mo_en); 42 | 43 | ok_mo *mo_es = mo_read(es_file); 44 | if (strcmp("Archivo", ok_mo_value_in_context(mo_es, "Menu", "File")) != 0) { 45 | printf("Failure: context\n"); 46 | return 1; 47 | } 48 | ok_mo_free(mo_es); 49 | 50 | ok_mo *mo_zh = mo_read(zh_file); 51 | char hello_utf8[] = {(char)0xe4, (char)0xbd, (char)0xa0, (char)0xe5, (char)0xa5, (char)0xbd, 0}; 52 | if (strcmp(hello_utf8, ok_mo_value(mo_zh, "Hello")) != 0) { 53 | printf("Failure: utf8\n"); 54 | return 1; 55 | } 56 | ok_mo_free(mo_zh); 57 | 58 | free(en_file); 59 | free(es_file); 60 | free(zh_file); 61 | 62 | printf("Success: MO (gettext)\n"); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /test/mo_test.h: -------------------------------------------------------------------------------- 1 | #ifndef MO_TEST_H 2 | #define MO_TEST_H 3 | 4 | #include 5 | 6 | int gettext_test(const char *path_to_gettext_files, bool verbose); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /test/png.dict: -------------------------------------------------------------------------------- 1 | # AFL dictionary for PNG images (only sections used by ok_png) 2 | 3 | header_png="\x89PNG\x0d\x0a\x1a\x0a" 4 | 5 | section_IHDR="IHDR" 6 | section_PLTE="PLTE" 7 | section_tRNS="tRNS" 8 | section_IDAT="IDAT" 9 | section_IEND="IEND" 10 | section_CgBI="CgBI" 11 | -------------------------------------------------------------------------------- /test/png_suite_test.c: -------------------------------------------------------------------------------- 1 | #include "ok_png.h" 2 | #include "png_suite_test.h" 3 | #include "test_common.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #ifdef __APPLE__ 11 | #include 12 | #endif 13 | 14 | enum png_test_type { 15 | test_normal, 16 | test_info_only, 17 | test_allocator, 18 | }; 19 | 20 | // This is just copied form a directory listing of the PNG Suite files 21 | static const char *filenames[] = { 22 | "basi0g01", 23 | "basi0g02", 24 | "basi0g04", 25 | "basi0g08", 26 | "basi0g16", 27 | "basi2c08", 28 | "basi2c16", 29 | "basi3p01", 30 | "basi3p02", 31 | "basi3p04", 32 | "basi3p08", 33 | "basi4a08", 34 | "basi4a16", 35 | "basi6a08", 36 | "basi6a16", 37 | "basn0g01", 38 | "basn0g02", 39 | "basn0g04", 40 | "basn0g08", 41 | "basn0g16", 42 | "basn2c08", 43 | "basn2c16", 44 | "basn3p01", 45 | "basn3p02", 46 | "basn3p04", 47 | "basn3p08", 48 | "basn4a08", 49 | "basn4a16", 50 | "basn6a08", 51 | "basn6a16", 52 | "bgai4a08", 53 | "bgai4a16", 54 | "bgan6a08", 55 | "bgan6a16", 56 | "bgbn4a08", 57 | "bggn4a16", 58 | "bgwn6a08", 59 | "bgyn6a16", 60 | "ccwn2c08", 61 | "ccwn3p08", 62 | "cdfn2c08", 63 | "cdhn2c08", 64 | "cdsn2c08", 65 | "cdun2c08", 66 | "ch1n3p04", 67 | "ch2n3p08", 68 | "cm0n0g04", 69 | "cm7n0g04", 70 | "cm9n0g04", 71 | "cs3n2c16", 72 | "cs3n3p08", 73 | "cs5n2c08", 74 | "cs5n3p08", 75 | "cs8n2c08", 76 | "cs8n3p08", 77 | "ct0n0g04", 78 | "ct1n0g04", 79 | "cten0g04", 80 | "ctfn0g04", 81 | "ctgn0g04", 82 | "cthn0g04", 83 | "ctjn0g04", 84 | "ctzn0g04", 85 | "f00n0g08", 86 | "f00n2c08", 87 | "f01n0g08", 88 | "f01n2c08", 89 | "f02n0g08", 90 | "f02n2c08", 91 | "f03n0g08", 92 | "f03n2c08", 93 | "f04n0g08", 94 | "f04n2c08", 95 | "f99n0g04", 96 | "g03n0g16", 97 | "g03n2c08", 98 | "g03n3p04", 99 | "g04n0g16", 100 | "g04n2c08", 101 | "g04n3p04", 102 | "g05n0g16", 103 | "g05n2c08", 104 | "g05n3p04", 105 | "g07n0g16", 106 | "g07n2c08", 107 | "g07n3p04", 108 | "g10n0g16", 109 | "g10n2c08", 110 | "g10n3p04", 111 | "g25n0g16", 112 | "g25n2c08", 113 | "g25n3p04", 114 | "oi1n0g16", 115 | "oi1n2c16", 116 | "oi2n0g16", 117 | "oi2n2c16", 118 | "oi4n0g16", 119 | "oi4n2c16", 120 | "oi9n0g16", 121 | "oi9n2c16", 122 | "PngSuite", 123 | "pp0n2c16", 124 | "pp0n6a08", 125 | // Xcode's pngcrush croaks on these two files. Ignore. 126 | #if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 127 | "ps1n0g08", 128 | #endif 129 | "ps1n2c16", 130 | #if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0 131 | "ps2n0g08", 132 | #endif 133 | "ps2n2c16", 134 | "s01i3p01", 135 | "s01n3p01", 136 | "s02i3p01", 137 | "s02n3p01", 138 | "s03i3p01", 139 | "s03n3p01", 140 | "s04i3p01", 141 | "s04n3p01", 142 | "s05i3p02", 143 | "s05n3p02", 144 | "s06i3p02", 145 | "s06n3p02", 146 | "s07i3p02", 147 | "s07n3p02", 148 | "s08i3p02", 149 | "s08n3p02", 150 | "s09i3p02", 151 | "s09n3p02", 152 | "s32i3p04", 153 | "s32n3p04", 154 | "s33i3p04", 155 | "s33n3p04", 156 | "s34i3p04", 157 | "s34n3p04", 158 | "s35i3p04", 159 | "s35n3p04", 160 | "s36i3p04", 161 | "s36n3p04", 162 | "s37i3p04", 163 | "s37n3p04", 164 | "s38i3p04", 165 | "s38n3p04", 166 | "s39i3p04", 167 | "s39n3p04", 168 | "s40i3p04", 169 | "s40n3p04", 170 | "tbbn0g04", 171 | "tbbn2c16", 172 | "tbbn3p08", 173 | "tbgn2c16", 174 | "tbgn3p08", 175 | "tbrn2c08", 176 | "tbwn0g16", 177 | "tbwn3p08", 178 | "tbyn3p08", 179 | "tm3n3p02", 180 | "tp0n0g08", 181 | "tp0n2c08", 182 | "tp0n3p08", 183 | "tp1n3p08", 184 | "z00n2c08", 185 | "z03n2c08", 186 | "z06n2c08", 187 | "z09n2c08", 188 | // Invalid files: 189 | "xc1n0g08", 190 | "xc9n2c08", 191 | "xcrn0g04", 192 | //"xcsn0g01", // incorrect checksum - ok_png ignores checksums 193 | "xd0n2c08", 194 | "xd3n2c08", 195 | "xd9n2c08", 196 | "xdtn0g01", 197 | //"xhdn0g08", // incorrect checksum - ok_png ignores checksums 198 | "xlfn0g04", 199 | "xs1n0g01", 200 | "xs2n0g01", 201 | "xs4n0g01", 202 | "xs7n0g01", 203 | }; 204 | 205 | static bool test_image(const char *path_to_png_suite, 206 | const char *path_to_rgba_files, 207 | const char *name, 208 | enum png_test_type test_type, bool verbose) { 209 | bool success = false; 210 | 211 | char *rgba_filename = get_full_path(path_to_rgba_files, name, "rgba"); 212 | unsigned long rgba_data_length; 213 | uint8_t *rgba_data = read_file(rgba_filename, &rgba_data_length); 214 | 215 | #if TARGET_OS_IPHONE 216 | // On iOS, Apple stores PNG data with premultiplied alpha. 217 | // Unpremultiplying would lose precision, so instead, premultiply the raw RGBA data 218 | // for comparison purposes. 219 | ok_png_decode_flags decode_flags = OK_PNG_COLOR_FORMAT_RGBA | OK_PNG_PREMULTIPLIED_ALPHA; 220 | for (uint8_t *src = rgba_data; src < rgba_data + rgba_data_length; src += 4) { 221 | const uint8_t a = src[3]; 222 | if (a == 0) { 223 | src[0] = 0; 224 | src[1] = 0; 225 | src[2] = 0; 226 | } else if (a < 255) { 227 | src[0] = (a * src[0] + 127) / 255; 228 | src[1] = (a * src[1] + 127) / 255; 229 | src[2] = (a * src[2] + 127) / 255; 230 | } 231 | } 232 | #else 233 | ok_png_decode_flags decode_flags = OK_PNG_COLOR_FORMAT_RGBA; 234 | #endif 235 | 236 | const ok_png_allocator allocator = { 237 | .alloc = custom_alloc, 238 | .free = custom_free, 239 | .image_alloc = custom_image_alloc 240 | }; 241 | 242 | // Load via ok_png 243 | char *in_filename = get_full_path(path_to_png_suite, name, "png"); 244 | FILE *file = fopen(in_filename, "rb"); 245 | if (file) { 246 | ok_png png = { 0 }; 247 | switch (test_type) { 248 | case test_normal: 249 | png = ok_png_read(file, decode_flags); 250 | break; 251 | case test_info_only: 252 | png = ok_png_read(file, decode_flags | OK_PNG_INFO_ONLY); 253 | break; 254 | case test_allocator: 255 | png = ok_png_read_with_allocator(file, decode_flags, allocator, NULL); 256 | break; 257 | } 258 | fclose(file); 259 | 260 | bool info_only = test_type == test_info_only; 261 | success = compare(name, "png", png.data, png.stride, png.width, png.height, 262 | rgba_data, rgba_data_length, info_only, 0, verbose); 263 | free(png.data); 264 | } else { 265 | printf("Warning: File not found: %s.png\n", name); 266 | success = true; 267 | } 268 | 269 | free(rgba_data); 270 | free(rgba_filename); 271 | free(in_filename); 272 | 273 | return success; 274 | } 275 | 276 | int png_suite_test(const char *path_to_png_suite, const char *path_to_rgba_files, bool verbose) { 277 | const int num_files = sizeof(filenames) / sizeof(filenames[0]); 278 | if (verbose) { 279 | printf("Testing %i files in path \"%s\".\n", num_files, path_to_png_suite); 280 | } 281 | 282 | double startTime = clock() / (double)CLOCKS_PER_SEC; 283 | int num_failures = 0; 284 | for (int i = 0; i < num_files; i++) { 285 | bool success = test_image(path_to_png_suite, path_to_rgba_files, filenames[i], test_normal, 286 | verbose); 287 | if (!success) { 288 | num_failures++; 289 | continue; 290 | } 291 | success = test_image(path_to_png_suite, path_to_rgba_files, filenames[i], test_info_only, 292 | verbose); 293 | if (!success) { 294 | num_failures++; 295 | continue; 296 | } 297 | 298 | success = test_image(path_to_png_suite, path_to_rgba_files, filenames[i], test_allocator, 299 | verbose); 300 | if (!success) { 301 | num_failures++; 302 | } 303 | } 304 | double endTime = clock() / (double)CLOCKS_PER_SEC; 305 | double elapsedTime = endTime - startTime; 306 | printf("Success: PNG %i of %i\n", (num_files - num_failures), num_files); 307 | if (verbose) { 308 | printf("Duration: %f seconds\n", elapsedTime); 309 | } 310 | return num_failures; 311 | } 312 | -------------------------------------------------------------------------------- /test/png_suite_test.h: -------------------------------------------------------------------------------- 1 | #ifndef PNG_SUITE_TEST_H 2 | #define PNG_SUITE_TEST_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | int png_suite_test(const char *path_to_png_suite, const char *path_to_rgba_files, bool verbose); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /test/png_write_test.c: -------------------------------------------------------------------------------- 1 | #include "png_write_test.h" 2 | #include "test_common.h" 3 | #include "ok_png.h" 4 | #include "ok_png_write.h" 5 | 6 | #include 7 | #include 8 | #if defined(__APPLE__) 9 | # include 10 | # if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR 11 | # include "file_compat.h" 12 | # define USE_FC_DATADIR 13 | # endif 14 | #endif 15 | #if !defined(PATH_MAX) 16 | # define PATH_MAX 4096 17 | #endif 18 | 19 | static int api_test(const char *output_dir, bool verbose) { 20 | const char *test_name = "api_test_image"; 21 | char path[PATH_MAX]; 22 | snprintf(path, sizeof(path), "%s%s.png", output_dir, test_name); 23 | 24 | const uint8_t image_data[8] = { 0xff, 0xff, 0xbd, 0xff, 0xff, 0xbd, 0xc3, 0xff }; 25 | const uint8_t palette[6] = { 0x00, 0x00, 0x00, 0xd2, 0x32, 0x14 }; 26 | const uint8_t palette_alpha[2] = { 0x00, 0xff }; 27 | 28 | FILE *file = fopen(path, "wb"); 29 | bool success = ok_png_write_to_file(file, (ok_png_write_params){ 30 | .width = 8, 31 | .height = 8, 32 | .data = image_data, 33 | .bit_depth = 1, 34 | .color_type = OK_PNG_WRITE_COLOR_TYPE_PALETTE, 35 | .additional_chunks = (ok_png_write_chunk *[]){ 36 | &(ok_png_write_chunk){ 37 | .name = "PLTE", 38 | .data = palette, 39 | .length = sizeof(palette), 40 | }, 41 | &(ok_png_write_chunk){ 42 | .name = "tRNS", 43 | .data = palette_alpha, 44 | .length = sizeof(palette_alpha), 45 | }, 46 | NULL 47 | } 48 | }); 49 | fclose(file); 50 | if (!success) { 51 | return 1; 52 | } 53 | 54 | #define C0 0x00, 0x00, 0x00, 0x00 55 | #define C1 0xd2, 0x32, 0x14, 0xff 56 | const uint8_t expected_rgba[8 * 8 * 4] = { 57 | C1, C1, C1, C1, C1, C1, C1, C1, // 0xff 58 | C1, C1, C1, C1, C1, C1, C1, C1, // 0xff 59 | C1, C0, C1, C1, C1, C1, C0, C1, // 0xbd 60 | C1, C1, C1, C1, C1, C1, C1, C1, // 0xff 61 | C1, C1, C1, C1, C1, C1, C1, C1, // 0xff 62 | C1, C0, C1, C1, C1, C1, C0, C1, // 0xbd 63 | C1, C1, C0, C0, C0, C0, C1, C1, // 0xc3 64 | C1, C1, C1, C1, C1, C1, C1, C1, // 0xff 65 | }; 66 | #undef C0 67 | #undef C1 68 | 69 | FILE *in_file = fopen(path, "rb"); 70 | if (!in_file) { 71 | printf("Error: Couldn't open file for reading\n"); 72 | return 1; 73 | } 74 | ok_png png = ok_png_read(in_file, OK_PNG_COLOR_FORMAT_RGBA); 75 | fclose(in_file); 76 | if (png.error_code != OK_PNG_SUCCESS) { 77 | printf("Error reading PNG data (error %i)\n", png.error_code); 78 | return 1; 79 | } 80 | 81 | // Compare written vs expected RGBA 82 | success = compare(test_name, "png", png.data, png.stride, png.width, png.height, expected_rgba, sizeof(expected_rgba), false, 0, verbose); 83 | 84 | free(png.data); 85 | remove(path); 86 | 87 | return success ? 0 : 1; 88 | } 89 | 90 | static int test_image(const char *output_dir, ok_png_write_params params, bool verbose) { 91 | ok_png png = { 0 }; 92 | uint8_t *original_rgba_data = NULL; 93 | bool success = false; 94 | char test_name[PATH_MAX]; 95 | snprintf(test_name, sizeof(test_name), "png_write_%ux%u", params.width, params.height); 96 | 97 | // Fill an image with data 98 | const size_t original_rgba_data_len = (size_t)params.width * 4 * params.height; 99 | original_rgba_data = malloc(original_rgba_data_len); 100 | if (!original_rgba_data) { 101 | printf("Error: Couldn't allocate memory\n"); 102 | goto cleanup; 103 | } 104 | for (size_t i = 0; i < original_rgba_data_len; i++) { 105 | original_rgba_data[i] = i & 0xff; 106 | } 107 | params.data = original_rgba_data; 108 | 109 | // Write image to PNG file 110 | char path[PATH_MAX]; 111 | snprintf(path, sizeof(path), "%s%s.png", output_dir, test_name); 112 | FILE *out_file = fopen(path, "wb"); 113 | if (!out_file) { 114 | printf("Error: Couldn't open file for writing\n"); 115 | goto cleanup; 116 | } 117 | bool write_success = ok_png_write_to_file(out_file, params); 118 | fclose(out_file); 119 | if (!write_success) { 120 | printf("Error writing PNG data\n"); 121 | goto cleanup; 122 | } 123 | 124 | // Read image from PNG file (without any data conversion) 125 | FILE *in_file = fopen(path, "rb"); 126 | if (!in_file) { 127 | printf("Error: Couldn't open file for reading\n"); 128 | goto cleanup; 129 | } 130 | if (params.apple_cgbi_format) { 131 | png = ok_png_read(in_file, (ok_png_decode_flags)(OK_PNG_COLOR_FORMAT_BGRA | OK_PNG_PREMULTIPLIED_ALPHA)); 132 | } else { 133 | png = ok_png_read(in_file, OK_PNG_COLOR_FORMAT_RGBA); 134 | } 135 | fclose(in_file); 136 | if (png.error_code != OK_PNG_SUCCESS) { 137 | printf("Error reading PNG data (error %i)\n", png.error_code); 138 | goto cleanup; 139 | } 140 | 141 | // Compare original vs. read 142 | success = compare(test_name, "png", png.data, png.stride, png.width, png.height, original_rgba_data, original_rgba_data_len, false, 0, verbose); 143 | if (!success) { 144 | goto cleanup; 145 | } 146 | 147 | #if defined(__APPLE__) && TARGET_OS_OSX 148 | if (!params.apple_cgbi_format) { 149 | char command[4096]; 150 | snprintf(command, sizeof(command), "magick %s /dev/null", path); 151 | success = (system(command) == 0); 152 | if (!success) { 153 | printf("Error checking via convert command\n"); 154 | goto cleanup; 155 | } 156 | goto cleanup; 157 | } 158 | #endif 159 | 160 | // Cleanup 161 | cleanup: 162 | remove(path); 163 | free(original_rgba_data); 164 | free(png.data); 165 | return success; 166 | } 167 | 168 | static size_t uncompressed_size(uint32_t width, uint32_t height, uint32_t bpp, bool apple_cgbi_format) { 169 | size_t data_size = (((size_t)width * bpp) + 1) * height; // RGBA data + filter per row 170 | size_t stored_block_count = (data_size + 0xffff - 1) / 0xffff; // Number of stored blocks (max size 0xffff) 171 | size_t wrapper = apple_cgbi_format ? 0 : 2 + 4; // zlib header (2 bytes), adler (4 bytes) 172 | return wrapper + 5 * stored_block_count + data_size; 173 | } 174 | 175 | // This tests writing various size images; doesn't test CRC or Adler checksums (ok_png reader ignores them) 176 | int png_write_test(bool verbose) { 177 | // Get output dir 178 | char output_dir[PATH_MAX]; 179 | #if defined(USE_FC_DATADIR) 180 | if (fc_datadir("ok_file_formats", output_dir, PATH_MAX)) { 181 | printf("Error: Couldn't get datadir\n"); 182 | return 1; 183 | } 184 | #else 185 | output_dir[0] = '\0'; 186 | #endif 187 | 188 | int num_tests = 0; 189 | int num_failures = 0; 190 | 191 | num_tests++; 192 | num_failures += api_test(output_dir, verbose); 193 | 194 | // Test params. Image data filled in by test_image() 195 | const ok_png_write_params test_params[] = { 196 | (ok_png_write_params) { 197 | .width = 100, .height = 100, 198 | .color_type = OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA, 199 | }, 200 | (ok_png_write_params) { 201 | .width = 65536, .height = 1, // Multiple stored blocks; Lots of deflating without buffering 202 | .color_type = OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA, 203 | }, 204 | (ok_png_write_params) { 205 | .width = 100, .height = 1, 206 | .buffer_size = (uint32_t)uncompressed_size(100, 1, 4, false), // Exactly one IDAT chunk 207 | .color_type = OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA, 208 | }, 209 | (ok_png_write_params) { 210 | .width = 100, .height = 1, 211 | .buffer_size = (uint32_t)uncompressed_size(100, 1, 4, false) - 4, // Adler in a separate IDAT chunk 212 | .color_type = OK_PNG_WRITE_COLOR_TYPE_RGB_ALPHA, 213 | }, 214 | }; 215 | 216 | for (size_t i = 0; i < sizeof(test_params) / sizeof(*test_params); i++) { 217 | ok_png_write_params params = test_params[i]; 218 | 219 | // Test params as is 220 | num_tests++; 221 | if (!test_image(output_dir, params, verbose)) { 222 | num_failures++; 223 | } 224 | 225 | // Test again as CgBI 226 | params.apple_cgbi_format = true; 227 | num_tests++; 228 | if (!test_image(output_dir, params, verbose)) { 229 | num_failures++; 230 | } 231 | } 232 | 233 | printf("Success: PNG write %i of %i\n", (num_tests - num_failures), num_tests); 234 | return num_failures; 235 | } 236 | -------------------------------------------------------------------------------- /test/png_write_test.h: -------------------------------------------------------------------------------- 1 | #ifndef PNG_WRITE_TEST_H 2 | #define PNG_WRITE_TEST_H 3 | 4 | #include 5 | 6 | int png_write_test(bool verbose); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /test/test_common.c: -------------------------------------------------------------------------------- 1 | #include "ok_jpg.h" 2 | #include "ok_png.h" 3 | #include "test_common.h" 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef min 9 | #define min(a, b) ((a) < (b) ? (a) : (b)) 10 | #endif 11 | 12 | #ifndef max 13 | #define max(a, b) ((a) > (b) ? (a) : (b)) 14 | #endif 15 | 16 | static const int CUSTOM_MEMORY_STRIDE_ALIGNMENT = 512; // To test strides 17 | static const size_t CUSTOM_MEMORY_MAX = 1024 * 1024 * 1024; // No more than 1GB of memory per image 18 | 19 | void *custom_alloc(void *user_data, size_t size) { 20 | (void)user_data; 21 | return malloc(size); 22 | } 23 | 24 | void custom_free(void *user_data, void *memory) { 25 | (void)user_data; 26 | free(memory); 27 | } 28 | 29 | void custom_image_alloc(void *user_data, uint32_t width, uint32_t height, uint8_t bpp, 30 | uint8_t **dst_buffer, uint32_t *dst_stride) { 31 | (void)user_data; 32 | const int alignment = CUSTOM_MEMORY_STRIDE_ALIGNMENT; 33 | uint64_t stride = (uint64_t)width * bpp; 34 | uint64_t aligned_stride = (stride + alignment - 1) / alignment * alignment; 35 | uint64_t size = aligned_stride * height; 36 | size_t platform_size = (size_t)size; 37 | 38 | if (aligned_stride <= UINT32_MAX && platform_size == size && platform_size <= CUSTOM_MEMORY_MAX) { 39 | *dst_stride = (uint32_t)aligned_stride; 40 | *dst_buffer = malloc(platform_size); 41 | } 42 | } 43 | 44 | uint8_t *custom_audio_alloc(void *user_data, uint64_t num_frames, uint8_t num_channels, uint8_t bit_depth) { 45 | (void)user_data; 46 | uint64_t size = num_frames * num_channels * (bit_depth / 8); 47 | size_t platform_size = (size_t)size; 48 | if (platform_size == 0 || platform_size != size) { 49 | return NULL; 50 | } 51 | return malloc(platform_size); 52 | } 53 | 54 | static void print_image(const uint8_t *data, const uint32_t width, const uint32_t height) { 55 | if (data) { 56 | for (uint32_t y = 0; y < height; y++) { 57 | for (uint32_t x = 0; x < width * 4; x++) { 58 | if ((x & 3) == 0) { 59 | printf("|"); 60 | } 61 | uint8_t b = data[y * (width * 4) + x]; 62 | printf("%02x", b); 63 | } 64 | printf("\n"); 65 | } 66 | } 67 | } 68 | 69 | static void print_image_diff(const uint8_t *data, const uint32_t width, const uint32_t height) { 70 | if (data) { 71 | for (uint32_t y = 0; y < height; y++) { 72 | int max_diff = 0; 73 | for (uint32_t x = 0; x < width * 4; x++) { 74 | max_diff = max(max_diff, data[y * (width * 4) + x]); 75 | if (((x + 1) & 3) == 0) { 76 | printf("%01x", min(15, max_diff)); 77 | max_diff = 0; 78 | } 79 | } 80 | printf("\n"); 81 | } 82 | } 83 | } 84 | 85 | char *append_path(const char *path, const char *name) { 86 | return get_full_path(path, name, ""); 87 | } 88 | 89 | bool parent_path(char *path) { 90 | #ifdef _WIN32 91 | const char sep = '\\'; 92 | #else 93 | const char sep = '/'; 94 | #endif 95 | 96 | char *result = strrchr(path, sep); 97 | if (result) { 98 | *result = '\0'; 99 | return true; 100 | } else { 101 | return false; 102 | } 103 | } 104 | 105 | char *get_full_path(const char *path, const char *name, const char *ext) { 106 | #ifdef _WIN32 107 | const char *sep = "\\"; 108 | #else 109 | const char *sep = "/"; 110 | #endif 111 | size_t path_len = strlen(path); 112 | size_t ext_len = strlen(ext); 113 | size_t name_len = strlen(name); 114 | char *file_name = malloc(path_len + 1 + name_len + 1 + ext_len + 1); 115 | memcpy(file_name, path, path_len + 1); 116 | if (path_len > 0 && path[path_len - 1] != sep[0]) { 117 | strncat(file_name, sep, 1); 118 | } 119 | strncat(file_name, name, name_len); 120 | if (ext_len > 0) { 121 | strncat(file_name, ".", 1); 122 | strncat(file_name, ext, ext_len); 123 | } 124 | return file_name; 125 | } 126 | 127 | uint8_t *read_file(const char *filename, unsigned long *length) { 128 | uint8_t *buffer; 129 | FILE *fp = fopen(filename, "rb"); 130 | 131 | if (fp) { 132 | fseek(fp, 0, SEEK_END); 133 | long tell = ftell(fp); 134 | if (tell < 0) { 135 | buffer = NULL; 136 | *length = 0; 137 | } else { 138 | *length = (unsigned long)tell; 139 | fseek(fp, 0, SEEK_SET); 140 | buffer = malloc(*length); 141 | if (buffer) { 142 | fread(buffer, 1, *length, fp); 143 | } 144 | } 145 | fclose(fp); 146 | } else { 147 | buffer = NULL; 148 | *length = 0; 149 | } 150 | 151 | return buffer; 152 | } 153 | 154 | static bool fuzzy_memcmp(const uint8_t *data1, const uint8_t *data2, 155 | size_t pitch1, size_t pitch2, 156 | size_t width, size_t height, 157 | uint8_t fuzziness, double *p_identical, int *peak_diff) { 158 | int identical = 0; 159 | bool success = true; 160 | 161 | *peak_diff = 0; 162 | 163 | for (size_t i = 0; i < height; i++) { 164 | const uint8_t *row1 = data1 + i * pitch1; 165 | const uint8_t *row2 = data2 + i * pitch2; 166 | if (fuzziness == 0) { 167 | if (memcmp(row1, row2, width) != 0) { 168 | return false; 169 | } 170 | } else { 171 | const uint8_t *row1_end = row1 + width; 172 | while (row1 < row1_end) { 173 | int diff = abs(*row1 - *row2); 174 | if (diff <= 1) { 175 | identical++; 176 | } 177 | if (diff > *peak_diff) { 178 | *peak_diff = diff; 179 | } 180 | if (diff > fuzziness) { 181 | success = false; 182 | } 183 | row1++; 184 | row2++; 185 | } 186 | } 187 | } 188 | *p_identical = (double)identical / (width * height); 189 | return success; 190 | } 191 | 192 | bool compare(const char *name, const char *ext, 193 | const uint8_t *image_data, uint32_t image_data_stride, 194 | uint32_t image_width, uint32_t image_height, 195 | const uint8_t *rgba_data, unsigned long rgba_data_length, 196 | bool info_only, uint8_t fuzziness, bool verbose) { 197 | double p_identical; 198 | int peak_diff; 199 | bool success = false; 200 | if (info_only) { 201 | if (rgba_data_length > 0 && image_width * image_height * 4 != rgba_data_length) { 202 | printf("Failure: Incorrect dimensions for %s.%s " 203 | "(%u x %u - data length should be %lu but is %u)\n", 204 | name, ext, image_width, image_height, rgba_data_length, 205 | (image_width * image_height * 4)); 206 | } else if (image_data != NULL) { 207 | printf("Failure: Data incorrectly loaded for %s.%s \n", name, ext); 208 | } else { 209 | if (verbose) { 210 | printf("File: %16.16s.%s (Info only: %u x %u)\n", name, ext, 211 | image_width, image_height); 212 | } 213 | success = true; 214 | } 215 | } else if (!image_data && (!rgba_data || rgba_data_length == 0)) { 216 | if (verbose) { 217 | printf("File: %16.16s.%s (invalid file correctly detected).\n", name, ext); 218 | } 219 | success = true; 220 | } else if (!image_data) { 221 | printf("Failure: Couldn't load %s.%s.\n", name, ext); 222 | } else if (!rgba_data) { 223 | printf("Warning: Couldn't load %s.rgba. Possibly invalid file.\n", name); 224 | success = true; 225 | } else if (image_width * image_height * 4 != rgba_data_length) { 226 | printf("Failure: Incorrect dimensions for %s.%s " 227 | "(%u x %u - data length should be %lu but is %u)\n", name, ext, 228 | image_width, image_height, rgba_data_length, (image_width * image_height * 4)); 229 | } else if (!fuzzy_memcmp(image_data, rgba_data, image_data_stride, image_width * 4, 230 | image_width * 4, image_height, 231 | fuzziness, &p_identical, &peak_diff)) { 232 | if (fuzziness > 0) { 233 | printf("Failure: Data is different for image %s.%s (%f%% diff<=1, peak diff=%i)\n", 234 | name, ext, (p_identical * 100.0), peak_diff); 235 | } else { 236 | printf("Failure: Data is different for image %s.%s\n", name, ext); 237 | } 238 | if (verbose) { 239 | printf("raw:\n"); 240 | print_image(rgba_data, image_width, image_height); 241 | printf("as decoded:\n"); 242 | print_image(image_data, image_width, image_height); 243 | uint8_t *diff_data = malloc(rgba_data_length); 244 | for (unsigned long i = 0; i < rgba_data_length; i++) { 245 | diff_data[i] = (uint8_t)abs(rgba_data[i] - image_data[i]); 246 | } 247 | printf("diff:\n"); 248 | print_image_diff(diff_data, image_width, image_height); 249 | free(diff_data); 250 | } 251 | } else if (fuzziness > 0) { 252 | if (verbose) { 253 | printf("File: %16.16s.%s (%9.5f%% diff<=1, peak diff=%i)\n", name, ext, 254 | (p_identical * 100.0), peak_diff); 255 | } 256 | success = true; 257 | } else { 258 | if (verbose) { 259 | printf("File: %16.16s.%s\n", name, ext); 260 | } 261 | success = true; 262 | } 263 | return success; 264 | } 265 | -------------------------------------------------------------------------------- /test/test_common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void *custom_alloc(void *user_data, size_t size); 6 | 7 | void custom_free(void *user_data, void *memory); 8 | 9 | void custom_image_alloc(void *user_data, uint32_t width, uint32_t height, uint8_t bpp, 10 | uint8_t **dst_buffer, uint32_t *dst_stride); 11 | 12 | uint8_t *custom_audio_alloc(void *user_data, uint64_t num_frames, uint8_t num_channels, 13 | uint8_t bit_depth); 14 | 15 | char *append_path(const char *path, const char *name); 16 | 17 | // Converts a path to the parent path. Returns true on success. 18 | bool parent_path(char *path); 19 | 20 | char *get_full_path(const char *path, const char *name, const char *ext); 21 | 22 | uint8_t *read_file(const char *filename, unsigned long *length); 23 | 24 | // Tests if two images are the same. 25 | // If fuzziness > 0, then the diff of the pixel values have to be within (fuzziness). 26 | bool compare(const char *name, const char *ext, 27 | const uint8_t *image_data, uint32_t image_data_stride, 28 | uint32_t image_width, uint32_t image_height, 29 | const uint8_t *rgba_data, unsigned long rgba_data_length, 30 | bool info_only, uint8_t fuzziness, bool verbose); 31 | -------------------------------------------------------------------------------- /test/wav/sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/wav/sound.wav -------------------------------------------------------------------------------- /test/wav/sound2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brackeen/ok-file-formats/8e63bd5c728c04fc20e872839a9a616d28944bcc/test/wav/sound2.wav -------------------------------------------------------------------------------- /test/wav_test.c: -------------------------------------------------------------------------------- 1 | #include "wav_test.h" 2 | #include "ok_wav.h" 3 | #include "test_common.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef min 10 | #define min(a, b) ((a) < (b) ? (a) : (b)) 11 | #endif 12 | 13 | enum wav_test_type { 14 | test_normal, 15 | test_allocator, 16 | }; 17 | 18 | static void print_diff(const uint8_t *data1, const uint8_t *data2, const unsigned long length) { 19 | printf("Expected: Actual:\n"); 20 | if (data1 && data2) { 21 | unsigned long i = 0; 22 | while (i < length) { 23 | printf("\x1B[39m"); // Default color 24 | unsigned long count = min(length - i, 16); 25 | for (unsigned long j = 0; j < count; j++) { 26 | uint8_t b = data1[i + j]; 27 | printf("%02x ", b); 28 | } 29 | for (unsigned long j = count; j < 16; j++) { 30 | printf(" "); 31 | } 32 | printf("| "); 33 | for (unsigned long j = 0; j < count; j++) { 34 | uint8_t b = data2[i + j]; 35 | if (b == data1[i + j]) { 36 | printf("\x1B[39m"); // Default color 37 | } else { 38 | printf("\x1B[31m"); // Red 39 | } 40 | printf("%02x ", b); 41 | } 42 | printf("\n"); 43 | i += count; 44 | } 45 | printf("\x1B[39m"); // Default color 46 | } 47 | } 48 | 49 | static bool test_wav(const char *path, const char *container_type, const char *format, 50 | int channels, enum wav_test_type test_type, bool verbose) { 51 | char src_filename[256]; 52 | bool success = false; 53 | 54 | // Load ok_wav 55 | snprintf(src_filename, sizeof(src_filename), "sound-%s-%dch", format, channels); 56 | char *src_path = get_full_path(path, src_filename, container_type); 57 | FILE *file = fopen(src_path, "rb"); 58 | if (!file) { 59 | printf("Warning: %24.24s.%s not found.\n", src_filename, container_type); 60 | return true; 61 | } 62 | const ok_wav_allocator allocator = { 63 | .alloc = custom_alloc, 64 | .free = custom_free, 65 | .audio_alloc = custom_audio_alloc 66 | }; 67 | 68 | ok_wav wav = { 0 }; 69 | switch (test_type) { 70 | case test_normal: 71 | wav = ok_wav_read(file, OK_WAV_ENDIAN_NO_CONVERSION); 72 | break; 73 | case test_allocator: 74 | wav = ok_wav_read_with_allocator(file, OK_WAV_ENDIAN_NO_CONVERSION, allocator, NULL); 75 | break; 76 | } 77 | fclose(file); 78 | free(src_path); 79 | 80 | if (!wav.data) { 81 | printf("File: %24.24s.%s (Couldn't load data. Error %i).\n", src_filename, 82 | container_type, wav.error_code); 83 | } else { 84 | // Load raw 85 | char *raw_path = get_full_path(path, src_filename, "raw"); 86 | unsigned long expected_length = 0; 87 | void *raw_data = read_file(raw_path, &expected_length); 88 | free(raw_path); 89 | 90 | // Compare 91 | unsigned long length = (unsigned long)(wav.num_frames * wav.num_channels * 92 | (wav.bit_depth / 8)); 93 | 94 | if (expected_length != length) { 95 | printf("File: %24.24s.%s (Invalid data length: Expected %lu, got %lu).\n", 96 | src_filename, container_type, expected_length, length); 97 | } else { 98 | success = memcmp(wav.data, raw_data, length) == 0; 99 | if (!success) { 100 | printf("File: %24.24s.%s (Data mismatch).\n", src_filename, container_type); 101 | if (verbose) { 102 | print_diff(raw_data, wav.data, length); 103 | } 104 | } 105 | } 106 | free(raw_data); 107 | free(wav.data); 108 | } 109 | 110 | return success; 111 | } 112 | 113 | int wav_test(const char *path, bool verbose) { 114 | const int channels[] = { 1, 2 }; 115 | const char *caf_data_formats[] = { 116 | "I8", "ulaw", "alaw", "ima4", 117 | "BEI16", "BEI24", "BEI32", "BEF32", "BEF64", 118 | "LEI16", "LEI24", "LEI32", "LEF32", "LEF64" }; 119 | const char *wav_data_formats[] = { 120 | "UI8", "ulaw-wav", "alaw-wav", "ima-adpcm", "ms-adpcm", 121 | "BEI16", "BEI24", "BEI32", "BEF32", "BEF64", 122 | "LEI16", "LEI24", "LEI32", "LEF32", "LEF64" }; 123 | 124 | const int num_channels = sizeof(channels) / sizeof(channels[0]); 125 | const int num_caf_types = sizeof(caf_data_formats) / sizeof(caf_data_formats[0]); 126 | const int num_wav_types = sizeof(wav_data_formats) / sizeof(wav_data_formats[0]); 127 | 128 | const int num_files = (num_caf_types + num_wav_types) * num_channels; 129 | if (verbose) { 130 | printf("Testing %i files in path \"%s\".\n", num_files, path); 131 | } 132 | 133 | double startTime = clock() / (double)CLOCKS_PER_SEC; 134 | int num_failures = 0; 135 | for (int i = 0; i < num_channels; i++) { 136 | bool success; 137 | for (int j = 0; j < num_caf_types; j++) { 138 | success = test_wav(path, "caf", caf_data_formats[j], channels[i], test_normal, verbose); 139 | if (!success) { 140 | num_failures++; 141 | } 142 | success = test_wav(path, "caf", caf_data_formats[j], channels[i], test_allocator, verbose); 143 | if (!success) { 144 | num_failures++; 145 | } 146 | } 147 | 148 | for (int j = 0; j < num_wav_types; j++) { 149 | success = test_wav(path, "wav", wav_data_formats[j], channels[i], test_normal, verbose); 150 | if (!success) { 151 | num_failures++; 152 | } 153 | success = test_wav(path, "wav", wav_data_formats[j], channels[i], test_allocator, verbose); 154 | if (!success) { 155 | num_failures++; 156 | } 157 | } 158 | } 159 | 160 | double endTime = clock() / (double)CLOCKS_PER_SEC; 161 | double elapsedTime = endTime - startTime; 162 | printf("Success: WAV %i of %i\n", (num_files - num_failures), num_files); 163 | if (verbose) { 164 | printf("Duration: %f seconds\n", elapsedTime); 165 | } 166 | 167 | #if 0 168 | char *test_path = append_path(path, "../../wav/issue-21.wav"); 169 | FILE *file = fopen(test_path, "rb"); 170 | if (!file) { 171 | printf("Not found: %s\n", test_path); 172 | } else { 173 | printf("Testing %s\n", test_path); 174 | ok_wav wav = ok_wav_read(file, OK_WAV_ENDIAN_NO_CONVERSION); 175 | fclose(file); 176 | free(wav.data); 177 | } 178 | free(test_path); 179 | 180 | #endif 181 | 182 | return num_failures; 183 | } 184 | -------------------------------------------------------------------------------- /test/wav_test.h: -------------------------------------------------------------------------------- 1 | #ifndef WAV_TEST_H 2 | #define WAV_TEST_H 3 | 4 | #include 5 | 6 | int wav_test(const char *path_to_wav_files, bool verbose); 7 | 8 | #endif 9 | --------------------------------------------------------------------------------