├── .gitignore ├── Makefile ├── png2tga.c ├── upng.h ├── glview.c ├── README └── upng.c /.gitignore: -------------------------------------------------------------------------------- 1 | png2tga 2 | glview 3 | *.o 4 | *.sh 5 | *.png 6 | *.tga 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UNAME := $(shell uname) 2 | ifeq ($(UNAME), Darwin) 3 | CFLAGS := -framework OpenGL 4 | else 5 | CFLAGS := -lgl 6 | endif 7 | 8 | all: png2tga glview 9 | 10 | png2tga: png2tga.c upng.c upng.h Makefile 11 | $(CC) -o png2tga png2tga.c upng.c -Wall -pedantic -g -O0 12 | 13 | glview: glview.c upng.c upng.h Makefile 14 | $(CC) -o glview glview.c upng.c -Wall -pedantic -g -O3 -flto -lSDL $(CFLAGS) 15 | -------------------------------------------------------------------------------- /png2tga.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "upng.h" 5 | 6 | #define HI(w) (((w) >> 8) & 0xFF) 7 | #define LO(w) ((w) & 0xFF) 8 | 9 | int main(int argc, char** argv) { 10 | FILE* fh; 11 | upng_t* upng; 12 | unsigned width, height, depth; 13 | unsigned x, y, d; 14 | 15 | if (argc <= 2) { 16 | return 0; 17 | } 18 | 19 | upng = upng_new_from_file(argv[1]); 20 | if (upng_get_error(upng) == UPNG_EOK) { 21 | printf("error: %u %u\n", upng_get_error(upng), upng_get_error_line(upng)); 22 | return 0; 23 | } 24 | 25 | width = upng_get_width(upng); 26 | height = upng_get_height(upng); 27 | depth = upng_get_bpp(upng) / 8; 28 | 29 | printf("size: %ux%ux%u (%u)\n", width, height, upng_get_bpp(upng), upng_get_size(upng)); 30 | printf("format: %u\n", upng_get_format(upng)); 31 | 32 | if (upng_get_format(upng) == UPNG_RGB8 || upng_get_format(upng) == UPNG_RGBA8) { 33 | fh = fopen(argv[2], "wb"); 34 | fprintf(fh, "%c%c%c", 0, 0, 2); 35 | fprintf(fh, "%c%c%c%c%c", 0, 0, 0, 0, 0); 36 | fprintf(fh, "%c%c%c%c%c%c%c%c%c%c", 0, 0, 0, 0, LO(width), HI(width), LO(height), HI(height), upng_get_bpp(upng), upng_get_bitdepth(upng)); 37 | 38 | for (y = 0; y != height; ++y) { 39 | for (x = 0; x != width; ++x) { 40 | for (d = 0; d != depth; ++d) { 41 | putc(upng_get_buffer(upng)[(height - y - 1) * width * depth + x * depth + (depth - d - 1)], fh); 42 | } 43 | } 44 | } 45 | 46 | fclose(fh); 47 | } 48 | 49 | upng_free(upng); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /upng.h: -------------------------------------------------------------------------------- 1 | /* 2 | uPNG -- derived from LodePNG version 20100808 3 | 4 | Copyright (c) 2005-2010 Lode Vandevenne 5 | Copyright (c) 2010 Sean Middleditch 6 | 7 | This software is provided 'as-is', without any express or implied 8 | warranty. In no event will the authors be held liable for any damages 9 | arising from the use of this software. 10 | 11 | Permission is granted to anyone to use this software for any purpose, 12 | including commercial applications, and to alter it and redistribute it 13 | freely, subject to the following restrictions: 14 | 15 | 1. The origin of this software must not be misrepresented; you must not 16 | claim that you wrote the original software. If you use this software 17 | in a product, an acknowledgment in the product documentation would be 18 | appreciated but is not required. 19 | 20 | 2. Altered source versions must be plainly marked as such, and must not be 21 | misrepresented as being the original software. 22 | 23 | 3. This notice may not be removed or altered from any source 24 | distribution. 25 | */ 26 | 27 | #if !defined(UPNG_H) 28 | #define UPNG_H 29 | 30 | typedef enum upng_error { 31 | UPNG_EOK = 0, /* success (no error) */ 32 | UPNG_ENOMEM = 1, /* memory allocation failed */ 33 | UPNG_ENOTFOUND = 2, /* resource not found (file missing) */ 34 | UPNG_ENOTPNG = 3, /* image data does not have a PNG header */ 35 | UPNG_EMALFORMED = 4, /* image data is not a valid PNG image */ 36 | UPNG_EUNSUPPORTED = 5, /* critical PNG chunk type is not supported */ 37 | UPNG_EUNINTERLACED = 6, /* image interlacing is not supported */ 38 | UPNG_EUNFORMAT = 7, /* image color format is not supported */ 39 | UPNG_EPARAM = 8 /* invalid parameter to method call */ 40 | } upng_error; 41 | 42 | typedef enum upng_format { 43 | UPNG_BADFORMAT, 44 | UPNG_RGB8, 45 | UPNG_RGB16, 46 | UPNG_RGBA8, 47 | UPNG_RGBA16, 48 | UPNG_LUMINANCE1, 49 | UPNG_LUMINANCE2, 50 | UPNG_LUMINANCE4, 51 | UPNG_LUMINANCE8, 52 | UPNG_LUMINANCE_ALPHA1, 53 | UPNG_LUMINANCE_ALPHA2, 54 | UPNG_LUMINANCE_ALPHA4, 55 | UPNG_LUMINANCE_ALPHA8 56 | } upng_format; 57 | 58 | typedef struct upng_t upng_t; 59 | 60 | upng_t* upng_new_from_bytes (const unsigned char* buffer, unsigned long size); 61 | upng_t* upng_new_from_file (const char* path); 62 | void upng_free (upng_t* upng); 63 | 64 | upng_error upng_header (upng_t* upng); 65 | upng_error upng_decode (upng_t* upng); 66 | 67 | upng_error upng_get_error (const upng_t* upng); 68 | unsigned upng_get_error_line (const upng_t* upng); 69 | 70 | unsigned upng_get_width (const upng_t* upng); 71 | unsigned upng_get_height (const upng_t* upng); 72 | unsigned upng_get_bpp (const upng_t* upng); 73 | unsigned upng_get_bitdepth (const upng_t* upng); 74 | unsigned upng_get_components (const upng_t* upng); 75 | unsigned upng_get_pixelsize (const upng_t* upng); 76 | upng_format upng_get_format (const upng_t* upng); 77 | 78 | const unsigned char* upng_get_buffer (const upng_t* upng); 79 | unsigned upng_get_size (const upng_t* upng); 80 | 81 | #endif /*defined(UPNG_H)*/ 82 | -------------------------------------------------------------------------------- /glview.c: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef __APPLE__ 3 | #include 4 | #else 5 | #include 6 | #endif 7 | #include 8 | #include 9 | 10 | #include "upng.h" 11 | 12 | static GLuint checkboard(unsigned w, unsigned h) { 13 | unsigned char* buffer; 14 | unsigned x, y, xc = 0; 15 | char dark = 0; 16 | GLuint texture; 17 | 18 | buffer = (unsigned char*)calloc(w * h, 3); 19 | 20 | for (y = 0; y != h; ++y) { 21 | for (x = 0; x != w; ++x, ++xc) { 22 | if ((xc % (w >> 3)) == 0) { 23 | dark = 1 - dark; 24 | } 25 | 26 | if (dark) { 27 | buffer[y * w * 3 + x * 3 + 0] = 0x6F; 28 | buffer[y * w * 3 + x * 3 + 1] = 0x6F; 29 | buffer[y * w * 3 + x * 3 + 2] = 0x6F; 30 | } else { 31 | buffer[y * w * 3 + x * 3 + 0] = 0xAF; 32 | buffer[y * w * 3 + x * 3 + 1] = 0xAF; 33 | buffer[y * w * 3 + x * 3 + 2] = 0xAF; 34 | } 35 | } 36 | 37 | if ((y % (h >> 3)) == 0) { 38 | dark = 1 - dark; 39 | } 40 | } 41 | 42 | glEnable(GL_TEXTURE_2D); 43 | glGenTextures(1, &texture); 44 | glBindTexture(GL_TEXTURE_2D, texture); 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 46 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 47 | glTexImage2D(GL_TEXTURE_2D, 0, 3, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); 48 | 49 | free(buffer); 50 | 51 | return texture; 52 | } 53 | 54 | int main(int argc, char** argv) { 55 | SDL_Event event; 56 | upng_t* upng; 57 | GLuint texture, cb; 58 | 59 | if (argc <= 1) { 60 | return 0; 61 | } 62 | 63 | upng = upng_new_from_file(argv[1]); 64 | upng_decode(upng); 65 | if (upng_get_error(upng) != UPNG_EOK) { 66 | printf("error: %u %u\n", upng_get_error(upng), upng_get_error_line(upng)); 67 | return 0; 68 | } 69 | 70 | SDL_Init(SDL_INIT_VIDEO); 71 | SDL_SetVideoMode(upng_get_width(upng), upng_get_height(upng), 0, SDL_OPENGL|SDL_DOUBLEBUF); 72 | 73 | glDisable(GL_DEPTH_TEST); 74 | glDisable(GL_CULL_FACE); 75 | glEnable(GL_BLEND); 76 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 77 | glClearColor(0.f, 0.f, 0.f, 0.f); 78 | 79 | glMatrixMode(GL_PROJECTION); 80 | glLoadIdentity(); 81 | glOrtho(0, 1, 0, 1, 0, 1); 82 | 83 | glMatrixMode(GL_MODELVIEW); 84 | glLoadIdentity(); 85 | 86 | cb = checkboard(upng_get_width(upng), upng_get_height(upng)); 87 | 88 | glEnable(GL_TEXTURE_2D); 89 | glGenTextures(1, &texture); 90 | glBindTexture(GL_TEXTURE_2D, texture); 91 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 92 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 93 | 94 | switch (upng_get_components(upng)) { 95 | case 1: 96 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, upng_get_width(upng), upng_get_height(upng), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, upng_get_buffer(upng)); 97 | break; 98 | case 2: 99 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, upng_get_width(upng), upng_get_height(upng), 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, upng_get_buffer(upng)); 100 | break; 101 | case 3: 102 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, upng_get_width(upng), upng_get_height(upng), 0, GL_RGB, GL_UNSIGNED_BYTE, upng_get_buffer(upng)); 103 | break; 104 | case 4: 105 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, upng_get_width(upng), upng_get_height(upng), 0, GL_RGBA, GL_UNSIGNED_BYTE, upng_get_buffer(upng)); 106 | break; 107 | default: 108 | return 1; 109 | } 110 | 111 | upng_free(upng); 112 | 113 | while (SDL_WaitEvent(&event)) { 114 | if (event.type == SDL_QUIT) { 115 | break; 116 | } 117 | 118 | glClear(GL_COLOR_BUFFER_BIT); 119 | 120 | glBindTexture(GL_TEXTURE_2D, cb); 121 | glBegin(GL_QUADS); 122 | glTexCoord2f(0.f, 1.f); 123 | glVertex2f(0.f, 0.f); 124 | 125 | glTexCoord2f(0.f, 0.f); 126 | glVertex2f(0.f, 1.f); 127 | 128 | glTexCoord2f(1.f, 0.f); 129 | glVertex2f(1.f, 1.f); 130 | 131 | glTexCoord2f(1.f, 1.f); 132 | glVertex2f(1.f, 0.f); 133 | glEnd(); 134 | 135 | glBindTexture(GL_TEXTURE_2D, texture); 136 | glBegin(GL_QUADS); 137 | glTexCoord2f(0.f, 1.f); 138 | glVertex2f(0.f, 0.f); 139 | 140 | glTexCoord2f(0.f, 0.f); 141 | glVertex2f(0.f, 1.f); 142 | 143 | glTexCoord2f(1.f, 0.f); 144 | glVertex2f(1.f, 1.f); 145 | 146 | glTexCoord2f(1.f, 1.f); 147 | glVertex2f(1.f, 0.f); 148 | glEnd(); 149 | 150 | SDL_GL_SwapBuffers(); 151 | } 152 | 153 | glDeleteTextures(1, &texture); 154 | glDeleteTextures(1, &cb); 155 | SDL_Quit(); 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | uPNG -- derived from LodePNG version 20100808 2 | ========================================== 3 | 4 | Copying 5 | ------- 6 | 7 | Copyright (c) 2005-2010 Lode Vandevenne 8 | Copyright (c) 2010 Sean Middleditch 9 | 10 | This software is provided 'as-is', without any express or implied 11 | warranty. In no event will the authors be held liable for any damages 12 | arising from the use of this software. 13 | 14 | Permission is granted to anyone to use this software for any purpose, 15 | including commercial applications, and to alter it and redistribute it 16 | freely, subject to the following restrictions: 17 | 18 | 1. The origin of this software must not be misrepresented; you must not 19 | claim that you wrote the original software. If you use this software 20 | in a product, an acknowledgment in the product documentation would be 21 | appreciated but is not required. 22 | 23 | 2. Altered source versions must be plainly marked as such, and must not be 24 | misrepresented as being the original software. 25 | 26 | 3. This notice may not be removed or altered from any source 27 | distribution. 28 | 29 | Features 30 | -------- 31 | 32 | uPNG supports loading and decoding PNG images into a simple byte buffer, suitable 33 | for passing directly to OpenGL as texture data. 34 | 35 | uPNG does NOT support interlaced images, paletted images, and fixed-transparency. 36 | Checksums are NOT verified and corrupt image data may be undetected. 37 | 38 | It DOES support RGB, RGBA, greyscale, and greyscale-with-alpha images. RGB and 39 | RGBA are currently only supported in 8-bit color depths, and greyscale images 40 | are supported in either 1-, 2-, 4-, or 8-bit color depths. 41 | 42 | WARNING: the source project that uPNG is derived from, LodePNG, did not have 43 | the cleanest or best documented code. Several potential buffer overflows in the 44 | original source have been fixed in uPNG, but there may be more. Do NOT use uPNG 45 | to load data from untrusted sources, e.g. the Web. Doing so may open a 46 | remotely exploitable buffer overflow attack in your application. 47 | 48 | Installation 49 | ------------ 50 | 51 | Copy the upng.c and upng.h files into your project, and add them to your build 52 | system. upng.c will compile as C++ if necessary. 53 | 54 | Usage 55 | ----- 56 | 57 | To load a PNG, you must create an upng_t instance, load the raw PNG into the 58 | decoder, and then you can query the upng_t for image properties and the 59 | decoded image buffer. 60 | 61 | upng_t* upng; 62 | 63 | upng = upng_new_from_file("image.png"); 64 | if (upng != NULL) { 65 | upng_decode(upng); 66 | if (upng_get_error(upng) == UPNG_EOK) { 67 | /* do stuff with image */ 68 | } 69 | 70 | upng_free(upng); 71 | } 72 | 73 | You can load a PNG either from an in-memory buffer of bytes or from a file 74 | specified by file path. 75 | 76 | upng_new_from_bytes(const unsigned char*, unsigned long length) 77 | upng_new_from_file(const char*) 78 | 79 | Once an upng_t object is created, you can read just its header properties, 80 | decode the entire file, and release its resources. 81 | 82 | upng_header(upng_t*) Reads just the header, sets image properties 83 | upng_decode(upng_t*) Decodes image data 84 | upng_free(upng_t*) Frees the resources attached to a upng_t object 85 | 86 | The query functions are: 87 | 88 | upng_get_width(upng_t*) Returns width of image in pixels 89 | upng_get_height(upng_t*) Returns height of image in pixels 90 | upng_get_size(upng_t*) Returns the total size of the image buffer in bytes 91 | upng_get_bpp(upng_t*) Returns the number of bits per pixel (e.g., 32 for 8-bit RGBA) 92 | upng_get_bitdepth(upng_t*) Returns the number of bits per component (e.g., 8 for 8-bit RGBA) 93 | upng_get_pixelsize(upng_t*) Returns the number of bytes per pixel (e.g., 4 for 8-bit RGBA) 94 | upng_get_components(upng_t*) Returns the number of components per pixel (e.g., 4 for 8-bit RGBA) 95 | upng_get_format(upng_t*) Returns the format of the image buffer (see below) 96 | upng_get_buffer(upng_t*) Returns a pointer to the image buffer 97 | 98 | Additionally, for error handling, you can use: 99 | 100 | upng_get_error(upng_t*) Returns the error state of the upng object (UPNG_EOK means no error) 101 | upng_get_error_line(upng_t*) Returns the line in the upng.c file where the error state was set 102 | 103 | The formats supported are: 104 | 105 | UPNG_RGB8 24-bit RGB 106 | UPNG_RGB16 48-bit RGB 107 | UPNG_RGBA8 32-bit RGBA 108 | UPNG_RGBA16 64-bit RGBA 109 | UPNG_LUMINANCE8 8-bit Greyscale 110 | UPNG_LUMINANCEA8 8-bit Greyscale w/ 8-bit Alpha 111 | 112 | Possible error states are: 113 | 114 | UPNG_EOK No error (success) 115 | UPNG_ENOMEM Out of memory 116 | UPNG_ENOTFOUND Resource not found 117 | UPNG_ENOTPNG Invalid file header (not a PNG image) 118 | UPNG_EMALFORMED PNG image data does not follow spec and is malformed 119 | UPNG_EUNSUPPORTED PNG image data is well-formed but not supported by uPNG 120 | 121 | TODO 122 | ---- 123 | 124 | - Audit the code (particularly the Huffman decoder) for buffer overflows. Make sure 125 | uPNG is safe to use even with image data from untrusted sources. 126 | 127 | - Make the decompressor work in a streaming/buffered manner, so that we don't need 128 | to stitch together the PNG IDATA chunks before decompressing, shaving off one 129 | unnecessary allocation. 130 | 131 | - Update the unfiltering code to work on the decompressed image buffer, rather than 132 | needing a separate output buffer. The removal of the Adam7 de-interlacing support 133 | makes this easier. Removes another unnecessary allocation. 134 | 135 | - Update the decoder API to work in a stream/buffered manner, so files can be read 136 | without needing to allocate a temporary buffer. This removes yet another 137 | unnecessary allocation. 138 | 139 | - Update the decoder API to allow the user to provide an output buffer, so that 140 | PNG images can be decoded directly to mapped texture memory. Removes the need 141 | for the last unnecessary allocation. 142 | 143 | - Test that greyscale images with less than 8-bits of depth actually work, fix 144 | or remove if they do not. 145 | 146 | - Provide optional format conversion (as an extension to byte swizzling) to 147 | convert input PNGs in one format to one of a (limited) set of target output 148 | formats commonly used for texturing. 149 | 150 | - Provide floating-point conversion, at least for 16-bit source images, for 151 | HDR textures. 152 | 153 | - Provide vertical flipping of decoded image data for APIs that prefer textures 154 | with an origin in the lower-left instead of upper-left. 155 | -------------------------------------------------------------------------------- /upng.c: -------------------------------------------------------------------------------- 1 | /* 2 | uPNG -- derived from LodePNG version 20100808 3 | 4 | Copyright (c) 2005-2010 Lode Vandevenne 5 | Copyright (c) 2010 Sean Middleditch 6 | 7 | This software is provided 'as-is', without any express or implied 8 | warranty. In no event will the authors be held liable for any damages 9 | arising from the use of this software. 10 | 11 | Permission is granted to anyone to use this software for any purpose, 12 | including commercial applications, and to alter it and redistribute it 13 | freely, subject to the following restrictions: 14 | 15 | 1. The origin of this software must not be misrepresented; you must not 16 | claim that you wrote the original software. If you use this software 17 | in a product, an acknowledgment in the product documentation would be 18 | appreciated but is not required. 19 | 20 | 2. Altered source versions must be plainly marked as such, and must not be 21 | misrepresented as being the original software. 22 | 23 | 3. This notice may not be removed or altered from any source 24 | distribution. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "upng.h" 33 | 34 | #define MAKE_BYTE(b) ((b) & 0xFF) 35 | #define MAKE_DWORD(a,b,c,d) ((MAKE_BYTE(a) << 24) | (MAKE_BYTE(b) << 16) | (MAKE_BYTE(c) << 8) | MAKE_BYTE(d)) 36 | #define MAKE_DWORD_PTR(p) MAKE_DWORD((p)[0], (p)[1], (p)[2], (p)[3]) 37 | 38 | #define CHUNK_IHDR MAKE_DWORD('I','H','D','R') 39 | #define CHUNK_IDAT MAKE_DWORD('I','D','A','T') 40 | #define CHUNK_IEND MAKE_DWORD('I','E','N','D') 41 | 42 | #define FIRST_LENGTH_CODE_INDEX 257 43 | #define LAST_LENGTH_CODE_INDEX 285 44 | 45 | #define NUM_DEFLATE_CODE_SYMBOLS 288 /*256 literals, the end code, some length codes, and 2 unused codes */ 46 | #define NUM_DISTANCE_SYMBOLS 32 /*the distance codes have their own symbols, 30 used, 2 unused */ 47 | #define NUM_CODE_LENGTH_CODES 19 /*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros */ 48 | #define MAX_SYMBOLS 288 /* largest number of symbols used by any tree type */ 49 | 50 | #define DEFLATE_CODE_BITLEN 15 51 | #define DISTANCE_BITLEN 15 52 | #define CODE_LENGTH_BITLEN 7 53 | #define MAX_BIT_LENGTH 15 /* largest bitlen used by any tree type */ 54 | 55 | #define DEFLATE_CODE_BUFFER_SIZE (NUM_DEFLATE_CODE_SYMBOLS * 2) 56 | #define DISTANCE_BUFFER_SIZE (NUM_DISTANCE_SYMBOLS * 2) 57 | #define CODE_LENGTH_BUFFER_SIZE (NUM_DISTANCE_SYMBOLS * 2) 58 | 59 | #define SET_ERROR(upng,code) do { (upng)->error = (code); (upng)->error_line = __LINE__; } while (0) 60 | 61 | #define upng_chunk_length(chunk) MAKE_DWORD_PTR(chunk) 62 | #define upng_chunk_type(chunk) MAKE_DWORD_PTR((chunk) + 4) 63 | #define upng_chunk_critical(chunk) (((chunk)[4] & 32) == 0) 64 | 65 | typedef enum upng_state { 66 | UPNG_ERROR = -1, 67 | UPNG_DECODED = 0, 68 | UPNG_HEADER = 1, 69 | UPNG_NEW = 2 70 | } upng_state; 71 | 72 | typedef enum upng_color { 73 | UPNG_LUM = 0, 74 | UPNG_RGB = 2, 75 | UPNG_LUMA = 4, 76 | UPNG_RGBA = 6 77 | } upng_color; 78 | 79 | typedef struct upng_source { 80 | const unsigned char* buffer; 81 | unsigned long size; 82 | char owning; 83 | } upng_source; 84 | 85 | struct upng_t { 86 | unsigned width; 87 | unsigned height; 88 | 89 | upng_color color_type; 90 | unsigned color_depth; 91 | upng_format format; 92 | 93 | unsigned char* buffer; 94 | unsigned long size; 95 | 96 | upng_error error; 97 | unsigned error_line; 98 | 99 | upng_state state; 100 | upng_source source; 101 | }; 102 | 103 | typedef struct huffman_tree { 104 | unsigned* tree2d; 105 | unsigned maxbitlen; /*maximum number of bits a single code can get */ 106 | unsigned numcodes; /*number of symbols in the alphabet = number of codes */ 107 | } huffman_tree; 108 | 109 | static const unsigned LENGTH_BASE[29] = { /*the base lengths represented by codes 257-285 */ 110 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 111 | 67, 83, 99, 115, 131, 163, 195, 227, 258 112 | }; 113 | 114 | static const unsigned LENGTH_EXTRA[29] = { /*the extra bits used by codes 257-285 (added to base length) */ 115 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 116 | 5, 5, 5, 0 117 | }; 118 | 119 | static const unsigned DISTANCE_BASE[30] = { /*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree) */ 120 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 121 | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 122 | }; 123 | 124 | static const unsigned DISTANCE_EXTRA[30] = { /*the extra bits of backwards distances (added to base) */ 125 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 126 | 11, 11, 12, 12, 13, 13 127 | }; 128 | 129 | static const unsigned CLCL[NUM_CODE_LENGTH_CODES] /*the order in which "code length alphabet code lengths" are stored, out of this the huffman tree of the dynamic huffman tree lengths is generated */ 130 | = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; 131 | 132 | static const unsigned FIXED_DEFLATE_CODE_TREE[NUM_DEFLATE_CODE_SYMBOLS * 2] = { 133 | 289, 370, 290, 307, 546, 291, 561, 292, 293, 300, 294, 297, 295, 296, 0, 1, 134 | 2, 3, 298, 299, 4, 5, 6, 7, 301, 304, 302, 303, 8, 9, 10, 11, 305, 306, 12, 135 | 13, 14, 15, 308, 339, 309, 324, 310, 317, 311, 314, 312, 313, 16, 17, 18, 136 | 19, 315, 316, 20, 21, 22, 23, 318, 321, 319, 320, 24, 25, 26, 27, 322, 323, 137 | 28, 29, 30, 31, 325, 332, 326, 329, 327, 328, 32, 33, 34, 35, 330, 331, 36, 138 | 37, 38, 39, 333, 336, 334, 335, 40, 41, 42, 43, 337, 338, 44, 45, 46, 47, 139 | 340, 355, 341, 348, 342, 345, 343, 344, 48, 49, 50, 51, 346, 347, 52, 53, 140 | 54, 55, 349, 352, 350, 351, 56, 57, 58, 59, 353, 354, 60, 61, 62, 63, 356, 141 | 363, 357, 360, 358, 359, 64, 65, 66, 67, 361, 362, 68, 69, 70, 71, 364, 142 | 367, 365, 366, 72, 73, 74, 75, 368, 369, 76, 77, 78, 79, 371, 434, 372, 143 | 403, 373, 388, 374, 381, 375, 378, 376, 377, 80, 81, 82, 83, 379, 380, 84, 144 | 85, 86, 87, 382, 385, 383, 384, 88, 89, 90, 91, 386, 387, 92, 93, 94, 95, 145 | 389, 396, 390, 393, 391, 392, 96, 97, 98, 99, 394, 395, 100, 101, 102, 103, 146 | 397, 400, 398, 399, 104, 105, 106, 107, 401, 402, 108, 109, 110, 111, 404, 147 | 419, 405, 412, 406, 409, 407, 408, 112, 113, 114, 115, 410, 411, 116, 117, 148 | 118, 119, 413, 416, 414, 415, 120, 121, 122, 123, 417, 418, 124, 125, 126, 149 | 127, 420, 427, 421, 424, 422, 423, 128, 129, 130, 131, 425, 426, 132, 133, 150 | 134, 135, 428, 431, 429, 430, 136, 137, 138, 139, 432, 433, 140, 141, 142, 151 | 143, 435, 483, 436, 452, 568, 437, 438, 445, 439, 442, 440, 441, 144, 145, 152 | 146, 147, 443, 444, 148, 149, 150, 151, 446, 449, 447, 448, 152, 153, 154, 153 | 155, 450, 451, 156, 157, 158, 159, 453, 468, 454, 461, 455, 458, 456, 457, 154 | 160, 161, 162, 163, 459, 460, 164, 165, 166, 167, 462, 465, 463, 464, 168, 155 | 169, 170, 171, 466, 467, 172, 173, 174, 175, 469, 476, 470, 473, 471, 472, 156 | 176, 177, 178, 179, 474, 475, 180, 181, 182, 183, 477, 480, 478, 479, 184, 157 | 185, 186, 187, 481, 482, 188, 189, 190, 191, 484, 515, 485, 500, 486, 493, 158 | 487, 490, 488, 489, 192, 193, 194, 195, 491, 492, 196, 197, 198, 199, 494, 159 | 497, 495, 496, 200, 201, 202, 203, 498, 499, 204, 205, 206, 207, 501, 508, 160 | 502, 505, 503, 504, 208, 209, 210, 211, 506, 507, 212, 213, 214, 215, 509, 161 | 512, 510, 511, 216, 217, 218, 219, 513, 514, 220, 221, 222, 223, 516, 531, 162 | 517, 524, 518, 521, 519, 520, 224, 225, 226, 227, 522, 523, 228, 229, 230, 163 | 231, 525, 528, 526, 527, 232, 233, 234, 235, 529, 530, 236, 237, 238, 239, 164 | 532, 539, 533, 536, 534, 535, 240, 241, 242, 243, 537, 538, 244, 245, 246, 165 | 247, 540, 543, 541, 542, 248, 249, 250, 251, 544, 545, 252, 253, 254, 255, 166 | 547, 554, 548, 551, 549, 550, 256, 257, 258, 259, 552, 553, 260, 261, 262, 167 | 263, 555, 558, 556, 557, 264, 265, 266, 267, 559, 560, 268, 269, 270, 271, 168 | 562, 565, 563, 564, 272, 273, 274, 275, 566, 567, 276, 277, 278, 279, 569, 169 | 572, 570, 571, 280, 281, 282, 283, 573, 574, 284, 285, 286, 287, 0, 0 170 | }; 171 | 172 | static const unsigned FIXED_DISTANCE_TREE[NUM_DISTANCE_SYMBOLS * 2] = { 173 | 33, 48, 34, 41, 35, 38, 36, 37, 0, 1, 2, 3, 39, 40, 4, 5, 6, 7, 42, 45, 43, 174 | 44, 8, 9, 10, 11, 46, 47, 12, 13, 14, 15, 49, 56, 50, 53, 51, 52, 16, 17, 175 | 18, 19, 54, 55, 20, 21, 22, 23, 57, 60, 58, 59, 24, 25, 26, 27, 61, 62, 28, 176 | 29, 30, 31, 0, 0 177 | }; 178 | 179 | static unsigned char read_bit(unsigned long *bitpointer, const unsigned char *bitstream) 180 | { 181 | unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> ((*bitpointer) & 0x7)) & 1); 182 | (*bitpointer)++; 183 | return result; 184 | } 185 | 186 | static unsigned read_bits(unsigned long *bitpointer, const unsigned char *bitstream, unsigned long nbits) 187 | { 188 | unsigned result = 0, i; 189 | for (i = 0; i < nbits; i++) 190 | result |= ((unsigned)read_bit(bitpointer, bitstream)) << i; 191 | return result; 192 | } 193 | 194 | /* the buffer must be numcodes*2 in size! */ 195 | static void huffman_tree_init(huffman_tree* tree, unsigned* buffer, unsigned numcodes, unsigned maxbitlen) 196 | { 197 | tree->tree2d = buffer; 198 | 199 | tree->numcodes = numcodes; 200 | tree->maxbitlen = maxbitlen; 201 | } 202 | 203 | /*given the code lengths (as stored in the PNG file), generate the tree as defined by Deflate. maxbitlen is the maximum bits that a code in the tree can have. return value is error.*/ 204 | static void huffman_tree_create_lengths(upng_t* upng, huffman_tree* tree, const unsigned *bitlen) 205 | { 206 | unsigned tree1d[MAX_SYMBOLS]; 207 | unsigned blcount[MAX_BIT_LENGTH]; 208 | unsigned nextcode[MAX_BIT_LENGTH+1]; 209 | unsigned bits, n, i; 210 | unsigned nodefilled = 0; /*up to which node it is filled */ 211 | unsigned treepos = 0; /*position in the tree (1 of the numcodes columns) */ 212 | 213 | /* initialize local vectors */ 214 | memset(blcount, 0, sizeof(blcount)); 215 | memset(nextcode, 0, sizeof(nextcode)); 216 | 217 | /*step 1: count number of instances of each code length */ 218 | for (bits = 0; bits < tree->numcodes; bits++) { 219 | blcount[bitlen[bits]]++; 220 | } 221 | 222 | /*step 2: generate the nextcode values */ 223 | for (bits = 1; bits <= tree->maxbitlen; bits++) { 224 | nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1; 225 | } 226 | 227 | /*step 3: generate all the codes */ 228 | for (n = 0; n < tree->numcodes; n++) { 229 | if (bitlen[n] != 0) { 230 | tree1d[n] = nextcode[bitlen[n]]++; 231 | } 232 | } 233 | 234 | /*convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means uninited, a value >= numcodes is an address to another bit, a value < numcodes is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as many columns as codes - 1 235 | a good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. Here, the internal nodes are stored (what their 0 and 1 option point to). There is only memory for such good tree currently, if there are more nodes (due to too long length codes), error 55 will happen */ 236 | for (n = 0; n < tree->numcodes * 2; n++) { 237 | tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet */ 238 | } 239 | 240 | for (n = 0; n < tree->numcodes; n++) { /*the codes */ 241 | for (i = 0; i < bitlen[n]; i++) { /*the bits for this code */ 242 | unsigned char bit = (unsigned char)((tree1d[n] >> (bitlen[n] - i - 1)) & 1); 243 | /* check if oversubscribed */ 244 | if (treepos > tree->numcodes - 2) { 245 | SET_ERROR(upng, UPNG_EMALFORMED); 246 | return; 247 | } 248 | 249 | if (tree->tree2d[2 * treepos + bit] == 32767) { /*not yet filled in */ 250 | if (i + 1 == bitlen[n]) { /*last bit */ 251 | tree->tree2d[2 * treepos + bit] = n; /*put the current code in it */ 252 | treepos = 0; 253 | } else { /*put address of the next step in here, first that address has to be found of course (it's just nodefilled + 1)... */ 254 | nodefilled++; 255 | tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; /*addresses encoded with numcodes added to it */ 256 | treepos = nodefilled; 257 | } 258 | } else { 259 | treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; 260 | } 261 | } 262 | } 263 | 264 | for (n = 0; n < tree->numcodes * 2; n++) { 265 | if (tree->tree2d[n] == 32767) { 266 | tree->tree2d[n] = 0; /*remove possible remaining 32767's */ 267 | } 268 | } 269 | } 270 | 271 | static unsigned huffman_decode_symbol(upng_t *upng, const unsigned char *in, unsigned long *bp, const huffman_tree* codetree, unsigned long inlength) 272 | { 273 | unsigned treepos = 0, ct; 274 | unsigned char bit; 275 | for (;;) { 276 | /* error: end of input memory reached without endcode */ 277 | if (((*bp) & 0x07) == 0 && ((*bp) >> 3) > inlength) { 278 | SET_ERROR(upng, UPNG_EMALFORMED); 279 | return 0; 280 | } 281 | 282 | bit = read_bit(bp, in); 283 | 284 | ct = codetree->tree2d[(treepos << 1) | bit]; 285 | if (ct < codetree->numcodes) { 286 | return ct; 287 | } 288 | 289 | treepos = ct - codetree->numcodes; 290 | if (treepos >= codetree->numcodes) { 291 | SET_ERROR(upng, UPNG_EMALFORMED); 292 | return 0; 293 | } 294 | } 295 | } 296 | 297 | /* get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ 298 | static void get_tree_inflate_dynamic(upng_t* upng, huffman_tree* codetree, huffman_tree* codetreeD, huffman_tree* codelengthcodetree, const unsigned char *in, unsigned long *bp, unsigned long inlength) 299 | { 300 | unsigned codelengthcode[NUM_CODE_LENGTH_CODES]; 301 | unsigned bitlen[NUM_DEFLATE_CODE_SYMBOLS]; 302 | unsigned bitlenD[NUM_DISTANCE_SYMBOLS]; 303 | unsigned n, hlit, hdist, hclen, i; 304 | 305 | /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated */ 306 | /*C-code note: use no "return" between ctor and dtor of an uivector! */ 307 | if ((*bp) >> 3 >= inlength - 2) { 308 | SET_ERROR(upng, UPNG_EMALFORMED); 309 | return; 310 | } 311 | 312 | /* clear bitlen arrays */ 313 | memset(bitlen, 0, sizeof(bitlen)); 314 | memset(bitlenD, 0, sizeof(bitlenD)); 315 | 316 | /*the bit pointer is or will go past the memory */ 317 | hlit = read_bits(bp, in, 5) + 257; /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already */ 318 | hdist = read_bits(bp, in, 5) + 1; /*number of distance codes. Unlike the spec, the value 1 is added to it here already */ 319 | hclen = read_bits(bp, in, 4) + 4; /*number of code length codes. Unlike the spec, the value 4 is added to it here already */ 320 | 321 | for (i = 0; i < NUM_CODE_LENGTH_CODES; i++) { 322 | if (i < hclen) { 323 | codelengthcode[CLCL[i]] = read_bits(bp, in, 3); 324 | } else { 325 | codelengthcode[CLCL[i]] = 0; /*if not, it must stay 0 */ 326 | } 327 | } 328 | 329 | huffman_tree_create_lengths(upng, codelengthcodetree, codelengthcode); 330 | 331 | /* bail now if we encountered an error earlier */ 332 | if (upng->error != UPNG_EOK) { 333 | return; 334 | } 335 | 336 | /*now we can use this tree to read the lengths for the tree that this function will return */ 337 | i = 0; 338 | while (i < hlit + hdist) { /*i is the current symbol we're reading in the part that contains the code lengths of lit/len codes and dist codes */ 339 | unsigned code = huffman_decode_symbol(upng, in, bp, codelengthcodetree, inlength); 340 | if (upng->error != UPNG_EOK) { 341 | break; 342 | } 343 | 344 | if (code <= 15) { /*a length code */ 345 | if (i < hlit) { 346 | bitlen[i] = code; 347 | } else { 348 | bitlenD[i - hlit] = code; 349 | } 350 | i++; 351 | } else if (code == 16) { /*repeat previous */ 352 | unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6) */ 353 | unsigned value; /*set value to the previous code */ 354 | 355 | if ((*bp) >> 3 >= inlength) { 356 | SET_ERROR(upng, UPNG_EMALFORMED); 357 | break; 358 | } 359 | /*error, bit pointer jumps past memory */ 360 | replength += read_bits(bp, in, 2); 361 | 362 | if ((i - 1) < hlit) { 363 | value = bitlen[i - 1]; 364 | } else { 365 | value = bitlenD[i - hlit - 1]; 366 | } 367 | 368 | /*repeat this value in the next lengths */ 369 | for (n = 0; n < replength; n++) { 370 | /* i is larger than the amount of codes */ 371 | if (i >= hlit + hdist) { 372 | SET_ERROR(upng, UPNG_EMALFORMED); 373 | break; 374 | } 375 | 376 | if (i < hlit) { 377 | bitlen[i] = value; 378 | } else { 379 | bitlenD[i - hlit] = value; 380 | } 381 | i++; 382 | } 383 | } else if (code == 17) { /*repeat "0" 3-10 times */ 384 | unsigned replength = 3; /*read in the bits that indicate repeat length */ 385 | if ((*bp) >> 3 >= inlength) { 386 | SET_ERROR(upng, UPNG_EMALFORMED); 387 | break; 388 | } 389 | 390 | /*error, bit pointer jumps past memory */ 391 | replength += read_bits(bp, in, 3); 392 | 393 | /*repeat this value in the next lengths */ 394 | for (n = 0; n < replength; n++) { 395 | /* error: i is larger than the amount of codes */ 396 | if (i >= hlit + hdist) { 397 | SET_ERROR(upng, UPNG_EMALFORMED); 398 | break; 399 | } 400 | 401 | if (i < hlit) { 402 | bitlen[i] = 0; 403 | } else { 404 | bitlenD[i - hlit] = 0; 405 | } 406 | i++; 407 | } 408 | } else if (code == 18) { /*repeat "0" 11-138 times */ 409 | unsigned replength = 11; /*read in the bits that indicate repeat length */ 410 | /* error, bit pointer jumps past memory */ 411 | if ((*bp) >> 3 >= inlength) { 412 | SET_ERROR(upng, UPNG_EMALFORMED); 413 | break; 414 | } 415 | 416 | replength += read_bits(bp, in, 7); 417 | 418 | /*repeat this value in the next lengths */ 419 | for (n = 0; n < replength; n++) { 420 | /* i is larger than the amount of codes */ 421 | if (i >= hlit + hdist) { 422 | SET_ERROR(upng, UPNG_EMALFORMED); 423 | break; 424 | } 425 | if (i < hlit) 426 | bitlen[i] = 0; 427 | else 428 | bitlenD[i - hlit] = 0; 429 | i++; 430 | } 431 | } else { 432 | /* somehow an unexisting code appeared. This can never happen. */ 433 | SET_ERROR(upng, UPNG_EMALFORMED); 434 | break; 435 | } 436 | } 437 | 438 | if (upng->error == UPNG_EOK && bitlen[256] == 0) { 439 | SET_ERROR(upng, UPNG_EMALFORMED); 440 | } 441 | 442 | /*the length of the end code 256 must be larger than 0 */ 443 | /*now we've finally got hlit and hdist, so generate the code trees, and the function is done */ 444 | if (upng->error == UPNG_EOK) { 445 | huffman_tree_create_lengths(upng, codetree, bitlen); 446 | } 447 | if (upng->error == UPNG_EOK) { 448 | huffman_tree_create_lengths(upng, codetreeD, bitlenD); 449 | } 450 | } 451 | 452 | /*inflate a block with dynamic of fixed Huffman tree*/ 453 | static void inflate_huffman(upng_t* upng, unsigned char* out, unsigned long outsize, const unsigned char *in, unsigned long *bp, unsigned long *pos, unsigned long inlength, unsigned btype) 454 | { 455 | unsigned codetree_buffer[DEFLATE_CODE_BUFFER_SIZE]; 456 | unsigned codetreeD_buffer[DISTANCE_BUFFER_SIZE]; 457 | unsigned done = 0; 458 | 459 | huffman_tree codetree; 460 | huffman_tree codetreeD; 461 | 462 | if (btype == 1) { 463 | /* fixed trees */ 464 | huffman_tree_init(&codetree, (unsigned*)FIXED_DEFLATE_CODE_TREE, NUM_DEFLATE_CODE_SYMBOLS, DEFLATE_CODE_BITLEN); 465 | huffman_tree_init(&codetreeD, (unsigned*)FIXED_DISTANCE_TREE, NUM_DISTANCE_SYMBOLS, DISTANCE_BITLEN); 466 | } else if (btype == 2) { 467 | /* dynamic trees */ 468 | unsigned codelengthcodetree_buffer[CODE_LENGTH_BUFFER_SIZE]; 469 | huffman_tree codelengthcodetree; 470 | 471 | huffman_tree_init(&codetree, codetree_buffer, NUM_DEFLATE_CODE_SYMBOLS, DEFLATE_CODE_BITLEN); 472 | huffman_tree_init(&codetreeD, codetreeD_buffer, NUM_DISTANCE_SYMBOLS, DISTANCE_BITLEN); 473 | huffman_tree_init(&codelengthcodetree, codelengthcodetree_buffer, NUM_CODE_LENGTH_CODES, CODE_LENGTH_BITLEN); 474 | get_tree_inflate_dynamic(upng, &codetree, &codetreeD, &codelengthcodetree, in, bp, inlength); 475 | } 476 | 477 | while (done == 0) { 478 | unsigned code = huffman_decode_symbol(upng, in, bp, &codetree, inlength); 479 | if (upng->error != UPNG_EOK) { 480 | return; 481 | } 482 | 483 | if (code == 256) { 484 | /* end code */ 485 | done = 1; 486 | } else if (code <= 255) { 487 | /* literal symbol */ 488 | if ((*pos) >= outsize) { 489 | SET_ERROR(upng, UPNG_EMALFORMED); 490 | return; 491 | } 492 | 493 | /* store output */ 494 | out[(*pos)++] = (unsigned char)(code); 495 | } else if (code >= FIRST_LENGTH_CODE_INDEX && code <= LAST_LENGTH_CODE_INDEX) { /*length code */ 496 | /* part 1: get length base */ 497 | unsigned long length = LENGTH_BASE[code - FIRST_LENGTH_CODE_INDEX]; 498 | unsigned codeD, distance, numextrabitsD; 499 | unsigned long start, forward, backward, numextrabits; 500 | 501 | /* part 2: get extra bits and add the value of that to length */ 502 | numextrabits = LENGTH_EXTRA[code - FIRST_LENGTH_CODE_INDEX]; 503 | 504 | /* error, bit pointer will jump past memory */ 505 | if (((*bp) >> 3) >= inlength) { 506 | SET_ERROR(upng, UPNG_EMALFORMED); 507 | return; 508 | } 509 | length += read_bits(bp, in, numextrabits); 510 | 511 | /*part 3: get distance code */ 512 | codeD = huffman_decode_symbol(upng, in, bp, &codetreeD, inlength); 513 | if (upng->error != UPNG_EOK) { 514 | return; 515 | } 516 | 517 | /* invalid distance code (30-31 are never used) */ 518 | if (codeD > 29) { 519 | SET_ERROR(upng, UPNG_EMALFORMED); 520 | return; 521 | } 522 | 523 | distance = DISTANCE_BASE[codeD]; 524 | 525 | /*part 4: get extra bits from distance */ 526 | numextrabitsD = DISTANCE_EXTRA[codeD]; 527 | 528 | /* error, bit pointer will jump past memory */ 529 | if (((*bp) >> 3) >= inlength) { 530 | SET_ERROR(upng, UPNG_EMALFORMED); 531 | return; 532 | } 533 | 534 | distance += read_bits(bp, in, numextrabitsD); 535 | 536 | /*part 5: fill in all the out[n] values based on the length and dist */ 537 | start = (*pos); 538 | backward = start - distance; 539 | 540 | if ((*pos) + length >= outsize) { 541 | SET_ERROR(upng, UPNG_EMALFORMED); 542 | return; 543 | } 544 | 545 | for (forward = 0; forward < length; forward++) { 546 | out[(*pos)++] = out[backward]; 547 | backward++; 548 | 549 | if (backward >= start) { 550 | backward = start - distance; 551 | } 552 | } 553 | } 554 | } 555 | } 556 | 557 | static void inflate_uncompressed(upng_t* upng, unsigned char* out, unsigned long outsize, const unsigned char *in, unsigned long *bp, unsigned long *pos, unsigned long inlength) 558 | { 559 | unsigned long p; 560 | unsigned len, nlen, n; 561 | 562 | /* go to first boundary of byte */ 563 | while (((*bp) & 0x7) != 0) { 564 | (*bp)++; 565 | } 566 | p = (*bp) / 8; /*byte position */ 567 | 568 | /* read len (2 bytes) and nlen (2 bytes) */ 569 | if (p >= inlength - 4) { 570 | SET_ERROR(upng, UPNG_EMALFORMED); 571 | return; 572 | } 573 | 574 | len = in[p] + 256 * in[p + 1]; 575 | p += 2; 576 | nlen = in[p] + 256 * in[p + 1]; 577 | p += 2; 578 | 579 | /* check if 16-bit nlen is really the one's complement of len */ 580 | if (len + nlen != 65535) { 581 | SET_ERROR(upng, UPNG_EMALFORMED); 582 | return; 583 | } 584 | 585 | if ((*pos) + len >= outsize) { 586 | SET_ERROR(upng, UPNG_EMALFORMED); 587 | return; 588 | } 589 | 590 | /* read the literal data: len bytes are now stored in the out buffer */ 591 | if (p + len > inlength) { 592 | SET_ERROR(upng, UPNG_EMALFORMED); 593 | return; 594 | } 595 | 596 | for (n = 0; n < len; n++) { 597 | out[(*pos)++] = in[p++]; 598 | } 599 | 600 | (*bp) = p * 8; 601 | } 602 | 603 | /*inflate the deflated data (cfr. deflate spec); return value is the error*/ 604 | static upng_error uz_inflate_data(upng_t* upng, unsigned char* out, unsigned long outsize, const unsigned char *in, unsigned long insize, unsigned long inpos) 605 | { 606 | unsigned long bp = 0; /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte) */ 607 | unsigned long pos = 0; /*byte position in the out buffer */ 608 | 609 | unsigned done = 0; 610 | 611 | while (done == 0) { 612 | unsigned btype; 613 | 614 | /* ensure next bit doesn't point past the end of the buffer */ 615 | if ((bp >> 3) >= insize) { 616 | SET_ERROR(upng, UPNG_EMALFORMED); 617 | return upng->error; 618 | } 619 | 620 | /* read block control bits */ 621 | done = read_bit(&bp, &in[inpos]); 622 | btype = read_bit(&bp, &in[inpos]) | (read_bit(&bp, &in[inpos]) << 1); 623 | 624 | /* process control type appropriateyly */ 625 | if (btype == 3) { 626 | SET_ERROR(upng, UPNG_EMALFORMED); 627 | return upng->error; 628 | } else if (btype == 0) { 629 | inflate_uncompressed(upng, out, outsize, &in[inpos], &bp, &pos, insize); /*no compression */ 630 | } else { 631 | inflate_huffman(upng, out, outsize, &in[inpos], &bp, &pos, insize, btype); /*compression, btype 01 or 10 */ 632 | } 633 | 634 | /* stop if an error has occured */ 635 | if (upng->error != UPNG_EOK) { 636 | return upng->error; 637 | } 638 | } 639 | 640 | return upng->error; 641 | } 642 | 643 | static upng_error uz_inflate(upng_t* upng, unsigned char *out, unsigned long outsize, const unsigned char *in, unsigned long insize) 644 | { 645 | /* we require two bytes for the zlib data header */ 646 | if (insize < 2) { 647 | SET_ERROR(upng, UPNG_EMALFORMED); 648 | return upng->error; 649 | } 650 | 651 | /* 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way */ 652 | if ((in[0] * 256 + in[1]) % 31 != 0) { 653 | SET_ERROR(upng, UPNG_EMALFORMED); 654 | return upng->error; 655 | } 656 | 657 | /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec */ 658 | if ((in[0] & 15) != 8 || ((in[0] >> 4) & 15) > 7) { 659 | SET_ERROR(upng, UPNG_EMALFORMED); 660 | return upng->error; 661 | } 662 | 663 | /* the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary." */ 664 | if (((in[1] >> 5) & 1) != 0) { 665 | SET_ERROR(upng, UPNG_EMALFORMED); 666 | return upng->error; 667 | } 668 | 669 | /* create output buffer */ 670 | uz_inflate_data(upng, out, outsize, in, insize, 2); 671 | 672 | return upng->error; 673 | } 674 | 675 | /*Paeth predicter, used by PNG filter type 4*/ 676 | static int paeth_predictor(int a, int b, int c) 677 | { 678 | int p = a + b - c; 679 | int pa = p > a ? p - a : a - p; 680 | int pb = p > b ? p - b : b - p; 681 | int pc = p > c ? p - c : c - p; 682 | 683 | if (pa <= pb && pa <= pc) 684 | return a; 685 | else if (pb <= pc) 686 | return b; 687 | else 688 | return c; 689 | } 690 | 691 | static void unfilter_scanline(upng_t* upng, unsigned char *recon, const unsigned char *scanline, const unsigned char *precon, unsigned long bytewidth, unsigned char filterType, unsigned long length) 692 | { 693 | /* 694 | For PNG filter method 0 695 | unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1) 696 | precon is the previous unfiltered scanline, recon the result, scanline the current one 697 | the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead 698 | recon and scanline MAY be the same memory address! precon must be disjoint. 699 | */ 700 | 701 | unsigned long i; 702 | switch (filterType) { 703 | case 0: 704 | for (i = 0; i < length; i++) 705 | recon[i] = scanline[i]; 706 | break; 707 | case 1: 708 | for (i = 0; i < bytewidth; i++) 709 | recon[i] = scanline[i]; 710 | for (i = bytewidth; i < length; i++) 711 | recon[i] = scanline[i] + recon[i - bytewidth]; 712 | break; 713 | case 2: 714 | if (precon) 715 | for (i = 0; i < length; i++) 716 | recon[i] = scanline[i] + precon[i]; 717 | else 718 | for (i = 0; i < length; i++) 719 | recon[i] = scanline[i]; 720 | break; 721 | case 3: 722 | if (precon) { 723 | for (i = 0; i < bytewidth; i++) 724 | recon[i] = scanline[i] + precon[i] / 2; 725 | for (i = bytewidth; i < length; i++) 726 | recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); 727 | } else { 728 | for (i = 0; i < bytewidth; i++) 729 | recon[i] = scanline[i]; 730 | for (i = bytewidth; i < length; i++) 731 | recon[i] = scanline[i] + recon[i - bytewidth] / 2; 732 | } 733 | break; 734 | case 4: 735 | if (precon) { 736 | for (i = 0; i < bytewidth; i++) 737 | recon[i] = (unsigned char)(scanline[i] + paeth_predictor(0, precon[i], 0)); 738 | for (i = bytewidth; i < length; i++) 739 | recon[i] = (unsigned char)(scanline[i] + paeth_predictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); 740 | } else { 741 | for (i = 0; i < bytewidth; i++) 742 | recon[i] = scanline[i]; 743 | for (i = bytewidth; i < length; i++) 744 | recon[i] = (unsigned char)(scanline[i] + paeth_predictor(recon[i - bytewidth], 0, 0)); 745 | } 746 | break; 747 | default: 748 | SET_ERROR(upng, UPNG_EMALFORMED); 749 | break; 750 | } 751 | } 752 | 753 | static void unfilter(upng_t* upng, unsigned char *out, const unsigned char *in, unsigned w, unsigned h, unsigned bpp) 754 | { 755 | /* 756 | For PNG filter method 0 757 | this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 it's called 7 times) 758 | out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline 759 | w and h are image dimensions or dimensions of reduced image, bpp is bpp per pixel 760 | in and out are allowed to be the same memory address! 761 | */ 762 | 763 | unsigned y; 764 | unsigned char *prevline = 0; 765 | 766 | unsigned long bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise */ 767 | unsigned long linebytes = (w * bpp + 7) / 8; 768 | 769 | for (y = 0; y < h; y++) { 770 | unsigned long outindex = linebytes * y; 771 | unsigned long inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row */ 772 | unsigned char filterType = in[inindex]; 773 | 774 | unfilter_scanline(upng, &out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes); 775 | if (upng->error != UPNG_EOK) { 776 | return; 777 | } 778 | 779 | prevline = &out[outindex]; 780 | } 781 | } 782 | 783 | static void remove_padding_bits(unsigned char *out, const unsigned char *in, unsigned long olinebits, unsigned long ilinebits, unsigned h) 784 | { 785 | /* 786 | After filtering there are still padding bpp if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user. 787 | in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bpp, out must have >= olinebits*h bpp, olinebits must be <= ilinebits 788 | also used to move bpp after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 789 | only useful if (ilinebits - olinebits) is a value in the range 1..7 790 | */ 791 | unsigned y; 792 | unsigned long diff = ilinebits - olinebits; 793 | unsigned long obp = 0, ibp = 0; /*bit pointers */ 794 | for (y = 0; y < h; y++) { 795 | unsigned long x; 796 | for (x = 0; x < olinebits; x++) { 797 | unsigned char bit = (unsigned char)((in[(ibp) >> 3] >> (7 - ((ibp) & 0x7))) & 1); 798 | ibp++; 799 | 800 | if (bit == 0) 801 | out[(obp) >> 3] &= (unsigned char)(~(1 << (7 - ((obp) & 0x7)))); 802 | else 803 | out[(obp) >> 3] |= (1 << (7 - ((obp) & 0x7))); 804 | ++obp; 805 | } 806 | ibp += diff; 807 | } 808 | } 809 | 810 | /*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks*/ 811 | static void post_process_scanlines(upng_t* upng, unsigned char *out, unsigned char *in, const upng_t* info_png) 812 | { 813 | unsigned bpp = upng_get_bpp(info_png); 814 | unsigned w = info_png->width; 815 | unsigned h = info_png->height; 816 | 817 | if (bpp == 0) { 818 | SET_ERROR(upng, UPNG_EMALFORMED); 819 | return; 820 | } 821 | 822 | if (bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { 823 | unfilter(upng, in, in, w, h, bpp); 824 | if (upng->error != UPNG_EOK) { 825 | return; 826 | } 827 | remove_padding_bits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); 828 | } else { 829 | unfilter(upng, out, in, w, h, bpp); /*we can immediatly filter into the out buffer, no other steps needed */ 830 | } 831 | } 832 | 833 | static upng_format determine_format(upng_t* upng) { 834 | switch (upng->color_type) { 835 | case UPNG_LUM: 836 | switch (upng->color_depth) { 837 | case 1: 838 | return UPNG_LUMINANCE1; 839 | case 2: 840 | return UPNG_LUMINANCE2; 841 | case 4: 842 | return UPNG_LUMINANCE4; 843 | case 8: 844 | return UPNG_LUMINANCE8; 845 | default: 846 | return UPNG_BADFORMAT; 847 | } 848 | case UPNG_RGB: 849 | switch (upng->color_depth) { 850 | case 8: 851 | return UPNG_RGB8; 852 | case 16: 853 | return UPNG_RGB16; 854 | default: 855 | return UPNG_BADFORMAT; 856 | } 857 | case UPNG_LUMA: 858 | switch (upng->color_depth) { 859 | case 1: 860 | return UPNG_LUMINANCE_ALPHA1; 861 | case 2: 862 | return UPNG_LUMINANCE_ALPHA2; 863 | case 4: 864 | return UPNG_LUMINANCE_ALPHA4; 865 | case 8: 866 | return UPNG_LUMINANCE_ALPHA8; 867 | default: 868 | return UPNG_BADFORMAT; 869 | } 870 | case UPNG_RGBA: 871 | switch (upng->color_depth) { 872 | case 8: 873 | return UPNG_RGBA8; 874 | case 16: 875 | return UPNG_RGBA16; 876 | default: 877 | return UPNG_BADFORMAT; 878 | } 879 | default: 880 | return UPNG_BADFORMAT; 881 | } 882 | } 883 | 884 | static void upng_free_source(upng_t* upng) 885 | { 886 | if (upng->source.owning != 0) { 887 | free((void*)upng->source.buffer); 888 | } 889 | 890 | upng->source.buffer = NULL; 891 | upng->source.size = 0; 892 | upng->source.owning = 0; 893 | } 894 | 895 | /*read the information from the header and store it in the upng_Info. return value is error*/ 896 | upng_error upng_header(upng_t* upng) 897 | { 898 | /* if we have an error state, bail now */ 899 | if (upng->error != UPNG_EOK) { 900 | return upng->error; 901 | } 902 | 903 | /* if the state is not NEW (meaning we are ready to parse the header), stop now */ 904 | if (upng->state != UPNG_NEW) { 905 | return upng->error; 906 | } 907 | 908 | /* minimum length of a valid PNG file is 29 bytes 909 | * FIXME: verify this against the specification, or 910 | * better against the actual code below */ 911 | if (upng->source.size < 29) { 912 | SET_ERROR(upng, UPNG_ENOTPNG); 913 | return upng->error; 914 | } 915 | 916 | /* check that PNG header matches expected value */ 917 | if (upng->source.buffer[0] != 137 || upng->source.buffer[1] != 80 || upng->source.buffer[2] != 78 || upng->source.buffer[3] != 71 || upng->source.buffer[4] != 13 || upng->source.buffer[5] != 10 || upng->source.buffer[6] != 26 || upng->source.buffer[7] != 10) { 918 | SET_ERROR(upng, UPNG_ENOTPNG); 919 | return upng->error; 920 | } 921 | 922 | /* check that the first chunk is the IHDR chunk */ 923 | if (MAKE_DWORD_PTR(upng->source.buffer + 12) != CHUNK_IHDR) { 924 | SET_ERROR(upng, UPNG_EMALFORMED); 925 | return upng->error; 926 | } 927 | 928 | /* read the values given in the header */ 929 | upng->width = MAKE_DWORD_PTR(upng->source.buffer + 16); 930 | upng->height = MAKE_DWORD_PTR(upng->source.buffer + 20); 931 | upng->color_depth = upng->source.buffer[24]; 932 | upng->color_type = (upng_color)upng->source.buffer[25]; 933 | 934 | /* determine our color format */ 935 | upng->format = determine_format(upng); 936 | if (upng->format == UPNG_BADFORMAT) { 937 | SET_ERROR(upng, UPNG_EUNFORMAT); 938 | return upng->error; 939 | } 940 | 941 | /* check that the compression method (byte 27) is 0 (only allowed value in spec) */ 942 | if (upng->source.buffer[26] != 0) { 943 | SET_ERROR(upng, UPNG_EMALFORMED); 944 | return upng->error; 945 | } 946 | 947 | /* check that the compression method (byte 27) is 0 (only allowed value in spec) */ 948 | if (upng->source.buffer[27] != 0) { 949 | SET_ERROR(upng, UPNG_EMALFORMED); 950 | return upng->error; 951 | } 952 | 953 | /* check that the compression method (byte 27) is 0 (spec allows 1, but uPNG does not support it) */ 954 | if (upng->source.buffer[28] != 0) { 955 | SET_ERROR(upng, UPNG_EUNINTERLACED); 956 | return upng->error; 957 | } 958 | 959 | upng->state = UPNG_HEADER; 960 | return upng->error; 961 | } 962 | 963 | /*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ 964 | upng_error upng_decode(upng_t* upng) 965 | { 966 | const unsigned char *chunk; 967 | unsigned char* compressed; 968 | unsigned char* inflated; 969 | unsigned long compressed_size = 0, compressed_index = 0; 970 | unsigned long inflated_size; 971 | upng_error error; 972 | 973 | /* if we have an error state, bail now */ 974 | if (upng->error != UPNG_EOK) { 975 | return upng->error; 976 | } 977 | 978 | /* parse the main header, if necessary */ 979 | upng_header(upng); 980 | if (upng->error != UPNG_EOK) { 981 | return upng->error; 982 | } 983 | 984 | /* if the state is not HEADER (meaning we are ready to decode the image), stop now */ 985 | if (upng->state != UPNG_HEADER) { 986 | return upng->error; 987 | } 988 | 989 | /* release old result, if any */ 990 | if (upng->buffer != 0) { 991 | free(upng->buffer); 992 | upng->buffer = 0; 993 | upng->size = 0; 994 | } 995 | 996 | /* first byte of the first chunk after the header */ 997 | chunk = upng->source.buffer + 33; 998 | 999 | /* scan through the chunks, finding the size of all IDAT chunks, and also 1000 | * verify general well-formed-ness */ 1001 | while (chunk < upng->source.buffer + upng->source.size) { 1002 | unsigned long length; 1003 | const unsigned char *data; /*the data in the chunk */ 1004 | 1005 | /* make sure chunk header is not larger than the total compressed */ 1006 | if ((unsigned long)(chunk - upng->source.buffer + 12) > upng->source.size) { 1007 | SET_ERROR(upng, UPNG_EMALFORMED); 1008 | return upng->error; 1009 | } 1010 | 1011 | /* get length; sanity check it */ 1012 | length = upng_chunk_length(chunk); 1013 | if (length > INT_MAX) { 1014 | SET_ERROR(upng, UPNG_EMALFORMED); 1015 | return upng->error; 1016 | } 1017 | 1018 | /* make sure chunk header+paylaod is not larger than the total compressed */ 1019 | if ((unsigned long)(chunk - upng->source.buffer + length + 12) > upng->source.size) { 1020 | SET_ERROR(upng, UPNG_EMALFORMED); 1021 | return upng->error; 1022 | } 1023 | 1024 | /* get pointer to payload */ 1025 | data = chunk + 8; 1026 | 1027 | /* parse chunks */ 1028 | if (upng_chunk_type(chunk) == CHUNK_IDAT) { 1029 | compressed_size += length; 1030 | } else if (upng_chunk_type(chunk) == CHUNK_IEND) { 1031 | break; 1032 | } else if (upng_chunk_critical(chunk)) { 1033 | SET_ERROR(upng, UPNG_EUNSUPPORTED); 1034 | return upng->error; 1035 | } 1036 | 1037 | chunk += upng_chunk_length(chunk) + 12; 1038 | } 1039 | 1040 | /* allocate enough space for the (compressed and filtered) image data */ 1041 | compressed = (unsigned char*)malloc(compressed_size); 1042 | if (compressed == NULL) { 1043 | SET_ERROR(upng, UPNG_ENOMEM); 1044 | return upng->error; 1045 | } 1046 | 1047 | /* scan through the chunks again, this time copying the values into 1048 | * our compressed buffer. there's no reason to validate anything a second time. */ 1049 | chunk = upng->source.buffer + 33; 1050 | while (chunk < upng->source.buffer + upng->source.size) { 1051 | unsigned long length; 1052 | const unsigned char *data; /*the data in the chunk */ 1053 | 1054 | length = upng_chunk_length(chunk); 1055 | data = chunk + 8; 1056 | 1057 | /* parse chunks */ 1058 | if (upng_chunk_type(chunk) == CHUNK_IDAT) { 1059 | memcpy(compressed + compressed_index, data, length); 1060 | compressed_index += length; 1061 | } else if (upng_chunk_type(chunk) == CHUNK_IEND) { 1062 | break; 1063 | } 1064 | 1065 | chunk += upng_chunk_length(chunk) + 12; 1066 | } 1067 | 1068 | /* allocate space to store inflated (but still filtered) data */ 1069 | inflated_size = ((upng->width * (upng->height * upng_get_bpp(upng) + 7)) / 8) + upng->height; 1070 | inflated = (unsigned char*)malloc(inflated_size); 1071 | if (inflated == NULL) { 1072 | free(compressed); 1073 | SET_ERROR(upng, UPNG_ENOMEM); 1074 | return upng->error; 1075 | } 1076 | 1077 | /* decompress image data */ 1078 | error = uz_inflate(upng, inflated, inflated_size, compressed, compressed_size); 1079 | if (error != UPNG_EOK) { 1080 | free(compressed); 1081 | free(inflated); 1082 | return upng->error; 1083 | } 1084 | 1085 | /* free the compressed compressed data */ 1086 | free(compressed); 1087 | 1088 | /* allocate final image buffer */ 1089 | upng->size = (upng->height * upng->width * upng_get_bpp(upng) + 7) / 8; 1090 | upng->buffer = (unsigned char*)malloc(upng->size); 1091 | if (upng->buffer == NULL) { 1092 | free(inflated); 1093 | upng->size = 0; 1094 | SET_ERROR(upng, UPNG_ENOMEM); 1095 | return upng->error; 1096 | } 1097 | 1098 | /* unfilter scanlines */ 1099 | post_process_scanlines(upng, upng->buffer, inflated, upng); 1100 | free(inflated); 1101 | 1102 | if (upng->error != UPNG_EOK) { 1103 | free(upng->buffer); 1104 | upng->buffer = NULL; 1105 | upng->size = 0; 1106 | } else { 1107 | upng->state = UPNG_DECODED; 1108 | } 1109 | 1110 | /* we are done with our input buffer; free it if we own it */ 1111 | upng_free_source(upng); 1112 | 1113 | return upng->error; 1114 | } 1115 | 1116 | static upng_t* upng_new(void) 1117 | { 1118 | upng_t* upng; 1119 | 1120 | upng = (upng_t*)malloc(sizeof(upng_t)); 1121 | if (upng == NULL) { 1122 | return NULL; 1123 | } 1124 | 1125 | upng->buffer = NULL; 1126 | upng->size = 0; 1127 | 1128 | upng->width = upng->height = 0; 1129 | 1130 | upng->color_type = UPNG_RGBA; 1131 | upng->color_depth = 8; 1132 | upng->format = UPNG_RGBA8; 1133 | 1134 | upng->state = UPNG_NEW; 1135 | 1136 | upng->error = UPNG_EOK; 1137 | upng->error_line = 0; 1138 | 1139 | upng->source.buffer = NULL; 1140 | upng->source.size = 0; 1141 | upng->source.owning = 0; 1142 | 1143 | return upng; 1144 | } 1145 | 1146 | upng_t* upng_new_from_bytes(const unsigned char* buffer, unsigned long size) 1147 | { 1148 | upng_t* upng = upng_new(); 1149 | if (upng == NULL) { 1150 | return NULL; 1151 | } 1152 | 1153 | upng->source.buffer = buffer; 1154 | upng->source.size = size; 1155 | upng->source.owning = 0; 1156 | 1157 | return upng; 1158 | } 1159 | 1160 | upng_t* upng_new_from_file(const char *filename) 1161 | { 1162 | upng_t* upng; 1163 | unsigned char *buffer; 1164 | FILE *file; 1165 | long size; 1166 | 1167 | upng = upng_new(); 1168 | if (upng == NULL) { 1169 | return NULL; 1170 | } 1171 | 1172 | file = fopen(filename, "rb"); 1173 | if (file == NULL) { 1174 | SET_ERROR(upng, UPNG_ENOTFOUND); 1175 | return upng; 1176 | } 1177 | 1178 | /* get filesize */ 1179 | fseek(file, 0, SEEK_END); 1180 | size = ftell(file); 1181 | rewind(file); 1182 | 1183 | /* read contents of the file into the vector */ 1184 | buffer = (unsigned char *)malloc((unsigned long)size); 1185 | if (buffer == NULL) { 1186 | fclose(file); 1187 | SET_ERROR(upng, UPNG_ENOMEM); 1188 | return upng; 1189 | } 1190 | fread(buffer, 1, (unsigned long)size, file); 1191 | fclose(file); 1192 | 1193 | /* set the read buffer as our source buffer, with owning flag set */ 1194 | upng->source.buffer = buffer; 1195 | upng->source.size = size; 1196 | upng->source.owning = 1; 1197 | 1198 | return upng; 1199 | } 1200 | 1201 | void upng_free(upng_t* upng) 1202 | { 1203 | /* deallocate image buffer */ 1204 | if (upng->buffer != NULL) { 1205 | free(upng->buffer); 1206 | } 1207 | 1208 | /* deallocate source buffer, if necessary */ 1209 | upng_free_source(upng); 1210 | 1211 | /* deallocate struct itself */ 1212 | free(upng); 1213 | } 1214 | 1215 | upng_error upng_get_error(const upng_t* upng) 1216 | { 1217 | return upng->error; 1218 | } 1219 | 1220 | unsigned upng_get_error_line(const upng_t* upng) 1221 | { 1222 | return upng->error_line; 1223 | } 1224 | 1225 | unsigned upng_get_width(const upng_t* upng) 1226 | { 1227 | return upng->width; 1228 | } 1229 | 1230 | unsigned upng_get_height(const upng_t* upng) 1231 | { 1232 | return upng->height; 1233 | } 1234 | 1235 | unsigned upng_get_bpp(const upng_t* upng) 1236 | { 1237 | return upng_get_bitdepth(upng) * upng_get_components(upng); 1238 | } 1239 | 1240 | unsigned upng_get_components(const upng_t* upng) 1241 | { 1242 | switch (upng->color_type) { 1243 | case UPNG_LUM: 1244 | return 1; 1245 | case UPNG_RGB: 1246 | return 3; 1247 | case UPNG_LUMA: 1248 | return 2; 1249 | case UPNG_RGBA: 1250 | return 4; 1251 | default: 1252 | return 0; 1253 | } 1254 | } 1255 | 1256 | unsigned upng_get_bitdepth(const upng_t* upng) 1257 | { 1258 | return upng->color_depth; 1259 | } 1260 | 1261 | unsigned upng_get_pixelsize(const upng_t* upng) 1262 | { 1263 | unsigned bits = upng_get_bitdepth(upng) * upng_get_components(upng); 1264 | bits += bits % 8; 1265 | return bits; 1266 | } 1267 | 1268 | upng_format upng_get_format(const upng_t* upng) 1269 | { 1270 | return upng->format; 1271 | } 1272 | 1273 | const unsigned char* upng_get_buffer(const upng_t* upng) 1274 | { 1275 | return upng->buffer; 1276 | } 1277 | 1278 | unsigned upng_get_size(const upng_t* upng) 1279 | { 1280 | return upng->size; 1281 | } 1282 | --------------------------------------------------------------------------------