Browse Source

Merge branch 'master' of https://github.com/godotengine/godot

Juan Linietsky 9 years ago
parent
commit
15429d6ac9
53 changed files with 3799 additions and 3139 deletions
  1. 20 0
      core/bind/core_bind.cpp
  2. 2 0
      core/bind/core_bind.h
  3. 1 1
      core/os/input.h
  4. 5 0
      core/os/thread.cpp
  5. 3 1
      core/os/thread.h
  6. 4 2
      drivers/png/SCsub
  7. 232 0
      drivers/png/arm/arm_init.c
  8. 11 1
      drivers/png/arm/filter_neon.S
  9. 51 34
      drivers/png/example.c
  10. 231 167
      drivers/png/png.c
  11. 212 278
      drivers/png/png.h
  12. 37 35
      drivers/png/pngconf.h
  13. 9 13
      drivers/png/pngdebug.h
  14. 46 34
      drivers/png/pngerror.c
  15. 55 9
      drivers/png/pngget.c
  16. 3 4
      drivers/png/pnginfo.h
  17. 81 83
      drivers/png/pnglibconf.h
  18. 6 6
      drivers/png/pngmem.c
  19. 38 657
      drivers/png/pngpread.c
  20. 182 54
      drivers/png/pngpriv.h
  21. 20 30
      drivers/png/pngread.c
  22. 2 2
      drivers/png/pngrio.c
  23. 139 89
      drivers/png/pngrtran.c
  24. 118 127
      drivers/png/pngrutil.c
  25. 220 63
      drivers/png/pngset.c
  26. 16 23
      drivers/png/pngstruct.h
  27. 109 6
      drivers/png/pngtrans.c
  28. 4 2
      drivers/png/pngwio.c
  29. 112 315
      drivers/png/pngwrite.c
  30. 16 4
      drivers/png/pngwtran.c
  31. 60 560
      drivers/png/pngwutil.c
  32. 25 1
      drivers/unix/thread_posix.cpp
  33. 1 0
      drivers/unix/thread_posix.h
  34. 435 6
      main/input_default.cpp
  35. 89 5
      main/input_default.h
  36. 2 0
      platform/iphone/platform_config.h
  37. 1 0
      platform/osx/platform_config.h
  38. 1 0
      platform/windows/SCsub
  39. 2 2
      platform/windows/detect.py
  40. 3 3
      platform/windows/godot_res.rc
  41. 528 0
      platform/windows/joystick.cpp
  42. 139 0
      platform/windows/joystick.h
  43. 8 260
      platform/windows/os_windows.cpp
  44. 4 37
      platform/windows/os_windows.h
  45. 1 0
      platform/x11/SCsub
  46. 1 1
      platform/x11/detect.py
  47. 402 0
      platform/x11/joystick_linux.cpp
  48. 93 0
      platform/x11/joystick_linux.h
  49. 9 193
      platform/x11/os_x11.cpp
  50. 6 25
      platform/x11/os_x11.h
  51. 2 1
      servers/audio/audio_server_sw.cpp
  52. 1 4
      tools/editor/editor_import_export.cpp
  53. 1 1
      tools/editor/plugins/script_editor_plugin.cpp

+ 20 - 0
core/bind/core_bind.cpp

@@ -1883,6 +1883,14 @@ void _Thread::_start_func(void *ud) {
 	Variant::CallError ce;
 	const Variant* arg[1]={&t->userdata};
 
+	// we don't know our thread pointer yet :(
+	if (t->name == "") {
+		// come up with a better name using maybe the filename on the Script?
+		//t->thread->set_name(t->target_method);
+	} else {
+		//t->thread->set_name(t->name);
+	};
+
 	t->ret=t->target_instance->call(t->target_method,arg,1,ce);
 	if (ce.error!=Variant::CallError::CALL_OK) {
 
@@ -1972,12 +1980,24 @@ Variant _Thread::wait_to_finish() {
 	return r;
 }
 
+Error _Thread::set_name(const String &p_name) {
+
+	name = p_name;
+
+	if (thread) {
+		return thread->set_name(p_name);
+	};
+
+	return OK;
+};
+
 void _Thread::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("start:Error","instance","method","userdata","priority"),&_Thread::start,DEFVAL(Variant()),DEFVAL(PRIORITY_NORMAL));
 	ObjectTypeDB::bind_method(_MD("get_id"),&_Thread::get_id);
 	ObjectTypeDB::bind_method(_MD("is_active"),&_Thread::is_active);
 	ObjectTypeDB::bind_method(_MD("wait_to_finish:Variant"),&_Thread::wait_to_finish);
+	ObjectTypeDB::bind_method(_MD("set_name:Error", "name"),&_Thread::set_name);
 
 	BIND_CONSTANT( PRIORITY_LOW );
 	BIND_CONSTANT( PRIORITY_NORMAL );

+ 2 - 0
core/bind/core_bind.h

@@ -508,6 +508,7 @@ protected:
 	Object *target_instance;
 	StringName target_method;
 	Thread *thread;
+	String name;
 	static void _bind_methods();
 	static void _start_func(void *ud);
 public:
@@ -523,6 +524,7 @@ public:
 	String get_id() const;
 	bool is_active() const;
 	Variant wait_to_finish();
+	Error set_name(const String& p_name);
 
 	_Thread();
 	~_Thread();

+ 1 - 1
core/os/input.h

@@ -62,7 +62,7 @@ public:
 
 	virtual float get_joy_axis(int p_device,int p_axis)=0;
 	virtual String get_joy_name(int p_idx)=0;
-	virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name)=0;
+	virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid)=0;
 
 
 	virtual Point2 get_mouse_pos() const=0;

+ 5 - 0
core/os/thread.cpp

@@ -58,6 +58,11 @@ void Thread::wait_to_finish(Thread *p_thread) {
 		
 }
 
+Error Thread::set_name(const String &p_name) {
+
+	return ERR_UNAVAILABLE;
+};
+
 Thread::Thread()
 {
 }

+ 3 - 1
core/os/thread.h

@@ -35,6 +35,7 @@
 	@author Juan Linietsky <[email protected]>
 */
 
+#include "ustring.h"
 
 typedef void (*ThreadCreateCallback)(void *p_userdata);
 
@@ -71,7 +72,8 @@ protected:
 	Thread();
 public:
 		
-	
+
+	virtual Error set_name(const String& p_name);
 		
 	virtual ID get_ID() const=0;
 	

+ 4 - 2
drivers/png/SCsub

@@ -22,7 +22,7 @@ png_sources = [
 	"png/image_loader_png.cpp"
 ]
 
-if ("neon_enabled" in env and env["neon_enabled"]):
+if ("neon_enabled" in env and env["neon_enabled"]):	
 	env_neon = env.Clone();
 	if "S_compiler" in env:
 		env_neon['CC'] = env['S_compiler']
@@ -30,7 +30,9 @@ if ("neon_enabled" in env and env["neon_enabled"]):
 	import os
 	# Currently .ASM filter_neon.S does not compile on NT.
 	if (os.name!="nt"):
-		png_sources.append(env_neon.Object("#drivers/png/filter_neon.S"))
+		env_neon.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=2"])
+		png_sources.append(env_neon.Object("#drivers/png/arm/arm_init.c"))
+		png_sources.append(env_neon.Object("#drivers/png/arm/filter_neon.S"))
 
 
 env.drivers_sources+=png_sources

+ 232 - 0
drivers/png/arm/arm_init.c

@@ -0,0 +1,232 @@
+
+/* arm_init.c - NEON optimised filter functions
+ *
+ * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Written by Mans Rullgard, 2011.
+ * Last changed in libpng 1.6.8 [December 19, 2013]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
+ * called.
+ */
+#define _POSIX_SOURCE 1
+
+#include "../pngpriv.h"
+
+#ifdef PNG_READ_SUPPORTED
+#if PNG_ARM_NEON_OPT > 0
+#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */
+#include <signal.h> /* for sig_atomic_t */
+
+#ifdef __ANDROID__
+/* Linux provides access to information about CPU capabilites via
+ * /proc/self/auxv, however Android blocks this while still claiming to be
+ * Linux.  The Andoid NDK, however, provides appropriate support.
+ *
+ * Documentation: http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html
+ */
+#include <cpu-features.h>
+
+static int
+png_have_neon(png_structp png_ptr)
+{
+   /* This is a whole lot easier than the mess below, however it is probably
+    * implemented as below, therefore it is better to cache the result (these
+    * function calls may be slow!)
+    */
+   PNG_UNUSED(png_ptr)
+   return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&
+      (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
+}
+#elif defined(__linux__)
+/* The generic __linux__ implementation requires reading /proc/self/auxv and
+ * looking at each element for one that records NEON capabilities.
+ */
+#include <unistd.h> /* for POSIX 1003.1 */
+#include <errno.h>  /* for EINTR */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <asm/hwcap.h>
+
+/* A read call may be interrupted, in which case it returns -1 and sets errno to
+ * EINTR if nothing was done, otherwise (if something was done) a partial read
+ * may result.
+ */
+static size_t
+safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
+{
+   size_t ntotal = 0;
+   char *buffer = png_voidcast(char*, buffer_in);
+
+   while (nbytes > 0)
+   {
+      unsigned int nread;
+      int iread;
+
+      /* Passing nread > INT_MAX to read is implementation defined in POSIX
+       * 1003.1, therefore despite the unsigned argument portable code must
+       * limit the value to INT_MAX!
+       */
+      if (nbytes > INT_MAX)
+         nread = INT_MAX;
+
+      else
+         nread = (unsigned int)/*SAFE*/nbytes;
+
+      iread = read(fd, buffer, nread);
+
+      if (iread == -1)
+      {
+         /* This is the devil in the details, a read can terminate early with 0
+          * bytes read because of EINTR, yet it still returns -1 otherwise end
+          * of file cannot be distinguished.
+          */
+         if (errno != EINTR)
+         {
+            png_warning(png_ptr, "/proc read failed");
+            return 0; /* I.e., a permanent failure */
+         }
+      }
+
+      else if (iread < 0)
+      {
+         /* Not a valid 'read' result: */
+         png_warning(png_ptr, "OS /proc read bug");
+         return 0;
+      }
+
+      else if (iread > 0)
+      {
+         /* Continue reading until a permanent failure, or EOF */
+         buffer += iread;
+         nbytes -= (unsigned int)/*SAFE*/iread;
+         ntotal += (unsigned int)/*SAFE*/iread;
+      }
+
+      else
+         return ntotal;
+   }
+
+   return ntotal; /* nbytes == 0 */
+}
+
+static int
+png_have_neon(png_structp png_ptr)
+{
+   int fd = open("/proc/self/auxv", O_RDONLY);
+   Elf32_auxv_t aux;
+
+   /* Failsafe: failure to open means no NEON */
+   if (fd == -1)
+   {
+      png_warning(png_ptr, "/proc/self/auxv open failed");
+      return 0;
+   }
+
+   while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
+   {
+      if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
+      {
+         close(fd);
+         return 1;
+      }
+   }
+
+   close(fd);
+   return 0;
+}
+#else
+   /* We don't know how to do a run-time check on this system */
+#  error "no support for run-time ARM NEON checks"
+#endif /* OS checks */
+#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
+
+#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
+#  error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
+#endif
+
+void
+png_init_filter_functions_neon(png_structp pp, unsigned int bpp)
+{
+   /* The switch statement is compiled in for ARM_NEON_API, the call to
+    * png_have_neon is compiled in for ARM_NEON_CHECK.  If both are defined
+    * the check is only performed if the API has not set the NEON option on
+    * or off explicitly.  In this case the check controls what happens.
+    *
+    * If the CHECK is not compiled in and the option is UNSET the behavior prior
+    * to 1.6.7 was to use the NEON code - this was a bug caused by having the
+    * wrong order of the 'ON' and 'default' cases.  UNSET now defaults to OFF,
+    * as documented in png.h
+    */
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+   switch ((pp->options >> PNG_ARM_NEON) & 3)
+   {
+      case PNG_OPTION_UNSET:
+         /* Allow the run-time check to execute if it has been enabled -
+          * thus both API and CHECK can be turned on.  If it isn't supported
+          * this case will fall through to the 'default' below, which just
+          * returns.
+          */
+#endif /* PNG_ARM_NEON_API_SUPPORTED */
+#ifdef PNG_ARM_NEON_CHECK_SUPPORTED
+         {
+            static volatile sig_atomic_t no_neon = -1; /* not checked */
+
+            if (no_neon < 0)
+               no_neon = !png_have_neon(pp);
+
+            if (no_neon)
+               return;
+         }
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+         break;
+#endif
+#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
+
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+      default: /* OFF or INVALID */
+         return;
+
+      case PNG_OPTION_ON:
+         /* Option turned on */
+         break;
+   }
+#endif
+
+   /* IMPORTANT: any new external functions used here must be declared using
+    * PNG_INTERNAL_FUNCTION in ../pngpriv.h.  This is required so that the
+    * 'prefix' option to configure works:
+    *
+    *    ./configure --with-libpng-prefix=foobar_
+    *
+    * Verify you have got this right by running the above command, doing a build
+    * and examining pngprefix.h; it must contain a #define for every external
+    * function you add.  (Notice that this happens automatically for the
+    * initialization function.)
+    */
+   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;
+
+   if (bpp == 3)
+   {
+      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;
+      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;
+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+         png_read_filter_row_paeth3_neon;
+   }
+
+   else if (bpp == 4)
+   {
+      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
+      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+          png_read_filter_row_paeth4_neon;
+   }
+}
+#endif /* PNG_ARM_NEON_OPT > 0 */
+#endif /* PNG_READ_SUPPORTED */

+ 11 - 1
drivers/png/filter_neon.S → drivers/png/arm/filter_neon.S

@@ -1,18 +1,27 @@
 
 /* filter_neon.S - NEON optimised filter functions
  *
- * Copyright (c) 2011 Glenn Randers-Pehrson
+ * Copyright (c) 2013 Glenn Randers-Pehrson
  * Written by Mans Rullgard, 2011.
+ * Last changed in libpng 1.5.17 [June 27, 2013]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
+/* This is required to get the symbol renames, which are #defines, and also
+ * includes the definition (or not) of PNG_ARM_NEON_OPT.
+ */
+#define PNG_VERSION_INFO_ONLY
+#include "../pngpriv.h"
+
 #if defined(__linux__) && defined(__ELF__)
 .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
 #endif
 
+#if PNG_ARM_NEON_OPT > 0
+
 #ifdef __ELF__
 #   define ELF
 #else
@@ -223,3 +232,4 @@ func    png_read_filter_row_paeth3_neon, export=1
 
         pop             {r4,pc}
 endfunc
+#endif /* PNG_ARM_NEON_OPT > 0 */

+ 51 - 34
drivers/png/example.c

@@ -2,8 +2,8 @@
 #if 0 /* in case someone actually tries to compile this */
 
 /* example.c - an example of using libpng
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Maintained 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Maintained 1998-2014 Glenn Randers-Pehrson
  * Maintained 1996, 1997 Andreas Dilger
  * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
  */
@@ -89,7 +89,7 @@ void read_png(char *file_name)  /* We need to open the file */
 {
    png_structp png_ptr;
    png_infop info_ptr;
-   unsigned int sig_read = 0;
+   int sig_read = 0;
    png_uint_32 width, height;
    int bit_depth, color_type, interlace_type;
    FILE *fp;
@@ -98,7 +98,7 @@ void read_png(char *file_name)  /* We need to open the file */
       return (ERROR);
 
 #else no_open_file /* prototype 2 */
-void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
+void read_png(FILE *fp, int sig_read)  /* File is already open */
 {
    png_structp png_ptr;
    png_infop info_ptr;
@@ -188,7 +188,7 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
     * are mutually exclusive.
     */
 
-   /* Tell libpng to strip 16 bit/color files down to 8 bits/color.
+   /* Tell libpng to strip 16 bits/color files down to 8 bits/color.
     * Use accurate scaling if it's available, otherwise just chop off the
     * low byte.
     */
@@ -259,9 +259,9 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
    /* If we don't have another value */
    else
    {
-      screen_gamma = 2.2;  /* A good guess for a PC monitor in a dimly
-                              lit room */
-      screen_gamma = 1.7 or 1.0;  /* A good guess for Mac systems */
+      screen_gamma = PNG_DEFAULT_sRGB;  /* A good guess for a PC monitor
+                                           in a dimly lit room */
+      screen_gamma = PNG_GAMMA_MAC_18 or 1.0; /* Good guesses for Mac systems */
    }
 
    /* Tell libpng to handle the gamma conversion for you.  The final call
@@ -273,7 +273,7 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
    int intent;
 
    if (png_get_sRGB(png_ptr, info_ptr, &intent))
-      png_set_gamma(png_ptr, screen_gamma, 0.45455);
+      png_set_gamma(png_ptr, screen_gamma, PNG_DEFAULT_sRGB);
    else
    {
       double image_gamma;
@@ -284,7 +284,7 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
    }
 
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
-   /* Quantize RGB files down to 8 bit palette or reduce palettes
+   /* Quantize RGB files down to 8-bit palette or reduce palettes
     * to the number of colors available on your screen.
     */
    if (color_type & PNG_COLOR_MASK_COLOR)
@@ -336,7 +336,7 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
    /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
    png_set_swap_alpha(png_ptr);
 
-   /* Swap bytes of 16 bit files to least significant byte first */
+   /* Swap bytes of 16-bit files to least significant byte first */
    png_set_swap(png_ptr);
 
    /* Add filler (or alpha) byte (before/after each RGB triplet) */
@@ -695,25 +695,38 @@ void write_png(char *file_name /* , ... other image information ... */)
    png_set_gAMA(png_ptr, info_ptr, gamma);
 
    /* Optionally write comments into the image */
-   text_ptr[0].key = "Title";
-   text_ptr[0].text = "Mona Lisa";
-   text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
-   text_ptr[0].itxt_length = 0;
-   text_ptr[0].lang = NULL;
-   text_ptr[0].lang_key = NULL;
-   text_ptr[1].key = "Author";
-   text_ptr[1].text = "Leonardo DaVinci";
-   text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
-   text_ptr[1].itxt_length = 0;
-   text_ptr[1].lang = NULL;
-   text_ptr[1].lang_key = NULL;
-   text_ptr[2].key = "Description";
-   text_ptr[2].text = "<long text>";
-   text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
-   text_ptr[2].itxt_length = 0;
-   text_ptr[2].lang = NULL;
-   text_ptr[2].lang_key = NULL;
-   png_set_text(png_ptr, info_ptr, text_ptr, 3);
+   {
+      png_text text_ptr[3];
+
+      char key0[]="Title";
+      char text0[]="Mona Lisa";
+      text_ptr[0].key = key0;
+      text_ptr[0].text = text0;
+      text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+      text_ptr[0].itxt_length = 0;
+      text_ptr[0].lang = NULL;
+      text_ptr[0].lang_key = NULL;
+
+      char key1[]="Author";
+      char text1[]="Leonardo DaVinci";
+      text_ptr[1].key = key1;
+      text_ptr[1].text = text1;
+      text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+      text_ptr[1].itxt_length = 0;
+      text_ptr[1].lang = NULL;
+      text_ptr[1].lang_key = NULL;
+
+      char key2[]="Description";
+      char text2[]="<long text>";
+      text_ptr[2].key = key2;
+      text_ptr[2].text = text2;
+      text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+      text_ptr[2].itxt_length = 0;
+      text_ptr[2].lang = NULL;
+      text_ptr[2].lang_key = NULL;
+
+      png_set_text(write_ptr, write_info_ptr, text_ptr, 3);
+   }
 
    /* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */
 
@@ -737,7 +750,7 @@ void write_png(char *file_name /* , ... other image information ... */)
     */
 
    /* Once we write out the header, the compression type on the text
-    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+    * chunk gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
     * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
     * at the end.
     */
@@ -771,11 +784,11 @@ void write_png(char *file_name /* , ... other image information ... */)
    /* Swap bytes of 16-bit files to most significant byte first */
    png_set_swap(png_ptr);
 
-   /* Swap bits of 1, 2, 4 bit packed pixel formats */
+   /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
    png_set_packswap(png_ptr);
 
    /* Turn on interlace handling if you are not using png_write_image() */
-   if (interlacing)
+   if (interlacing != 0)
       number_passes = png_set_interlace_handling(png_ptr);
 
    else
@@ -786,12 +799,16 @@ void write_png(char *file_name /* , ... other image information ... */)
     * use the first method if you aren't handling interlacing yourself.
     */
    png_uint_32 k, height, width;
-   png_byte image[height][width*bytes_per_pixel];
+
+   /* In this example, "image" is a one-dimensional array of bytes */
+   png_byte image[height*width*bytes_per_pixel];
+
    png_bytep row_pointers[height];
 
    if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
      png_error (png_ptr, "Image is too tall to process in memory");
 
+   /* Set up pointers into your "image" byte array */
    for (k = 0; k < height; k++)
      row_pointers[k] = image + k*width*bytes_per_pixel;
 

+ 231 - 167
drivers/png/png.c

@@ -1,8 +1,8 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -14,7 +14,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_7 Your_png_h_is_not_version_1_5_7;
+typedef png_libpng_version_1_5_26 Your_png_h_is_not_version_1_5_26;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
@@ -26,15 +26,20 @@ typedef png_libpng_version_1_5_7 Your_png_h_is_not_version_1_5_7;
 void PNGAPI
 png_set_sig_bytes(png_structp png_ptr, int num_bytes)
 {
+   unsigned int nb = (unsigned int)num_bytes;
+
    png_debug(1, "in png_set_sig_bytes");
 
    if (png_ptr == NULL)
       return;
 
-   if (num_bytes > 8)
+   if (num_bytes < 0)
+      nb = 0;
+
+   if (nb > 8)
       png_error(png_ptr, "Too many bytes for PNG signature");
 
-   png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
+   png_ptr->sig_bytes = (png_byte)nb;
 }
 
 /* Checks whether the supplied bytes match the PNG signature.  We allow
@@ -73,13 +78,16 @@ PNG_FUNCTION(voidpf /* PRIVATE */,
 png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
 {
    png_voidp ptr;
-   png_structp p=(png_structp)png_ptr;
-   png_uint_32 save_flags=p->flags;
+   png_structp p;
+   png_uint_32 save_flags;
    png_alloc_size_t num_bytes;
 
    if (png_ptr == NULL)
       return (NULL);
 
+   p=(png_structp)png_ptr;
+   save_flags=p->flags;
+
    if (items > PNG_UINT_32_MAX/size)
    {
      png_warning (p, "Potential overflow in png_zalloc()");
@@ -146,9 +154,10 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
       do
       {
          uInt safeLength = (uInt)length;
+#ifndef __COVERITY__
          if (safeLength == 0)
             safeLength = (uInt)-1; /* evil, but safe */
-
+#endif
          crc = crc32(crc, ptr, safeLength);
 
          /* The following should never issue compiler warnings, if they do the
@@ -171,49 +180,51 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
 int
 png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver)
 {
-   if (user_png_ver)
+     /* Libpng versions 1.0.0 and later are binary compatible if the version
+      * string matches through the second '.'; we must recompile any
+      * applications that use any older library version.
+      */
+
+   if (user_png_ver != NULL)
    {
-      int i = 0;
+      int i = -1;
+      int found_dots = 0;
 
       do
       {
-         if (user_png_ver[i] != png_libpng_ver[i])
+         i++;
+         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
             png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-      } while (png_libpng_ver[i++]);
+         if (user_png_ver[i] == '.')
+            found_dots++;
+      } while (found_dots < 2 && user_png_ver[i] != 0 &&
+            PNG_LIBPNG_VER_STRING[i] != 0);
    }
 
    else
       png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
 
-   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+   if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0)
    {
-     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
-      * we must recompile any applications that use any older library version.
-      * For versions after libpng 1.0, we will be compatible, so we need
-      * only check the first digit.
-      */
-      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
-          (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
-          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
-      {
 #ifdef PNG_WARNINGS_SUPPORTED
-         size_t pos = 0;
-         char m[128];
+      size_t pos = 0;
+      char m[128];
 
-         pos = png_safecat(m, sizeof m, pos, "Application built with libpng-");
-         pos = png_safecat(m, sizeof m, pos, user_png_ver);
-         pos = png_safecat(m, sizeof m, pos, " but running with ");
-         pos = png_safecat(m, sizeof m, pos, png_libpng_ver);
+      pos = png_safecat(m, (sizeof m), pos,
+          "Application built with libpng-");
+      pos = png_safecat(m, (sizeof m), pos, user_png_ver);
+      pos = png_safecat(m, (sizeof m), pos, " but running with ");
+      pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
+      PNG_UNUSED(pos)
 
-         png_warning(png_ptr, m);
+      png_warning(png_ptr, m);
 #endif
 
 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
-         png_ptr->flags = 0;
+      png_ptr->flags = 0;
 #endif
 
-         return 0;
-      }
+      return 0;
    }
 
    /* Success return. */
@@ -300,6 +311,8 @@ png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
       png_destroy_struct(info_ptr);
       info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
       *ptr_ptr = info_ptr;
+      if (info_ptr == NULL)
+         return;
    }
 
    /* Set everything to 0 */
@@ -337,42 +350,43 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 
 #ifdef PNG_TEXT_SUPPORTED
    /* Free text item num or (if num == -1) all text items */
-   if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
+   if (info_ptr->text != 0 &&
+       ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
-         if (info_ptr->text && info_ptr->text[num].key)
-         {
-            png_free(png_ptr, info_ptr->text[num].key);
-            info_ptr->text[num].key = NULL;
-         }
+         png_free(png_ptr, info_ptr->text[num].key);
+         info_ptr->text[num].key = NULL;
       }
 
       else
       {
          int i;
+
          for (i = 0; i < info_ptr->num_text; i++)
-             png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
+            png_free(png_ptr, info_ptr->text[i].key);
+
          png_free(png_ptr, info_ptr->text);
          info_ptr->text = NULL;
-         info_ptr->num_text=0;
+         info_ptr->num_text = 0;
       }
    }
 #endif
 
 #ifdef PNG_tRNS_SUPPORTED
    /* Free any tRNS entry */
-   if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
+   if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0)
    {
+      info_ptr->valid &= ~PNG_INFO_tRNS;
       png_free(png_ptr, info_ptr->trans_alpha);
       info_ptr->trans_alpha = NULL;
-      info_ptr->valid &= ~PNG_INFO_tRNS;
+      info_ptr->num_trans = 0;
    }
 #endif
 
 #ifdef PNG_sCAL_SUPPORTED
    /* Free any sCAL entry */
-   if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
+   if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0)
    {
       png_free(png_ptr, info_ptr->scal_s_width);
       png_free(png_ptr, info_ptr->scal_s_height);
@@ -384,20 +398,20 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 
 #ifdef PNG_pCAL_SUPPORTED
    /* Free any pCAL entry */
-   if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
+   if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
    {
       png_free(png_ptr, info_ptr->pcal_purpose);
       png_free(png_ptr, info_ptr->pcal_units);
       info_ptr->pcal_purpose = NULL;
       info_ptr->pcal_units = NULL;
+
       if (info_ptr->pcal_params != NULL)
          {
             int i;
-            for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
-            {
+
+            for (i = 0; i < info_ptr->pcal_nparams; i++)
                png_free(png_ptr, info_ptr->pcal_params[i]);
-               info_ptr->pcal_params[i] = NULL;
-            }
+
             png_free(png_ptr, info_ptr->pcal_params);
             info_ptr->pcal_params = NULL;
          }
@@ -406,8 +420,8 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 #endif
 
 #ifdef PNG_iCCP_SUPPORTED
-   /* Free any iCCP entry */
-   if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
+   /* Free any profile entry */
+   if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0)
    {
       png_free(png_ptr, info_ptr->iccp_name);
       png_free(png_ptr, info_ptr->iccp_profile);
@@ -419,74 +433,62 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 
 #ifdef PNG_sPLT_SUPPORTED
    /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
-   if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
+   if (info_ptr->splt_palettes != 0 &&
+       ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
-         if (info_ptr->splt_palettes)
-         {
-            png_free(png_ptr, info_ptr->splt_palettes[num].name);
-            png_free(png_ptr, info_ptr->splt_palettes[num].entries);
-            info_ptr->splt_palettes[num].name = NULL;
-            info_ptr->splt_palettes[num].entries = NULL;
-         }
+         png_free(png_ptr, info_ptr->splt_palettes[num].name);
+         png_free(png_ptr, info_ptr->splt_palettes[num].entries);
+         info_ptr->splt_palettes[num].name = NULL;
+         info_ptr->splt_palettes[num].entries = NULL;
       }
 
       else
       {
-         if (info_ptr->splt_palettes_num)
-         {
-            int i;
-            for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
-               png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
+         int i;
 
-            png_free(png_ptr, info_ptr->splt_palettes);
-            info_ptr->splt_palettes = NULL;
-            info_ptr->splt_palettes_num = 0;
+         for (i = 0; i < info_ptr->splt_palettes_num; i++)
+         {
+            png_free(png_ptr, info_ptr->splt_palettes[i].name);
+            png_free(png_ptr, info_ptr->splt_palettes[i].entries);
          }
+
+         png_free(png_ptr, info_ptr->splt_palettes);
+         info_ptr->splt_palettes = NULL;
+         info_ptr->splt_palettes_num = 0;
          info_ptr->valid &= ~PNG_INFO_sPLT;
       }
    }
 #endif
 
 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
-   if (png_ptr->unknown_chunk.data)
-   {
-      png_free(png_ptr, png_ptr->unknown_chunk.data);
-      png_ptr->unknown_chunk.data = NULL;
-   }
-
-   if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
+   if (info_ptr->unknown_chunks != 0 &&
+       ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
-          if (info_ptr->unknown_chunks)
-          {
-             png_free(png_ptr, info_ptr->unknown_chunks[num].data);
-             info_ptr->unknown_chunks[num].data = NULL;
-          }
+          png_free(png_ptr, info_ptr->unknown_chunks[num].data);
+          info_ptr->unknown_chunks[num].data = NULL;
       }
 
       else
       {
          int i;
 
-         if (info_ptr->unknown_chunks_num)
-         {
-            for (i = 0; i < info_ptr->unknown_chunks_num; i++)
-               png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
+         for (i = 0; i < info_ptr->unknown_chunks_num; i++)
+            png_free(png_ptr, info_ptr->unknown_chunks[i].data);
 
-            png_free(png_ptr, info_ptr->unknown_chunks);
-            info_ptr->unknown_chunks = NULL;
-            info_ptr->unknown_chunks_num = 0;
-         }
+         png_free(png_ptr, info_ptr->unknown_chunks);
+         info_ptr->unknown_chunks = NULL;
+         info_ptr->unknown_chunks_num = 0;
       }
    }
 #endif
 
 #ifdef PNG_hIST_SUPPORTED
    /* Free any hIST entry */
-   if ((mask & PNG_FREE_HIST)  & info_ptr->free_me)
+   if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)
    {
       png_free(png_ptr, info_ptr->hist);
       info_ptr->hist = NULL;
@@ -495,9 +497,9 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 #endif
 
    /* Free any PLTE entry that was internally allocated */
-   if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
+   if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0)
    {
-      png_zfree(png_ptr, info_ptr->palette);
+      png_free(png_ptr, info_ptr->palette);
       info_ptr->palette = NULL;
       info_ptr->valid &= ~PNG_INFO_PLTE;
       info_ptr->num_palette = 0;
@@ -505,16 +507,14 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
 
 #ifdef PNG_INFO_IMAGE_SUPPORTED
    /* Free any image bits attached to the info structure */
-   if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
+   if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
    {
-      if (info_ptr->row_pointers)
+      if (info_ptr->row_pointers != 0)
       {
-         int row;
-         for (row = 0; row < (int)info_ptr->height; row++)
-         {
+         png_uint_32 row;
+         for (row = 0; row < info_ptr->height; row++)
             png_free(png_ptr, info_ptr->row_pointers[row]);
-            info_ptr->row_pointers[row] = NULL;
-         }
+
          png_free(png_ptr, info_ptr->row_pointers);
          info_ptr->row_pointers = NULL;
       }
@@ -655,14 +655,15 @@ png_get_copyright(png_const_structp png_ptr)
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-     "libpng version 1.5.7 - December 15, 2011" PNG_STRING_NEWLINE \
-     "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
+     "libpng version 1.5.26 - December 17, 2015" PNG_STRING_NEWLINE \
+     "Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson" \
+     PNG_STRING_NEWLINE \
      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
      PNG_STRING_NEWLINE;
 #  else
-      return "libpng version 1.5.7 - December 15, 2011\
-      Copyright (c) 1998-2011 Glenn Randers-Pehrson\
+      return "libpng version 1.5.26 - December 17, 2015\
+      Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
 #  endif
@@ -892,7 +893,8 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
 
    /* Check xy and, implicitly, z.  Note that wide gamut color spaces typically
     * have end points with 0 tristimulus values (these are impossible end
-    * points, but they are used to cover the possible colors.)
+    * points, but they are used to cover the possible colors).  We check
+    * xy.whitey against 5, not 0, to avoid a possible integer overflow.
     */
    if (xy.redx < 0 || xy.redx > PNG_FP_1) return 1;
    if (xy.redy < 0 || xy.redy > PNG_FP_1-xy.redx) return 1;
@@ -901,7 +903,7 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
    if (xy.bluex < 0 || xy.bluex > PNG_FP_1) return 1;
    if (xy.bluey < 0 || xy.bluey > PNG_FP_1-xy.bluex) return 1;
    if (xy.whitex < 0 || xy.whitex > PNG_FP_1) return 1;
-   if (xy.whitey < 0 || xy.whitey > PNG_FP_1-xy.whitex) return 1;
+   if (xy.whitey < 5 || xy.whitey > PNG_FP_1-xy.whitex) return 1;
 
    /* The reverse calculation is more difficult because the original tristimulus
     * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
@@ -969,8 +971,8 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
     * and it is certain that it becomes unstable where the end points are close
     * together.
     *
-    * So this code uses the perhaps slighly less optimal but more understandable
-    * and totally obvious approach of calculating color-scale.
+    * So this code uses the perhaps slightly less optimal but more
+    * understandable and totally obvious approach of calculating color-scale.
     *
     * This algorithm depends on the precision in white-scale and that is
     * (1/white-y), so we can immediately see that as white-y approaches 0 the
@@ -1165,6 +1167,17 @@ int png_XYZ_from_xy_checked(png_structp png_ptr, png_XYZ *XYZ, png_xy xy)
 }
 #endif
 
+#ifdef __GNUC__
+/* This exists solely to work round a warning from GNU C. */
+static int /* PRIVATE */
+png_gt(size_t a, size_t b)
+{
+    return a > b;
+}
+#else
+#   define png_gt(a,b) ((a) > (b))
+#endif
+
 void /* PRIVATE */
 png_check_IHDR(png_structp png_ptr,
    png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -1179,53 +1192,68 @@ png_check_IHDR(png_structp png_ptr,
       png_warning(png_ptr, "Image width is zero in IHDR");
       error = 1;
    }
-
-   if (height == 0)
+   else if (width > PNG_UINT_31_MAX)
    {
-      png_warning(png_ptr, "Image height is zero in IHDR");
+      png_warning(png_ptr, "Invalid image width in IHDR");
       error = 1;
    }
 
-#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (width > png_ptr->user_width_max)
-
-#  else
-   if (width > PNG_USER_WIDTH_MAX)
-#  endif
+   else if (png_gt(width,
+                   (PNG_SIZE_MAX >> 3) /* 8-byte RGBA pixels */
+                   - 48                /* big_row_buf hack */
+                   - 1                 /* filter byte */
+                   - 7*8               /* rounding width to multiple of 8 pix */
+                   - 8))               /* extra max_pixel_depth pad */
    {
-      png_warning(png_ptr, "Image width exceeds user limit in IHDR");
+      /* The size of the row must be within the limits of this architecture.
+       * Because the read code can perform arbitrary transformations the
+       * maximum size is checked here.  Because the code in png_read_start_row
+       * adds extra space "for safety's sake" in several places a conservative
+       * limit is used here.
+       *
+       * NOTE: it would be far better to check the size that is actually used,
+       * but the effect in the real world is minor and the changes are more
+       * extensive, therefore much more dangerous and much more difficult to
+       * write in a way that avoids compiler warnings.
+       */
+      png_warning(png_ptr, "Image width is too large for this architecture");
       error = 1;
    }
-
-#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (height > png_ptr->user_height_max)
-#  else
-   if (height > PNG_USER_HEIGHT_MAX)
-#  endif
+   else
    {
-      png_warning(png_ptr, "Image height exceeds user limit in IHDR");
-      error = 1;
+#     ifdef PNG_SET_USER_LIMITS_SUPPORTED
+      if (width > png_ptr->user_width_max)
+#     else
+      if (width > PNG_USER_WIDTH_MAX)
+#     endif
+      {
+         png_warning(png_ptr, "Image width exceeds user limit in IHDR");
+         error = 1;
+      }
    }
 
-   if (width > PNG_UINT_31_MAX)
+   if (height == 0)
    {
-      png_warning(png_ptr, "Invalid image width in IHDR");
+      png_warning(png_ptr, "Image height is zero in IHDR");
       error = 1;
    }
-
-   if (height > PNG_UINT_31_MAX)
+   else if (height > PNG_UINT_31_MAX)
    {
       png_warning(png_ptr, "Invalid image height in IHDR");
       error = 1;
    }
-
-   if (width > (PNG_UINT_32_MAX
-                 >> 3)      /* 8-byte RGBA pixels */
-                 - 48       /* bigrowbuf hack */
-                 - 1        /* filter byte */
-                 - 7*8      /* rounding of width to multiple of 8 pixels */
-                 - 8)       /* extra max_pixel_depth pad */
-      png_warning(png_ptr, "Width is too large for libpng to process pixels");
+   else
+   {
+#     ifdef PNG_SET_USER_LIMITS_SUPPORTED
+      if (height > png_ptr->user_height_max)
+#     else
+      if (height > PNG_USER_HEIGHT_MAX)
+#     endif
+      {
+         png_warning(png_ptr, "Image height exceeds user limit in IHDR");
+         error = 1;
+      }
+   }
 
    /* Check other values */
    if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
@@ -1458,7 +1486,7 @@ png_check_fp_string(png_const_charp string, png_size_t size)
 }
 #endif /* pCAL or sCAL */
 
-#ifdef PNG_READ_sCAL_SUPPORTED
+#ifdef PNG_sCAL_SUPPORTED
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
 /* Utility used below - a simple accurate power of ten from an integral
  * exponent.
@@ -1467,7 +1495,7 @@ static double
 png_pow10(int power)
 {
    int recip = 0;
-   double d = 1;
+   double d = 1.0;
 
    /* Handle negative exponent with a reciprocal at the end because
     * 10 is exact whereas .1 is inexact in base 2
@@ -1481,7 +1509,7 @@ png_pow10(int power)
    if (power > 0)
    {
       /* Decompose power bitwise. */
-      double mult = 10;
+      double mult = 10.0;
       do
       {
          if (power & 1) d *= mult;
@@ -1490,7 +1518,7 @@ png_pow10(int power)
       }
       while (power > 0);
 
-      if (recip) d = 1/d;
+      if (recip != 0) d = 1/d;
    }
    /* else power is 0 and d is 1 */
 
@@ -1600,7 +1628,8 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
             {
                double d;
 
-               fp *= 10;
+               fp *= 10.0;
+
                /* Use modf here, not floor and subtract, so that
                 * the separation is done in one step.  At the end
                 * of the loop don't break the number into parts so
@@ -1613,7 +1642,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
                {
                   d = floor(fp + .5);
 
-                  if (d > 9)
+                  if (d > 9.0)
                   {
                      /* Rounding up to 10, handle that here. */
                      if (czero > 0)
@@ -1621,9 +1650,10 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
                         --czero, d = 1;
                         if (cdigits == 0) --clead;
                      }
+
                      else
                      {
-                        while (cdigits > 0 && d > 9)
+                        while (cdigits > 0 && d > 9.0)
                         {
                            int ch = *--ascii;
 
@@ -1648,7 +1678,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
                          * exponent but take into account the leading
                          * decimal point.
                          */
-                        if (d > 9)  /* cdigits == 0 */
+                        if (d > 9.0)  /* cdigits == 0 */
                         {
                            if (exp_b10 == (-1))
                            {
@@ -1669,18 +1699,19 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
                               ++exp_b10;
 
                            /* In all cases we output a '1' */
-                           d = 1;
+                           d = 1.0;
                         }
                      }
                   }
                   fp = 0; /* Guarantees termination below. */
                }
 
-               if (d == 0)
+               if (d == 0.0)
                {
                   ++czero;
                   if (cdigits == 0) ++clead;
                }
+
                else
                {
                   /* Included embedded zeros in the digit count. */
@@ -1708,6 +1739,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
                                                                  above */
                      --exp_b10;
                   }
+
                   *ascii++ = (char)(48 + (int)d), ++cdigits;
                }
             }
@@ -1718,7 +1750,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
             /* Check for an exponent, if we don't need one we are
              * done and just need to terminate the string.  At
              * this point exp_b10==(-1) is effectively if flag - it got
-             * to '-1' because of the decrement after outputing
+             * to '-1' because of the decrement after outputting
              * the decimal point above (the exponent required is
              * *not* -1!)
              */
@@ -1726,7 +1758,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
             {
                /* The following only happens if we didn't output the
                 * leading zeros above for negative exponent, so this
-                * doest add to the digit requirement.  Note that the
+                * doesn't add to the digit requirement.  Note that the
                 * two zeros here can only be output if the two leading
                 * zeros were *not* output, so this doesn't increase
                 * the output count.
@@ -1900,7 +1932,7 @@ png_fixed(png_structp png_ptr, double fp, png_const_charp text)
 #endif
 
 #if defined(PNG_READ_GAMMA_SUPPORTED) || \
-    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
+    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
 /* muldiv functions */
 /* This API takes signed arguments and rounds the result to the nearest
  * integer (or, for a fixed point number - the standard argument - to
@@ -2004,7 +2036,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
             if (s00 >= (D >> 1))
                ++result;
 
-            if (negative)
+            if (negative != 0)
                result = -result;
 
             /* Check for overflow. */
@@ -2040,26 +2072,31 @@ png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
 }
 #endif
 
-#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED)
+/* more fixed point functions for gamma and cHRM (xy/XYZ) suport. */
 /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
 png_fixed_point
 png_reciprocal(png_fixed_point a)
 {
+   if (a != 0)
+   {
 #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
-   double r = floor(1E10/a+.5);
+     double r = floor(1E10/a+.5);
 
-   if (r <= 2147483647. && r >= -2147483648.)
-      return (png_fixed_point)r;
+     if (r <= 2147483647. && r >= -2147483648.)
+        return (png_fixed_point)r;
 #else
-   png_fixed_point res;
+     png_fixed_point res;
 
-   if (png_muldiv(&res, 100000, 100000, a))
-      return res;
+     if (png_muldiv(&res, 100000, 100000, a))
+        return res;
 #endif
+   }
 
    return 0; /* error/overflow */
 }
 
+#ifdef PNG_READ_GAMMA_SUPPORTED
 /* A local convenience routine. */
 static png_fixed_point
 png_product2(png_fixed_point a, png_fixed_point b)
@@ -2081,6 +2118,7 @@ png_product2(png_fixed_point a, png_fixed_point b)
 
    return 0; /* overflow */
 }
+#endif /* READ_GAMMA */
 
 /* The inverse of the above. */
 png_fixed_point
@@ -2088,17 +2126,20 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b)
 {
    /* The required result is 1/a * 1/b; the following preserves accuracy. */
 #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
-   double r = 1E15/a;
-   r /= b;
-   r = floor(r+.5);
+   if (a != 0 && b != 0)
+   {
+      double r = 1E15/a;
+      r /= b;
+      r = floor(r+.5);
 
-   if (r <= 2147483647. && r >= -2147483648.)
-      return (png_fixed_point)r;
+      if (r <= 2147483647. && r >= -2147483648.)
+         return (png_fixed_point)r;
+   }
 #else
-   /* This may overflow because the range of png_fixed_point isn't symmetric,
-    * but this API is only used for the product of file and screen gamma so it
-    * doesn't matter that the smallest number it can produce is 1/21474, not
-    * 1/100000
+   /* This may overflow because the range of png_fixed_point isn't
+    * symmetric, but this API is only used for the product of file and
+    * screen gamma so it doesn't matter that the smallest number it can
+    * produce is 1/21474, not 1/100000
     */
    png_fixed_point res = png_product2(a, b);
 
@@ -2108,7 +2149,7 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b)
 
    return 0; /* overflow */
 }
-#endif /* READ_GAMMA */
+#endif /* READ_GAMMA || cHRM */
 
 #ifdef PNG_CHECK_cHRM_SUPPORTED
 /* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
@@ -2519,6 +2560,7 @@ png_gamma_significant(png_fixed_point gamma_val)
        gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
 }
 
+#ifdef PNG_16BIT_SUPPORTED
 /* Internal function to build a single 16-bit table - the table consists of
  * 'num' 256-entry subtables, where 'num' is determined by 'shift' - the amount
  * to shift the input values right (or 16-number_of_signifiant_bits).
@@ -2567,7 +2609,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
                double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);
                sub_table[j] = (png_uint_16)d;
 #           else
-               if (shift)
+               if (shift != 0)
                   ig = (ig * 65535U + max_by_2)/max;
 
                sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
@@ -2583,7 +2625,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
          {
             png_uint_32 ig = (j << (8-shift)) + i;
 
-            if (shift)
+            if (shift != 0)
                ig = (ig * 65535U + max_by_2)/max;
 
             sub_table[j] = (png_uint_16)ig;
@@ -2591,6 +2633,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
       }
    }
 }
+#endif
 
 /* NOTE: this function expects the *inverse* of the overall gamma transformation
  * required.
@@ -2868,3 +2911,24 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
 }
 #endif /* READ_GAMMA */
 #endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+/* HARDWARE OPTION SUPPORT */
+#ifdef PNG_SET_OPTION_SUPPORTED
+int PNGAPI
+png_set_option(png_structp png_ptr, int option, int onoff)
+{
+   if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&
+      (option & 1) == 0)
+   {
+      int mask = 3 << option;
+      int setting = (2 + (onoff != 0)) << option;
+      int current = png_ptr->options;
+
+      png_ptr->options = (png_byte)((current & ~mask) | setting);
+
+      return (current & mask) >> option;
+   }
+
+   return PNG_OPTION_INVALID;
+}
+#endif

+ 212 - 278
drivers/png/png.h

@@ -1,8 +1,9 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.5.7 - December 15, 2011
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * libpng version 1.5.26, December 17, 2015
+ *
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -11,182 +12,9 @@
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.5.7 - December 15, 2011: Glenn
+ *   libpng versions 0.97, January 1998, through 1.5.26, December 17, 2015:
+ *     Glenn Randers-Pehrson.
  *   See also "Contributing Authors", below.
- *
- * Note about libpng version numbers:
- *
- *   Due to various miscommunications, unforeseen code incompatibilities
- *   and occasional factors outside the authors' control, version numbering
- *   on the library has not always been consistent and straightforward.
- *   The following table summarizes matters since version 0.89c, which was
- *   the first widely used release:
- *
- *    source                 png.h  png.h  shared-lib
- *    version                string   int  version
- *    -------                ------ -----  ----------
- *    0.89c "1.0 beta 3"     0.89      89  1.0.89
- *    0.90  "1.0 beta 4"     0.90      90  0.90  [should have been 2.0.90]
- *    0.95  "1.0 beta 5"     0.95      95  0.95  [should have been 2.0.95]
- *    0.96  "1.0 beta 6"     0.96      96  0.96  [should have been 2.0.96]
- *    0.97b "1.00.97 beta 7" 1.00.97   97  1.0.1 [should have been 2.0.97]
- *    0.97c                  0.97      97  2.0.97
- *    0.98                   0.98      98  2.0.98
- *    0.99                   0.99      98  2.0.99
- *    0.99a-m                0.99      99  2.0.99
- *    1.00                   1.00     100  2.1.0 [100 should be 10000]
- *    1.0.0      (from here on, the   100  2.1.0 [100 should be 10000]
- *    1.0.1       png.h string is   10001  2.1.0
- *    1.0.1a-e    identical to the  10002  from here on, the shared library
- *    1.0.2       source version)   10002  is 2.V where V is the source code
- *    1.0.2a-b                      10003  version, except as noted.
- *    1.0.3                         10003
- *    1.0.3a-d                      10004
- *    1.0.4                         10004
- *    1.0.4a-f                      10005
- *    1.0.5 (+ 2 patches)           10005
- *    1.0.5a-d                      10006
- *    1.0.5e-r                      10100 (not source compatible)
- *    1.0.5s-v                      10006 (not binary compatible)
- *    1.0.6 (+ 3 patches)           10006 (still binary incompatible)
- *    1.0.6d-f                      10007 (still binary incompatible)
- *    1.0.6g                        10007
- *    1.0.6h                        10007  10.6h (testing xy.z so-numbering)
- *    1.0.6i                        10007  10.6i
- *    1.0.6j                        10007  2.1.0.6j (incompatible with 1.0.0)
- *    1.0.7beta11-14        DLLNUM  10007  2.1.0.7beta11-14 (binary compatible)
- *    1.0.7beta15-18           1    10007  2.1.0.7beta15-18 (binary compatible)
- *    1.0.7rc1-2               1    10007  2.1.0.7rc1-2 (binary compatible)
- *    1.0.7                    1    10007  (still compatible)
- *    1.0.8beta1-4             1    10008  2.1.0.8beta1-4
- *    1.0.8rc1                 1    10008  2.1.0.8rc1
- *    1.0.8                    1    10008  2.1.0.8
- *    1.0.9beta1-6             1    10009  2.1.0.9beta1-6
- *    1.0.9rc1                 1    10009  2.1.0.9rc1
- *    1.0.9beta7-10            1    10009  2.1.0.9beta7-10
- *    1.0.9rc2                 1    10009  2.1.0.9rc2
- *    1.0.9                    1    10009  2.1.0.9
- *    1.0.10beta1              1    10010  2.1.0.10beta1
- *    1.0.10rc1                1    10010  2.1.0.10rc1
- *    1.0.10                   1    10010  2.1.0.10
- *    1.0.11beta1-3            1    10011  2.1.0.11beta1-3
- *    1.0.11rc1                1    10011  2.1.0.11rc1
- *    1.0.11                   1    10011  2.1.0.11
- *    1.0.12beta1-2            2    10012  2.1.0.12beta1-2
- *    1.0.12rc1                2    10012  2.1.0.12rc1
- *    1.0.12                   2    10012  2.1.0.12
- *    1.1.0a-f                 -    10100  2.1.1.0a-f (branch abandoned)
- *    1.2.0beta1-2             2    10200  2.1.2.0beta1-2
- *    1.2.0beta3-5             3    10200  3.1.2.0beta3-5
- *    1.2.0rc1                 3    10200  3.1.2.0rc1
- *    1.2.0                    3    10200  3.1.2.0
- *    1.2.1beta1-4             3    10201  3.1.2.1beta1-4
- *    1.2.1rc1-2               3    10201  3.1.2.1rc1-2
- *    1.2.1                    3    10201  3.1.2.1
- *    1.2.2beta1-6            12    10202  12.so.0.1.2.2beta1-6
- *    1.0.13beta1             10    10013  10.so.0.1.0.13beta1
- *    1.0.13rc1               10    10013  10.so.0.1.0.13rc1
- *    1.2.2rc1                12    10202  12.so.0.1.2.2rc1
- *    1.0.13                  10    10013  10.so.0.1.0.13
- *    1.2.2                   12    10202  12.so.0.1.2.2
- *    1.2.3rc1-6              12    10203  12.so.0.1.2.3rc1-6
- *    1.2.3                   12    10203  12.so.0.1.2.3
- *    1.2.4beta1-3            13    10204  12.so.0.1.2.4beta1-3
- *    1.0.14rc1               13    10014  10.so.0.1.0.14rc1
- *    1.2.4rc1                13    10204  12.so.0.1.2.4rc1
- *    1.0.14                  10    10014  10.so.0.1.0.14
- *    1.2.4                   13    10204  12.so.0.1.2.4
- *    1.2.5beta1-2            13    10205  12.so.0.1.2.5beta1-2
- *    1.0.15rc1-3             10    10015  10.so.0.1.0.15rc1-3
- *    1.2.5rc1-3              13    10205  12.so.0.1.2.5rc1-3
- *    1.0.15                  10    10015  10.so.0.1.0.15
- *    1.2.5                   13    10205  12.so.0.1.2.5
- *    1.2.6beta1-4            13    10206  12.so.0.1.2.6beta1-4
- *    1.0.16                  10    10016  10.so.0.1.0.16
- *    1.2.6                   13    10206  12.so.0.1.2.6
- *    1.2.7beta1-2            13    10207  12.so.0.1.2.7beta1-2
- *    1.0.17rc1               10    10017  12.so.0.1.0.17rc1
- *    1.2.7rc1                13    10207  12.so.0.1.2.7rc1
- *    1.0.17                  10    10017  12.so.0.1.0.17
- *    1.2.7                   13    10207  12.so.0.1.2.7
- *    1.2.8beta1-5            13    10208  12.so.0.1.2.8beta1-5
- *    1.0.18rc1-5             10    10018  12.so.0.1.0.18rc1-5
- *    1.2.8rc1-5              13    10208  12.so.0.1.2.8rc1-5
- *    1.0.18                  10    10018  12.so.0.1.0.18
- *    1.2.8                   13    10208  12.so.0.1.2.8
- *    1.2.9beta1-3            13    10209  12.so.0.1.2.9beta1-3
- *    1.2.9beta4-11           13    10209  12.so.0.9[.0]
- *    1.2.9rc1                13    10209  12.so.0.9[.0]
- *    1.2.9                   13    10209  12.so.0.9[.0]
- *    1.2.10beta1-7           13    10210  12.so.0.10[.0]
- *    1.2.10rc1-2             13    10210  12.so.0.10[.0]
- *    1.2.10                  13    10210  12.so.0.10[.0]
- *    1.4.0beta1-5            14    10400  14.so.0.0[.0]
- *    1.2.11beta1-4           13    10211  12.so.0.11[.0]
- *    1.4.0beta7-8            14    10400  14.so.0.0[.0]
- *    1.2.11                  13    10211  12.so.0.11[.0]
- *    1.2.12                  13    10212  12.so.0.12[.0]
- *    1.4.0beta9-14           14    10400  14.so.0.0[.0]
- *    1.2.13                  13    10213  12.so.0.13[.0]
- *    1.4.0beta15-36          14    10400  14.so.0.0[.0]
- *    1.4.0beta37-87          14    10400  14.so.14.0[.0]
- *    1.4.0rc01               14    10400  14.so.14.0[.0]
- *    1.4.0beta88-109         14    10400  14.so.14.0[.0]
- *    1.4.0rc02-08            14    10400  14.so.14.0[.0]
- *    1.4.0                   14    10400  14.so.14.0[.0]
- *    1.4.1beta01-03          14    10401  14.so.14.1[.0]
- *    1.4.1rc01               14    10401  14.so.14.1[.0]
- *    1.4.1beta04-12          14    10401  14.so.14.1[.0]
- *    1.4.1                   14    10401  14.so.14.1[.0]
- *    1.4.2                   14    10402  14.so.14.2[.0]
- *    1.4.3                   14    10403  14.so.14.3[.0]
- *    1.4.4                   14    10404  14.so.14.4[.0]
- *    1.5.0beta01-58          15    10500  15.so.15.0[.0]
- *    1.5.0rc01-07            15    10500  15.so.15.0[.0]
- *    1.5.0                   15    10500  15.so.15.0[.0]
- *    1.5.1beta01-11          15    10501  15.so.15.1[.0]
- *    1.5.1rc01-02            15    10501  15.so.15.1[.0]
- *    1.5.1                   15    10501  15.so.15.1[.0]
- *    1.5.2beta01-03          15    10502  15.so.15.2[.0]
- *    1.5.2rc01-03            15    10502  15.so.15.2[.0]
- *    1.5.2                   15    10502  15.so.15.2[.0]
- *    1.5.3beta01-10          15    10503  15.so.15.3[.0]
- *    1.5.3rc01-02            15    10503  15.so.15.3[.0]
- *    1.5.3beta11             15    10503  15.so.15.3[.0]
- *    1.5.3 [omitted]
- *    1.5.4beta01-08          15    10504  15.so.15.4[.0]
- *    1.5.4rc01               15    10504  15.so.15.4[.0]
- *    1.5.4                   15    10504  15.so.15.4[.0]
- *    1.5.5beta01-08          15    10505  15.so.15.5[.0]
- *    1.5.5rc01               15    10505  15.so.15.5[.0]
- *    1.5.5                   15    10505  15.so.15.5[.0]
- *    1.5.6beta01-07          15    10506  15.so.15.6[.0]
- *    1.5.6rc01-03            15    10506  15.so.15.6[.0]
- *    1.5.6                   15    10506  15.so.15.6[.0]
- *    1.5.7beta01-05          15    10507  15.so.15.7[.0]
- *    1.5.7rc01-03            15    10507  15.so.15.7[.0]
- *    1.5.7                   15    10507  15.so.15.7[.0]
- *
- *   Henceforth the source version will match the shared-library major
- *   and minor numbers; the shared-library major version number will be
- *   used for changes in backward compatibility, as it is intended.  The
- *   PNG_LIBPNG_VER macro, which is not used within libpng but is available
- *   for applications, is an unsigned integer of the form xyyzz corresponding
- *   to the source version x.y.z (leading zeros in y and z).  Beta versions
- *   were given the previous public release number plus a letter, until
- *   version 1.0.6j; from then on they were given the upcoming public
- *   release number plus "betaNN" or "rcN".
- *
- *   Binary incompatibility exists only when applications make direct access
- *   to the info_ptr or png_ptr members through png.h, and the compiled
- *   application is loaded with a different version of the library.
- *
- *   DLLNUM will change each time there are forward or backward changes
- *   in binary compatibility (e.g., when a new feature is added).
- *
- * See libpng-manual.txt or libpng.3 for more information.  The PNG
- * specification is available as a W3C Recommendation and as an ISO
- * Specification, <http://www.w3.org/TR/2003/REC-PNG-20031110/
  */
 
 /*
@@ -197,20 +25,16 @@
  *
  * This code is released under the libpng license.
  *
- * libpng versions 1.2.6, August 15, 2004, through 1.5.7, December 15, 2011, are
- * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-1.2.5
- * with the following individual added to the list of Contributing Authors:
- *
- *    Cosmin Truta
- *
- * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
- * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-1.0.6
- * with the following individuals added to the list of Contributing Authors:
+ * libpng versions 1.0.7, July 1, 2000, through 1.5.26, December 17, 2015, are
+ * Copyright (c) 2000-2002, 2004, 2006-2015 Glenn Randers-Pehrson, are
+ * derived from libpng-1.0.6, and are distributed according to the same
+ * disclaimer and license as libpng-1.0.6 with the following individuals
+ * added to the list of Contributing Authors:
  *
  *    Simon-Pierre Cadieux
  *    Eric S. Raymond
+ *    Mans Rullgard
+ *    Cosmin Truta
  *    Gilles Vollant
  *
  * and with the following additions to the disclaimer:
@@ -223,18 +47,20 @@
  *    the user.
  *
  * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
- * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-0.96,
- * with the following individuals added to the list of Contributing Authors:
+ * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+ * libpng-0.96, and are distributed according to the same disclaimer and
+ * license as libpng-0.96, with the following individuals added to the list
+ * of Contributing Authors:
  *
  *    Tom Lane
  *    Glenn Randers-Pehrson
  *    Willem van Schaik
  *
  * libpng versions 0.89, June 1996, through 0.96, May 1997, are
- * Copyright (c) 1996, 1997 Andreas Dilger
- * Distributed according to the same disclaimer and license as libpng-0.88,
- * with the following individuals added to the list of Contributing Authors:
+ * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+ * and are distributed according to the same disclaimer and license as
+ * libpng-0.88, with the following individuals added to the list of
+ * Contributing Authors:
  *
  *    John Bowler
  *    Kevin Bracey
@@ -244,7 +70,7 @@
  *    Tom Tanner
  *
  * libpng versions 0.5, May 1995, through 0.88, January 1996, are
- * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
  *
  * For the purposes of this copyright and license, "Contributing Authors"
  * is defined as the following set of individuals:
@@ -272,29 +98,32 @@
  *   2. Altered versions must be plainly marked as such and must not
  *      be misrepresented as being the original source.
  *
- *   3. This Copyright notice may not be removed or altered from
- *      any source or altered source distribution.
+ *   3. This Copyright notice may not be removed or altered from any
+ *      source or altered source distribution.
  *
  * The Contributing Authors and Group 42, Inc. specifically permit, without
  * fee, and encourage the use of this source code as a component to
  * supporting the PNG file format in commercial products.  If you use this
  * source code in a product, acknowledgment is not required but would be
  * appreciated.
+ *
+ * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.
  */
 
 /*
  * A "png_get_copyright" function is available, for convenient use in "about"
  * boxes and the like:
  *
- *     printf("%s", png_get_copyright(NULL));
+ *    printf("%s", png_get_copyright(NULL));
  *
  * Also, the PNG logo (in PNG format, of course) is supplied in the
  * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
  */
 
 /*
- * Libpng is OSI Certified Open Source Software.  OSI Certified is a
- * certification mark of the Open Source Initiative.
+ * Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is
+ * a certification mark of the Open Source Initiative. OSI has not addressed
+ * the additional disclaimers inserted at version 1.0.7.
  */
 
 /*
@@ -305,17 +134,90 @@
  * Thanks to Frank J. T. Wojcik for helping with the documentation.
  */
 
+/* Note about libpng version numbers:
+ *
+ *    Due to various miscommunications, unforeseen code incompatibilities
+ *    and occasional factors outside the authors' control, version numbering
+ *    on the library has not always been consistent and straightforward.
+ *    The following table summarizes matters since version 0.89c, which was
+ *    the first widely used release:
+ *
+ *    source                 png.h  png.h  shared-lib
+ *    version                string   int  version
+ *    -------                ------ -----  ----------
+ *    0.89c "1.0 beta 3"     0.89      89  1.0.89
+ *    0.90  "1.0 beta 4"     0.90      90  0.90  [should have been 2.0.90]
+ *    0.95  "1.0 beta 5"     0.95      95  0.95  [should have been 2.0.95]
+ *    0.96  "1.0 beta 6"     0.96      96  0.96  [should have been 2.0.96]
+ *    0.97b "1.00.97 beta 7" 1.00.97   97  1.0.1 [should have been 2.0.97]
+ *    0.97c                  0.97      97  2.0.97
+ *    0.98                   0.98      98  2.0.98
+ *    0.99                   0.99      98  2.0.99
+ *    0.99a-m                0.99      99  2.0.99
+ *    1.00                   1.00     100  2.1.0 [100 should be 10000]
+ *    1.0.0      (from here on, the   100  2.1.0 [100 should be 10000]
+ *    1.0.1       png.h string is   10001  2.1.0
+ *    1.0.1a-e    identical to the  10002  from here on, the shared library
+ *    1.0.2       source version)   10002  is 2.V where V is the source code
+ *    1.0.2a-b                      10003  version, except as noted.
+ *    1.0.3                         10003
+ *    1.0.3a-d                      10004
+ *    1.0.4                         10004
+ *    1.0.4a-f                      10005
+ *    1.0.5 (+ 2 patches)           10005
+ *    1.0.5a-d                      10006
+ *    1.0.5e-r                      10100 (not source compatible)
+ *    1.0.5s-v                      10006 (not binary compatible)
+ *    1.0.6 (+ 3 patches)           10006 (still binary incompatible)
+ *    1.0.6d-f                      10007 (still binary incompatible)
+ *    1.0.6g                        10007
+ *    1.0.6h                        10007  10.6h (testing xy.z so-numbering)
+ *    1.0.6i                        10007  10.6i
+ *    1.0.6j                        10007  2.1.0.6j (incompatible with 1.0.0)
+ *    1.0.7beta11-14        DLLNUM  10007  2.1.0.7beta11-14 (binary compatible)
+ *    1.0.7beta15-18           1    10007  2.1.0.7beta15-18 (binary compatible)
+ *    1.0.7rc1-2               1    10007  2.1.0.7rc1-2 (binary compatible)
+ *    1.0.7                    1    10007  (still compatible)
+ *    ...
+ *    1.0.19                  10    10019  10.so.0.19[.0]
+ *    ...
+ *    1.2.53                  13    10253  12.so.0.53[.0]
+ *    ...
+ *    1.5.25                  15    10525  15.so.15.25[.0]
+ *
+ *    Henceforth the source version will match the shared-library major
+ *    and minor numbers; the shared-library major version number will be
+ *    used for changes in backward compatibility, as it is intended.  The
+ *    PNG_LIBPNG_VER macro, which is not used within libpng but is available
+ *    for applications, is an unsigned integer of the form xyyzz corresponding
+ *    to the source version x.y.z (leading zeros in y and z).  Beta versions
+ *    were given the previous public release number plus a letter, until
+ *    version 1.0.6j; from then on they were given the upcoming public
+ *    release number plus "betaNN" or "rcNN".
+ *
+ *    Binary incompatibility exists only when applications make direct access
+ *    to the info_ptr or png_ptr members through png.h, and the compiled
+ *    application is loaded with a different version of the library.
+ *
+ *    DLLNUM will change each time there are forward or backward changes
+ *    in binary compatibility (e.g., when a new feature is added).
+ *
+ * See libpng.txt or libpng.3 for more information.  The PNG specification
+ * is available as a W3C Recommendation and as an ISO Specification,
+ * <http://www.w3.org/TR/2003/REC-PNG-20031110/
+ */
+
 /*
  * Y2K compliance in libpng:
  * =========================
  *
- *    December 15, 2011
+ *    December 17, 2015
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.5.7 are Y2K compliant.  It is my belief that
+ *    upward through 1.5.26 are Y2K compliant.  It is my belief that
  *    earlier versions were also Y2K compliant.
  *
  *    Libpng only has two year fields.  One is a 2-byte unsigned integer
@@ -326,7 +228,8 @@
  *        "png_uint_16 year" in png_time_struct.
  *
  *    The string is
- *        "png_char time_buffer" in png_struct
+ *        "char time_buffer[29]" in png_struct.  This will be no
+ *    longer used in libpng-1.6.0 and will be removed from libpng-1.7.0.
  *
  *    There are seven time-related functions:
  *        png.c: png_convert_to_rfc_1123() in png.c
@@ -366,16 +269,18 @@
 /* This is not the place to learn how to use libpng. The file libpng-manual.txt
  * describes how to use libpng, and the file example.c summarizes it
  * with some code on which to build.  This file is useful for looking
- * at the actual function definitions and structure components.
+ * at the actual function definitions and structure components.  If that
+ * file has been stripped from your copy of libpng, you can find it at
+ * <http://www.libpng.org/pub/png/libpng-manual.txt>
  *
  * If you just need to read a PNG file and don't want to read the documentation
  * skip to the end of this file and read the section entitled 'simplified API'.
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.5.7"
+#define PNG_LIBPNG_VER_STRING "1.5.26"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.5.7 - December 15, 2011\n"
+     " libpng version 1.5.26 - December 17, 2015\n"
 
 #define PNG_LIBPNG_VER_SONUM   15
 #define PNG_LIBPNG_VER_DLLNUM  15
@@ -383,7 +288,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   5
-#define PNG_LIBPNG_VER_RELEASE 7
+#define PNG_LIBPNG_VER_RELEASE 26
 
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
@@ -406,7 +311,7 @@
 #define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with
                                        PNG_LIBPNG_BUILD_PRIVATE */
 
-#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_BETA
+#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
 
 /* Careful here.  At one time, Guy wanted to use 082, but that would be octal.
  * We must not include leading zeros.
@@ -414,7 +319,7 @@
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10507 /* 1.5.7 */
+#define PNG_LIBPNG_VER 10526 /* 1.5.26 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -447,7 +352,7 @@
 
 /* Machine specific configuration. */
 #  include "pngconf.h"
-#endif
+#endif /* PNG_VERSION_INFO_ONLY */
 
 /*
  * Added at libpng-1.2.8
@@ -536,7 +441,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_5_7;
+typedef char* png_libpng_version_1_5_26;
 
 /* Three color definitions.  The order of the red, green, and blue, (and the
  * exact size) is not important, although the size of the fields need to
@@ -1007,11 +912,13 @@ PNG_EXPORTA(5, png_structp, png_create_write_struct,
     png_error_ptr warn_fn),
     PNG_ALLOCATED);
 
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
 PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size,
     (png_const_structp png_ptr));
 
 PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structp png_ptr,
     png_size_t size));
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
 
 /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
  * match up.
@@ -1145,9 +1052,9 @@ PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structp png_ptr));
 #define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/
 
 PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structp png_ptr,
-    int error_action, double red, double green));
+    int error_action, double red, double green))
 PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structp png_ptr,
-    int error_action, png_fixed_point red, png_fixed_point green));
+    int error_action, png_fixed_point red, png_fixed_point green))
 
 PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp
     png_ptr));
@@ -1215,9 +1122,9 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
 #define PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */
 
 PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode,
-    double output_gamma));
+    double output_gamma))
 PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr,
-    int mode, png_fixed_point output_gamma));
+    int mode, png_fixed_point output_gamma))
 #endif
 
 #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
@@ -1440,10 +1347,10 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr));
  */
 PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr,
     png_const_color_16p background_color, int background_gamma_code,
-    int need_expand, double background_gamma));
+    int need_expand, double background_gamma))
 PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr,
     png_const_color_16p background_color, int background_gamma_code,
-    int need_expand, png_fixed_point background_gamma));
+    int need_expand, png_fixed_point background_gamma))
 #endif
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
 #  define PNG_BACKGROUND_GAMMA_UNKNOWN 0
@@ -1492,9 +1399,9 @@ PNG_EXPORT(49, void, png_set_quantize,
  */
 PNG_FP_EXPORT(50, void, png_set_gamma,
     (png_structp png_ptr, double screen_gamma,
-    double override_file_gamma));
+    double override_file_gamma))
 PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr,
-    png_fixed_point screen_gamma, png_fixed_point override_file_gamma));
+    png_fixed_point screen_gamma, png_fixed_point override_file_gamma))
 #endif
 
 #ifdef PNG_WRITE_FLUSH_SUPPORTED
@@ -1623,47 +1530,17 @@ PNG_EXPORT(67, void, png_set_filter,
 #define PNG_FILTER_VALUE_PAETH 4
 #define PNG_FILTER_VALUE_LAST  5
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */
-/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
- * defines, either the default (minimum-sum-of-absolute-differences), or
- * the experimental method (weighted-minimum-sum-of-absolute-differences).
- *
- * Weights are factors >= 1.0, indicating how important it is to keep the
- * filter type consistent between rows.  Larger numbers mean the current
- * filter is that many times as likely to be the same as the "num_weights"
- * previous filters.  This is cumulative for each previous row with a weight.
- * There needs to be "num_weights" values in "filter_weights", or it can be
- * NULL if the weights aren't being specified.  Weights have no influence on
- * the selection of the first row filter.  Well chosen weights can (in theory)
- * improve the compression for a given image.
- *
- * Costs are factors >= 1.0 indicating the relative decoding costs of a
- * filter type.  Higher costs indicate more decoding expense, and are
- * therefore less likely to be selected over a filter with lower computational
- * costs.  There needs to be a value in "filter_costs" for each valid filter
- * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
- * setting the costs.  Costs try to improve the speed of decompression without
- * unduly increasing the compressed image size.
- *
- * A negative weight or cost indicates the default value is to be used, and
- * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
- * The default values for both weights and costs are currently 1.0, but may
- * change if good general weighting/cost heuristics can be found.  If both
- * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
- * to the UNWEIGHTED method, but with added encoding time/computation.
- */
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
 PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structp png_ptr,
     int heuristic_method, int num_weights, png_const_doublep filter_weights,
-    png_const_doublep filter_costs));
+    png_const_doublep filter_costs))
 PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
     (png_structp png_ptr,
     int heuristic_method, int num_weights, png_const_fixed_point_p
-    filter_weights, png_const_fixed_point_p filter_costs));
+    filter_weights, png_const_fixed_point_p filter_costs))
 #endif /*  PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
 
-/* Heuristic used for row filter selection.  These defines should NOT be
- * changed.
- */
+/* The following are no longer used and will be removed from libpng-1.7: */
 #define PNG_FILTER_HEURISTIC_DEFAULT    0  /* Currently "UNWEIGHTED" */
 #define PNG_FILTER_HEURISTIC_UNWEIGHTED 1  /* Used by libpng < 0.95 */
 #define PNG_FILTER_HEURISTIC_WEIGHTED   2  /* Experimental feature */
@@ -1677,6 +1554,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
  * for PNG images, and do considerably fewer caclulations.  In the future,
  * these values may not correspond directly to the zlib compression levels.
  */
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
 PNG_EXPORT(69, void, png_set_compression_level,
     (png_structp png_ptr, int level));
 
@@ -1694,7 +1572,7 @@ PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr,
 
 PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr,
     int method));
-#endif
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
 
 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
 /* Also set zlib parameters for compressing non-IDAT chunks */
@@ -1716,6 +1594,7 @@ PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp
 PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr,
     int method));
 #endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
+#endif /* WRITE */
 
 /* These next functions are called for input/output, memory, and error
  * handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,
@@ -1927,6 +1806,8 @@ PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr,
 #else
 /* Fatal error in PNG image of libpng - can't continue */
 PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN);
+#  define png_error(s1,s2) png_err(s1)
+#  define png_chunk_error(s1,s2) png_err(s1)
 #endif
 
 #ifdef PNG_WARNINGS_SUPPORTED
@@ -1937,6 +1818,9 @@ PNG_EXPORT(105, void, png_warning, (png_structp png_ptr,
 /* Non-fatal error in libpng, chunk name is prepended to message. */
 PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr,
     png_const_charp warning_message));
+#else
+#  define png_warning(s1,s2) ((void)(s1))
+#  define png_chunk_warning(s1,s2) ((void)(s1))
 #endif
 
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
@@ -2040,9 +1924,9 @@ PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,
 
 /* Returns pixel aspect ratio, computed from pHYs chunk data.  */
 PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,
-    (png_const_structp png_ptr, png_const_infop info_ptr));
+    (png_const_structp png_ptr, png_const_infop info_ptr))
 PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,
-    (png_const_structp png_ptr, png_const_infop info_ptr));
+    (png_const_structp png_ptr, png_const_infop info_ptr))
 
 /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
 PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,
@@ -2075,11 +1959,11 @@ PNG_EXPORT(132, void, png_set_bKGD, (png_structp png_ptr, png_infop info_ptr,
 PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr,
    png_const_infop info_ptr, double *white_x, double *white_y, double *red_x,
     double *red_y, double *green_x, double *green_y, double *blue_x,
-    double *blue_y));
+    double *blue_y))
 PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr,
     png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z,
     double *green_X, double *green_Y, double *green_Z, double *blue_X,
-    double *blue_Y, double *blue_Z));
+    double *blue_Y, double *blue_Z))
 #ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */
 PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
     (png_const_structp png_ptr,
@@ -2087,7 +1971,7 @@ PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
     png_fixed_point *int_white_y, png_fixed_point *int_red_x,
     png_fixed_point *int_red_y, png_fixed_point *int_green_x,
     png_fixed_point *int_green_y, png_fixed_point *int_blue_x,
-    png_fixed_point *int_blue_y));
+    png_fixed_point *int_blue_y))
 #endif
 PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
     (png_structp png_ptr, png_const_infop info_ptr,
@@ -2095,46 +1979,46 @@ PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
     png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
     png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
     png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
-    png_fixed_point *int_blue_Z));
+    png_fixed_point *int_blue_Z))
 #endif
 
 #ifdef PNG_cHRM_SUPPORTED
 PNG_FP_EXPORT(135, void, png_set_cHRM,
     (png_structp png_ptr, png_infop info_ptr,
     double white_x, double white_y, double red_x, double red_y, double green_x,
-    double green_y, double blue_x, double blue_y));
+    double green_y, double blue_x, double blue_y))
 PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr,
     png_infop info_ptr, double red_X, double red_Y, double red_Z,
     double green_X, double green_Y, double green_Z, double blue_X,
-    double blue_Y, double blue_Z));
+    double blue_Y, double blue_Z))
 PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr,
     png_infop info_ptr, png_fixed_point int_white_x,
     png_fixed_point int_white_y, png_fixed_point int_red_x,
     png_fixed_point int_red_y, png_fixed_point int_green_x,
     png_fixed_point int_green_y, png_fixed_point int_blue_x,
-    png_fixed_point int_blue_y));
+    png_fixed_point int_blue_y))
 PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr,
     png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
     png_fixed_point int_red_Z, png_fixed_point int_green_X,
     png_fixed_point int_green_Y, png_fixed_point int_green_Z,
     png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
-    png_fixed_point int_blue_Z));
+    png_fixed_point int_blue_Z))
 #endif
 
 #ifdef PNG_gAMA_SUPPORTED
 PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA,
     (png_const_structp png_ptr, png_const_infop info_ptr,
-    double *file_gamma));
+    double *file_gamma))
 PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,
     (png_const_structp png_ptr, png_const_infop info_ptr,
-    png_fixed_point *int_file_gamma));
+    png_fixed_point *int_file_gamma))
 #endif
 
 #ifdef PNG_gAMA_SUPPORTED
 PNG_FP_EXPORT(139, void, png_set_gAMA, (png_structp png_ptr,
-    png_infop info_ptr, double file_gamma));
+    png_infop info_ptr, double file_gamma))
 PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_structp png_ptr,
-    png_infop info_ptr, png_fixed_point int_file_gamma));
+    png_infop info_ptr, png_fixed_point int_file_gamma))
 #endif
 
 #ifdef PNG_hIST_SUPPORTED
@@ -2300,7 +2184,7 @@ PNG_EXPORT(167, void, png_set_tRNS,
 #ifdef PNG_sCAL_SUPPORTED
 PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL,
     (png_const_structp png_ptr, png_const_infop info_ptr,
-    int *unit, double *width, double *height));
+    int *unit, double *width, double *height))
 #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
 /* NOTE: this API is currently implemented using floating point arithmetic,
  * consequently it can only be used on systems with floating point support.
@@ -2310,7 +2194,7 @@ PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL,
 PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,
     (png_structp png_ptr, png_const_infop info_ptr, int *unit,
     png_fixed_point *width,
-    png_fixed_point *height));
+    png_fixed_point *height))
 #endif
 PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
     (png_const_structp png_ptr, png_const_infop info_ptr,
@@ -2318,10 +2202,10 @@ PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
 
 PNG_FP_EXPORT(170, void, png_set_sCAL,
     (png_structp png_ptr, png_infop info_ptr,
-    int unit, double width, double height));
+    int unit, double width, double height))
 PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_structp png_ptr,
    png_infop info_ptr, int unit, png_fixed_point width,
-   png_fixed_point height));
+   png_fixed_point height))
 PNG_EXPORT(171, void, png_set_sCAL_s,
     (png_structp png_ptr, png_infop info_ptr,
     int unit, png_const_charp swidth, png_const_charp sheight));
@@ -2434,17 +2318,17 @@ PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,
     (png_const_structp png_ptr, png_const_infop info_ptr));
 
 PNG_FP_EXPORT(196, float, png_get_x_offset_inches,
-    (png_const_structp png_ptr, png_const_infop info_ptr));
+    (png_const_structp png_ptr, png_const_infop info_ptr))
 #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
 PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,
-    (png_structp png_ptr, png_const_infop info_ptr));
+    (png_structp png_ptr, png_const_infop info_ptr))
 #endif
 
 PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structp png_ptr,
-    png_const_infop info_ptr));
+    png_const_infop info_ptr))
 #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
 PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,
-    (png_structp png_ptr, png_const_infop info_ptr));
+    (png_structp png_ptr, png_const_infop info_ptr))
 #endif
 
 #  ifdef PNG_pHYs_SUPPORTED
@@ -2627,10 +2511,60 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
 
 #  define png_get_int_32(buf) \
      ((png_int_32)((*(buf) & 0x80) \
-      ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \
+      ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \
       : (png_int_32)png_get_uint_32(buf)))
 #endif
 
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+PNG_EXPORT(234, void, png_set_check_for_invalid_index, (png_structp png_ptr,
+    int allowed));
+#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+PNG_EXPORT(235, int, png_get_palette_max, (png_const_structp png_ptr,
+    png_const_infop info_ptr));
+#  endif
+#endif /* CHECK_FOR_INVALID_INDEX */
+
+/*******************************************************************************
+ *  IMPLEMENTATION OPTIONS
+ *******************************************************************************
+ *
+ * Support for arbitrary implementation-specific optimizations.  The API allows
+ * particular options to be turned on or off.  'Option' is the number of the
+ * option and 'onoff' is 0 (off) or non-0 (on).  The value returned is given
+ * by the PNG_OPTION_ defines below.
+ *
+ * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions,
+ *           are detected at run time, however sometimes it may be impossible
+ *           to do this in user mode, in which case it is necessary to discover
+ *           the capabilities in an OS specific way.  Such capabilities are
+ *           listed here when libpng has support for them and must be turned
+ *           ON by the application if present.
+ *
+ * SOFTWARE: sometimes software optimizations actually result in performance
+ *           decrease on some architectures or systems, or with some sets of
+ *           PNG images.  'Software' options allow such optimizations to be
+ *           selected at run time.
+ */
+#ifdef PNG_SET_OPTION_SUPPORTED
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
+#endif
+#define PNG_OPTION_NEXT  2 /* Next option - numbers must be even */
+
+/* Return values: NOTE: there are four values and 'off' is *not* zero */
+#define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
+#define PNG_OPTION_INVALID 1 /* Option number out of range */
+#define PNG_OPTION_OFF     2
+#define PNG_OPTION_ON      3
+
+PNG_EXPORT(236, int, png_set_option, (png_structp png_ptr, int option,
+   int onoff));
+#endif
+
+/*******************************************************************************
+ *  END OF HARDWARE OPTIONS
+ ******************************************************************************/
+
 /* Maintainer: Put new public prototypes here ^, in libpng.3, and project
  * defs
  */
@@ -2640,7 +2574,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
  * scripts/symbols.def as well.
  */
 #ifdef PNG_EXPORT_LAST_ORDINAL
-  PNG_EXPORT_LAST_ORDINAL(233);
+  PNG_EXPORT_LAST_ORDINAL(236);
 #endif
 
 #ifdef __cplusplus

+ 37 - 35
drivers/png/pngconf.h

@@ -1,9 +1,9 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.5.7 - December 15, 2011
+ * libpng version 1.5.26, December 17, 2015
  *
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -11,9 +11,7 @@
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
- */
-
-/* Any machine specific code is near the front of this file, so if you
+ * Any machine specific code is near the front of this file, so if you
  * are configuring libpng for a machine, you may want to read the section
  * starting here down to where it starts to typedef png_color, png_text,
  * and png_info.
@@ -25,7 +23,7 @@
 #ifndef PNG_BUILDING_SYMBOL_TABLE
 /* PNG_NO_LIMITS_H may be used to turn off the use of the standard C
  * definition file for  machine specific limits, this may impact the
- * correctness of the definitons below (see uses of INT_MAX).
+ * correctness of the definitions below (see uses of INT_MAX).
  */
 #  ifndef PNG_NO_LIMITS_H
 #    include <limits.h>
@@ -51,8 +49,8 @@
 
 /* This controls optimization of the reading of 16 and 32 bit values
  * from PNG files.  It can be set on a per-app-file basis - it
- * just changes whether a macro is used to the function is called.
- * The library builder sets the default, if read functions are not
+ * just changes whether a macro is used when the function is called.
+ * The library builder sets the default; if read functions are not
  * built into the library the macro implementation is forced on.
  */
 #ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED
@@ -177,18 +175,16 @@
  * ==========================
  * This code is used at build time to find PNG_IMPEXP, the API settings
  * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL
- * import processing is possible.  On Windows/x86 systems it also sets
+ * import processing is possible.  On Windows systems it also sets
  * compiler-specific macros to the values required to change the calling
  * conventions of the various functions.
  */
-#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
-      defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) ) &&\
-    ( defined(_X86_) || defined(_X64_) || defined(_M_IX86) ||\
-      defined(_M_X64) || defined(_M_IA64) )
-  /* Windows system (DOS doesn't support DLLs) running on x86/x64.  Includes
-   * builds under Cygwin or MinGW.  Also includes Watcom builds but these need
-   * special treatment because they are not compatible with GCC or Visual C
-   * because of different calling conventions.
+#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
+    defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+  /* Windows system (DOS doesn't support DLLs).  Includes builds under Cygwin or
+   * MinGW on any architecture currently supported by Windows.  Also includes
+   * Watcom builds but these need special treatment because they are not
+   * compatible with GCC or Visual C because of different calling conventions.
    */
 #  if PNG_API_RULE == 2
     /* If this line results in an error, either because __watcall is not
@@ -199,9 +195,12 @@
 #    define PNGCAPI __watcall
 #  endif
 
-#  if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
+#  if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800))
 #    define PNGCAPI __cdecl
 #    if PNG_API_RULE == 1
+       /* If this line results in an error __stdcall is not understood and
+        * PNG_API_RULE should not have been set to '1'.
+        */
 #      define PNGAPI __stdcall
 #    endif
 #  else
@@ -239,7 +238,7 @@
 #    endif
 #  endif /* compiler */
 
-#else /* !Windows/x86 */
+#else /* !Windows */
 #  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
 #    define PNGAPI _System
 #  else /* !Windows/x86 && !OS/2 */
@@ -337,6 +336,7 @@
    * functions in png.h will generate compiler warnings.  Added at libpng
    * version 1.2.41.
    */
+
 #  if defined(__GNUC__)
 #    ifndef PNG_USE_RESULT
 #      define PNG_USE_RESULT __attribute__((__warn_unused_result__))
@@ -344,21 +344,23 @@
 #    ifndef PNG_NORETURN
 #      define PNG_NORETURN   __attribute__((__noreturn__))
 #    endif
-#    ifndef PNG_ALLOCATED
-#      define PNG_ALLOCATED  __attribute__((__malloc__))
-#    endif
-#    ifndef PNG_DEPRECATED
-#      define PNG_DEPRECATED __attribute__((__deprecated__))
-#    endif
-#    ifndef PNG_PRIVATE
-#      if 0 /* Doesn't work so we use deprecated instead*/
-#        define PNG_PRIVATE \
-          __attribute__((warning("This function is not exported by libpng.")))
-#      else
-#        define PNG_PRIVATE \
-          __attribute__((__deprecated__))
+#    if __GNUC__ >= 3
+#      ifndef PNG_ALLOCATED
+#        define PNG_ALLOCATED  __attribute__((__malloc__))
 #      endif
-#    endif
+#      ifndef PNG_DEPRECATED
+#        define PNG_DEPRECATED __attribute__((__deprecated__))
+#      endif
+#      ifndef PNG_PRIVATE
+#        if 0 /* Doesn't work so we use deprecated instead*/
+#          define PNG_PRIVATE \
+            __attribute__((warning("This function is not exported by libpng.")))
+#        else
+#          define PNG_PRIVATE \
+            __attribute__((__deprecated__))
+#        endif
+#      endif
+#    endif /* __GNUC__ >= 3 */
 #  endif /* __GNUC__ */
 
 #  if defined(_MSC_VER)  && (_MSC_VER >= 1300)
@@ -400,7 +402,7 @@
 #ifndef PNG_FP_EXPORT     /* A floating point API. */
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
 #     define PNG_FP_EXPORT(ordinal, type, name, args)\
-         PNG_EXPORT(ordinal, type, name, args)
+         PNG_EXPORT(ordinal, type, name, args);
 #  else                   /* No floating point APIs */
 #     define PNG_FP_EXPORT(ordinal, type, name, args)
 #  endif
@@ -408,7 +410,7 @@
 #ifndef PNG_FIXED_EXPORT  /* A fixed point API. */
 #  ifdef PNG_FIXED_POINT_SUPPORTED
 #     define PNG_FIXED_EXPORT(ordinal, type, name, args)\
-         PNG_EXPORT(ordinal, type, name, args)
+         PNG_EXPORT(ordinal, type, name, args);
 #  else                   /* No fixed point APIs */
 #     define PNG_FIXED_EXPORT(ordinal, type, name, args)
 #  endif

+ 9 - 13
drivers/png/pngdebug.h

@@ -1,12 +1,11 @@
 
 /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
  *
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.18 [February 6, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
- *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
@@ -25,7 +24,7 @@
  *   (actually ((void)0)).
  *
  *   level: level of detail of message, starting at 0.  A level 'n'
- *          message is preceded by 'n' tab characters (not implemented
+ *          message is preceded by 'n' 3-space indentations (not implemented
  *          on Microsoft compilers unless PNG_DEBUG_FILE is also
  *          defined, to allow debug DLL compilation with no standard IO).
  *   message: a printf(3) style text string.  A trailing '\n' is added
@@ -77,32 +76,29 @@
 #      endif /* PNG_DEBUG_FILE */
 
 #      if (PNG_DEBUG > 1)
-/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on
- * non-ISO compilers
- */
 #        ifdef __STDC__
 #          ifndef png_debug
 #            define png_debug(l,m) \
        do { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
-         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "   " : \
+         (num_tabs==2 ? "      " : (num_tabs>2 ? "         " : "")))); \
        } while (0)
 #          endif
 #          ifndef png_debug1
 #            define png_debug1(l,m,p1) \
        do { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
-         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "   " : \
+         (num_tabs==2 ? "      " : (num_tabs>2 ? "         " : ""))),p1); \
        } while (0)
 #          endif
 #          ifndef png_debug2
 #            define png_debug2(l,m,p1,p2) \
        do { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
-         (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "   " : \
+         (num_tabs==2 ? "      " : (num_tabs>2 ? "         " : ""))),p1,p2);\
        } while (0)
 #          endif
 #        else /* __STDC __ */

+ 46 - 34
drivers/png/pngerror.c

@@ -1,8 +1,8 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -161,7 +161,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
          case PNG_NUMBER_FORMAT_02u:
             /* Expects at least 2 digits. */
             mincount = 2;
-            /* fall through */
+            /* FALL THROUGH */
 
          case PNG_NUMBER_FORMAT_u:
             *--end = digits[number % 10];
@@ -171,7 +171,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
          case PNG_NUMBER_FORMAT_02x:
             /* This format expects at least two digits */
             mincount = 2;
-            /* fall through */
+            /* FALL THROUGH */
 
          case PNG_NUMBER_FORMAT_x:
             *--end = digits[number & 0xf];
@@ -193,7 +193,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
           * drop the decimal point.  If the number is a true zero handle that
           * here.
           */
-         if (output)
+         if (output != 0)
             *--end = '.';
          else if (number == 0) /* and !output */
             *--end = '0';
@@ -281,35 +281,40 @@ void
 png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
    png_const_charp message)
 {
-   /* The internal buffer is just 128 bytes - enough for all our messages,
-    * overflow doesn't happen because this code checks!
+   /* The internal buffer is just 192 bytes - enough for all our messages,
+    * overflow doesn't happen because this code checks!  If someone figures
+    * out how to send us a message longer than 192 bytes, all that will
+    * happen is that the message will be truncated appropriately.
     */
-   size_t i;
-   char msg[128];
-
-   for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i)
+   size_t i = 0; /* Index in the msg[] buffer: */
+   char msg[192];
+
+   /* Each iteration through the following loop writes at most one character
+    * to msg[i++] then returns here to validate that there is still space for
+    * the trailing '\0'.  It may (in the case of a parameter) read more than
+    * one character from message[]; it must check for '\0' and continue to the
+    * test if it finds the end of string.
+    */
+   while (i<(sizeof msg)-1 && *message != '\0')
    {
-      if (*message == '@')
+      /* '@' at end of string is now just printed (previously it was skipped);
+       * it is an error in the calling code to terminate the string with @.
+       */
+      if (p != NULL && *message == '@' && message[1] != '\0')
       {
-         int parameter = -1;
-         switch (*++message)
-         {
-            case '1':
-               parameter = 0;
-               break;
-
-            case '2':
-               parameter = 1;
-               break;
+         int parameter_char = *++message; /* Consume the '@' */
+         static const char valid_parameters[] = "123456789";
+         int parameter = 0;
 
-            case '\0':
-               continue; /* To break out of the for loop above. */
-
-            default:
-               break;
-         }
+         /* Search for the parameter digit, the index in the string is the
+          * parameter to use.
+          */
+         while (valid_parameters[parameter] != parameter_char &&
+            valid_parameters[parameter] != '\0')
+            ++parameter;
 
-         if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT)
+         /* If the parameter digit is out of range it will just get printed. */
+         if (parameter < PNG_WARNING_PARAMETER_COUNT)
          {
             /* Append this parameter */
             png_const_charp parm = p[parameter];
@@ -319,28 +324,32 @@ png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
              * that parm[] has been initialized, so there is no guarantee of a
              * trailing '\0':
              */
-            for (; i<(sizeof msg)-1 && parm != '\0' && parm < pend; ++i)
-               msg[i] = *parm++;
+            while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
+               msg[i++] = *parm++;
 
+            /* Consume the parameter digit too: */
             ++message;
             continue;
          }
 
          /* else not a parameter and there is a character after the @ sign; just
-          * copy that.
+          * copy that.  This is known not to be '\0' because of the test above.
           */
       }
 
       /* At this point *message can't be '\0', even in the bad parameter case
        * above where there is a lone '@' at the end of the message string.
        */
-      msg[i] = *message++;
+      msg[i++] = *message++;
    }
 
    /* i is always less than (sizeof msg), so: */
    msg[i] = '\0';
 
-   /* And this is the formatted message: */
+   /* And this is the formatted message, it may be larger than
+    * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these are
+    * not (currently) formatted.
+    */
    png_warning(png_ptr, msg);
 }
 #endif /* PNG_WARNINGS_SUPPORTED */
@@ -569,6 +578,9 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN)
    png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val);
 #  endif
    }
+#else
+   PNG_UNUSED(png_ptr);
+   PNG_UNUSED(val);
 #endif
    /* Here if not setjmp support or if png_ptr is null. */
    PNG_ABORT();

+ 55 - 9
drivers/png/pngget.c

@@ -1,8 +1,8 @@
 
 /* pngget.c - retrieval of values from info struct
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -123,6 +123,9 @@ png_get_x_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
          if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
             return (info_ptr->x_pixels_per_unit);
       }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -140,6 +143,9 @@ png_get_y_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
       if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
          return (info_ptr->y_pixels_per_unit);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -157,6 +163,9 @@ png_get_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
           info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)
          return (info_ptr->x_pixels_per_unit);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -175,6 +184,9 @@ png_get_pixel_aspect_ratio(png_const_structp png_ptr, png_const_infop info_ptr)
          return ((float)((float)info_ptr->y_pixels_per_unit
              /(float)info_ptr->x_pixels_per_unit));
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return ((float)0.0);
@@ -203,6 +215,9 @@ png_get_pixel_aspect_ratio_fixed(png_const_structp png_ptr,
           (png_int_32)info_ptr->x_pixels_per_unit))
          return res;
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return 0;
@@ -220,6 +235,9 @@ png_get_x_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr)
       if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
          return (info_ptr->x_offset);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -236,6 +254,9 @@ png_get_y_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr)
       if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
          return (info_ptr->y_offset);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -252,6 +273,9 @@ png_get_x_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr)
       if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
          return (info_ptr->x_offset);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -268,6 +292,9 @@ png_get_y_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr)
       if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
          return (info_ptr->y_offset);
    }
+#else
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(info_ptr)
 #endif
 
    return (0);
@@ -646,7 +673,7 @@ png_get_gAMA(png_const_structp png_ptr, png_const_infop info_ptr,
    png_fixed_point igamma;
    png_uint_32 ok = png_get_gAMA_fixed(png_ptr, info_ptr, &igamma);
 
-   if (ok)
+   if (ok != 0)
       *file_gamma = png_float(png_ptr, igamma, "png_get_gAMA");
 
    return ok;
@@ -741,14 +768,20 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
 {
    png_debug1(1, "in %s retrieval function", "IHDR");
 
-   if (png_ptr == NULL || info_ptr == NULL || width == NULL ||
-       height == NULL || bit_depth == NULL || color_type == NULL)
+   if (png_ptr == NULL || info_ptr == NULL)
       return (0);
 
-   *width = info_ptr->width;
-   *height = info_ptr->height;
-   *bit_depth = info_ptr->bit_depth;
-   *color_type = info_ptr->color_type;
+   if (width != NULL)
+       *width = info_ptr->width;
+
+   if (height != NULL)
+       *height = info_ptr->height;
+
+   if (bit_depth != NULL)
+       *bit_depth = info_ptr->bit_depth;
+
+   if (color_type != NULL)
+       *color_type = info_ptr->color_type;
 
    if (compression_type != NULL)
       *compression_type = info_ptr->compression_type;
@@ -1121,4 +1154,17 @@ png_get_io_chunk_name (png_structp png_ptr)
 }
 #endif /* ?PNG_IO_STATE_SUPPORTED */
 
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+int PNGAPI
+png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
+{
+   if (png_ptr != NULL && info_ptr != NULL)
+      return png_ptr->num_palette_max;
+
+   return (-1);
+}
+#  endif
+#endif
+
 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+ 3 - 4
drivers/png/pnginfo.h

@@ -1,12 +1,11 @@
 
 /* pnginfo.h - header file for PNG reference library
  *
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.0 [January 6, 2011]
+ * Copyright (c) 1998-2002,2004,2006-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
- *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
@@ -242,7 +241,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
 #ifdef PNG_sPLT_SUPPORTED
    /* Data on sPLT chunks (there may be more than one). */
    png_sPLT_tp splt_palettes;
-   png_uint_32 splt_palettes_num;
+   int splt_palettes_num;
 #endif
 
 #ifdef PNG_sCAL_SUPPORTED

+ 81 - 83
drivers/png/pnglibconf.h

@@ -1,51 +1,28 @@
-
-/* libpng STANDARD API DEFINITION */
-
+/* 1.5.26 STANDARD API DEFINITION */
 /* pnglibconf.h - library build configuration */
 
-/* Libpng 1.5.7 - December 15, 2011 */
+/* libpng version 1.5.26 - December 17, 2015 */
 
-/* Copyright (c) 1998-2011 Glenn Randers-Pehrson */
+/* Copyright (c) 1998-2015 Glenn Randers-Pehrson */
 
 /* This code is released under the libpng license. */
 /* For conditions of distribution and use, see the disclaimer */
 /* and license in png.h */
 
 /* pnglibconf.h */
+/* Machine generated file: DO NOT EDIT */
 /* Derived from: scripts/pnglibconf.dfa */
-/* If you edit this file by hand you must obey the rules expressed in */
-/* pnglibconf.dfa with respect to the dependencies between the following */
-/* symbols.  It is much better to generate a new file using */
-/* scripts/libpngconf.mak */
-
 #ifndef PNGLCONF_H
 #define PNGLCONF_H
-/* settings */
-#define PNG_API_RULE 0
-#define PNG_CALLOC_SUPPORTED
-#define PNG_COST_SHIFT 3
-#define PNG_DEFAULT_READ_MACROS 1
-#define PNG_GAMMA_THRESHOLD_FIXED 5000
-#define PNG_MAX_GAMMA_8 11
-#define PNG_QUANTIZE_BLUE_BITS 5
-#define PNG_QUANTIZE_GREEN_BITS 5
-#define PNG_QUANTIZE_RED_BITS 5
-#define PNG_sCAL_PRECISION 5
-#define PNG_USER_CHUNK_CACHE_MAX 0
-#define PNG_USER_CHUNK_MALLOC_MAX 0
-#define PNG_USER_HEIGHT_MAX 1000000
-#define PNG_USER_WIDTH_MAX 1000000
-#define PNG_WEIGHT_SHIFT 8
-#define PNG_ZBUF_SIZE 8192
-/* end of settings */
 /* options */
 #define PNG_16BIT_SUPPORTED
-#define PNG_ALIGN_MEMORY_SUPPORTED
+#define PNG_ALIGNED_MEMORY_SUPPORTED
+/*#undef PNG_ARM_NEON_API_SUPPORTED*/
+/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
 #define PNG_BENIGN_ERRORS_SUPPORTED
-#define PNG_bKGD_SUPPORTED
 #define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
 #define PNG_CHECK_cHRM_SUPPORTED
-#define PNG_cHRM_SUPPORTED
 #define PNG_CONSOLE_IO_SUPPORTED
 #define PNG_CONVERT_tIME_SUPPORTED
 #define PNG_EASY_ACCESS_SUPPORTED
@@ -54,20 +31,12 @@
 #define PNG_FIXED_POINT_SUPPORTED
 #define PNG_FLOATING_ARITHMETIC_SUPPORTED
 #define PNG_FLOATING_POINT_SUPPORTED
-#define PNG_FORMAT_AFIRST_SUPPORTED
-#define PNG_FORMAT_BGR_SUPPORTED
-#define PNG_gAMA_SUPPORTED
+#define PNG_GET_PALETTE_MAX_SUPPORTED
 #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-#define PNG_hIST_SUPPORTED
-#define PNG_iCCP_SUPPORTED
 #define PNG_INCH_CONVERSIONS_SUPPORTED
 #define PNG_INFO_IMAGE_SUPPORTED
 #define PNG_IO_STATE_SUPPORTED
-#define PNG_iTXt_SUPPORTED
 #define PNG_MNG_FEATURES_SUPPORTED
-#define PNG_oFFs_SUPPORTED
-#define PNG_pCAL_SUPPORTED
-#define PNG_pHYs_SUPPORTED
 #define PNG_POINTER_INDEXING_SUPPORTED
 #define PNG_PROGRESSIVE_READ_SUPPORTED
 #define PNG_READ_16BIT_SUPPORTED
@@ -75,67 +44,62 @@
 #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
 #define PNG_READ_BACKGROUND_SUPPORTED
 #define PNG_READ_BGR_SUPPORTED
-#define PNG_READ_bKGD_SUPPORTED
-#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
 #define PNG_READ_COMPOSITE_NODIV_SUPPORTED
 #define PNG_READ_COMPRESSED_TEXT_SUPPORTED
 #define PNG_READ_EXPAND_16_SUPPORTED
 #define PNG_READ_EXPAND_SUPPORTED
 #define PNG_READ_FILLER_SUPPORTED
-#define PNG_READ_gAMA_SUPPORTED
 #define PNG_READ_GAMMA_SUPPORTED
+#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
 #define PNG_READ_GRAY_TO_RGB_SUPPORTED
-#define PNG_READ_hIST_SUPPORTED
-#define PNG_READ_iCCP_SUPPORTED
 #define PNG_READ_INTERLACING_SUPPORTED
 #define PNG_READ_INT_FUNCTIONS_SUPPORTED
 #define PNG_READ_INVERT_ALPHA_SUPPORTED
 #define PNG_READ_INVERT_SUPPORTED
-#define PNG_READ_iTXt_SUPPORTED
-#define PNG_READ_oFFs_SUPPORTED
 #define PNG_READ_OPT_PLTE_SUPPORTED
-#define PNG_READ_PACK_SUPPORTED
 #define PNG_READ_PACKSWAP_SUPPORTED
-#define PNG_READ_pCAL_SUPPORTED
-#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_PACK_SUPPORTED
 #define PNG_READ_QUANTIZE_SUPPORTED
 #define PNG_READ_RGB_TO_GRAY_SUPPORTED
-#define PNG_READ_sBIT_SUPPORTED
 #define PNG_READ_SCALE_16_TO_8_SUPPORTED
-#define PNG_READ_sCAL_SUPPORTED
 #define PNG_READ_SHIFT_SUPPORTED
-#define PNG_READ_sPLT_SUPPORTED
-#define PNG_READ_sRGB_SUPPORTED
 #define PNG_READ_STRIP_16_TO_8_SUPPORTED
 #define PNG_READ_STRIP_ALPHA_SUPPORTED
 #define PNG_READ_SUPPORTED
 #define PNG_READ_SWAP_ALPHA_SUPPORTED
 #define PNG_READ_SWAP_SUPPORTED
-#define PNG_READ_tEXt_SUPPORTED
 #define PNG_READ_TEXT_SUPPORTED
-#define PNG_READ_tIME_SUPPORTED
 #define PNG_READ_TRANSFORMS_SUPPORTED
-#define PNG_READ_tRNS_SUPPORTED
 #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
 #define PNG_READ_USER_CHUNKS_SUPPORTED
 #define PNG_READ_USER_TRANSFORM_SUPPORTED
+#define PNG_READ_bKGD_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
+#define PNG_READ_hIST_SUPPORTED
+#define PNG_READ_iCCP_SUPPORTED
+#define PNG_READ_iTXt_SUPPORTED
+#define PNG_READ_oFFs_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_sCAL_SUPPORTED
+#define PNG_READ_sPLT_SUPPORTED
+#define PNG_READ_sRGB_SUPPORTED
+#define PNG_READ_tEXt_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
 #define PNG_READ_zTXt_SUPPORTED
+/*#undef PNG_SAFE_LIMITS_SUPPORTED*/
 #define PNG_SAVE_INT_32_SUPPORTED
-#define PNG_sBIT_SUPPORTED
-#define PNG_sCAL_SUPPORTED
 #define PNG_SEQUENTIAL_READ_SUPPORTED
-#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED
-#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
 #define PNG_SETJMP_SUPPORTED
+/*#undef PNG_SET_OPTION_SUPPORTED*/
 #define PNG_SET_USER_LIMITS_SUPPORTED
-#define PNG_sPLT_SUPPORTED
-#define PNG_sRGB_SUPPORTED
 #define PNG_STDIO_SUPPORTED
-#define PNG_tEXt_SUPPORTED
 #define PNG_TEXT_SUPPORTED
 #define PNG_TIME_RFC1123_SUPPORTED
-#define PNG_tIME_SUPPORTED
-#define PNG_tRNS_SUPPORTED
 #define PNG_UNKNOWN_CHUNKS_SUPPORTED
 #define PNG_USER_CHUNKS_SUPPORTED
 #define PNG_USER_LIMITS_SUPPORTED
@@ -146,44 +110,78 @@
 #define PNG_WRITE_16BIT_SUPPORTED
 #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
 #define PNG_WRITE_BGR_SUPPORTED
-#define PNG_WRITE_bKGD_SUPPORTED
-#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
 #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
 #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
 #define PNG_WRITE_FILLER_SUPPORTED
 #define PNG_WRITE_FILTER_SUPPORTED
 #define PNG_WRITE_FLUSH_SUPPORTED
-#define PNG_WRITE_gAMA_SUPPORTED
-#define PNG_WRITE_hIST_SUPPORTED
-#define PNG_WRITE_iCCP_SUPPORTED
+#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
 #define PNG_WRITE_INTERLACING_SUPPORTED
 #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
 #define PNG_WRITE_INVERT_ALPHA_SUPPORTED
 #define PNG_WRITE_INVERT_SUPPORTED
-#define PNG_WRITE_iTXt_SUPPORTED
-#define PNG_WRITE_oFFs_SUPPORTED
 #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
-#define PNG_WRITE_PACK_SUPPORTED
 #define PNG_WRITE_PACKSWAP_SUPPORTED
-#define PNG_WRITE_pCAL_SUPPORTED
-#define PNG_WRITE_pHYs_SUPPORTED
-#define PNG_WRITE_sBIT_SUPPORTED
-#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_PACK_SUPPORTED
 #define PNG_WRITE_SHIFT_SUPPORTED
-#define PNG_WRITE_sPLT_SUPPORTED
-#define PNG_WRITE_sRGB_SUPPORTED
 #define PNG_WRITE_SUPPORTED
 #define PNG_WRITE_SWAP_ALPHA_SUPPORTED
 #define PNG_WRITE_SWAP_SUPPORTED
-#define PNG_WRITE_tEXt_SUPPORTED
 #define PNG_WRITE_TEXT_SUPPORTED
-#define PNG_WRITE_tIME_SUPPORTED
 #define PNG_WRITE_TRANSFORMS_SUPPORTED
-#define PNG_WRITE_tRNS_SUPPORTED
 #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
 #define PNG_WRITE_USER_TRANSFORM_SUPPORTED
 #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#define PNG_WRITE_bKGD_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
+#define PNG_WRITE_hIST_SUPPORTED
+#define PNG_WRITE_iCCP_SUPPORTED
+#define PNG_WRITE_iTXt_SUPPORTED
+#define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
+#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_sPLT_SUPPORTED
+#define PNG_WRITE_sRGB_SUPPORTED
+#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_SUPPORTED
 #define PNG_WRITE_zTXt_SUPPORTED
+#define PNG_bKGD_SUPPORTED
+#define PNG_cHRM_SUPPORTED
+#define PNG_gAMA_SUPPORTED
+#define PNG_hIST_SUPPORTED
+#define PNG_iCCP_SUPPORTED
+#define PNG_iTXt_SUPPORTED
+#define PNG_oFFs_SUPPORTED
+#define PNG_pCAL_SUPPORTED
+#define PNG_pHYs_SUPPORTED
+#define PNG_sBIT_SUPPORTED
+#define PNG_sCAL_SUPPORTED
+#define PNG_sPLT_SUPPORTED
+#define PNG_sRGB_SUPPORTED
+#define PNG_tEXt_SUPPORTED
+#define PNG_tIME_SUPPORTED
+#define PNG_tRNS_SUPPORTED
 #define PNG_zTXt_SUPPORTED
 /* end of options */
+/* settings */
+#define PNG_API_RULE 0
+#define PNG_DEFAULT_READ_MACROS 1
+#define PNG_GAMMA_THRESHOLD_FIXED 5000
+#define PNG_MAX_GAMMA_8 11
+#define PNG_QUANTIZE_BLUE_BITS 5
+#define PNG_QUANTIZE_GREEN_BITS 5
+#define PNG_QUANTIZE_RED_BITS 5
+#define PNG_USER_CHUNK_CACHE_MAX 1000
+#define PNG_USER_CHUNK_MALLOC_MAX 8000000
+#define PNG_USER_HEIGHT_MAX 1000000
+#define PNG_USER_WIDTH_MAX 1000000
+#define PNG_ZBUF_SIZE 8192
+#define PNG_sCAL_PRECISION 5
+/* end of settings */
 #endif /* PNGLCONF_H */

+ 6 - 6
drivers/png/pngmem.c

@@ -1,8 +1,8 @@
 
 /* pngmem.c - stub functions for memory allocation
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.13 [September 27, 2012]
+ * Copyright (c) 1998-2002,2004,2006-2012 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -56,7 +56,7 @@ png_create_struct_2,(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr),
    if (malloc_fn != NULL)
    {
       png_struct dummy_struct;
-      memset(&dummy_struct, 0, sizeof dummy_struct);
+      png_memset(&dummy_struct, 0, sizeof dummy_struct);
       dummy_struct.mem_ptr=mem_ptr;
       struct_ptr = (*(malloc_fn))(&dummy_struct, (png_alloc_size_t)size);
    }
@@ -90,7 +90,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
       if (free_fn != NULL)
       {
          png_struct dummy_struct;
-         memset(&dummy_struct, 0, sizeof dummy_struct);
+         png_memset(&dummy_struct, 0, sizeof dummy_struct);
          dummy_struct.mem_ptr=mem_ptr;
          (*(free_fn))(&dummy_struct, struct_ptr);
          return;
@@ -102,7 +102,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
 }
 
 /* Allocate memory.  For reasonable files, size should never exceed
- * 64K.  However, zlib may allocate more then 64K if you don't tell
+ * 64K.  However, zlib may allocate more than 64K if you don't tell
  * it not to.  See zconf.h and png.h for more information. zlib does
  * need to allocate exactly 64K, so whatever you call here must
  * have the ability to do that.
@@ -475,7 +475,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
 }
 
 /* Allocate memory.  For reasonable files, size should never exceed
- * 64K.  However, zlib may allocate more then 64K if you don't tell
+ * 64K.  However, zlib may allocate more than 64K if you don't tell
  * it not to.  See zconf.h and png.h for more information.  zlib does
  * need to allocate exactly 64K, so whatever you call here must
  * have the ability to do that.

+ 38 - 657
drivers/png/pngpread.c

@@ -1,8 +1,8 @@
 
 /* pngpread.c - read a png file in push mode
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -19,7 +19,6 @@
 #define PNG_READ_SIG_MODE   0
 #define PNG_READ_CHUNK_MODE 1
 #define PNG_READ_IDAT_MODE  2
-#define PNG_SKIP_MODE       3
 #define PNG_READ_tEXt_MODE  4
 #define PNG_READ_zTXt_MODE  5
 #define PNG_READ_DONE_MODE  6
@@ -49,7 +48,7 @@ png_process_data_pause(png_structp png_ptr, int save)
       /* It's easiest for the caller if we do the save, then the caller doesn't
        * have to supply the same data again:
        */
-      if (save)
+      if (save != 0)
          png_push_save_buffer(png_ptr);
       else
       {
@@ -71,32 +70,15 @@ png_process_data_pause(png_structp png_ptr, int save)
 png_uint_32 PNGAPI
 png_process_data_skip(png_structp png_ptr)
 {
-   png_uint_32 remaining = 0;
-
-   if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE &&
-      png_ptr->skip_length > 0)
-   {
-      /* At the end of png_process_data the buffer size must be 0 (see the loop
-       * above) so we can detect a broken call here:
-       */
-      if (png_ptr->buffer_size != 0)
-         png_error(png_ptr,
-            "png_process_data_skip called inside png_process_data");
-
-      /* If is impossible for there to be a saved buffer at this point -
-       * otherwise we could not be in SKIP mode.  This will also happen if
-       * png_process_skip is called inside png_process_data (but only very
-       * rarely.)
-       */
-      if (png_ptr->save_buffer_size != 0)
-         png_error(png_ptr, "png_process_data_skip called with saved data");
-
-      remaining = png_ptr->skip_length;
-      png_ptr->skip_length = 0;
-      png_ptr->process_mode = PNG_READ_CHUNK_MODE;
-   }
-
-   return remaining;
+    /* TODO: Deprecate and remove this API.
+     * Somewhere the implementation of this seems to have been lost,
+     * or abandoned.  It was only to support some internal back-door access
+     * to png_struct) in libpng-1.4.x.
+     */
+   png_warning(png_ptr,
+       "png_process_data_skip is not implemented in any current version"
+       " of libpng");
+   return 0;
 }
 
 /* What we do with the incoming data depends on what we were previously
@@ -128,36 +110,6 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
          break;
       }
 
-#ifdef PNG_READ_tEXt_SUPPORTED
-      case PNG_READ_tEXt_MODE:
-      {
-         png_push_read_tEXt(png_ptr, info_ptr);
-         break;
-      }
-
-#endif
-#ifdef PNG_READ_zTXt_SUPPORTED
-      case PNG_READ_zTXt_MODE:
-      {
-         png_push_read_zTXt(png_ptr, info_ptr);
-         break;
-      }
-
-#endif
-#ifdef PNG_READ_iTXt_SUPPORTED
-      case PNG_READ_iTXt_MODE:
-      {
-         png_push_read_iTXt(png_ptr, info_ptr);
-         break;
-      }
-
-#endif
-      case PNG_SKIP_MODE:
-      {
-         png_push_crc_finish(png_ptr);
-         break;
-      }
-
       default:
       {
          png_ptr->buffer_size = 0;
@@ -175,8 +127,8 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
 void /* PRIVATE */
 png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
 {
-   png_size_t num_checked = png_ptr->sig_bytes,
-             num_to_check = 8 - num_checked;
+   png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */
+       num_to_check = 8 - num_checked;
 
    if (png_ptr->buffer_size < num_to_check)
    {
@@ -196,6 +148,7 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
       else
          png_error(png_ptr, "PNG file corrupted by ASCII conversion");
    }
+
    else
    {
       if (png_ptr->sig_bytes >= 8)
@@ -305,8 +258,8 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
             png_error(png_ptr, "Missing PLTE before IDAT");
       }
    }
-
 #endif
+
    else if (chunk_name == png_PLTE)
    {
       if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -543,7 +496,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
          return;
       }
 
-      png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
    }
 
 #endif
@@ -556,7 +509,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
          return;
       }
 
-      png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
    }
 
 #endif
@@ -569,10 +522,11 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
          return;
       }
 
-      png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
    }
 
 #endif
+
    else
    {
       if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -580,80 +534,12 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
          png_push_save_buffer(png_ptr);
          return;
       }
-      png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
    }
 
    png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
 }
 
-void /* PRIVATE */
-png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
-{
-   png_ptr->process_mode = PNG_SKIP_MODE;
-   png_ptr->skip_length = skip;
-}
-
-void /* PRIVATE */
-png_push_crc_finish(png_structp png_ptr)
-{
-   if (png_ptr->skip_length && png_ptr->save_buffer_size)
-   {
-      png_size_t save_size = png_ptr->save_buffer_size;
-      png_uint_32 skip_length = png_ptr->skip_length;
-
-      /* We want the smaller of 'skip_length' and 'save_buffer_size', but
-       * they are of different types and we don't know which variable has the
-       * fewest bits.  Carefully select the smaller and cast it to the type of
-       * the larger - this cannot overflow.  Do not cast in the following test
-       * - it will break on either 16 or 64 bit platforms.
-       */
-      if (skip_length < save_size)
-         save_size = (png_size_t)skip_length;
-
-      else
-         skip_length = (png_uint_32)save_size;
-
-      png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
-
-      png_ptr->skip_length -= skip_length;
-      png_ptr->buffer_size -= save_size;
-      png_ptr->save_buffer_size -= save_size;
-      png_ptr->save_buffer_ptr += save_size;
-   }
-   if (png_ptr->skip_length && png_ptr->current_buffer_size)
-   {
-      png_size_t save_size = png_ptr->current_buffer_size;
-      png_uint_32 skip_length = png_ptr->skip_length;
-
-      /* We want the smaller of 'skip_length' and 'current_buffer_size', here,
-       * the same problem exists as above and the same solution.
-       */
-      if (skip_length < save_size)
-         save_size = (png_size_t)skip_length;
-
-      else
-         skip_length = (png_uint_32)save_size;
-
-      png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
-
-      png_ptr->skip_length -= skip_length;
-      png_ptr->buffer_size -= save_size;
-      png_ptr->current_buffer_size -= save_size;
-      png_ptr->current_buffer_ptr += save_size;
-   }
-   if (!png_ptr->skip_length)
-   {
-      if (png_ptr->buffer_size < 4)
-      {
-         png_push_save_buffer(png_ptr);
-         return;
-      }
-
-      png_crc_finish(png_ptr, 0);
-      png_ptr->process_mode = PNG_READ_CHUNK_MODE;
-   }
-}
-
 void PNGCBAPI
 png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
 {
@@ -663,6 +549,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
       return;
 
    ptr = buffer;
+
    if (png_ptr->save_buffer_size)
    {
       png_size_t save_size;
@@ -680,6 +567,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
       png_ptr->save_buffer_size -= save_size;
       png_ptr->save_buffer_ptr += save_size;
    }
+
    if (length && png_ptr->current_buffer_size)
    {
       png_size_t save_size;
@@ -709,6 +597,7 @@ png_push_save_buffer(png_structp png_ptr)
          png_bytep dp;
 
          istop = png_ptr->save_buffer_size;
+
          for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
              i < istop; i++, sp++, dp++)
          {
@@ -716,6 +605,7 @@ png_push_save_buffer(png_structp png_ptr)
          }
       }
    }
+
    if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
        png_ptr->save_buffer_max)
    {
@@ -730,8 +620,7 @@ png_push_save_buffer(png_structp png_ptr)
 
       new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
       old_buffer = png_ptr->save_buffer;
-      png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,
-          (png_size_t)new_max);
+      png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, new_max);
 
       if (png_ptr->save_buffer == NULL)
       {
@@ -743,6 +632,7 @@ png_push_save_buffer(png_structp png_ptr)
       png_free(png_ptr, old_buffer);
       png_ptr->save_buffer_max = new_max;
    }
+
    if (png_ptr->current_buffer_size)
    {
       png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
@@ -750,6 +640,7 @@ png_push_save_buffer(png_structp png_ptr)
       png_ptr->save_buffer_size += png_ptr->current_buffer_size;
       png_ptr->current_buffer_size = 0;
    }
+
    png_ptr->save_buffer_ptr = png_ptr->save_buffer;
    png_ptr->buffer_size = 0;
 }
@@ -851,6 +742,7 @@ png_push_read_IDAT(png_structp png_ptr)
       png_ptr->current_buffer_size -= save_size;
       png_ptr->current_buffer_ptr += save_size;
    }
+
    if (!png_ptr->idat_size)
    {
       if (png_ptr->buffer_size < 4)
@@ -911,6 +803,12 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
        */
       ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH);
 
+      /* Hack, added in 1.5.18: the progressive reader does not reset
+       * png_ptr->zstream, so any attempt to use it after the last IDAT fails
+       * (silently).  This allows the read code to do the reset when required.
+       */
+      png_ptr->flags |= PNG_FLAG_ZSTREAM_PROGRESSIVE;
+
       /* Check for any failure before proceeding. */
       if (ret != Z_OK && ret != Z_STREAM_END)
       {
@@ -1201,6 +1099,7 @@ png_push_process_row(png_structp png_ptr)
 void /* PRIVATE */
 png_read_push_finish_row(png_structp png_ptr)
 {
+#ifdef PNG_READ_INTERLACING_SUPPORTED
    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 
    /* Start of interlace block */
@@ -1219,6 +1118,7 @@ png_read_push_finish_row(png_structp png_ptr)
     * it, uncomment it here and in png.h
    static PNG_CONST png_byte FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
    */
+#endif
 
    png_ptr->row_number++;
    if (png_ptr->row_number < png_ptr->num_rows)
@@ -1262,525 +1162,6 @@ png_read_push_finish_row(png_structp png_ptr)
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
 }
 
-#ifdef PNG_READ_tEXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
-    length)
-{
-   if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
-      {
-         PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
-         png_error(png_ptr, "Out of place tEXt");
-         /* NOT REACHED */
-      }
-
-#ifdef PNG_MAX_MALLOC_64K
-   png_ptr->skip_length = 0;  /* This may not be necessary */
-
-   if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
-   {
-      png_warning(png_ptr, "tEXt chunk too large to fit in memory");
-      png_ptr->skip_length = length - (png_uint_32)65535L;
-      length = (png_uint_32)65535L;
-   }
-#endif
-
-   png_ptr->current_text = (png_charp)png_malloc(png_ptr,
-       (png_size_t)(length + 1));
-   png_ptr->current_text[length] = '\0';
-   png_ptr->current_text_ptr = png_ptr->current_text;
-   png_ptr->current_text_size = (png_size_t)length;
-   png_ptr->current_text_left = (png_size_t)length;
-   png_ptr->process_mode = PNG_READ_tEXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
-{
-   if (png_ptr->buffer_size && png_ptr->current_text_left)
-   {
-      png_size_t text_size;
-
-      if (png_ptr->buffer_size < png_ptr->current_text_left)
-         text_size = png_ptr->buffer_size;
-
-      else
-         text_size = png_ptr->current_text_left;
-
-      png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
-      png_ptr->current_text_left -= text_size;
-      png_ptr->current_text_ptr += text_size;
-   }
-   if (!(png_ptr->current_text_left))
-   {
-      png_textp text_ptr;
-      png_charp text;
-      png_charp key;
-      int ret;
-
-      if (png_ptr->buffer_size < 4)
-      {
-         png_push_save_buffer(png_ptr);
-         return;
-      }
-
-      png_push_crc_finish(png_ptr);
-
-#ifdef PNG_MAX_MALLOC_64K
-      if (png_ptr->skip_length)
-         return;
-#endif
-
-      key = png_ptr->current_text;
-
-      for (text = key; *text; text++)
-         /* Empty loop */ ;
-
-      if (text < key + png_ptr->current_text_size)
-         text++;
-
-      text_ptr = (png_textp)png_malloc(png_ptr, png_sizeof(png_text));
-      text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
-      text_ptr->key = key;
-      text_ptr->itxt_length = 0;
-      text_ptr->lang = NULL;
-      text_ptr->lang_key = NULL;
-      text_ptr->text = text;
-
-      ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
-      png_free(png_ptr, key);
-      png_free(png_ptr, text_ptr);
-      png_ptr->current_text = NULL;
-
-      if (ret)
-         png_warning(png_ptr, "Insufficient memory to store text chunk");
-   }
-}
-#endif
-
-#ifdef PNG_READ_zTXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
-   length)
-{
-   if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
-   {
-      PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
-      png_error(png_ptr, "Out of place zTXt");
-      /* NOT REACHED */
-   }
-
-#ifdef PNG_MAX_MALLOC_64K
-   /* We can't handle zTXt chunks > 64K, since we don't have enough space
-    * to be able to store the uncompressed data.  Actually, the threshold
-    * is probably around 32K, but it isn't as definite as 64K is.
-    */
-   if (length > (png_uint_32)65535L)
-   {
-      png_warning(png_ptr, "zTXt chunk too large to fit in memory");
-      png_push_crc_skip(png_ptr, length);
-      return;
-   }
-#endif
-
-   png_ptr->current_text = (png_charp)png_malloc(png_ptr,
-       (png_size_t)(length + 1));
-   png_ptr->current_text[length] = '\0';
-   png_ptr->current_text_ptr = png_ptr->current_text;
-   png_ptr->current_text_size = (png_size_t)length;
-   png_ptr->current_text_left = (png_size_t)length;
-   png_ptr->process_mode = PNG_READ_zTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
-{
-   if (png_ptr->buffer_size && png_ptr->current_text_left)
-   {
-      png_size_t text_size;
-
-      if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
-         text_size = png_ptr->buffer_size;
-
-      else
-         text_size = png_ptr->current_text_left;
-
-      png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
-      png_ptr->current_text_left -= text_size;
-      png_ptr->current_text_ptr += text_size;
-   }
-   if (!(png_ptr->current_text_left))
-   {
-      png_textp text_ptr;
-      png_charp text;
-      png_charp key;
-      int ret;
-      png_size_t text_size, key_size;
-
-      if (png_ptr->buffer_size < 4)
-      {
-         png_push_save_buffer(png_ptr);
-         return;
-      }
-
-      png_push_crc_finish(png_ptr);
-
-      key = png_ptr->current_text;
-
-      for (text = key; *text; text++)
-         /* Empty loop */ ;
-
-      /* zTXt can't have zero text */
-      if (text >= key + png_ptr->current_text_size)
-      {
-         png_ptr->current_text = NULL;
-         png_free(png_ptr, key);
-         return;
-      }
-
-      text++;
-
-      if (*text != PNG_TEXT_COMPRESSION_zTXt) /* Check compression byte */
-      {
-         png_ptr->current_text = NULL;
-         png_free(png_ptr, key);
-         return;
-      }
-
-      text++;
-
-      png_ptr->zstream.next_in = (png_bytep)text;
-      png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
-          (text - key));
-      png_ptr->zstream.next_out = png_ptr->zbuf;
-      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-
-      key_size = text - key;
-      text_size = 0;
-      text = NULL;
-      ret = Z_STREAM_END;
-
-      while (png_ptr->zstream.avail_in)
-      {
-         ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
-         if (ret != Z_OK && ret != Z_STREAM_END)
-         {
-            inflateReset(&png_ptr->zstream);
-            png_ptr->zstream.avail_in = 0;
-            png_ptr->current_text = NULL;
-            png_free(png_ptr, key);
-            png_free(png_ptr, text);
-            return;
-         }
-
-         if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
-         {
-            if (text == NULL)
-            {
-               text = (png_charp)png_malloc(png_ptr,
-                   (png_ptr->zbuf_size
-                   - png_ptr->zstream.avail_out + key_size + 1));
-
-               png_memcpy(text + key_size, png_ptr->zbuf,
-                   png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-
-               png_memcpy(text, key, key_size);
-
-               text_size = key_size + png_ptr->zbuf_size -
-                   png_ptr->zstream.avail_out;
-
-               *(text + text_size) = '\0';
-            }
-
-            else
-            {
-               png_charp tmp;
-
-               tmp = text;
-               text = (png_charp)png_malloc(png_ptr, text_size +
-                   (png_ptr->zbuf_size
-                   - png_ptr->zstream.avail_out + 1));
-
-               png_memcpy(text, tmp, text_size);
-               png_free(png_ptr, tmp);
-
-               png_memcpy(text + text_size, png_ptr->zbuf,
-                   png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-
-               text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
-               *(text + text_size) = '\0';
-            }
-
-            if (ret != Z_STREAM_END)
-            {
-               png_ptr->zstream.next_out = png_ptr->zbuf;
-               png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-            }
-         }
-         else
-         {
-            break;
-         }
-
-         if (ret == Z_STREAM_END)
-            break;
-      }
-
-      inflateReset(&png_ptr->zstream);
-      png_ptr->zstream.avail_in = 0;
-
-      if (ret != Z_STREAM_END)
-      {
-         png_ptr->current_text = NULL;
-         png_free(png_ptr, key);
-         png_free(png_ptr, text);
-         return;
-      }
-
-      png_ptr->current_text = NULL;
-      png_free(png_ptr, key);
-      key = text;
-      text += key_size;
-
-      text_ptr = (png_textp)png_malloc(png_ptr,
-          png_sizeof(png_text));
-      text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
-      text_ptr->key = key;
-      text_ptr->itxt_length = 0;
-      text_ptr->lang = NULL;
-      text_ptr->lang_key = NULL;
-      text_ptr->text = text;
-
-      ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
-      png_free(png_ptr, key);
-      png_free(png_ptr, text_ptr);
-
-      if (ret)
-         png_warning(png_ptr, "Insufficient memory to store text chunk");
-   }
-}
-#endif
-
-#ifdef PNG_READ_iTXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
-    length)
-{
-   if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
-   {
-      PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
-      png_error(png_ptr, "Out of place iTXt");
-      /* NOT REACHED */
-   }
-
-#ifdef PNG_MAX_MALLOC_64K
-   png_ptr->skip_length = 0;  /* This may not be necessary */
-
-   if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
-   {
-      png_warning(png_ptr, "iTXt chunk too large to fit in memory");
-      png_ptr->skip_length = length - (png_uint_32)65535L;
-      length = (png_uint_32)65535L;
-   }
-#endif
-
-   png_ptr->current_text = (png_charp)png_malloc(png_ptr,
-       (png_size_t)(length + 1));
-   png_ptr->current_text[length] = '\0';
-   png_ptr->current_text_ptr = png_ptr->current_text;
-   png_ptr->current_text_size = (png_size_t)length;
-   png_ptr->current_text_left = (png_size_t)length;
-   png_ptr->process_mode = PNG_READ_iTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr)
-{
-
-   if (png_ptr->buffer_size && png_ptr->current_text_left)
-   {
-      png_size_t text_size;
-
-      if (png_ptr->buffer_size < png_ptr->current_text_left)
-         text_size = png_ptr->buffer_size;
-
-      else
-         text_size = png_ptr->current_text_left;
-
-      png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
-      png_ptr->current_text_left -= text_size;
-      png_ptr->current_text_ptr += text_size;
-   }
-
-   if (!(png_ptr->current_text_left))
-   {
-      png_textp text_ptr;
-      png_charp key;
-      int comp_flag;
-      png_charp lang;
-      png_charp lang_key;
-      png_charp text;
-      int ret;
-
-      if (png_ptr->buffer_size < 4)
-      {
-         png_push_save_buffer(png_ptr);
-         return;
-      }
-
-      png_push_crc_finish(png_ptr);
-
-#ifdef PNG_MAX_MALLOC_64K
-      if (png_ptr->skip_length)
-         return;
-#endif
-
-      key = png_ptr->current_text;
-
-      for (lang = key; *lang; lang++)
-         /* Empty loop */ ;
-
-      if (lang < key + png_ptr->current_text_size - 3)
-         lang++;
-
-      comp_flag = *lang++;
-      lang++;     /* Skip comp_type, always zero */
-
-      for (lang_key = lang; *lang_key; lang_key++)
-         /* Empty loop */ ;
-
-      lang_key++;        /* Skip NUL separator */
-
-      text=lang_key;
-
-      if (lang_key < key + png_ptr->current_text_size - 1)
-      {
-         for (; *text; text++)
-            /* Empty loop */ ;
-      }
-
-      if (text < key + png_ptr->current_text_size)
-         text++;
-
-      text_ptr = (png_textp)png_malloc(png_ptr,
-          png_sizeof(png_text));
-
-      text_ptr->compression = comp_flag + 2;
-      text_ptr->key = key;
-      text_ptr->lang = lang;
-      text_ptr->lang_key = lang_key;
-      text_ptr->text = text;
-      text_ptr->text_length = 0;
-      text_ptr->itxt_length = png_strlen(text);
-
-      ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
-      png_ptr->current_text = NULL;
-
-      png_free(png_ptr, text_ptr);
-      if (ret)
-         png_warning(png_ptr, "Insufficient memory to store iTXt chunk");
-   }
-}
-#endif
-
-/* This function is called when we haven't found a handler for this
- * chunk.  If there isn't a problem with the chunk itself (ie a bad chunk
- * name or a critical chunk), the chunk is (currently) silently ignored.
- */
-void /* PRIVATE */
-png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32
-    length)
-{
-   png_uint_32 skip = 0;
-   png_uint_32 chunk_name = png_ptr->chunk_name;
-
-   if (PNG_CHUNK_CRITICAL(chunk_name))
-   {
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
-      if (png_chunk_unknown_handling(png_ptr, chunk_name) !=
-          PNG_HANDLE_CHUNK_ALWAYS
-#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
-          && png_ptr->read_user_chunk_fn == NULL
-#endif
-          )
-#endif
-         png_chunk_error(png_ptr, "unknown critical chunk");
-
-      PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
-   }
-
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
-   /* TODO: the code below is apparently just using the
-    * png_struct::unknown_chunk member as a temporarily variable, it should be
-    * possible to eliminate both it and the temporary buffer.
-    */
-   if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
-   {
-#ifdef PNG_MAX_MALLOC_64K
-      if (length > 65535)
-      {
-         png_warning(png_ptr, "unknown chunk too large to fit in memory");
-         skip = length - 65535;
-         length = 65535;
-      }
-#endif
-      /* This is just a record for the user; libpng doesn't use the character
-       * form of the name.
-       */
-      PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
-
-      /* The following cast should be safe because of the check above. */
-      png_ptr->unknown_chunk.size = (png_size_t)length;
-
-      if (length == 0)
-         png_ptr->unknown_chunk.data = NULL;
-
-      else
-      {
-         png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr,
-            png_ptr->unknown_chunk.size);
-         png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data,
-            png_ptr->unknown_chunk.size);
-      }
-
-#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
-      if (png_ptr->read_user_chunk_fn != NULL)
-      {
-         /* Callback to user unknown chunk handler */
-         int ret;
-         ret = (*(png_ptr->read_user_chunk_fn))
-             (png_ptr, &png_ptr->unknown_chunk);
-
-         if (ret < 0)
-            png_chunk_error(png_ptr, "error in user chunk");
-
-         if (ret == 0)
-         {
-            if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
-               if (png_chunk_unknown_handling(png_ptr, chunk_name) !=
-                   PNG_HANDLE_CHUNK_ALWAYS)
-                  png_chunk_error(png_ptr, "unknown critical chunk");
-            png_set_unknown_chunks(png_ptr, info_ptr,
-                &png_ptr->unknown_chunk, 1);
-         }
-      }
-
-      else
-#endif
-         png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
-      png_free(png_ptr, png_ptr->unknown_chunk.data);
-      png_ptr->unknown_chunk.data = NULL;
-   }
-
-   else
-#endif
-      skip=length;
-   png_push_crc_skip(png_ptr, skip);
-}
-
 void /* PRIVATE */
 png_push_have_info(png_structp png_ptr, png_infop info_ptr)
 {
@@ -1816,7 +1197,7 @@ png_progressive_combine_row (png_structp png_ptr, png_bytep old_row,
     * it must be png_ptr->row_buf+1
     */
    if (new_row != NULL)
-      png_combine_row(png_ptr, old_row, 1/*display*/);
+      png_combine_row(png_ptr, old_row, 1/*blocky display*/);
 }
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
 

+ 182 - 54
drivers/png/pngpriv.h

@@ -1,13 +1,11 @@
 
 /* pngpriv.h - private declarations for use inside libpng
  *
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
@@ -39,6 +37,7 @@
  */
 #define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
 
+#ifndef PNG_VERSION_INFO_ONLY
 /* This is required for the definition of abort(), used as a last ditch
  * error handler when all else fails.
  */
@@ -46,6 +45,7 @@
 
 /* This is used to find 'offsetof', used below for alignment tests. */
 #include <stddef.h>
+#endif /* !PNG_VERSION_INFO_ONLY */
 
 #define PNGLIB_BUILD /*libpng is being built, not used*/
 
@@ -125,21 +125,68 @@
 #endif
 
 #include "png.h"
-#include "pnginfo.h"
-#include "pngstruct.h"
 
 /* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */
 #ifndef PNG_DLL_EXPORT
 #  define PNG_DLL_EXPORT
 #endif
 
-/* This is used for 16 bit gamma tables - only the top level pointers are const,
- * this could be changed:
+/* Compile time options.
+ * =====================
+ * In a multi-arch build the compiler may compile the code several times for the
+ * same object module, producing different binaries for different architectures.
+ * When this happens configure-time setting of the target host options cannot be
+ * done and this interferes with the handling of the ARM NEON optimizations, and
+ * possibly other similar optimizations.  Put additional tests here; in general
+ * this is needed when the same option can be changed at both compile time and
+ * run time depending on the target OS (i.e. iOS vs Android.)
+ *
+ * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because
+ * this is not possible with certain compilers (Oracle SUN OS CC), as a result
+ * it is necessary to ensure that all extern functions that *might* be used
+ * regardless of $(CFLAGS) get declared in this file.  The test on __ARM_NEON__
+ * below is one example of this behavior because it is controlled by the
+ * presence or not of -mfpu=neon on the GCC command line, it is possible to do
+ * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely
+ * do this.
  */
-typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
+#ifndef PNG_ARM_NEON_OPT
+   /* ARM NEON optimizations are being controlled by the compiler settings,
+    * typically the target FPU.  If the FPU has been set to NEON (-mfpu=neon
+    * with GCC) then the compiler will define __ARM_NEON__ and we can rely
+    * unconditionally on NEON instructions not crashing, otherwise we must
+    * disable use of NEON instructions.
+    *
+    * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they
+    * can only be turned on automatically if that is supported too.  If
+    * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail
+    * to compile with an appropriate #error if ALIGNED_MEMORY has been turned
+    * off.
+    */
+#  if defined(__ARM_NEON__) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+#     define PNG_ARM_NEON_OPT 2
+#  else
+#     define PNG_ARM_NEON_OPT 0
+#  endif
+#endif
 
-/* Added at libpng-1.2.9 */
-/* Moved to pngpriv.h at libpng-1.5.0 */
+
+#if PNG_ARM_NEON_OPT > 0
+   /* NEON optimizations are to be at least considered by libpng, so enable the
+    * callbacks to do this.
+    */
+#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon
+#endif
+
+/* SECURITY and SAFETY:
+ *
+ * By default libpng is built without any internal limits on image size,
+ * individual heap (png_malloc) allocations or the total amount of memory used.
+ * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used
+ * (unless individually overridden).  These limits are believed to be fairly
+ * safe, but builders of secure systems should verify the values against the
+ * real system capabilities.
+ */
 
 /* config.h is created by and PNG_CONFIGURE_LIBPNG is set by the "configure"
  * script.  We may need it here to get the correct configuration on things
@@ -151,9 +198,11 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  endif
 #endif
 
-/* Moved to pngpriv.h at libpng-1.5.0 */
-/* NOTE: some of these may have been used in external applications as
- * these definitions were exposed in pngconf.h prior to 1.5.
+/* SECURITY and SAFETY:
+ *
+ * libpng is built with support for internal limits on image dimensions and
+ * memory usage.  These are documented in scripts/pnglibconf.dfa of the
+ * source and recorded in the machine generated header file pnglibconf.h.
  */
 
 /* If you are running on a machine where you cannot allocate more
@@ -171,6 +220,11 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  define PNG_MAX_MALLOC_64K
 #endif
 
+/* Moved to pngpriv.h at libpng-1.5.0 */
+/* NOTE: some of these may have been used in external applications as
+ * these definitions were exposed in pngconf.h prior to 1.5.
+ */
+
 #ifndef PNG_UNUSED
 /* Unused formal parameter warnings are silenced using the following macro
  * which is expected to have no bad effects on performance (optimizing
@@ -206,7 +260,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
    /* Modern compilers support restrict, but assume not for anything not
     * recognized here:
     */
-#  if defined __GNUC__ || defined _MSC_VER || defined __WATCOMC__
+#  if defined(__GNUC__) || defined(_MSC_VER) || defined(__WATCOMC__)
 #     define PNG_RESTRICT restrict
 #  else
 #     define PNG_RESTRICT
@@ -220,8 +274,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #ifdef PNG_WARNINGS_SUPPORTED
 #  define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;
 #else
-#  define png_warning(s1,s2) ((void)(s1))
-#  define png_chunk_warning(s1,s2) ((void)(s1))
 #  define png_warning_parameter(p,number,string) ((void)0)
 #  define png_warning_parameter_unsigned(p,number,format,value) ((void)0)
 #  define png_warning_parameter_signed(p,number,format,value) ((void)0)
@@ -229,8 +281,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  define PNG_WARNING_PARAMETERS(p)
 #endif
 #ifndef PNG_ERROR_TEXT_SUPPORTED
-#  define png_error(s1,s2) png_err(s1)
-#  define png_chunk_error(s1,s2) png_err(s1)
 #  define png_fixed_error(s1,s2) png_err(s1)
 #endif
 
@@ -268,6 +318,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  define PNGFAPI /* PRIVATE */
 #endif
 
+#ifndef PNG_VERSION_INFO_ONLY
 /* Other defines specific to compilers can go here.  Try to keep
  * them inside an appropriate ifdef/endif pair for portability.
  */
@@ -312,6 +363,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
     defined(_WIN32) || defined(__WIN32__)
 #  include <windows.h>  /* defines _WINDOWS_ macro */
 #endif
+#endif /* !PNG_VERSION_INFO_ONLY */
 
 /* Moved here around 1.5.0beta36 from pngconf.h */
 /* Users may want to use these so they are not private.  Any library
@@ -341,13 +393,9 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  ifdef _WINDOWS_  /* Favor Windows over C runtime fns */
 #    define CVT_PTR(ptr)         (ptr)
 #    define CVT_PTR_NOCHECK(ptr) (ptr)
-#    ifdef WINRT_ENABLED
-#      define png_strlen  strlen
-#    else
-#      define png_strlen  lstrlenA
-#    endif
+#    define png_strlen  lstrlenA
 #    define png_memcmp  memcmp
-#    define png_memcpy  CopyMemory
+#    define png_memcpy  memcpy
 #    define png_memset  memset
 #  else
 #    define CVT_PTR(ptr)         (ptr)
@@ -380,7 +428,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE
    /* This is used because in some compiler implementations non-aligned
     * structure members are supported, so the offsetof approach below fails.
-    * Set PNG_ALIGN_TO_SIZE=0 for compiler combinations where unaligned access
+    * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access
     * is good for performance.  Do not do this unless you have tested the result
     * and understand it.
     */
@@ -430,6 +478,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_BACKGROUND_IS_GRAY     0x800
 #define PNG_HAVE_PNG_SIGNATURE    0x1000
 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+#define PNG_HAVE_iCCP             0x4000
 
 /* Flags for the transformations the PNG library does on the image data */
 #define PNG_BGR                 0x0001
@@ -468,10 +517,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_STRUCT_PNG   0x0001
 #define PNG_STRUCT_INFO  0x0002
 
-/* Scaling factor for filter heuristic weighting calculations */
-#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
-#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
-
 /* Flags for the png_ptr->flags rather than declaring a byte for each one */
 #define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001
 #define PNG_FLAG_ZLIB_CUSTOM_LEVEL        0x0002
@@ -494,7 +539,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_FLAG_STRIP_ERROR_NUMBERS      0x40000
 #define PNG_FLAG_STRIP_ERROR_TEXT         0x80000
 #define PNG_FLAG_MALLOC_NULL_MEM_OK       0x100000
-                                  /*      0x200000  unused */
+#define PNG_FLAG_ZSTREAM_PROGRESSIVE      0x200000
                                   /*      0x400000  unused */
 #define PNG_FLAG_BENIGN_ERRORS_WARN       0x800000  /* Added to libpng-1.4.0 */
 #define PNG_FLAG_ZTXT_CUSTOM_STRATEGY    0x1000000  /* 5 lines added */
@@ -580,8 +625,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\
     ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))
 #else
+#ifndef PNG_VERSION_INFO_ONLY
 PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp,
    png_const_charp text));
+#endif /* !PNG_VERSION_INFO_ONLY */
 #endif
 #endif
 
@@ -655,6 +702,18 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp,
 #define PNG_GAMMA_MAC_INVERSE 65909
 #define PNG_GAMMA_sRGB_INVERSE 45455
 
+/* Almost everything below is C specific; the #defines above can be used in
+ * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.
+ */
+#ifndef PNG_VERSION_INFO_ONLY
+
+#include "pngstruct.h"
+#include "pnginfo.h"
+
+/* This is used for 16 bit gamma tables -- only the top level pointers are
+ * const; this could be changed:
+ */
+typedef const png_uint_16p * png_const_uint_16pp;
 
 /* Inhibit C++ name-mangling for libpng functions but not for system calls. */
 #ifdef __cplusplus
@@ -786,10 +845,8 @@ PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
 PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
 #  endif
-#  ifdef PNG_FIXED_POINT_SUPPORTED
 PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr,
     png_fixed_point file_gamma));
-#  endif
 #endif
 
 #ifdef PNG_WRITE_sBIT_SUPPORTED
@@ -844,13 +901,6 @@ PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr,
     png_const_uint_16p hist, int num_hist));
 #endif
 
-/* Chunks that have keywords */
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
-    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
-    png_const_charp key, png_charpp new_key));
-#endif
-
 #ifdef PNG_WRITE_tEXt_SUPPORTED
 PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_const_charp key,
     png_const_charp text, png_size_t text_len));
@@ -956,8 +1006,8 @@ PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
 /* Unfilter a row: check the filter value before calling this, there is no point
  * calling it for PNG_FILTER_VALUE_NONE.
  */
-PNG_EXTERN void png_read_filter_row PNGARG((png_structp pp, png_row_infop row_info,
-    png_bytep row, png_const_bytep prev_row, int filter));
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp pp, png_row_infop
+    row_info, png_bytep row, png_const_bytep prev_row, int filter));
 
 PNG_EXTERN void png_read_filter_row_up_neon PNGARG((png_row_infop row_info,
     png_bytep row, png_const_bytep prev_row));
@@ -1222,10 +1272,8 @@ PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
     png_uint_32 length));
 #endif
 
-#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
 PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
     png_infop info_ptr, png_uint_32 length));
-#endif
 
 PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
     png_uint_32 chunk_name));
@@ -1258,9 +1306,6 @@ PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
 PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
     png_infop info_ptr));
 PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
-    png_uint_32 length));
-PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
 PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
 PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
     png_bytep buffer, png_size_t buffer_length));
@@ -1359,6 +1404,13 @@ PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr,
     int color_type, int interlace_type, int compression_type,
     int filter_type));
 
+/* Added at libpng version 1.5.10 */
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+PNG_EXTERN void png_do_check_palette_indexes PNGARG((png_structp png_ptr,
+    png_row_infop row_info));
+#endif
+
 /* Free all memory used by the read (old method - NOT DLL EXPORTED) */
 PNG_EXTERN void png_read_destroy PNGARG((png_structp png_ptr,
     png_infop info_ptr, png_infop end_info_ptr));
@@ -1449,14 +1501,16 @@ PNG_EXTERN void png_formatted_warning(png_structp png_ptr,
 /* ASCII to FP interfaces, currently only implemented if sCAL
  * support is required.
  */
-#if defined(PNG_READ_sCAL_SUPPORTED)
+#ifdef PNG_sCAL_SUPPORTED
 /* MAX_DIGITS is actually the maximum number of characters in an sCAL
  * width or height, derived from the precision (number of significant
  * digits - a build time settable option) and assumpitions about the
  * maximum ridiculous exponent.
  */
 #define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)
+#endif
 
+#ifdef PNG_sCAL_SUPPORTED
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 PNG_EXTERN void png_ascii_from_fp PNGARG((png_structp png_ptr, png_charp ascii,
     png_size_t size, double fp, unsigned int precision));
@@ -1540,15 +1594,15 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr,
 #define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)
 #define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)
 #define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)
- 
-/* The actual parser.  This can be called repeatedly, it updates
+
+/* The actual parser.  This can be called repeatedly. It updates
  * the index into the string and the state variable (which must
- * be initialzed to 0).  It returns a result code, as above.  There
+ * be initialized to 0).  It returns a result code, as above.  There
  * is no point calling the parser any more if it fails to advance to
  * the end of the string - it is stuck on an invalid character (or
  * terminated by '\0').
  *
- * Note that the pointer will consume an E or even an E+ then leave
+ * Note that the pointer will consume an E or even an E+ and then leave
  * a 'maybe' state even though a preceding integer.fraction is valid.
  * The PNG_FP_WAS_VALID flag indicates that a preceding substring was
  * a valid number.  It's possible to recover from this by calling
@@ -1587,7 +1641,7 @@ PNG_EXTERN png_fixed_point png_muldiv_warn PNGARG((png_structp png_ptr,
     png_fixed_point a, png_int_32 multiplied_by, png_int_32 divided_by));
 #endif
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED)
 /* Calculate a reciprocal - used for gamma values.  This returns
  * 0 if the argument is 0 in order to maintain an undefined value,
  * there are no warnings.
@@ -1622,7 +1676,80 @@ PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr,
     int bit_depth));
 #endif
 
-/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */
+/* Missing declarations if FIXED_POINT is *not* supported - fixed properly
+ * in libpng 1.6
+ */
+#ifndef PNG_FIXED_POINT_SUPPORTED
+#ifdef PNG_cHRM_SUPPORTED
+PNG_EXTERN png_uint_32 png_get_cHRM_XYZ_fixed PNGARG(
+    (png_structp png_ptr, png_const_infop info_ptr,
+    png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+    png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+    png_fixed_point *int_blue_Z));
+PNG_EXTERN void png_set_cHRM_XYZ_fixed PNGARG((png_structp png_ptr,
+    png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
+    png_fixed_point int_red_Z, png_fixed_point int_green_X,
+    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+    png_fixed_point int_blue_Z));
+PNG_EXTERN void png_set_cHRM_fixed PNGARG((png_structp png_ptr,
+    png_infop info_ptr, png_fixed_point int_white_x,
+    png_fixed_point int_white_y, png_fixed_point int_red_x,
+    png_fixed_point int_red_y, png_fixed_point int_green_x,
+    png_fixed_point int_green_y, png_fixed_point int_blue_x,
+    png_fixed_point int_blue_y));
+#endif
+
+#ifdef PNG_gAMA_SUPPORTED
+PNG_EXTERN png_uint_32 png_get_gAMA_fixed PNGARG(
+    (png_const_structp png_ptr, png_const_infop info_ptr,
+    png_fixed_point *int_file_gamma));
+PNG_EXTERN void png_set_gAMA_fixed PNGARG((png_structp png_ptr,
+    png_infop info_ptr, png_fixed_point int_file_gamma));
+#endif
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+PNG_EXTERN void png_set_background_fixed PNGARG((png_structp png_ptr,
+    png_const_color_16p background_color, int background_gamma_code,
+    int need_expand, png_fixed_point background_gamma));
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+PNG_EXTERN void png_set_alpha_mode_fixed PNGARG((png_structp png_ptr,
+    int mode, png_fixed_point output_gamma));
+#endif
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+PNG_EXTERN void png_set_gamma_fixed PNGARG((png_structp png_ptr,
+    png_fixed_point screen_gamma, png_fixed_point override_file_gamma));
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+PNG_EXTERN void png_set_rgb_to_gray_fixed PNGARG((png_structp png_ptr,
+    int error_action, png_fixed_point red, png_fixed_point green));
+#endif
+#endif /* FIX MISSING !FIXED_POINT DECLARATIONS */
+
+/* These are initialization functions for hardware specific PNG filter
+ * optimizations; list these here then select the appropriate one at compile
+ * time using the macro PNG_FILTER_OPTIMIZATIONS.  If the macro is not defined
+ * the generic code is used.
+ */
+#ifdef PNG_FILTER_OPTIMIZATIONS
+PNG_EXTERN void PNG_FILTER_OPTIMIZATIONS(png_structp png_ptr, unsigned int bpp);
+   /* Just declare the optimization that will be used */
+#else
+   /* List *all* the possible optimizations here - this branch is required if
+    * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in
+    * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing.
+    */
+PNG_EXTERN void png_init_filter_functions_neon(png_structp png_ptr,
+    unsigned int bpp);
+#endif
+
+/* Maintainer: Put new private prototypes here ^ */
 
 #include "pngdebug.h"
 
@@ -1630,4 +1757,5 @@ PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr,
 }
 #endif
 
+#endif /* PNG_VERSION_INFO_ONLY */
 #endif /* PNGPRIV_H */

+ 20 - 30
drivers/png/pngread.c

@@ -1,8 +1,8 @@
 
 /* pngread.c - read a PNG file
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -67,15 +67,11 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    png_ptr->user_width_max = PNG_USER_WIDTH_MAX;
    png_ptr->user_height_max = PNG_USER_HEIGHT_MAX;
 
-#  ifdef PNG_USER_CHUNK_CACHE_MAX
    /* Added at libpng-1.2.43 and 1.4.0 */
    png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
-#  endif
 
-#  ifdef PNG_SET_USER_CHUNK_MALLOC_MAX
    /* Added at libpng-1.2.43 and 1.4.1 */
    png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
-#  endif
 #endif
 
 #ifdef PNG_SETJMP_SUPPORTED
@@ -104,7 +100,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    if (!png_user_version_check(png_ptr, user_png_ver))
       png_cleanup_needed = 1;
 
-   if (!png_cleanup_needed)
+   if (png_cleanup_needed == 0)
    {
    /* Initialize zbuf - compression buffer */
    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
@@ -118,7 +114,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    png_ptr->zstream.zfree = png_zfree;
    png_ptr->zstream.opaque = (voidpf)png_ptr;
 
-   if (!png_cleanup_needed)
+   if (png_cleanup_needed == 0)
    {
       switch (inflateInit(&png_ptr->zstream))
       {
@@ -145,7 +141,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
       }
    }
 
-   if (png_cleanup_needed)
+   if (png_cleanup_needed != 0)
    {
       /* Clean up PNG structure and deallocate any memory. */
       png_free(png_ptr, png_ptr->zbuf);
@@ -563,7 +559,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
       if (ret == Z_STREAM_END)
       {
          if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
-            png_ptr->idat_size)
+             png_ptr->idat_size)
             png_benign_error(png_ptr, "Extra compressed data");
          png_ptr->mode |= PNG_AFTER_IDAT;
          png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
@@ -621,7 +617,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
 #ifdef PNG_READ_INTERLACING_SUPPORTED
    /* Blow up interlaced rows to full size */
    if (png_ptr->interlaced &&
-      (png_ptr->transformations & PNG_INTERLACE))
+       (png_ptr->transformations & PNG_INTERLACE))
    {
       if (png_ptr->pass < 6)
          png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,
@@ -805,6 +801,13 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
 
    png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
 
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+   /* Report invalid palette index; added at libng-1.5.10 */
+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+      png_ptr->num_palette_max > png_ptr->num_palette)
+     png_benign_error(png_ptr, "Read palette index exceeding num_palette");
+#endif
+
    do
    {
       png_uint_32 length = png_read_chunk_header(png_ptr);
@@ -1070,12 +1073,6 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
    png_free(png_ptr, png_ptr->save_buffer);
 #endif
 
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-#ifdef PNG_TEXT_SUPPORTED
-   png_free(png_ptr, png_ptr->current_text);
-#endif /* PNG_TEXT_SUPPORTED */
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-
    /* Save the important info out of the png_struct, in case it is
     * being used again.
     */
@@ -1122,9 +1119,8 @@ png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 #ifdef PNG_INFO_IMAGE_SUPPORTED
 void PNGAPI
-png_read_png(png_structp png_ptr, png_infop info_ptr,
-                           int transforms,
-                           voidp params)
+png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms,
+    voidp params)
 {
    int row;
 
@@ -1194,7 +1190,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
    if (transforms & PNG_TRANSFORM_EXPAND)
       if ((png_ptr->bit_depth < 8) ||
           (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
-          (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+          (info_ptr->valid & PNG_INFO_tRNS))
          png_set_expand(png_ptr);
 #endif
 
@@ -1213,14 +1209,8 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
     * [0,65535] to the original [0,7] or [0,31], or whatever range the
     * colors were originally in:
     */
-   if ((transforms & PNG_TRANSFORM_SHIFT)
-       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
-   {
-      png_color_8p sig_bit;
-
-      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
-      png_set_shift(png_ptr, sig_bit);
-   }
+   if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT))
+      png_set_shift(png_ptr, &info_ptr->sig_bit);
 #endif
 
 #ifdef PNG_READ_BGR_SUPPORTED
@@ -1290,7 +1280,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
 
       for (row = 0; row < (int)info_ptr->height; row++)
          info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
-            png_get_rowbytes(png_ptr, info_ptr));
+             png_get_rowbytes(png_ptr, info_ptr));
    }
 
    png_read_image(png_ptr, info_ptr->row_pointers);

+ 2 - 2
drivers/png/pngrio.c

@@ -2,7 +2,7 @@
 /* pngrio.c - functions for data input
  *
  * Last changed in libpng 1.5.0 [January 6, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -26,7 +26,7 @@
  * reads from a file pointer.  Note that this routine sometimes gets called
  * with very small lengths, so you should implement some kind of simple
  * buffering if you are using unbuffered reads.  This should never be asked
- * to read more then 64K on a 16 bit machine.
+ * to read more than 64K on a 16 bit machine.
  */
 void /* PRIVATE */
 png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)

+ 139 - 89
drivers/png/pngrtran.c

@@ -1,8 +1,8 @@
 
 /* pngrtran.c - transforms the data in a row for PNG readers
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.24 [November 12, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -114,7 +114,7 @@ png_set_background_fixed(png_structp png_ptr,
       png_sizeof(png_color_16));
    png_ptr->background_gamma = background_gamma;
    png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
-   if (need_expand)
+   if (need_expand != 0)
       png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
    else
       png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
@@ -194,8 +194,10 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma,
        */
 #     ifdef PNG_READ_sRGB_SUPPORTED
          png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
+#     else
+         PNG_UNUSED(png_ptr)
 #     endif
-      if (is_screen)
+      if (is_screen != 0)
          output_gamma = PNG_GAMMA_sRGB;
       else
          output_gamma = PNG_GAMMA_sRGB_INVERSE;
@@ -204,7 +206,7 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma,
    else if (output_gamma == PNG_GAMMA_MAC_18 ||
       output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
    {
-      if (is_screen)
+      if (is_screen != 0)
          output_gamma = PNG_GAMMA_MAC_OLD;
       else
          output_gamma = PNG_GAMMA_MAC_INVERSE;
@@ -329,7 +331,7 @@ png_set_alpha_mode_fixed(png_structp png_ptr, int mode,
    /* Finally, if pre-multiplying, set the background fields to achieve the
     * desired result.
     */
-   if (compose)
+   if (compose != 0)
    {
       /* And obtain alpha pre-multiplication by composing on black: */
       png_memset(&png_ptr->background, 0, sizeof png_ptr->background);
@@ -389,7 +391,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
 
    png_ptr->transformations |= PNG_QUANTIZE;
 
-   if (!full_quantize)
+   if (full_quantize == 0)
    {
       int i;
 
@@ -444,12 +446,12 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
                }
             }
 
-            if (done)
+            if (done != 0)
                break;
          }
 
          /* Swap the palette around, and set up a table, if necessary */
-         if (full_quantize)
+         if (full_quantize != 0)
          {
             int j = num_palette;
 
@@ -632,7 +634,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
                         num_new_palette--;
                         palette[png_ptr->index_to_palette[j]]
                             = palette[num_new_palette];
-                        if (!full_quantize)
+                        if (full_quantize == 0)
                         {
                            int k;
 
@@ -700,7 +702,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
    }
    png_ptr->num_palette = (png_uint_16)num_palette;
 
-   if (full_quantize)
+   if (full_quantize != 0)
    {
       int i;
       png_bytep distance;
@@ -969,7 +971,7 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
          png_uint_16 red_int, green_int;
 
          /* NOTE: this calculation does not round, but this behavior is retained
-          * for consistency, the inaccuracy is very small.  The code here always
+          * for consistency; the inaccuracy is very small.  The code here always
           * overwrites the coefficients, regardless of whether they have been
           * defaulted or set already.
           */
@@ -1068,7 +1070,7 @@ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
  * the palette.
  */
 
-/*For the moment 'png_init_palette_transformations' and
+/* For the moment 'png_init_palette_transformations' and
  * 'png_init_rgb_transformations' only do some flag canceling optimizations.
  * The intent is that these two routines should have palette or rgb operations
  * extracted from 'png_init_read_transformations'.
@@ -1093,25 +1095,31 @@ png_init_palette_transformations(png_structp png_ptr)
 
       /* Ignore if all the entries are opaque (unlikely!) */
       for (i=0; i<png_ptr->num_trans; ++i)
+      {
          if (png_ptr->trans_alpha[i] == 255)
             continue;
          else if (png_ptr->trans_alpha[i] == 0)
             input_has_transparency = 1;
          else
+         {
+            input_has_transparency = 1;
             input_has_alpha = 1;
+            break;
+         }
+      }
    }
 
    /* If no alpha we can optimize. */
-   if (!input_has_alpha)
+   if (input_has_alpha == 0)
    {
       /* Any alpha means background and associative alpha processing is
-       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+       * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
        * and ENCODE_ALPHA are irrelevant.
        */
       png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
       png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
 
-      if (!input_has_transparency)
+      if (input_has_transparency == 0)
          png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
    }
 
@@ -1167,10 +1175,10 @@ png_init_rgb_transformations(png_structp png_ptr)
    int input_has_transparency = png_ptr->num_trans > 0;
 
    /* If no alpha we can optimize. */
-   if (!input_has_alpha)
+   if (input_has_alpha == 0)
    {
       /* Any alpha means background and associative alpha processing is
-       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+       * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
        * and ENCODE_ALPHA are irrelevant.
        */
 #     ifdef PNG_READ_ALPHA_MODE_SUPPORTED
@@ -1178,7 +1186,7 @@ png_init_rgb_transformations(png_structp png_ptr)
          png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
 #     endif
 
-      if (!input_has_transparency)
+      if (input_has_transparency == 0)
          png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
    }
 
@@ -1221,7 +1229,7 @@ png_init_rgb_transformations(png_structp png_ptr)
             default:
 
             case 8:
-               /* Already 8 bits, fall through */
+               /* FALL THROUGH (already 8 bits) */
 
             case 16:
                /* Already a full 16 bits */
@@ -1304,7 +1312,7 @@ png_init_read_transformations(png_structp png_ptr)
        * the code immediately below if the transform can be handled outside the
        * row loop.
        */
-      if (gamma_correction)
+      if (gamma_correction != 0)
          png_ptr->transformations |= PNG_GAMMA;
 
       else
@@ -1313,7 +1321,7 @@ png_init_read_transformations(png_structp png_ptr)
 #endif
 
    /* Certain transformations have the effect of preventing other
-    * transformations that happen afterward in png_do_read_transformations,
+    * transformations that happen afterward in png_do_read_transformations;
     * resolve the interdependencies here.  From the code of
     * png_do_read_transformations the order is:
     *
@@ -1702,11 +1710,11 @@ png_init_read_transformations(png_structp png_ptr)
             g_sig = png_gamma_significant(g);
             gs_sig = png_gamma_significant(gs);
 
-            if (g_sig)
+            if (g_sig != 0)
                png_ptr->background_1.gray = png_gamma_correct(png_ptr,
                    png_ptr->background.gray, g);
 
-            if (gs_sig)
+            if (gs_sig != 0)
                png_ptr->background.gray = png_gamma_correct(png_ptr,
                    png_ptr->background.gray, gs);
 
@@ -1715,7 +1723,7 @@ png_init_read_transformations(png_structp png_ptr)
                 (png_ptr->background.red != png_ptr->background.gray))
             {
                /* RGB or RGBA with color background */
-               if (g_sig)
+               if (g_sig != 0)
                {
                   png_ptr->background_1.red = png_gamma_correct(png_ptr,
                       png_ptr->background.red, g);
@@ -1727,7 +1735,7 @@ png_init_read_transformations(png_structp png_ptr)
                       png_ptr->background.blue, g);
                }
 
-               if (gs_sig)
+               if (gs_sig != 0)
                {
                   png_ptr->background.red = png_gamma_correct(png_ptr,
                       png_ptr->background.red, gs);
@@ -1770,8 +1778,8 @@ png_init_read_transformations(png_structp png_ptr)
          int num_palette = png_ptr->num_palette;
          int i;
 
-         /*NOTE: there are other transformations that should probably be in here
-          * too.
+         /* NOTE: there are other transformations that should probably be in
+          * here too.
           */
          for (i = 0; i < num_palette; i++)
          {
@@ -1830,12 +1838,15 @@ png_init_read_transformations(png_structp png_ptr)
 
 #ifdef PNG_READ_SHIFT_SUPPORTED
    if ((png_ptr->transformations & PNG_SHIFT) &&
+      !(png_ptr->transformations & PNG_EXPAND) &&
        (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
    {
       int i;
       int istop = png_ptr->num_palette;
       int shift = 8 - png_ptr->sig_bit.red;
 
+      png_ptr->transformations &= ~PNG_SHIFT;
+
       /* significant bits can be in the range 1 to 7 for a meaninful result, if
        * the number of significant bits is 0 then no shift is done (this is an
        * error condition which is silently ignored.)
@@ -1895,6 +1906,9 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
 
          info_ptr->bit_depth = 8;
          info_ptr->num_trans = 0;
+
+         if (png_ptr->palette == NULL)
+            png_error (png_ptr, "Palette is NULL in indexed image");
       }
       else
       {
@@ -2042,10 +2056,10 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
 defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
    if (png_ptr->transformations & PNG_USER_TRANSFORM)
    {
-      if (info_ptr->bit_depth < png_ptr->user_transform_depth)
+      if (png_ptr->user_transform_depth)
          info_ptr->bit_depth = png_ptr->user_transform_depth;
 
-      if (info_ptr->channels < png_ptr->user_transform_channels)
+      if (png_ptr->user_transform_channels)
          info_ptr->channels = png_ptr->user_transform_channels;
    }
 #endif
@@ -2064,7 +2078,7 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
    png_ptr->info_rowbytes = info_ptr->rowbytes;
 
 #ifndef PNG_READ_EXPAND_SUPPORTED
-   if (png_ptr)
+   if (png_ptr != NULL)
       return;
 #endif
 }
@@ -2141,7 +2155,7 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
           png_do_rgb_to_gray(png_ptr, row_info,
               png_ptr->row_buf + 1);
 
-      if (rgb_error)
+      if (rgb_error != 0)
       {
          png_ptr->rgb_to_gray_status=1;
          if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
@@ -2195,8 +2209,8 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
       png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
 #endif
 
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
-   (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)
    if (png_ptr->transformations & PNG_COMPOSE)
       png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
 #endif
@@ -2207,8 +2221,8 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
       /* Because RGB_TO_GRAY does the gamma transform. */
       !(png_ptr->transformations & PNG_RGB_TO_GRAY) &&
 #endif
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
-   (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)
       /* Because PNG_COMPOSE does the gamma transform if there is something to
        * do (if there is an alpha channel or transparency.)
        */
@@ -2274,7 +2288,7 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
 #endif
 
 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
-   /*NOTE: moved here in 1.5.4 (from much later in this list.) */
+   /* NOTE: moved here in 1.5.4 (from much later in this list.) */
    if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
        (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
       png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
@@ -2296,6 +2310,13 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
       png_do_unpack(row_info, png_ptr->row_buf + 1);
 #endif
 
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+   /* Added at libpng-1.5.10 */
+   if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+       png_ptr->num_palette_max >= 0)
+      png_do_check_palette_indexes(png_ptr, row_info);
+#endif
+
 #ifdef PNG_READ_BGR_SUPPORTED
    if (png_ptr->transformations & PNG_BGR)
       png_do_bgr(row_info, png_ptr->row_buf + 1);
@@ -2512,7 +2533,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row,
                have_shift = 1;
          }
 
-         if (!have_shift)
+         if (have_shift == 0)
             return;
       }
 
@@ -2948,13 +2969,13 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             png_bytep dp = sp  + (png_size_t)row_width * 2;
             for (i = 1; i < row_width; i++)
             {
-               *(--dp) = hi_filler;
                *(--dp) = lo_filler;
+               *(--dp) = hi_filler;
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
             }
-            *(--dp) = hi_filler;
             *(--dp) = lo_filler;
+            *(--dp) = hi_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 32;
             row_info->rowbytes = row_width * 4;
@@ -2969,8 +2990,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             {
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
-               *(--dp) = hi_filler;
                *(--dp) = lo_filler;
+               *(--dp) = hi_filler;
             }
             row_info->channels = 2;
             row_info->pixel_depth = 32;
@@ -3029,8 +3050,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             png_bytep dp = sp  + (png_size_t)row_width * 2;
             for (i = 1; i < row_width; i++)
             {
-               *(--dp) = hi_filler;
                *(--dp) = lo_filler;
+               *(--dp) = hi_filler;
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
@@ -3038,8 +3059,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
             }
-            *(--dp) = hi_filler;
             *(--dp) = lo_filler;
+            *(--dp) = hi_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 64;
             row_info->rowbytes = row_width * 8;
@@ -3058,8 +3079,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
                *(--dp) = *(--sp);
-               *(--dp) = hi_filler;
                *(--dp) = lo_filler;
+               *(--dp) = hi_filler;
             }
 
             row_info->channels = 4;
@@ -3273,7 +3294,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
                   *(dp++) = red;
                }
 
-               if (have_alpha)
+               if (have_alpha != 0)
                   *(dp++) = *(sp++);
             }
          }
@@ -3293,7 +3314,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
                if (red != green || red != blue)
                {
                   rgb_error |= 1;
-                  /*NOTE: this is the historical approach which simply
+                  /* NOTE: this is the historical approach which simply
                    * truncates the results.
                    */
                   *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
@@ -3302,7 +3323,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
                else
                   *(dp++) = red;
 
-               if (have_alpha)
+               if (have_alpha != 0)
                   *(dp++) = *(sp++);
             }
          }
@@ -3320,11 +3341,17 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
             for (i = 0; i < row_width; i++)
             {
                png_uint_16 red, green, blue, w;
-
+#if 0 /* Coverity doesn't like this */
                red   = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
                green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
                blue  = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+#else
+               png_byte hi,lo;
 
+               hi=*(sp)++; lo=*(sp)++; red   = (png_uint_16)((hi << 8) | (lo));
+               hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
+               hi=*(sp)++; lo=*(sp)++; blue  = (png_uint_16)((hi << 8) | (lo));
+#endif
                if (red == green && red == blue)
                {
                   if (png_ptr->gamma_16_table != NULL)
@@ -3354,7 +3381,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
                *(dp++) = (png_byte)((w>>8) & 0xff);
                *(dp++) = (png_byte)(w & 0xff);
 
-               if (have_alpha)
+               if (have_alpha != 0)
                {
                   *(dp++) = *(sp++);
                   *(dp++) = *(sp++);
@@ -3388,7 +3415,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
                *(dp++) = (png_byte)((gray16>>8) & 0xff);
                *(dp++) = (png_byte)(gray16 & 0xff);
 
-               if (have_alpha)
+               if (have_alpha != 0)
                {
                   *(dp++) = *(sp++);
                   *(dp++) = *(sp++);
@@ -3467,8 +3494,8 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette)
 
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
-   (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)
 /* Replace any alpha or transparency with the supplied background color.
  * "background" is already in the screen gamma, while "background_1" is
  * at a gamma of 1.0.  Paletted files have already been taken care of.
@@ -3514,7 +3541,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         *sp |= (png_byte)(png_ptr->background.gray << shift);
                      }
 
-                     if (!shift)
+                     if (shift == 0)
                      {
                         shift = 7;
                         sp++;
@@ -3551,7 +3578,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                            *sp |= (png_byte)(g << shift);
                         }
 
-                        if (!shift)
+                        if (shift == 0)
                         {
                            shift = 6;
                            sp++;
@@ -3576,7 +3603,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                            *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
-                        if (!shift)
+                        if (shift == 0)
                         {
                            shift = 6;
                            sp++;
@@ -3614,7 +3641,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                            *sp |= (png_byte)(g << shift);
                         }
 
-                        if (!shift)
+                        if (shift == 0)
                         {
                            shift = 4;
                            sp++;
@@ -3639,7 +3666,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                            *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
-                        if (!shift)
+                        if (shift == 0)
                         {
                            shift = 4;
                            sp++;
@@ -3695,8 +3722,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         if (v == png_ptr->trans_color.gray)
                         {
                            /* Background is already in screen gamma */
-                           *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
-                           *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+                           *sp = (png_byte)((png_ptr->background.gray >> 8)
+                                & 0xff);
+                           *(sp + 1) = (png_byte)(png_ptr->background.gray
+                                & 0xff);
                         }
 
                         else
@@ -3719,8 +3748,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                         if (v == png_ptr->trans_color.gray)
                         {
-                           *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
-                           *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+                           *sp = (png_byte)((png_ptr->background.gray >> 8)
+                                & 0xff);
+                           *(sp + 1) = (png_byte)(png_ptr->background.gray
+                                & 0xff);
                         }
                      }
                   }
@@ -3800,9 +3831,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         /* Background is already in screen gamma */
                         *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
-                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
-                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+                                & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green
+                                & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+                                & 0xff);
                         *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
@@ -3843,9 +3877,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                      {
                         *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
-                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
-                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+                                & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green
+                                & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+                                & 0xff);
                         *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
                   }
@@ -3882,7 +3919,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                         v = gamma_to_1[*sp];
                         png_composite(w, v, a, png_ptr->background_1.gray);
-                        if (!optimize)
+                        if (optimize == 0)
                            w = gamma_from_1[w];
                         *sp = w;
                      }
@@ -3900,7 +3937,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         *sp = (png_byte)png_ptr->background.gray;
 
                      else if (a < 0xff)
-                        png_composite(*sp, *sp, a, png_ptr->background_1.gray);
+                        png_composite(*sp, *sp, a, png_ptr->background.gray);
                   }
                }
             }
@@ -3928,7 +3965,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                      else if (a == 0)
                      {
                         /* Background is already in screen gamma */
-                        *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                        *sp = (png_byte)((png_ptr->background.gray >> 8)
+                                & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                      }
 
@@ -3938,7 +3976,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                         g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
                         png_composite_16(v, g, a, png_ptr->background_1.gray);
-                        if (optimize)
+                        if (optimize != 0)
                            w = v;
                         else
                            w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
@@ -3958,7 +3996,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                      if (a == 0)
                      {
-                        *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                        *sp = (png_byte)((png_ptr->background.gray >> 8)
+                                & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                      }
 
@@ -3967,7 +4006,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         png_uint_16 g, v;
 
                         g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
-                        png_composite_16(v, g, a, png_ptr->background_1.gray);
+                        png_composite_16(v, g, a, png_ptr->background.gray);
                         *sp = (png_byte)((v >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(v & 0xff);
                      }
@@ -4011,17 +4050,17 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                         v = gamma_to_1[*sp];
                         png_composite(w, v, a, png_ptr->background_1.red);
-                        if (!optimize) w = gamma_from_1[w];
+                        if (optimize == 0) w = gamma_from_1[w];
                         *sp = w;
 
                         v = gamma_to_1[*(sp + 1)];
                         png_composite(w, v, a, png_ptr->background_1.green);
-                        if (!optimize) w = gamma_from_1[w];
+                        if (optimize == 0) w = gamma_from_1[w];
                         *(sp + 1) = w;
 
                         v = gamma_to_1[*(sp + 2)];
                         png_composite(w, v, a, png_ptr->background_1.blue);
-                        if (!optimize) w = gamma_from_1[w];
+                        if (optimize == 0) w = gamma_from_1[w];
                         *(sp + 2) = w;
                      }
                   }
@@ -4088,9 +4127,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                         /* Background is already in screen gamma */
                         *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
-                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
-                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+                                & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green
+                                & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+                                & 0xff);
                         *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
@@ -4100,23 +4142,26 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 
                         v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
                         png_composite_16(w, v, a, png_ptr->background_1.red);
-                        if (!optimize)
-                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        if (optimize == 0)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+                               [w >> 8];
                         *sp = (png_byte)((w >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(w & 0xff);
 
                         v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
                         png_composite_16(w, v, a, png_ptr->background_1.green);
-                        if (!optimize)
-                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        if (optimize == 0)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+                               [w >> 8];
 
                         *(sp + 2) = (png_byte)((w >> 8) & 0xff);
                         *(sp + 3) = (png_byte)(w & 0xff);
 
                         v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
                         png_composite_16(w, v, a, png_ptr->background_1.blue);
-                        if (!optimize)
-                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        if (optimize == 0)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+                               [w >> 8];
 
                         *(sp + 4) = (png_byte)((w >> 8) & 0xff);
                         *(sp + 5) = (png_byte)(w & 0xff);
@@ -4137,9 +4182,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
                      {
                         *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
                         *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
-                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
-                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+                                & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green
+                                & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+                                & 0xff);
                         *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
@@ -4715,7 +4763,9 @@ png_do_expand(png_row_infop row_info, png_bytep row,
          {
             if (row_info->bit_depth == 8)
             {
-               gray = gray & 0xff;
+               /* NOTE: prior to libpng 1.5.14 this cleared out the top bits of
+                * 'gray', however if those are set it is an error.
+                */
                sp = row + (png_size_t)row_width - 1;
                dp = row + (png_size_t)(row_width << 1) - 1;
 

+ 118 - 127
drivers/png/pngrutil.c

@@ -1,8 +1,8 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.25 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -18,8 +18,6 @@
 
 #ifdef PNG_READ_SUPPORTED
 
-#define png_strtod(p,a,b) strtod(a,b)
-
 png_uint_32 PNGAPI
 png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
 {
@@ -91,7 +89,13 @@ png_get_int_32)(png_const_bytep buf)
       return uval;
 
    uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */
-   return -(png_int_32)uval;
+   if ((uval & 0x80000000) == 0) /* no overflow */
+       return -(png_int_32)uval;
+   /* The following has to be safe; this function only gets called on PNG data
+    * and if we get here that data is invalid.  0 is the most safe value and
+    * if not then an attacker would surely just generate a PNG with 0 instead.
+    */
+   return 0;
 }
 
 /* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
@@ -211,7 +215,7 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip)
       png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
    }
 
-   if (i)
+   if (i != 0)
    {
       png_crc_read(png_ptr, png_ptr->zbuf, i);
    }
@@ -267,7 +271,7 @@ png_crc_error(png_structp png_ptr)
    /* The chunk CRC must be serialized in a single I/O call. */
    png_read_data(png_ptr, crc_bytes, 4);
 
-   if (need_crc)
+   if (need_crc != 0)
    {
       crc = png_get_uint_32(crc_bytes);
       return ((int)(crc != png_ptr->crc));
@@ -284,6 +288,17 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
 {
    png_size_t count = 0;
 
+   /* HACK: added in libpng 1.5.18: the progressive reader always leaves
+    * png_ptr->zstream in a non-reset state.  This causes a reset if it needs to
+    * be used again.  This only copes with that one specific error; see libpng
+    * 1.6 for a better solution.
+    */
+   if ((png_ptr->flags & PNG_FLAG_ZSTREAM_PROGRESSIVE) != 0)
+   {
+      (void)inflateReset(&png_ptr->zstream);
+      png_ptr->flags &= ~PNG_FLAG_ZSTREAM_PROGRESSIVE;
+   }
+
    /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
     * even necessarily handle 65536 bytes) because the type uInt is "16 bits or
     * more".  Consequently it is necessary to chunk the input to zlib.  This
@@ -432,15 +447,16 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
       /* Now check the limits on this chunk - if the limit fails the
        * compressed data will be removed, the prefix will remain.
        */
-#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
-      if (png_ptr->user_chunk_malloc_max &&
+      if (prefix_size >= (~(png_size_t)0) - 1 ||
+         expanded_size >= (~(png_size_t)0) - 1 - prefix_size
+#ifdef PNG_USER_LIMITS_SUPPORTED
+         || (png_ptr->user_chunk_malloc_max &&
           (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
 #else
-#  ifdef PNG_USER_CHUNK_MALLOC_MAX
-      if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
+         || ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
           prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
-#  endif
 #endif
+         )
          png_warning(png_ptr, "Exceeded size limit while expanding chunk");
 
       /* If the size is zero either there was an error and a message
@@ -448,12 +464,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
        * and we have nothing to do - the code will exit through the
        * error case below.
        */
-#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
-    defined(PNG_USER_CHUNK_MALLOC_MAX)
       else if (expanded_size > 0)
-#else
-      if (expanded_size > 0)
-#endif
       {
          /* Success (maybe) - really uncompress the chunk. */
          png_size_t new_size = 0;
@@ -600,7 +611,7 @@ void /* PRIVATE */
 png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
    png_color palette[PNG_MAX_PALETTE_LENGTH];
-   int num, i;
+   int max_palette_length, num, i;
 #ifdef PNG_POINTER_INDEXING_SUPPORTED
    png_colorp pal_ptr;
 #endif
@@ -653,8 +664,22 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       }
    }
 
+   /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
    num = (int)length / 3;
 
+   /* If the palette has 256 or fewer entries but is too large for the bit
+    * depth, we don't issue an error, to preserve the behavior of previous
+    * libpng versions. We silently truncate the unused extra palette entries
+    * here.
+    */
+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      max_palette_length = (1 << png_ptr->bit_depth);
+   else
+      max_palette_length = PNG_MAX_PALETTE_LENGTH;
+
+   if (num > max_palette_length)
+      num = max_palette_length;
+
 #ifdef PNG_POINTER_INDEXING_SUPPORTED
    for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
    {
@@ -687,7 +712,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
 #endif
    {
-      png_crc_finish(png_ptr, 0);
+      png_crc_finish(png_ptr, (int) length - num * 3);
    }
 
 #ifndef PNG_READ_OPT_PLTE_SUPPORTED
@@ -1261,13 +1286,16 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       /* Should be an error, but we can cope with it */
       png_warning(png_ptr, "Out of place iCCP chunk");
 
-   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+   if ((png_ptr->mode & PNG_HAVE_iCCP) || (info_ptr != NULL &&
+      (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB))))
    {
       png_warning(png_ptr, "Duplicate iCCP chunk");
       png_crc_finish(png_ptr, length);
       return;
    }
 
+   png_ptr->mode |= PNG_HAVE_iCCP;
+
 #ifdef PNG_MAX_MALLOC_64K
    if (length > (png_uint_32)65535L)
    {
@@ -1279,7 +1307,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    png_free(png_ptr, png_ptr->chunkdata);
    png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -1299,7 +1327,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* There should be at least one zero (the compression type byte)
     * following the separator, and we should be on it
     */
-   if (profile >= png_ptr->chunkdata + slength - 1)
+   if (slength < 1U || profile >= png_ptr->chunkdata + slength - 1U)
    {
       png_free(png_ptr, png_ptr->chunkdata);
       png_ptr->chunkdata = NULL;
@@ -1310,7 +1338,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* Compression_type should always be zero */
    compression_type = *profile++;
 
-   if (compression_type)
+   if (compression_type != 0)
    {
       png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
       compression_type = 0x00;  /* Reset it to zero (libpng-1.0.6 through 1.0.8
@@ -1429,7 +1457,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
     * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
     * potential breakage point if the types in pngconf.h aren't exactly right.
     */
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -1448,7 +1476,8 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    ++entry_start;
 
    /* A sample depth should follow the separator, and we should be on it  */
-   if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
+   if (slength < 2U ||
+       entry_start > (png_bytep)png_ptr->chunkdata + slength - 2U)
    {
       png_free(png_ptr, png_ptr->chunkdata);
       png_ptr->chunkdata = NULL;
@@ -1797,16 +1826,16 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   num = length / 2 ;
-
-   if (num != (unsigned int)png_ptr->num_palette || num >
-       (unsigned int)PNG_MAX_PALETTE_LENGTH)
+   if (length > 2*PNG_MAX_PALETTE_LENGTH ||
+       length != (unsigned int) (2*png_ptr->num_palette))
    {
       png_warning(png_ptr, "Incorrect hIST chunk length");
       png_crc_finish(png_ptr, length);
       return;
    }
 
+   num = length / 2 ;
+
    for (i = 0; i < num; i++)
    {
       png_byte buf[2];
@@ -1956,7 +1985,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -1977,7 +2006,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* We need to have at least 12 bytes after the purpose string
     * in order to get the parameter information.
     */
-   if (endptr <= buf + 12)
+   if (endptr - buf <= 12)
    {
       png_warning(png_ptr, "Invalid pCAL data");
       png_free(png_ptr, png_ptr->chunkdata);
@@ -2105,7 +2134,7 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
    png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
 
@@ -2265,7 +2294,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
      return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -2310,7 +2339,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_ptr->chunkdata = NULL;
    png_free(png_ptr, text_ptr);
 
-   if (ret)
+   if (ret != 0)
       png_warning(png_ptr, "Insufficient memory to process text chunk");
 }
 #endif
@@ -2373,7 +2402,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -2389,7 +2418,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       /* Empty loop */ ;
 
    /* zTXt must have some text after the chunkdataword */
-   if (text >= png_ptr->chunkdata + slength - 2)
+   if (slength < 2U || text >= png_ptr->chunkdata + slength - 2U)
    {
       png_warning(png_ptr, "Truncated zTXt chunk");
       png_free(png_ptr, png_ptr->chunkdata);
@@ -2440,7 +2469,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_free(png_ptr, png_ptr->chunkdata);
    png_ptr->chunkdata = NULL;
 
-   if (ret)
+   if (ret != 0)
       png_error(png_ptr, "Insufficient memory to store zTXt chunk");
 }
 #endif
@@ -2453,7 +2482,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_textp text_ptr;
    png_charp key, lang, text, lang_key;
    int comp_flag;
-   int comp_type = 0;
+   int comp_type;
    int ret;
    png_size_t slength, prefix_len, data_len;
 
@@ -2504,7 +2533,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -2526,7 +2555,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
     * keyword
     */
 
-   if (lang >= png_ptr->chunkdata + slength - 3)
+   if (slength < 3U || lang >= png_ptr->chunkdata + slength - 3U)
    {
       png_warning(png_ptr, "Truncated iTXt chunk");
       png_free(png_ptr, png_ptr->chunkdata);
@@ -2534,18 +2563,30 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   else
-   {
-      comp_flag = *lang++;
-      comp_type = *lang++;
-   }
+   comp_flag = *lang++;
+   comp_type = *lang++;
 
-   if (comp_type || (comp_flag && comp_flag != PNG_TEXT_COMPRESSION_zTXt))
+   /* 1.5.14: The spec says "for uncompressed text decoders shall ignore [the
+    * compression type]".  The compression flag shall be 0 (no compression) or
+    * 1 (compressed with method 0 - deflate.)
+    */
+   if (comp_flag/*compressed*/ != 0)
    {
-      png_warning(png_ptr, "Unknown iTXt compression type or method");
-      png_free(png_ptr, png_ptr->chunkdata);
-      png_ptr->chunkdata = NULL;
-      return;
+     if (comp_flag != 1)
+     {
+        png_warning(png_ptr, "invalid iTXt compression flag");
+        png_free(png_ptr, png_ptr->chunkdata);
+        png_ptr->chunkdata = NULL;
+        return;
+     }
+
+     if (comp_type != 0)
+     {
+        png_warning(png_ptr, "unknown iTXt compression type");
+        png_free(png_ptr, png_ptr->chunkdata);
+        png_ptr->chunkdata = NULL;
+        return;
+     }
    }
 
    for (lang_key = lang; *lang_key; lang_key++)
@@ -2578,7 +2619,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    key=png_ptr->chunkdata;
 
-   if (comp_flag)
+   if (comp_flag/*compressed*/)
       png_decompress_chunk(png_ptr, comp_type,
           (size_t)length, prefix_len, &data_len);
 
@@ -2596,7 +2637,8 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   text_ptr->compression = (int)comp_flag + 1;
+   text_ptr->compression =
+      (comp_flag ? PNG_ITXT_COMPRESSION_zTXt : PNG_ITXT_COMPRESSION_NONE);
    text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
    text_ptr->lang = png_ptr->chunkdata + (lang - key);
    text_ptr->itxt_length = data_len;
@@ -2610,7 +2652,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_free(png_ptr, png_ptr->chunkdata);
    png_ptr->chunkdata = NULL;
 
-   if (ret)
+   if (ret != 0)
       png_error(png_ptr, "Insufficient memory to store iTXt chunk");
 }
 #endif
@@ -2787,7 +2829,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
 {
    unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
    png_const_bytep sp = png_ptr->row_buf + 1;
-   png_uint_32 row_width = png_ptr->width;
+   png_alloc_size_t row_width = png_ptr->width;
    unsigned int pass = png_ptr->pass;
    png_bytep end_ptr = 0;
    png_byte end_byte = 0;
@@ -2939,7 +2981,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
 #        define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\
             S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }
 
-#        define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) }
+#        define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) }
 
 #        define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
 
@@ -3050,7 +3092,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
          }
 
          /* Work out the bytes to copy. */
-         if (display)
+         if (display != 0)
          {
             /* When doing the 'block' algorithm the pixel in the pass gets
              * replicated to adjacent pixels.  This is why the even (0,2,4,6)
@@ -3060,7 +3102,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
 
             /* But don't allow this number to exceed the actual row width. */
             if (bytes_to_copy > row_width)
-               bytes_to_copy = row_width;
+               bytes_to_copy = (unsigned int)/*SAFE*/row_width;
          }
 
          else /* normal row; Adam7 only ever gives us one pixel to copy. */
@@ -3152,7 +3194,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
                   {
                      png_uint_32p dp32 = (png_uint_32p)dp;
                      png_const_uint_32p sp32 = (png_const_uint_32p)sp;
-                     unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+                     size_t skip = (bytes_to_jump-bytes_to_copy) /
                         sizeof (png_uint_32);
 
                      do
@@ -3193,7 +3235,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
                   {
                      png_uint_16p dp16 = (png_uint_16p)dp;
                      png_const_uint_16p sp16 = (png_const_uint_16p)sp;
-                     unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+                     size_t skip = (bytes_to_jump-bytes_to_copy) /
                         sizeof (png_uint_16);
 
                      do
@@ -3238,7 +3280,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
                   dp += bytes_to_jump;
                   row_width -= bytes_to_jump;
                   if (bytes_to_copy > row_width)
-                     bytes_to_copy = row_width;
+                     bytes_to_copy = (unsigned int)/*SAFE*/row_width;
                }
          }
 
@@ -3477,7 +3519,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
 
             for (i = 0; i < row_info->width; i++)
             {
-               png_byte v[8];
+               png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */
                int j;
 
                png_memcpy(v, sp, pixel_bytes);
@@ -3661,68 +3703,6 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
    }
 }
 
-#ifdef PNG_ARM_NEON
-
-#if 0
-#ifdef __linux__
-#include <stdio.h>
-#include <elf.h>
-#include <asm/hwcap.h>
-
-static int png_have_hwcap(unsigned cap)
-{
-   FILE *f = fopen("/proc/self/auxv", "r");
-   Elf32_auxv_t aux;
-   int have_cap = 0;
-
-   if (!f)
-      return 0;
-
-   while (fread(&aux, sizeof(aux), 1, f) > 0)
-   {
-      if (aux.a_type == AT_HWCAP &&
-          aux.a_un.a_val & cap)
-      {
-         have_cap = 1;
-         break;
-      }
-   }
-
-   fclose(f);
-
-   return have_cap;
-}
-#endif /* __linux__ */
-#endif
-static void
-png_init_filter_functions_neon(png_structp pp, unsigned int bpp)
-{
-#if 0
-#ifdef __linux__
-   if (!png_have_hwcap(HWCAP_NEON))
-      return;
-#endif
-#endif
-   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;
-
-   if (bpp == 3)
-   {
-      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;
-      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;
-      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = 
-         png_read_filter_row_paeth3_neon;
-   }
-
-   else if (bpp == 4)
-   {
-      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
-      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
-      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
-          png_read_filter_row_paeth4_neon;
-   }
-}
-#endif /* PNG_ARM_NEON */
-
 static void
 png_init_filter_functions(png_structp pp)
 {
@@ -3738,8 +3718,16 @@ png_init_filter_functions(png_structp pp)
       pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
          png_read_filter_row_paeth_multibyte_pixel;
 
-#ifdef PNG_ARM_NEON
-   png_init_filter_functions_neon(pp, bpp);
+#ifdef PNG_FILTER_OPTIMIZATIONS
+   /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to
+    * call to install hardware optimizations for the above functions; simply
+    * replace whatever elements of the pp->read_filter[] array with a hardware
+    * specific (or, for that matter, generic) optimization.
+    *
+    * To see an example of this examine what configure.ac does when
+    * --enable-arm-neon is specified on the command line.
+    */
+   PNG_FILTER_OPTIMIZATIONS(pp, bpp);
 #endif
 }
 
@@ -3747,10 +3735,13 @@ void /* PRIVATE */
 png_read_filter_row(png_structp pp, png_row_infop row_info, png_bytep row,
    png_const_bytep prev_row, int filter)
 {
-   if (pp->read_filter[0] == NULL)
-      png_init_filter_functions(pp);
    if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
+   {
+      if (pp->read_filter[0] == NULL)
+         png_init_filter_functions(pp);
+
       pp->read_filter[filter-1](row_info, row, prev_row);
+   }
 }
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED

+ 220 - 63
drivers/png/pngset.c

@@ -1,8 +1,8 @@
 
 /* pngset.c - storage of image information into info struct
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -20,6 +20,60 @@
 
 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
 
+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) ||\
+    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
+ *
+ * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
+ * trailing '\0').  If this routine returns 0 then there was no keyword, or a
+ * valid one could not be generated, and the caller must handle the error by not
+ * setting the keyword.
+ */
+static png_uint_32
+png_check_keyword(png_const_charp key, png_bytep new_key)
+{
+   png_uint_32 key_len = 0;
+   int space = 1;
+
+   if (key == NULL)
+   {
+      *new_key = 0;
+      return 0;
+   }
+
+   while (*key && key_len < 79)
+   {
+      png_byte ch = (png_byte)*key++;
+
+      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
+         *new_key++ = ch, ++key_len, space = 0;
+
+      else if (space == 0)
+      {
+         /* A space or an invalid character when one wasn't seen immediately
+          * before; output just a space.
+          */
+         *new_key++ = 32, ++key_len, space = 1;
+      }
+   }
+
+   if (key_len > 0 && space != 0) /* trailing space */
+      --key_len, --new_key;
+
+   /* Terminate the keyword */
+   *new_key = 0;
+
+   if (key_len == 0)
+      return 0;
+
+   return key_len;
+}
+#endif /* TEXT || pCAL || iCCP || sPLT */
+
 #ifdef PNG_bKGD_SUPPORTED
 void PNGAPI
 png_set_bKGD(png_structp png_ptr, png_infop info_ptr,
@@ -123,12 +177,12 @@ png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X,
       png_fixed(png_ptr, red_X, "cHRM Red X"),
       png_fixed(png_ptr, red_Y, "cHRM Red Y"),
       png_fixed(png_ptr, red_Z, "cHRM Red Z"),
-      png_fixed(png_ptr, green_X, "cHRM Red X"),
-      png_fixed(png_ptr, green_Y, "cHRM Red Y"),
-      png_fixed(png_ptr, green_Z, "cHRM Red Z"),
-      png_fixed(png_ptr, blue_X, "cHRM Red X"),
-      png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
-      png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
+      png_fixed(png_ptr, green_X, "cHRM Green X"),
+      png_fixed(png_ptr, green_Y, "cHRM Green Y"),
+      png_fixed(png_ptr, green_Z, "cHRM Green Z"),
+      png_fixed(png_ptr, blue_X, "cHRM Blue X"),
+      png_fixed(png_ptr, blue_Y, "cHRM Blue Y"),
+      png_fixed(png_ptr, blue_Z, "cHRM Blue Z"));
 }
 #  endif /* PNG_FLOATING_POINT_SUPPORTED */
 
@@ -149,7 +203,7 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
     * possible for 1/gamma to overflow the limit of 21474 and this means the
     * gamma value must be at least 5/100000 and hence at most 20000.0.  For
     * safety the limits here are a little narrower.  The values are 0.00016 to
-    * 6250.0, which are truly ridiculous gammma values (and will produce
+    * 6250.0, which are truly ridiculous gamma values (and will produce
     * displays that are all black or all white.)
     */
    if (file_gamma < 16 || file_gamma > 625000000)
@@ -252,16 +306,7 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
 
    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
 
-   /* Check for potential overflow */
-   if (width >
-       (PNG_UINT_32_MAX >> 3)      /* 8-byte RRGGBBAA pixels */
-       - 48       /* bigrowbuf hack */
-       - 1        /* filter byte */
-       - 7*8      /* rounding of width to multiple of 8 pixels */
-       - 8)       /* extra max_pixel_depth pad */
-      info_ptr->rowbytes = 0;
-   else
-      info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
+   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
 }
 
 #ifdef PNG_oFFs_SUPPORTED
@@ -287,6 +332,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
     png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
     int nparams, png_const_charp units, png_charpp params)
 {
+   png_byte new_purpose[80];
    png_size_t length;
    int i;
 
@@ -295,7 +341,15 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   length = png_strlen(purpose) + 1;
+   length = png_check_keyword(purpose, new_purpose);
+
+   if (length == 0)
+   {
+      png_warning(png_ptr, "pCAL: invalid purpose keyword");
+      return;
+   }
+      
+   ++length;
    png_debug1(3, "allocating purpose for info (%lu bytes)",
        (unsigned long)length);
 
@@ -318,7 +372,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
       return;
    }
 
-   png_memcpy(info_ptr->pcal_purpose, purpose, length);
+   png_memcpy(info_ptr->pcal_purpose, new_purpose, length);
 
    png_debug(3, "storing X0, X1, type, and nparams in info");
    info_ptr->pcal_X0 = X0;
@@ -517,12 +571,17 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
     png_const_colorp palette, int num_palette)
 {
 
+   png_uint_32 max_palette_length;
+
    png_debug1(1, "in %s storage function", "PLTE");
 
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
+   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
+   if (num_palette < 0 || num_palette > (int) max_palette_length)
    {
       if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
          png_error(png_ptr, "Invalid palette length");
@@ -541,8 +600,8 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
-    * of num_palette entries, in case of an invalid PNG file that has
-    * too-large sample values.
+    * of num_palette entries, in case of an invalid PNG file or incorrect
+    * call to png_set_PLTE() with too-large sample values.
     */
    png_ptr->palette = (png_colorp)png_calloc(png_ptr,
        PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
@@ -618,6 +677,7 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
     png_const_charp name, int compression_type,
     png_const_bytep profile, png_uint_32 proflen)
 {
+   png_byte new_name[80];
    png_charp new_iccp_name;
    png_bytep new_iccp_profile;
    png_size_t length;
@@ -627,7 +687,15 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
    if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
       return;
 
-   length = png_strlen(name)+1;
+   length = png_check_keyword(name, new_name);
+
+   if (length == 0)
+   {
+      png_warning(png_ptr, "iCCP: invalid keyword");
+      return;
+   }
+      
+   ++length;
    new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length);
 
    if (new_iccp_name == NULL)
@@ -636,7 +704,7 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
       return;
    }
 
-   png_memcpy(new_iccp_name, name, length);
+   png_memcpy(new_iccp_name, new_name, length);
    new_iccp_profile = (png_bytep)png_malloc_warn(png_ptr, proflen);
 
    if (new_iccp_profile == NULL)
@@ -671,7 +739,7 @@ png_set_text(png_structp png_ptr, png_infop info_ptr, png_const_textp text_ptr,
    int ret;
    ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
 
-   if (ret)
+   if (ret != 0)
       png_error(png_ptr, "Insufficient memory to store text");
 }
 
@@ -680,8 +748,9 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
     png_const_textp text_ptr, int num_text)
 {
    int i;
+   size_t element_size;
 
-   png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :
+  png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11 :
       (unsigned long)png_ptr->chunk_name);
 
    if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
@@ -690,26 +759,42 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
    /* Make sure we have enough space in the "text" array in info_struct
     * to hold all of the incoming text_ptr objects.
     */
+
+   element_size=png_sizeof(png_text);
+   if (num_text < 0 ||
+       num_text > INT_MAX - info_ptr->num_text - 8 ||
+       (unsigned int)/*SAFE*/(num_text +/*SAFE*/
+       info_ptr->num_text + 8) >=
+       PNG_SIZE_MAX/element_size)
+   {
+      png_warning(png_ptr, "too many text chunks");
+      return(0);
+   }
+
    if (info_ptr->num_text + num_text > info_ptr->max_text)
    {
+      int old_max_text = info_ptr->max_text;
+      int old_num_text = info_ptr->num_text;
+
       if (info_ptr->text != NULL)
       {
          png_textp old_text;
-         int old_max;
 
-         old_max = info_ptr->max_text;
          info_ptr->max_text = info_ptr->num_text + num_text + 8;
          old_text = info_ptr->text;
+
          info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
             (png_size_t)(info_ptr->max_text * png_sizeof(png_text)));
 
          if (info_ptr->text == NULL)
          {
-            png_free(png_ptr, old_text);
+            /* Restore to previous condition */
+            info_ptr->max_text = old_max_text;
+            info_ptr->text = old_text;
             return(1);
          }
 
-         png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
+         png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text *
              png_sizeof(png_text)));
          png_free(png_ptr, old_text);
       }
@@ -721,7 +806,12 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
          info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
              (png_size_t)(info_ptr->max_text * png_sizeof(png_text)));
          if (info_ptr->text == NULL)
+         {
+            /* Restore to previous condition */
+            info_ptr->num_text = old_num_text;
+            info_ptr->max_text = old_max_text;
             return(1);
+         }
          info_ptr->free_me |= PNG_FREE_TEXT;
       }
 
@@ -730,6 +820,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
    }
    for (i = 0; i < num_text; i++)
    {
+      png_byte new_key[80], new_lang[80];
       png_size_t text_length, key_len;
       png_size_t lang_len, lang_key_len;
       png_textp textp = &(info_ptr->text[info_ptr->num_text]);
@@ -744,7 +835,13 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
          continue;
       }
 
-      key_len = png_strlen(text_ptr[i].key);
+      key_len = png_check_keyword(text_ptr[i].key, new_key);
+
+      if (key_len == 0)
+      {
+         png_warning(png_ptr, "invalid text keyword");
+         continue;
+      }
 
       if (text_ptr[i].compression <= 0)
       {
@@ -757,8 +854,9 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
       {
          /* Set iTXt data */
 
+        /* Zero length language is OK */
          if (text_ptr[i].lang != NULL)
-            lang_len = png_strlen(text_ptr[i].lang);
+            lang_len = png_check_keyword(text_ptr[i].lang, new_lang);
 
          else
             lang_len = 0;
@@ -806,7 +904,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
           (key_len + lang_len + lang_key_len + text_length + 4),
           textp->key);
 
-      png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len));
+      png_memcpy(textp->key, new_key, (png_size_t)(key_len));
       *(textp->key + key_len) = '\0';
 
       if (text_ptr[i].compression > 0)
@@ -827,7 +925,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
          textp->text = textp->key + key_len + 1;
       }
 
-      if (text_length)
+      if (text_length != 0)
          png_memcpy(textp->text, text_ptr[i].text,
              (png_size_t)(text_length));
 
@@ -888,6 +986,12 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
+   if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH)
+      {
+        png_warning(png_ptr, "Ignoring invalid num_trans value");
+        return;
+      }
+
    if (trans_alpha != NULL)
    {
        /* It may not actually be necessary to set png_ptr->trans_alpha here;
@@ -907,16 +1011,19 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
 
    if (trans_color != NULL)
    {
-      int sample_max = (1 << info_ptr->bit_depth);
-
-      if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
-          (int)trans_color->gray > sample_max) ||
-          (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
-          ((int)trans_color->red > sample_max ||
-          (int)trans_color->green > sample_max ||
-          (int)trans_color->blue > sample_max)))
-         png_warning(png_ptr,
-            "tRNS chunk has out-of-range samples for bit_depth");
+      if (info_ptr->bit_depth < 16)
+      {
+         unsigned int sample_max = (1U << info_ptr->bit_depth) - 1U;
+
+         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
+             trans_color->gray > sample_max) ||
+             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+             (trans_color->red > sample_max ||
+             trans_color->green > sample_max ||
+             trans_color->blue > sample_max)))
+           png_warning(png_ptr,
+              "tRNS chunk has out-of-range samples for bit_depth");
+      }
 
       png_memcpy(&(info_ptr->trans_color), trans_color,
          png_sizeof(png_color_16));
@@ -949,14 +1056,25 @@ png_set_sPLT(png_structp png_ptr,
  */
 {
    png_sPLT_tp np;
-   int i;
+   int i, j;
+   size_t element_size;
 
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   np = (png_sPLT_tp)png_malloc_warn(png_ptr,
-       (info_ptr->splt_palettes_num + nentries) *
-       (png_size_t)png_sizeof(png_sPLT_t));
+   element_size = png_sizeof(png_sPLT_t);
+   if (nentries < 0 ||
+       nentries > INT_MAX-info_ptr->splt_palettes_num ||
+       (unsigned int)/*SAFE*/(nentries +/*SAFE*/
+       info_ptr->splt_palettes_num) >=
+       PNG_SIZE_MAX/element_size)
+      np=NULL;
+
+   else
+
+      np = (png_sPLT_tp)png_malloc_warn(png_ptr,
+          (info_ptr->splt_palettes_num + nentries) *
+          (png_size_t)png_sizeof(png_sPLT_t));
 
    if (np == NULL)
    {
@@ -970,13 +1088,22 @@ png_set_sPLT(png_structp png_ptr,
    png_free(png_ptr, info_ptr->splt_palettes);
    info_ptr->splt_palettes=NULL;
 
-   for (i = 0; i < nentries; i++)
+   for (i = j = 0; i < nentries; i++)
    {
-      png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
+      png_sPLT_tp to = np + info_ptr->splt_palettes_num + j;
       png_const_sPLT_tp from = entries + i;
+      png_byte new_name[80];
       png_size_t length;
 
-      length = png_strlen(from->name) + 1;
+      length = png_check_keyword(from->name, new_name);
+
+      if (length == 0)
+      {
+         png_warning(png_ptr, "sPLT: invalid keyword");
+         continue;
+      }
+
+      ++length; /* for trailing '\0' */
       to->name = (png_charp)png_malloc_warn(png_ptr, length);
 
       if (to->name == NULL)
@@ -986,7 +1113,7 @@ png_set_sPLT(png_structp png_ptr,
          continue;
       }
 
-      png_memcpy(to->name, from->name, length);
+      png_memcpy(to->name, new_name, length);
       to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
           from->nentries * png_sizeof(png_sPLT_entry));
 
@@ -1004,10 +1131,11 @@ png_set_sPLT(png_structp png_ptr,
 
       to->nentries = from->nentries;
       to->depth = from->depth;
+      ++j;
    }
 
    info_ptr->splt_palettes = np;
-   info_ptr->splt_palettes_num += nentries;
+   info_ptr->splt_palettes_num = j;
    info_ptr->valid |= PNG_INFO_sPLT;
    info_ptr->free_me |= PNG_FREE_SPLT;
 }
@@ -1020,13 +1148,23 @@ png_set_unknown_chunks(png_structp png_ptr,
 {
    png_unknown_chunkp np;
    int i;
+   size_t element_size;
 
    if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
       return;
 
-   np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
-       (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) *
-       png_sizeof(png_unknown_chunk));
+   element_size = png_sizeof(png_unknown_chunk);
+   if (num_unknowns < 0 ||
+       num_unknowns > INT_MAX-info_ptr->unknown_chunks_num ||
+       (unsigned int)/*SAFE*/(num_unknowns +/*SAFE*/
+       info_ptr->unknown_chunks_num) >=
+       PNG_SIZE_MAX/element_size)
+      np=NULL;
+
+   else
+      np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
+          (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) *
+          png_sizeof(png_unknown_chunk));
 
    if (np == NULL)
    {
@@ -1189,11 +1327,12 @@ png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
 
    info_ptr->row_pointers = row_pointers;
 
-   if (row_pointers)
+   if (row_pointers != NULL)
       info_ptr->valid |= PNG_INFO_IDAT;
 }
 #endif
 
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
 void PNGAPI
 png_set_compression_buffer_size(png_structp png_ptr, png_size_t size)
 {
@@ -1221,6 +1360,7 @@ png_set_compression_buffer_size(png_structp png_ptr, png_size_t size)
     png_ptr->zstream.avail_out = 0;
     png_ptr->zstream.avail_in = 0;
 }
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
 
 void PNGAPI
 png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask)
@@ -1239,7 +1379,7 @@ png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max,
 {
    /* Images with dimensions larger than these limits will be
     * rejected by png_set_IHDR().  To accept any PNG datastream
-    * regardless of dimensions, set both limits to 0x7ffffffL.
+    * regardless of dimensions, set both limits to 0x7fffffffL.
     */
    if (png_ptr == NULL)
       return;
@@ -1253,7 +1393,7 @@ void PNGAPI
 png_set_chunk_cache_max (png_structp png_ptr,
    png_uint_32 user_chunk_cache_max)
 {
-    if (png_ptr)
+    if (png_ptr != NULL)
        png_ptr->user_chunk_cache_max = user_chunk_cache_max;
 }
 
@@ -1262,7 +1402,7 @@ void PNGAPI
 png_set_chunk_malloc_max (png_structp png_ptr,
     png_alloc_size_t user_chunk_malloc_max)
 {
-   if (png_ptr)
+   if (png_ptr != NULL)
       png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
 }
 #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
@@ -1274,11 +1414,28 @@ png_set_benign_errors(png_structp png_ptr, int allowed)
 {
    png_debug(1, "in png_set_benign_errors");
 
-   if (allowed)
+   if (allowed != 0)
       png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
 
    else
       png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN;
 }
 #endif /* PNG_BENIGN_ERRORS_SUPPORTED */
+
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+/* Whether to report invalid palette index; added at libng-1.5.10
+ *   allowed  - one of 0: disable; 1: enable
+ */
+void PNGAPI
+png_set_check_for_invalid_index(png_structp png_ptr, int allowed)
+{
+   png_debug(1, "in png_set_check_for_invalid_index");
+
+   if (allowed != 0)
+      png_ptr->num_palette_max = 0;
+
+   else
+      png_ptr->num_palette_max = -1;
+}
+#endif
 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

+ 16 - 23
drivers/png/pngstruct.h

@@ -1,12 +1,11 @@
 
 /* pngstruct.h - header file for PNG reference library
  *
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.5 [September 22, 2011]
- *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
@@ -121,6 +120,12 @@ struct png_struct_def
    png_uint_32 crc;           /* current chunk CRC value */
    png_colorp palette;        /* palette from the input file */
    png_uint_16 num_palette;   /* number of color entries in palette */
+
+/* Added at libpng-1.5.10 */
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+   int num_palette_max;       /* maximum palette index found in IDAT */
+#endif
+
    png_uint_16 num_trans;     /* number of transparency values */
    png_byte compression;      /* file compression type (always 0) */
    png_byte filter;           /* file filter type (always 0) */
@@ -211,13 +216,6 @@ struct png_struct_def
    int process_mode;                 /* what push library is currently doing */
    int cur_palette;                  /* current push library palette index */
 
-#  ifdef PNG_TEXT_SUPPORTED
-     png_size_t current_text_size;   /* current size of text input data */
-     png_size_t current_text_left;   /* how much text left to read in input */
-     png_charp current_text;         /* current text chunk buffer */
-     png_charp current_text_ptr;     /* current location in current_text */
-#  endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */
-
 #endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
 
 #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
@@ -238,17 +236,8 @@ struct png_struct_def
    png_uint_16p hist;                /* histogram */
 #endif
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-   png_byte heuristic_method;        /* heuristic for row filter selection */
-   png_byte num_prev_filters;        /* number of weights for previous rows */
-   png_bytep prev_filters;           /* filter type(s) of previous row(s) */
-   png_uint_16p filter_weights;      /* weight(s) for previous line(s) */
-   png_uint_16p inv_filter_weights;  /* 1/weight(s) for previous line(s) */
-   png_uint_16p filter_costs;        /* relative filter calculation cost */
-   png_uint_16p inv_filter_costs;    /* 1/relative filter calculation cost */
-#endif
-
 #ifdef PNG_TIME_RFC1123_SUPPORTED
+   /* This is going to be unused in libpng16 and removed from libpng17 */
    char time_buffer[29]; /* String to hold RFC 1123 time text */
 #endif
 
@@ -283,9 +272,7 @@ struct png_struct_def
 #endif
 
 /* New member added in libpng-1.0.4 (renamed in 1.0.9) */
-#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
-    defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
-    defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
 /* Changed from png_byte to png_uint_32 at version 1.2.0 */
    png_uint_32 mng_features_permitted;
 #endif
@@ -354,7 +341,13 @@ struct png_struct_def
 /* New member added in libpng-1.5.6 */
    png_bytep big_prev_row;
 
+/* New member added in libpng-1.5.7 */
    void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
       png_bytep row, png_const_bytep prev_row);
+
+   /* Options */
+#ifdef PNG_SET_OPTION_SUPPORTED
+   png_byte options;           /* On/off state (up to 4 options) */
+#endif
 };
 #endif /* PNGSTRUCT_H */

+ 109 - 6
drivers/png/pngtrans.c

@@ -1,8 +1,8 @@
 
 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
  *
- * Last changed in libpng 1.5.4 [July 7, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -452,7 +452,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
    {
       if (row_info->bit_depth == 8)
       {
-         if (at_start) /* Skip initial filler */
+         if (at_start != 0) /* Skip initial filler */
             ++sp;
          else          /* Skip initial channel and, for sp, the filler */
             sp += 2, ++dp;
@@ -466,7 +466,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
 
       else if (row_info->bit_depth == 16)
       {
-         if (at_start) /* Skip initial filler */
+         if (at_start != 0) /* Skip initial filler */
             sp += 2;
          else          /* Skip initial channel and, for sp, the filler */
             sp += 4, dp += 2;
@@ -492,7 +492,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
    {
       if (row_info->bit_depth == 8)
       {
-         if (at_start) /* Skip initial filler */
+         if (at_start != 0) /* Skip initial filler */
             ++sp;
          else          /* Skip initial channels and, for sp, the filler */
             sp += 4, dp += 3;
@@ -506,7 +506,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
 
       else if (row_info->bit_depth == 16)
       {
-         if (at_start) /* Skip initial filler */
+         if (at_start != 0) /* Skip initial filler */
             sp += 2;
          else          /* Skip initial channels and, for sp, the filler */
             sp += 8, dp += 6;
@@ -619,6 +619,109 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
 }
 #endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
 
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+/* Added at libpng-1.5.10 */
+void /* PRIVATE */
+png_do_check_palette_indexes(png_structp png_ptr, png_row_infop row_info)
+{
+   if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
+      png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
+   {
+      /* Calculations moved outside switch in an attempt to stop different
+       * compiler warnings.  'padding' is in *bits* within the last byte, it is
+       * an 'int' because pixel_depth becomes an 'int' in the expression below,
+       * and this calculation is used because it avoids warnings that other
+       * forms produced on either GCC or MSVC.
+       */
+      int padding = (-row_info->pixel_depth * row_info->width) & 7;
+      png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
+
+      switch (row_info->bit_depth)
+      {
+         case 1:
+         {
+            /* in this case, all bytes must be 0 so we don't need
+             * to unpack the pixels except for the rightmost one.
+             */
+            for (; rp > png_ptr->row_buf; rp--)
+            {
+              if (*rp >> padding != 0)
+                 png_ptr->num_palette_max = 1;
+              padding = 0;
+            }
+
+            break;
+         }
+
+         case 2:
+         {
+            for (; rp > png_ptr->row_buf; rp--)
+            {
+              int i = ((*rp >> padding) & 0x03);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              i = (((*rp >> padding) >> 2) & 0x03);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              i = (((*rp >> padding) >> 4) & 0x03);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              i = (((*rp >> padding) >> 6) & 0x03);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              padding = 0;
+            }
+
+            break;
+         }
+
+         case 4:
+         {
+            for (; rp > png_ptr->row_buf; rp--)
+            {
+              int i = ((*rp >> padding) & 0x0f);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              i = (((*rp >> padding) >> 4) & 0x0f);
+
+              if (i > png_ptr->num_palette_max)
+                 png_ptr->num_palette_max = i;
+
+              padding = 0;
+            }
+
+            break;
+         }
+
+         case 8:
+         {
+            for (; rp > png_ptr->row_buf; rp--)
+            {
+               if (*rp > png_ptr->num_palette_max)
+                  png_ptr->num_palette_max = (int) *rp;
+            }
+
+            break;
+         }
+
+         default:
+            break;
+      }
+   }
+}
+#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */
+
 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
 #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED

+ 4 - 2
drivers/png/pngwio.c

@@ -1,8 +1,8 @@
 
 /* pngwio.c - functions for data output
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.18 [February 6, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -207,6 +207,8 @@ png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
 #  else
    png_ptr->output_flush_fn = output_flush_fn;
 #  endif
+#else
+   PNG_UNUSED(output_flush_fn)
 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
 
    /* It is an error to read while writing a png file */

+ 112 - 315
drivers/png/pngwrite.c

@@ -1,8 +1,8 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -34,85 +34,87 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
 
    if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
    {
-   /* Write PNG signature */
-   png_write_sig(png_ptr);
+      /* Write PNG signature */
+      png_write_sig(png_ptr);
 
 #ifdef PNG_MNG_FEATURES_SUPPORTED
-   if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
-       (png_ptr->mng_features_permitted))
-   {
-      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
-      png_ptr->mng_features_permitted = 0;
-   }
+      if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
+          (png_ptr->mng_features_permitted))
+      {
+         png_warning(png_ptr,
+             "MNG features are not allowed in a PNG datastream");
+         png_ptr->mng_features_permitted = 0;
+      }
 #endif
 
-   /* Write IHDR information. */
-   png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
-       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
-       info_ptr->filter_type,
+      /* Write IHDR information. */
+      png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+          info_ptr->bit_depth, info_ptr->color_type,
+          info_ptr->compression_type, info_ptr->filter_type,
 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
-       info_ptr->interlace_type);
+          info_ptr->interlace_type
 #else
-       0);
+          0
 #endif
-   /* The rest of these check to see if the valid field has the appropriate
-    * flag set, and if it does, writes the chunk.
-    */
+          );
+      /* The rest of these check to see if the valid field has the appropriate
+       * flag set, and if it does, writes the chunk.
+       */
 #ifdef PNG_WRITE_gAMA_SUPPORTED
-   if (info_ptr->valid & PNG_INFO_gAMA)
-      png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
+      if (info_ptr->valid & PNG_INFO_gAMA)
+         png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
 #endif
 #ifdef PNG_WRITE_sRGB_SUPPORTED
-   if (info_ptr->valid & PNG_INFO_sRGB)
-      png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
+      if (info_ptr->valid & PNG_INFO_sRGB)
+         png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
 #endif
 
 #ifdef PNG_WRITE_iCCP_SUPPORTED
-   if (info_ptr->valid & PNG_INFO_iCCP)
-      png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
-          (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
+      if (info_ptr->valid & PNG_INFO_iCCP)
+         png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
+             (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
 #endif
 #ifdef PNG_WRITE_sBIT_SUPPORTED
-   if (info_ptr->valid & PNG_INFO_sBIT)
-      png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+      if (info_ptr->valid & PNG_INFO_sBIT)
+         png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
 #endif
 #ifdef PNG_WRITE_cHRM_SUPPORTED
-   if (info_ptr->valid & PNG_INFO_cHRM)
-      png_write_cHRM_fixed(png_ptr,
-          info_ptr->x_white, info_ptr->y_white,
-          info_ptr->x_red, info_ptr->y_red,
-          info_ptr->x_green, info_ptr->y_green,
-          info_ptr->x_blue, info_ptr->y_blue);
+      if (info_ptr->valid & PNG_INFO_cHRM)
+         png_write_cHRM_fixed(png_ptr,
+             info_ptr->x_white, info_ptr->y_white,
+             info_ptr->x_red, info_ptr->y_red,
+             info_ptr->x_green, info_ptr->y_green,
+             info_ptr->x_blue, info_ptr->y_blue);
 #endif
 
 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
-   if (info_ptr->unknown_chunks_num)
-   {
-      png_unknown_chunk *up;
-
-      png_debug(5, "writing extra chunks");
-
-      for (up = info_ptr->unknown_chunks;
-           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
-           up++)
+      if (info_ptr->unknown_chunks_num)
       {
-         int keep = png_handle_as_unknown(png_ptr, up->name);
+         png_unknown_chunk *up;
 
-         if (keep != PNG_HANDLE_CHUNK_NEVER &&
-             up->location &&
-             !(up->location & PNG_HAVE_PLTE) &&
-             !(up->location & PNG_HAVE_IDAT) &&
-             !(up->location & PNG_AFTER_IDAT) &&
-             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
-             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+         png_debug(5, "writing extra chunks");
+
+         for (up = info_ptr->unknown_chunks;
+              up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+              up++)
          {
-            if (up->size == 0)
-               png_warning(png_ptr, "Writing zero-length unknown chunk");
+            int keep = png_handle_as_unknown(png_ptr, up->name);
+
+            if (keep != PNG_HANDLE_CHUNK_NEVER &&
+                up->location &&
+                !(up->location & PNG_HAVE_PLTE) &&
+                !(up->location & PNG_HAVE_IDAT) &&
+                !(up->location & PNG_AFTER_IDAT) &&
+                ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
+                (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+            {
+               if (up->size == 0)
+                  png_warning(png_ptr, "Writing zero-length unknown chunk");
 
-            png_write_chunk(png_ptr, up->name, up->data, up->size);
+               png_write_chunk(png_ptr, up->name, up->data, up->size);
+            }
          }
       }
-   }
 #endif
       png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
    }
@@ -223,11 +225,14 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
              info_ptr->text[i].lang,
              info_ptr->text[i].lang_key,
              info_ptr->text[i].text);
+         /* Mark this chunk as written */
+         if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+         else
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
 #else
-          png_warning(png_ptr, "Unable to write international text");
+         png_warning(png_ptr, "Unable to write international text");
 #endif
-          /* Mark this chunk as written */
-          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
       }
 
       /* If we want a compressed text chunk */
@@ -238,11 +243,11 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
          png_write_zTXt(png_ptr, info_ptr->text[i].key,
              info_ptr->text[i].text, 0,
              info_ptr->text[i].compression);
+         /* Mark this chunk as written */
+         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
 #else
          png_warning(png_ptr, "Unable to write compressed text");
 #endif
-         /* Mark this chunk as written */
-         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
       }
 
       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
@@ -305,6 +310,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
    if (!(png_ptr->mode & PNG_HAVE_IDAT))
       png_error(png_ptr, "No IDATs written into file");
 
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+   if (png_ptr->num_palette_max > png_ptr->num_palette)
+      png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+#endif
+
    /* See if user wants us to write information chunks */
    if (info_ptr != NULL)
    {
@@ -335,11 +345,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
                 info_ptr->text[i].lang,
                 info_ptr->text[i].lang_key,
                 info_ptr->text[i].text);
+            /* Mark this chunk as written */
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
 #else
             png_warning(png_ptr, "Unable to write international text");
 #endif
-            /* Mark this chunk as written */
-            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
          }
 
          else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
@@ -349,11 +359,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
             png_write_zTXt(png_ptr, info_ptr->text[i].key,
                 info_ptr->text[i].text, 0,
                 info_ptr->text[i].compression);
+            /* Mark this chunk as written */
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
 #else
             png_warning(png_ptr, "Unable to write compressed text");
 #endif
-            /* Mark this chunk as written */
-            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
          }
 
          else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
@@ -362,12 +372,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
             /* Write uncompressed chunk */
             png_write_tEXt(png_ptr, info_ptr->text[i].key,
                 info_ptr->text[i].text, 0);
+            /* Mark this chunk as written */
+            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
 #else
             png_warning(png_ptr, "Unable to write uncompressed text");
 #endif
-
-            /* Mark this chunk as written */
-            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
          }
       }
 #endif
@@ -415,7 +424,6 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
 }
 
 #ifdef PNG_CONVERT_tIME_SUPPORTED
-/* "tm" structure is not supported on WindowsCE */
 void PNGAPI
 png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime)
 {
@@ -451,9 +459,6 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
        warn_fn, NULL, NULL, NULL));
 }
 
-/* Alternate initialize png_ptr structure, and allocate any memory needed */
-static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */
-
 PNG_FUNCTION(png_structp,PNGAPI
 png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
     png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
@@ -495,14 +500,13 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
  */
 #ifdef USE_FAR_KEYWORD
    if (setjmp(tmp_jmpbuf))
+      png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
+   PNG_ABORT();
 #else
    if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */
-#endif
-#ifdef USE_FAR_KEYWORD
-   png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
-#endif
       PNG_ABORT();
 #endif
+#endif
 
 #ifdef PNG_USER_MEM_SUPPORTED
    png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
@@ -515,7 +519,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    /* Initialize zbuf - compression buffer */
    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
 
-   if (!png_cleanup_needed)
+   if (png_cleanup_needed == 0)
    {
       png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr,
           png_ptr->zbuf_size);
@@ -523,7 +527,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
          png_cleanup_needed = 1;
    }
 
-   if (png_cleanup_needed)
+   if (png_cleanup_needed != 0)
    {
        /* Clean up PNG structure and deallocate any memory. */
        png_free(png_ptr, png_ptr->zbuf);
@@ -539,10 +543,6 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
 
    png_set_write_fn(png_ptr, NULL, NULL, NULL);
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-   png_reset_filter_heuristics(png_ptr);
-#endif
-
    return (png_ptr);
 }
 
@@ -759,7 +759,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row)
    {
       png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
       /* This should always get caught above, but still ... */
-      if (!(row_info.width))
+      if (row_info.width == 0)
       {
          png_write_finish_row(png_ptr);
          return;
@@ -798,6 +798,14 @@ png_write_row(png_structp png_ptr, png_const_bytep row)
    }
 #endif
 
+/* Added at libpng-1.5.10 */
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+   /* Check for out-of-range palette index */
+   if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
+       png_ptr->num_palette_max >= 0)
+      png_do_check_palette_indexes(png_ptr, &row_info);
+#endif
+
    /* Find a filter if necessary, filter the row and write it out. */
    png_write_find_filter(png_ptr, &row_info);
 
@@ -851,7 +859,7 @@ png_write_flush(png_structp png_ptr)
             png_error(png_ptr, "zlib error");
       }
 
-      if (!(png_ptr->zstream.avail_out))
+      if ((png_ptr->zstream.avail_out) == 0)
       {
          /* Write the IDAT and reset the zlib output buffer */
          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
@@ -969,13 +977,6 @@ png_write_destroy(png_structp png_ptr)
    png_free(png_ptr, png_ptr->paeth_row);
 #endif
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-   /* Use this to save a little code space, it doesn't free the filter_costs */
-   png_reset_filter_heuristics(png_ptr);
-   png_free(png_ptr, png_ptr->filter_costs);
-   png_free(png_ptr, png_ptr->inv_filter_costs);
-#endif
-
 #ifdef PNG_SETJMP_SUPPORTED
    /* Reset structure */
    png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
@@ -1029,6 +1030,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
          case 5:
          case 6:
          case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+             /* FALL THROUGH */
 #endif /* PNG_WRITE_FILTER_SUPPORTED */
          case PNG_FILTER_VALUE_NONE:
             png_ptr->do_filter = PNG_FILTER_NONE; break;
@@ -1065,6 +1067,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
        */
       if (png_ptr->row_buf != NULL)
       {
+         png_ptr->do_filter = PNG_FILTER_NONE;
 #ifdef PNG_WRITE_FILTER_SUPPORTED
          if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
          {
@@ -1125,8 +1128,8 @@ png_set_filter(png_structp png_ptr, int method, int filters)
          }
 
          if (png_ptr->do_filter == PNG_NO_FILTERS)
-#endif /* PNG_WRITE_FILTER_SUPPORTED */
             png_ptr->do_filter = PNG_FILTER_NONE;
+#endif /* PNG_WRITE_FILTER_SUPPORTED */
       }
    }
    else
@@ -1140,122 +1143,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
  * filtered data going to zlib more consistent, hopefully resulting in
  * better compression.
  */
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED      /* GRR 970116 */
-/* Convenience reset API. */
-static void
-png_reset_filter_heuristics(png_structp png_ptr)
-{
-   /* Clear out any old values in the 'weights' - this must be done because if
-    * the app calls set_filter_heuristics multiple times with different
-    * 'num_weights' values we would otherwise potentially have wrong sized
-    * arrays.
-    */
-   png_ptr->num_prev_filters = 0;
-   png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
-   if (png_ptr->prev_filters != NULL)
-   {
-      png_bytep old = png_ptr->prev_filters;
-      png_ptr->prev_filters = NULL;
-      png_free(png_ptr, old);
-   }
-   if (png_ptr->filter_weights != NULL)
-   {
-      png_uint_16p old = png_ptr->filter_weights;
-      png_ptr->filter_weights = NULL;
-      png_free(png_ptr, old);
-   }
-
-   if (png_ptr->inv_filter_weights != NULL)
-   {
-      png_uint_16p old = png_ptr->inv_filter_weights;
-      png_ptr->inv_filter_weights = NULL;
-      png_free(png_ptr, old);
-   }
-
-   /* Leave the filter_costs - this array is fixed size. */
-}
-
-static int
-png_init_filter_heuristics(png_structp png_ptr, int heuristic_method,
-   int num_weights)
-{
-   if (png_ptr == NULL)
-      return 0;
-
-   /* Clear out the arrays */
-   png_reset_filter_heuristics(png_ptr);
-
-   /* Check arguments; the 'reset' function makes the correct settings for the
-    * unweighted case, but we must handle the weight case by initializing the
-    * arrays for the caller.
-    */
-   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-   {
-      int i;
-
-      if (num_weights > 0)
-      {
-         png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
-             (png_uint_32)(png_sizeof(png_byte) * num_weights));
-
-         /* To make sure that the weighting starts out fairly */
-         for (i = 0; i < num_weights; i++)
-         {
-            png_ptr->prev_filters[i] = 255;
-         }
-
-         png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
-             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
-
-         png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
-             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
-
-         for (i = 0; i < num_weights; i++)
-         {
-            png_ptr->inv_filter_weights[i] =
-            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
-         }
-
-         /* Safe to set this now */
-         png_ptr->num_prev_filters = (png_byte)num_weights;
-      }
-
-      /* If, in the future, there are other filter methods, this would
-       * need to be based on png_ptr->filter.
-       */
-      if (png_ptr->filter_costs == NULL)
-      {
-         png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
-             (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
-
-         png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
-             (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
-      }
-
-      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
-      {
-         png_ptr->inv_filter_costs[i] =
-         png_ptr->filter_costs[i] = PNG_COST_FACTOR;
-      }
-
-      /* All the arrays are inited, safe to set this: */
-      png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;
-
-      /* Return the 'ok' code. */
-      return 1;
-   }
-   else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
-      heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
-   {
-      return 1;
-   }
-   else
-   {
-      png_warning(png_ptr, "Unknown filter heuristic method");
-      return 0;
-   }
-}
-
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
 /* Provide floating and fixed point APIs */
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 void PNGAPI
@@ -1263,52 +1151,11 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
     int num_weights, png_const_doublep filter_weights,
     png_const_doublep filter_costs)
 {
-   png_debug(1, "in png_set_filter_heuristics");
-
-   /* The internal API allocates all the arrays and ensures that the elements of
-    * those arrays are set to the default value.
-    */
-   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
-      return;
-
-   /* If using the weighted method copy in the weights. */
-   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-   {
-      int i;
-      for (i = 0; i < num_weights; i++)
-      {
-         if (filter_weights[i] <= 0.0)
-         {
-            png_ptr->inv_filter_weights[i] =
-            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
-         }
-
-         else
-         {
-            png_ptr->inv_filter_weights[i] =
-                (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);
-
-            png_ptr->filter_weights[i] =
-                (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);
-         }
-      }
-
-      /* Here is where we set the relative costs of the different filters.  We
-       * should take the desired compression level into account when setting
-       * the costs, so that Paeth, for instance, has a high relative cost at low
-       * compression levels, while it has a lower relative cost at higher
-       * compression settings.  The filter types are in order of increasing
-       * relative cost, so it would be possible to do this with an algorithm.
-       */
-      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)
-      {
-         png_ptr->inv_filter_costs[i] =
-             (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);
-
-         png_ptr->filter_costs[i] =
-             (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);
-      }
-   }
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(heuristic_method)
+   PNG_UNUSED(num_weights)
+   PNG_UNUSED(filter_weights)
+   PNG_UNUSED(filter_costs)
 }
 #endif /* FLOATING_POINT */
 
@@ -1318,67 +1165,16 @@ png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method,
     int num_weights, png_const_fixed_point_p filter_weights,
     png_const_fixed_point_p filter_costs)
 {
-   png_debug(1, "in png_set_filter_heuristics_fixed");
-
-   /* The internal API allocates all the arrays and ensures that the elements of
-    * those arrays are set to the default value.
-    */
-   if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
-      return;
-
-   /* If using the weighted method copy in the weights. */
-   if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-   {
-      int i;
-      for (i = 0; i < num_weights; i++)
-      {
-         if (filter_weights[i] <= 0)
-         {
-            png_ptr->inv_filter_weights[i] =
-            png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
-         }
-
-         else
-         {
-            png_ptr->inv_filter_weights[i] = (png_uint_16)
-               ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);
-
-            png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*
-               PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);
-         }
-      }
-
-      /* Here is where we set the relative costs of the different filters.  We
-       * should take the desired compression level into account when setting
-       * the costs, so that Paeth, for instance, has a high relative cost at low
-       * compression levels, while it has a lower relative cost at higher
-       * compression settings.  The filter types are in order of increasing
-       * relative cost, so it would be possible to do this with an algorithm.
-       */
-      for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
-         if (filter_costs[i] >= PNG_FP_1)
-      {
-         png_uint_32 tmp;
-
-         /* Use a 32 bit unsigned temporary here because otherwise the
-          * intermediate value will be a 32 bit *signed* integer (ANSI rules)
-          * and this will get the wrong answer on division.
-          */
-         tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);
-         tmp /= filter_costs[i];
-
-         png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;
-
-         tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;
-         tmp /= PNG_FP_1;
-
-         png_ptr->filter_costs[i] = (png_uint_16)tmp;
-      }
-   }
+   PNG_UNUSED(png_ptr)
+   PNG_UNUSED(heuristic_method)
+   PNG_UNUSED(num_weights)
+   PNG_UNUSED(filter_weights)
+   PNG_UNUSED(filter_costs)
 }
 #endif /* FIXED_POINT */
-#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+#endif /* WRITE_WEIGHTED_FILTER */
 
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
 void PNGAPI
 png_set_compression_level(png_structp png_ptr, int level)
 {
@@ -1457,6 +1253,7 @@ png_set_compression_method(png_structp png_ptr, int method)
    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
    png_ptr->zlib_method = method;
 }
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
 
 /* The following were added to libpng-1.5.4 */
 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
@@ -1514,10 +1311,10 @@ png_set_text_compression_window_bits(png_structp png_ptr, int window_bits)
 #ifndef WBITS_8_OK
    /* Avoid libpng bug with 256-byte windows */
    if (window_bits == 8)
-      {
-        png_warning(png_ptr, "Text compression window is being reset to 512");
-        window_bits = 9;
-      }
+   {
+      png_warning(png_ptr, "Text compression window is being reset to 512");
+      window_bits = 9;
+   }
 
 #endif
    png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS;

+ 16 - 4
drivers/png/pngwtran.c

@@ -1,8 +1,8 @@
 
 /* pngwtran.c - transforms the data in a row for PNG writers
  *
- * Last changed in libpng 1.5.6 [November 3, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2012 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2012 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -45,8 +45,20 @@ png_do_write_transformations(png_structp png_ptr, png_row_infop row_info)
 
 #ifdef PNG_WRITE_FILLER_SUPPORTED
    if (png_ptr->transformations & PNG_FILLER)
-      png_do_strip_channel(row_info, png_ptr->row_buf + 1,
-         !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
+   {
+      if (png_ptr->color_type & (PNG_COLOR_MASK_ALPHA|PNG_COLOR_MASK_PALETTE))
+      {
+         /* GA, RGBA or palette; in any of these cases libpng will not do the
+          * the correct thing (whatever that might be).
+          */
+         png_warning(png_ptr, "incorrect png_set_filler call ignored");
+         png_ptr->transformations &= ~PNG_FILLER;
+      }
+
+      else
+         png_do_strip_channel(row_info, png_ptr->row_buf + 1,
+            !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
+   }
 #endif
 
 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED

+ 60 - 560
drivers/png/pngwutil.c

@@ -1,8 +1,8 @@
 
 /* pngwutil.c - utilities to write a PNG file
  *
- * Last changed in libpng 1.5.6 [November 3, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -30,19 +30,20 @@ png_save_uint_32(png_bytep buf, png_uint_32 i)
 }
 
 #ifdef PNG_SAVE_INT_32_SUPPORTED
-/* The png_save_int_32 function assumes integers are stored in two's
- * complement format.  If this isn't the case, then this routine needs to
- * be modified to write data in two's complement format.  Note that,
- * the following works correctly even if png_int_32 has more than 32 bits
- * (compare the more complex code required on read for sign extention.)
+/* PNG signed integers are saved in 32-bit 2's complement format.  ANSI C-90
+ * defines a cast of a signed integer to an unsigned integer either to preserve
+ * the value, if it is positive, or to calculate:
+ *
+ *     (UNSIGNED_MAX+1) + integer
+ *
+ * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
+ * negative integral value is added the result will be an unsigned value
+ * correspnding to the 2's complement representation.
  */
 void PNGAPI
 png_save_int_32(png_bytep buf, png_int_32 i)
 {
-   buf[0] = (png_byte)((i >> 24) & 0xff);
-   buf[1] = (png_byte)((i >> 16) & 0xff);
-   buf[2] = (png_byte)((i >> 8) & 0xff);
-   buf[3] = (png_byte)(i & 0xff);
+   png_save_uint_32(buf, i);
 }
 #endif
 
@@ -315,6 +316,7 @@ png_zlib_release(png_structp png_ptr)
 
       if (ret != Z_OK)
       {
+#ifdef PNG_WARNINGS_SUPPORTED
          png_const_charp err;
          PNG_WARNING_PARAMETERS(p)
 
@@ -349,6 +351,7 @@ png_zlib_release(png_structp png_ptr)
 
          png_formatted_warning(png_ptr, p,
             "zlib failed to reset compressor: @1(@2): @3");
+#endif
       }
    }
 
@@ -460,24 +463,21 @@ png_text_compress(png_structp png_ptr,
                old_ptr = comp->output_ptr;
 
                comp->output_ptr = (png_bytepp)png_malloc(png_ptr,
-                   (png_alloc_size_t)
-                   (comp->max_output_ptr * png_sizeof(png_charpp)));
+                   (comp->max_output_ptr * png_sizeof(png_bytep)));
 
                png_memcpy(comp->output_ptr, old_ptr, old_max
-                   * png_sizeof(png_charp));
+                   * png_sizeof(png_bytep));
 
                png_free(png_ptr, old_ptr);
             }
             else
                comp->output_ptr = (png_bytepp)png_malloc(png_ptr,
-                   (png_alloc_size_t)
-                   (comp->max_output_ptr * png_sizeof(png_charp)));
+                   (comp->max_output_ptr * png_sizeof(png_bytep)));
          }
 
          /* Save the data */
          comp->output_ptr[comp->num_output_ptr] =
-             (png_bytep)png_malloc(png_ptr,
-             (png_alloc_size_t)png_ptr->zbuf_size);
+             (png_bytep)png_malloc(png_ptr, png_ptr->zbuf_size);
 
          png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
              png_ptr->zbuf_size);
@@ -569,14 +569,15 @@ png_text_compress(png_structp png_ptr,
 
 /* Ship the compressed text out via chunk writes */
 static void /* PRIVATE */
-png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
+png_write_compressed_data_out(png_structp png_ptr, compression_state *comp,
+   png_size_t data_len)
 {
    int i;
 
    /* Handle the no-compression case */
    if (comp->input)
    {
-      png_write_chunk_data(png_ptr, comp->input, comp->input_len);
+      png_write_chunk_data(png_ptr, comp->input, data_len);
 
       return;
    }
@@ -585,7 +586,7 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
    /* The zbuf_size test is because the code below doesn't work if zbuf_size is
     * '1'; simply skip it to avoid memory overwrite.
     */
-   if (comp->input_len >= 2 && comp->input_len < 16384 && png_ptr->zbuf_size > 1)
+   if (data_len >= 2 && comp->input_len < 16384 && png_ptr->zbuf_size > 1)
    {
       unsigned int z_cmf;  /* zlib compression method and flags */
 
@@ -825,7 +826,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
    png_ptr->zstream.zfree = png_zfree;
    png_ptr->zstream.opaque = (voidpf)png_ptr;
 
-   if (!(png_ptr->do_filter))
+   if ((png_ptr->do_filter) == PNG_NO_FILTERS)
    {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
           png_ptr->bit_depth < 8)
@@ -895,17 +896,20 @@ void /* PRIVATE */
 png_write_PLTE(png_structp png_ptr, png_const_colorp palette,
     png_uint_32 num_pal)
 {
-   png_uint_32 i;
+   png_uint_32 max_palette_length, i;
    png_const_colorp pal_ptr;
    png_byte buf[3];
 
    png_debug(1, "in png_write_PLTE");
 
+   max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+      (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
    if ((
 #ifdef PNG_MNG_FEATURES_SUPPORTED
        !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
 #endif
-       num_pal == 0) || num_pal > 256)
+       num_pal == 0) || num_pal > max_palette_length)
    {
       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
@@ -1095,7 +1099,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
     png_const_charp profile, int profile_len)
 {
    png_size_t name_len;
-   png_charp new_name;
    compression_state comp;
    int embedded_profile_len = 0;
 
@@ -1107,8 +1110,7 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
    comp.input = NULL;
    comp.input_len = 0;
 
-   if ((name_len = png_check_keyword(png_ptr, name, &new_name)) == 0)
-      return;
+   name_len = png_strlen(name);
 
    if (compression_type != PNG_COMPRESSION_TYPE_BASE)
       png_warning(png_ptr, "Unknown compression type in iCCP chunk");
@@ -1127,8 +1129,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
    {
       png_warning(png_ptr,
           "Embedded profile length in iCCP chunk is negative");
-
-      png_free(png_ptr, new_name);
       return;
    }
 
@@ -1136,8 +1136,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
    {
       png_warning(png_ptr,
           "Embedded profile length too large in iCCP chunk");
-
-      png_free(png_ptr, new_name);
       return;
    }
 
@@ -1149,7 +1147,7 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
       profile_len = embedded_profile_len;
    }
 
-   if (profile_len)
+   if (profile_len != 0)
       profile_len = png_text_compress(png_ptr, profile,
           (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
 
@@ -1157,19 +1155,21 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
    png_write_chunk_header(png_ptr, png_iCCP,
        (png_uint_32)(name_len + profile_len + 2));
 
-   new_name[name_len + 1] = 0x00;
+   png_write_chunk_data(png_ptr, (png_bytep)name, name_len);
 
-   png_write_chunk_data(png_ptr, (png_bytep)new_name,
-       (png_size_t)(name_len + 2));
+   {
+      png_byte buffer[2];
+      buffer[0] = 0; /* terminate name */
+      buffer[1] = 0xFFU & compression_type;
+      png_write_chunk_data(png_ptr, buffer, 2);
+   }
 
-   if (profile_len)
+   if (profile_len != 0)
    {
-      comp.input_len = profile_len;
-      png_write_compressed_data_out(png_ptr, &comp);
+      png_write_compressed_data_out(png_ptr, &comp, profile_len);
    }
 
    png_write_chunk_end(png_ptr);
-   png_free(png_ptr, new_name);
 }
 #endif
 
@@ -1179,7 +1179,6 @@ void /* PRIVATE */
 png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
 {
    png_size_t name_len;
-   png_charp new_name;
    png_byte entrybuf[10];
    png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
    png_size_t palette_size = entry_size * spalette->nentries;
@@ -1190,14 +1189,13 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
 
    png_debug(1, "in png_write_sPLT");
 
-   if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0)
-      return;
+   name_len = png_strlen(spalette->name);
 
    /* Make sure we include the NULL after the name */
    png_write_chunk_header(png_ptr, png_sPLT,
        (png_uint_32)(name_len + 2 + palette_size));
 
-   png_write_chunk_data(png_ptr, (png_bytep)new_name,
+   png_write_chunk_data(png_ptr, (png_bytep)spalette->name,
        (png_size_t)(name_len + 1));
 
    png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1);
@@ -1253,7 +1251,6 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
 #endif
 
    png_write_chunk_end(png_ptr);
-   png_free(png_ptr, new_name);
 }
 #endif
 
@@ -1370,7 +1367,8 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha,
       }
 
       /* Write the chunk out as it is */
-      png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, (png_size_t)num_trans);
+      png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
+         (png_size_t)num_trans);
    }
 
    else if (color_type == PNG_COLOR_TYPE_GRAY)
@@ -1508,138 +1506,6 @@ png_write_hIST(png_structp png_ptr, png_const_uint_16p hist, int num_hist)
 }
 #endif
 
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
-    defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
- * and if invalid, correct the keyword rather than discarding the entire
- * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
- * length, forbids leading or trailing whitespace, multiple internal spaces,
- * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
- *
- * The new_key is allocated to hold the corrected keyword and must be freed
- * by the calling routine.  This avoids problems with trying to write to
- * static keywords without having to have duplicate copies of the strings.
- */
-png_size_t /* PRIVATE */
-png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key)
-{
-   png_size_t key_len;
-   png_const_charp ikp;
-   png_charp kp, dp;
-   int kflag;
-   int kwarn=0;
-
-   png_debug(1, "in png_check_keyword");
-
-   *new_key = NULL;
-
-   if (key == NULL || (key_len = png_strlen(key)) == 0)
-   {
-      png_warning(png_ptr, "zero length keyword");
-      return ((png_size_t)0);
-   }
-
-   png_debug1(2, "Keyword to be checked is '%s'", key);
-
-   *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
-
-   if (*new_key == NULL)
-   {
-      png_warning(png_ptr, "Out of memory while procesing keyword");
-      return ((png_size_t)0);
-   }
-
-   /* Replace non-printing characters with a blank and print a warning */
-   for (ikp = key, dp = *new_key; *ikp != '\0'; ikp++, dp++)
-   {
-      if ((png_byte)*ikp < 0x20 ||
-         ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1))
-      {
-         PNG_WARNING_PARAMETERS(p)
-
-         png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x,
-            (png_byte)*ikp);
-         png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1");
-         *dp = ' ';
-      }
-
-      else
-      {
-         *dp = *ikp;
-      }
-   }
-   *dp = '\0';
-
-   /* Remove any trailing white space. */
-   kp = *new_key + key_len - 1;
-   if (*kp == ' ')
-   {
-      png_warning(png_ptr, "trailing spaces removed from keyword");
-
-      while (*kp == ' ')
-      {
-         *(kp--) = '\0';
-         key_len--;
-      }
-   }
-
-   /* Remove any leading white space. */
-   kp = *new_key;
-   if (*kp == ' ')
-   {
-      png_warning(png_ptr, "leading spaces removed from keyword");
-
-      while (*kp == ' ')
-      {
-         kp++;
-         key_len--;
-      }
-   }
-
-   png_debug1(2, "Checking for multiple internal spaces in '%s'", kp);
-
-   /* Remove multiple internal spaces. */
-   for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
-   {
-      if (*kp == ' ' && kflag == 0)
-      {
-         *(dp++) = *kp;
-         kflag = 1;
-      }
-
-      else if (*kp == ' ')
-      {
-         key_len--;
-         kwarn = 1;
-      }
-
-      else
-      {
-         *(dp++) = *kp;
-         kflag = 0;
-      }
-   }
-   *dp = '\0';
-   if (kwarn)
-      png_warning(png_ptr, "extra interior spaces removed from keyword");
-
-   if (key_len == 0)
-   {
-      png_free(png_ptr, *new_key);
-      png_warning(png_ptr, "Zero length keyword");
-   }
-
-   if (key_len > 79)
-   {
-      png_warning(png_ptr, "keyword length must be 1 - 79 characters");
-      (*new_key)[79] = '\0';
-      key_len = 79;
-   }
-
-   return (key_len);
-}
-#endif
-
 #ifdef PNG_WRITE_tEXt_SUPPORTED
 /* Write a tEXt chunk */
 void /* PRIVATE */
@@ -1647,12 +1513,10 @@ png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
     png_size_t text_len)
 {
    png_size_t key_len;
-   png_charp new_key;
 
    png_debug(1, "in png_write_tEXt");
 
-   if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
-      return;
+   key_len = strlen(key);
 
    if (text == NULL || *text == '\0')
       text_len = 0;
@@ -1669,15 +1533,14 @@ png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
     * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
     * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
     */
-   png_write_chunk_data(png_ptr, (png_bytep)new_key,
+   png_write_chunk_data(png_ptr, (png_bytep)key,
        (png_size_t)(key_len + 1));
 
-   if (text_len)
+   if (text_len != 0)
       png_write_chunk_data(png_ptr, (png_const_bytep)text,
           (png_size_t)text_len);
 
    png_write_chunk_end(png_ptr);
-   png_free(png_ptr, new_key);
 }
 #endif
 
@@ -1689,7 +1552,6 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
 {
    png_size_t key_len;
    png_byte buf;
-   png_charp new_key;
    compression_state comp;
 
    png_debug(1, "in png_write_zTXt");
@@ -1700,16 +1562,11 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
    comp.input = NULL;
    comp.input_len = 0;
 
-   if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0)
-   {
-      png_free(png_ptr, new_key);
-      return;
-   }
+   key_len = strlen(key);
 
    if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
    {
-      png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
-      png_free(png_ptr, new_key);
+      png_write_tEXt(png_ptr, key, text, (png_size_t)0);
       return;
    }
 
@@ -1724,19 +1581,16 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
        (png_uint_32)(key_len+text_len + 2));
 
    /* Write key */
-   png_write_chunk_data(png_ptr, (png_bytep)new_key,
+   png_write_chunk_data(png_ptr, (png_bytep)key,
        (png_size_t)(key_len + 1));
 
-   png_free(png_ptr, new_key);
-
    buf = (png_byte)compression;
 
    /* Write compression */
    png_write_chunk_data(png_ptr, &buf, (png_size_t)1);
 
    /* Write the compressed data */
-   comp.input_len = text_len;
-   png_write_compressed_data_out(png_ptr, &comp);
+   png_write_compressed_data_out(png_ptr, &comp, text_len);
 
    /* Close the chunk */
    png_write_chunk_end(png_ptr);
@@ -1750,8 +1604,6 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
     png_const_charp lang, png_const_charp lang_key, png_const_charp text)
 {
    png_size_t lang_len, key_len, lang_key_len, text_len;
-   png_charp new_lang;
-   png_charp new_key = NULL;
    png_byte cbuf[2];
    compression_state comp;
 
@@ -1762,15 +1614,13 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
    comp.output_ptr = NULL;
    comp.input = NULL;
 
-   if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0)
-      return;
+   key_len = png_strlen(key);
 
-   if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang)) == 0)
-   {
-      png_warning(png_ptr, "Empty language field in iTXt chunk");
-      new_lang = NULL;
+   if (lang == NULL)
       lang_len = 0;
-   }
+
+   else
+      lang_len = png_strlen(lang);
 
    if (lang_key == NULL)
       lang_key_len = 0;
@@ -1805,7 +1655,7 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
     * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.
     * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
     */
-   png_write_chunk_data(png_ptr, (png_bytep)new_key, (png_size_t)(key_len + 1));
+   png_write_chunk_data(png_ptr, (png_bytep)key, (png_size_t)(key_len + 1));
 
    /* Set the compression flag */
    if (compression == PNG_ITXT_COMPRESSION_NONE ||
@@ -1821,18 +1671,15 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
    png_write_chunk_data(png_ptr, cbuf, (png_size_t)2);
 
    cbuf[0] = 0;
-   png_write_chunk_data(png_ptr, (new_lang ? (png_const_bytep)new_lang : cbuf),
+   png_write_chunk_data(png_ptr, (lang ? (png_const_bytep)lang : cbuf),
        (png_size_t)(lang_len + 1));
 
    png_write_chunk_data(png_ptr, (lang_key ? (png_const_bytep)lang_key : cbuf),
        (png_size_t)(lang_key_len + 1));
 
-   png_write_compressed_data_out(png_ptr, &comp);
+   png_write_compressed_data_out(png_ptr, &comp, text_len);
 
    png_write_chunk_end(png_ptr);
-
-   png_free(png_ptr, new_key);
-   png_free(png_ptr, new_lang);
 }
 #endif
 
@@ -1866,7 +1713,6 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
    png_size_t purpose_len, units_len, total_len;
    png_size_tp params_len;
    png_byte buf[10];
-   png_charp new_purpose;
    int i;
 
    png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
@@ -1874,7 +1720,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
    if (type >= PNG_EQUATION_LAST)
       png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
 
-   purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+   purpose_len = strlen(purpose) + 1;
    png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
    units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
    png_debug1(3, "pCAL units length = %d", (int)units_len);
@@ -1896,7 +1742,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
 
    png_debug1(3, "pCAL total length = %d", (int)total_len);
    png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);
-   png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose, purpose_len);
+   png_write_chunk_data(png_ptr, (png_const_bytep)purpose, purpose_len);
    png_save_int_32(buf, X0);
    png_save_int_32(buf + 4, X1);
    buf[8] = (png_byte)type;
@@ -1904,8 +1750,6 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
    png_write_chunk_data(png_ptr, buf, (png_size_t)10);
    png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len);
 
-   png_free(png_ptr, new_purpose);
-
    for (i = 0; i < nparams; i++)
    {
       png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
@@ -2430,20 +2274,9 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
    png_uint_32 mins, bpp;
    png_byte filter_to_do = png_ptr->do_filter;
    png_size_t row_bytes = row_info->rowbytes;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-   int num_p_filters = png_ptr->num_prev_filters;
-#endif
 
    png_debug(1, "in png_write_find_filter");
 
-#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-  if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
-  {
-     /* These will never be selected so we need not test them. */
-     filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
-  }
-#endif
-
    /* Find out how many bytes offset each pixel is */
    bpp = (row_info->pixel_depth + 7) >> 3;
 
@@ -2495,44 +2328,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
          sum += (v < 128) ? v : 256 - v;
       }
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         png_uint_32 sumhi, sumlo;
-         int j;
-         sumlo = sum & PNG_LOMASK;
-         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
-
-         /* Reduce the sum if we match any of the previous rows */
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
-            {
-               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         /* Factor in the cost of this filter (this is here for completeness,
-          * but it makes no sense to have a "cost" for the NONE filter, as
-          * it has the minimum possible computational cost - none).
-          */
-         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
-             PNG_COST_SHIFT;
-
-         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
-             PNG_COST_SHIFT;
-
-         if (sumhi > PNG_HIMASK)
-            sum = PNG_MAXSUM;
-
-         else
-            sum = (sumhi << PNG_HISHIFT) + sumlo;
-      }
-#endif
       mins = sum;
    }
 
@@ -2565,44 +2360,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
       png_size_t i;
       int v;
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      /* We temporarily increase the "minimum sum" by the factor we
-       * would reduce the sum of this filter, so that we can do the
-       * early exit comparison without scaling the sum each time.
-       */
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 lmhi, lmlo;
-         lmlo = lmins & PNG_LOMASK;
-         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
-            {
-               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
-             PNG_COST_SHIFT;
-
-         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
-             PNG_COST_SHIFT;
-
-         if (lmhi > PNG_HIMASK)
-            lmins = PNG_MAXSUM;
-
-         else
-            lmins = (lmhi << PNG_HISHIFT) + lmlo;
-      }
-#endif
-
       for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
            i++, rp++, dp++)
       {
@@ -2622,40 +2379,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
             break;
       }
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 sumhi, sumlo;
-         sumlo = sum & PNG_LOMASK;
-         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
-            {
-               sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
-             PNG_COST_SHIFT;
-
-         sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
-             PNG_COST_SHIFT;
-
-         if (sumhi > PNG_HIMASK)
-            sum = PNG_MAXSUM;
-
-         else
-            sum = (sumhi << PNG_HISHIFT) + sumlo;
-      }
-#endif
-
       if (sum < mins)
       {
          mins = sum;
@@ -2686,41 +2409,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
       png_size_t i;
       int v;
 
-
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 lmhi, lmlo;
-         lmlo = lmins & PNG_LOMASK;
-         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
-            {
-               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
-             PNG_COST_SHIFT;
-
-         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
-             PNG_COST_SHIFT;
-
-         if (lmhi > PNG_HIMASK)
-            lmins = PNG_MAXSUM;
-
-         else
-            lmins = (lmhi << PNG_HISHIFT) + lmlo;
-      }
-#endif
-
       for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
           pp = prev_row + 1; i < row_bytes; i++)
       {
@@ -2732,40 +2420,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
             break;
       }
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 sumhi, sumlo;
-         sumlo = sum & PNG_LOMASK;
-         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
-            {
-               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
-             PNG_COST_SHIFT;
-
-         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
-             PNG_COST_SHIFT;
-
-         if (sumhi > PNG_HIMASK)
-            sum = PNG_MAXSUM;
-
-         else
-            sum = (sumhi << PNG_HISHIFT) + sumlo;
-      }
-#endif
-
       if (sum < mins)
       {
          mins = sum;
@@ -2800,40 +2454,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
       png_size_t i;
       int v;
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 lmhi, lmlo;
-         lmlo = lmins & PNG_LOMASK;
-         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
-            {
-               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
-             PNG_COST_SHIFT;
-
-         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
-             PNG_COST_SHIFT;
-
-         if (lmhi > PNG_HIMASK)
-            lmins = PNG_MAXSUM;
-
-         else
-            lmins = (lmhi << PNG_HISHIFT) + lmlo;
-      }
-#endif
-
       for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
            pp = prev_row + 1; i < bpp; i++)
       {
@@ -2853,40 +2473,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
             break;
       }
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 sumhi, sumlo;
-         sumlo = sum & PNG_LOMASK;
-         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
-            {
-               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
-             PNG_COST_SHIFT;
-
-         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
-             PNG_COST_SHIFT;
-
-         if (sumhi > PNG_HIMASK)
-            sum = PNG_MAXSUM;
-
-         else
-            sum = (sumhi << PNG_HISHIFT) + sumlo;
-      }
-#endif
-
       if (sum < mins)
       {
          mins = sum;
@@ -2941,40 +2527,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
       png_size_t i;
       int v;
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 lmhi, lmlo;
-         lmlo = lmins & PNG_LOMASK;
-         lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
-            {
-               lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
-             PNG_COST_SHIFT;
-
-         lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
-             PNG_COST_SHIFT;
-
-         if (lmhi > PNG_HIMASK)
-            lmins = PNG_MAXSUM;
-
-         else
-            lmins = (lmhi << PNG_HISHIFT) + lmlo;
-      }
-#endif
-
       for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
           pp = prev_row + 1; i < bpp; i++)
       {
@@ -3028,40 +2580,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
             break;
       }
 
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-      if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
-      {
-         int j;
-         png_uint_32 sumhi, sumlo;
-         sumlo = sum & PNG_LOMASK;
-         sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
-         for (j = 0; j < num_p_filters; j++)
-         {
-            if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
-            {
-               sumlo = (sumlo * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-
-               sumhi = (sumhi * png_ptr->filter_weights[j]) >>
-                   PNG_WEIGHT_SHIFT;
-            }
-         }
-
-         sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
-             PNG_COST_SHIFT;
-
-         sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
-             PNG_COST_SHIFT;
-
-         if (sumhi > PNG_HIMASK)
-            sum = PNG_MAXSUM;
-
-         else
-            sum = (sumhi << PNG_HISHIFT) + sumlo;
-      }
-#endif
-
       if (sum < mins)
       {
          best_row = png_ptr->paeth_row;
@@ -3071,26 +2589,8 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
 
    /* Do the actual writing of the filtered row data from the chosen filter. */
    png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
-
-#ifdef PNG_WRITE_FILTER_SUPPORTED
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
-   /* Save the type of filter we picked this time for future calculations */
-   if (png_ptr->num_prev_filters > 0)
-   {
-      int j;
-
-      for (j = 1; j < num_p_filters; j++)
-      {
-         png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
-      }
-
-      png_ptr->prev_filters[j] = best_row[0];
-   }
-#endif
-#endif /* PNG_WRITE_FILTER_SUPPORTED */
 }
 
-
 /* Do the actual writing of a previously filtered row. */
 static void
 png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row,

+ 25 - 1
drivers/unix/thread_posix.cpp

@@ -45,8 +45,8 @@ Thread* ThreadPosix::create_thread_posix() {
 void *ThreadPosix::thread_callback(void *userdata) {
 
 	ThreadPosix *t=reinterpret_cast<ThreadPosix*>(userdata);
-	t->callback(t->user);
 	t->id=(ID)pthread_self();
+	t->callback(t->user);
 	return NULL;
 }
 
@@ -77,6 +77,30 @@ void ThreadPosix::wait_to_finish_func_posix(Thread* p_thread) {
 	tp->pthread=0;		
 }
 
+Error ThreadPosix::set_name(const String& p_name) {
+
+	ERR_FAIL_COND_V(pthread == 0, ERR_UNCONFIGURED);
+
+	#ifdef PTHREAD_RENAME_SELF
+
+	// check if thread is the same as caller
+	int caller = Thread::get_caller_ID();
+	int self = get_ID();
+	if (caller != self) {
+		ERR_EXPLAIN("On this platform, thread can only be renamed with calls from the threads to be renamed.");
+		ERR_FAIL_V(ERR_UNAVAILABLE);
+		return ERR_UNAVAILABLE;
+	};
+	int err = pthread_setname_np(p_name.utf8().get_data());
+	
+	#else
+
+	int err = pthread_setname_np(pthread, p_name.utf8().get_data());
+
+	#endif
+
+	return err == 0 ? OK : ERR_INVALID_PARAMETER;
+};
 
 void ThreadPosix::make_default() {
 

+ 1 - 0
drivers/unix/thread_posix.h

@@ -61,6 +61,7 @@ public:
 	
 	
 	virtual ID get_ID() const;
+	Error set_name(const String& p_name);
 	
 	static void make_default();
 	

+ 435 - 6
main/input_default.cpp

@@ -112,8 +112,8 @@ float InputDefault::get_joy_axis(int p_device,int p_axis) {
 
 	_THREAD_SAFE_METHOD_
 	int c = _combine_device(p_axis,p_device);
-	if (joy_axis.has(c)) {
-		return joy_axis[c];
+	if (_joy_axis.has(c)) {
+		return _joy_axis[c];
 	} else {
 		return 0;
 	}
@@ -122,13 +122,51 @@ float InputDefault::get_joy_axis(int p_device,int p_axis) {
 String InputDefault::get_joy_name(int p_idx) {
 
 	_THREAD_SAFE_METHOD_
-	return joy_names[p_idx];
+	return joy_names[p_idx].name;
 };
 
-void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name) {
+static String _hex_str(uint8_t p_byte) {
+
+	static const char* dict = "0123456789abcdef";
+	char ret[3];
+	ret[2] = 0;
+
+	ret[0] = dict[p_byte>>4];
+	ret[1] = dict[p_byte & 0xf];
+
+	return ret;
+};
+
+void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
 
 	_THREAD_SAFE_METHOD_
-	joy_names[p_idx] = p_connected ? p_name : "";
+			Joystick js;
+	js.name = p_connected ? p_name : "";
+	js.uid = p_connected ? p_guid : "";
+	js.mapping = -1;
+	js.hat_current = 0;
+
+	if (p_connected) {
+
+		String uidname = p_guid;
+		if (p_guid == "") {
+			int uidlen = MIN(p_name.length(), 16);
+			for (int i=0; i<uidlen; i++) {
+				uidname = uidname + _hex_str(p_name[i]);
+			};
+		};
+		js.uid = uidname;
+		//printf("looking for mappings for guid %ls\n", uidname.c_str());
+		int mapping = -1;
+		for (int i=0; i < map_db.size(); i++) {
+			if (js.uid == map_db[i].uid) {
+				mapping = i;
+				//printf("found mapping\n");
+			};
+		};
+		js.mapping = mapping;
+	};
+	joy_names[p_idx] = js;
 
 	emit_signal("joy_connection_changed", p_idx, p_connected);
 };
@@ -224,7 +262,7 @@ void InputDefault::set_joy_axis(int p_device,int p_axis,float p_value) {
 
 	_THREAD_SAFE_METHOD_
 	int c = _combine_device(p_axis,p_device);
-	joy_axis[c]=p_value;
+	_joy_axis[c]=p_value;
 }
 
 void InputDefault::set_accelerometer(const Vector3& p_accel) {
@@ -335,9 +373,400 @@ void InputDefault::set_mouse_in_window(bool p_in_window) {
 	}
 }
 
+// from github.com/gabomdq/SDL_GameControllerDB
+static const char *s_ControllerMappings [] =
+{
+	#ifdef WINDOWS_ENABLED
+	"8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+	"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+	"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+	"6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+	"6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+	"88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
+	"4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
+	"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
+	"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+	"6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,",
+	"4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,",
+	"00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,",
+	"00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,",
+	"28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,",
+	"ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,",
+	"8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+	"8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
+	"10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,",
+	"79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+	"4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+	"d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+	"a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,",
+	"8f0e0300000000000000504944564944,Trust GTX 28,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+	"4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+	"83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,",
+	"c911f055000000000000504944564944,GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+	"79000600000000000000504944564944,Generic Speedlink,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,",
+	"__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
+
+	#endif
+	#ifdef OSX_ENABLED
+	"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+	"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
+	"6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+	"6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+	"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */
+	"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+	"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+	"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+	#endif
+	#if X11_ENABLED
+	"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+	"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+	"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+	"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+	"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+	"030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,",
+	"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+	"03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,",
+	"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,",
+	"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,",
+	"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,",
+	"030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+	"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+	"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+	"030000006d04000016c2000010010000,Logitech Logitech Dual Action,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
+	"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,",
+	"030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,",
+	"030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
+	"030000004f04000008d0000000010000,Thrustmaster Run N Drive  Wireless,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,",
+	"0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+	"0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+	"030000006f0e00001f01000000010000,Generic X-Box pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+	"03000000280400000140000000010000,Gravis GamePad Pro USB ,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,",
+	"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+	"030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+	"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,",
+	"030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+	"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,",
+	"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+	"050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+	"060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,",
+	"03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+	"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,",
+	"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+	"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+	"030000008916000001fd000024010000,Razer Onza Classic Edition,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+	"030000005e040000d102000001010000,Microsoft X-Box One pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+	"03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+	"050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,",
+	"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+	"030000000d0f00002200000011010000,HORI CO.,LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,",
+	"030000000d0f00001000000011010000,HORI CO.,LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7",
+	"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+	"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,",
+	#endif
+
+	#if defined(__ANDROID__)
+	"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+	#endif
+	NULL
+};
+
 InputDefault::InputDefault() {
 
 	mouse_button_mask=0;
 	emulate_touch=false;
 	main_loop=NULL;
+
+	hat_map_default[HAT_UP].type = TYPE_BUTTON;
+	hat_map_default[HAT_UP].index = JOY_DPAD_UP;
+	hat_map_default[HAT_UP].value = 0;
+
+	hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
+	hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
+	hat_map_default[HAT_RIGHT].value = 0;
+
+	hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
+	hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
+	hat_map_default[HAT_DOWN].value = 0;
+
+	hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
+	hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
+	hat_map_default[HAT_LEFT].value = 0;
+
+	String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
+	if (env_mapping != "") {
+
+		Vector<String> entries = env_mapping.split("\n");
+		for (int i=0; i < entries.size(); i++) {
+			if (entries[i] == "")
+				continue;
+			parse_mapping(entries[i]);
+		};
+	};
+
+	int i = 0;
+	while (s_ControllerMappings[i]) {
+
+		parse_mapping(s_ControllerMappings[i++]);
+	};
 }
+
+
+uint32_t InputDefault::joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed) {
+
+	_THREAD_SAFE_METHOD_;
+	Joystick& joy = joy_names[p_device];
+	//printf("got button %i, mapping is %i\n", p_button, joy.mapping);
+	if (joy.last_buttons[p_button] == p_pressed) {
+		return p_last_id;
+		//printf("same button value\n");
+	}
+	joy.last_buttons[p_button] = p_pressed;
+	if (joy.mapping == -1) {
+		return _button_event(p_last_id, p_device, p_button, p_pressed);
+	};
+
+	Map<int,JoyEvent>::Element* el = map_db[joy.mapping].buttons.find(p_button);
+	if (!el) {
+		//don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis
+		//return _button_event(p_last_id, p_device, p_button, p_pressed);
+		return p_last_id;
+	};
+
+	JoyEvent map = el->get();
+	if (map.type == TYPE_BUTTON) {
+
+		return _button_event(p_last_id, p_device, map.index, p_pressed);
+	};
+
+	if (map.type == TYPE_AXIS) {
+		return _axis_event(p_last_id, p_device, map.index, p_pressed ? 1.0 : 0.0);
+	};
+
+	return p_last_id; // no event?
+};
+
+uint32_t InputDefault::joy_axis(uint32_t p_last_id, int p_device, int p_axis, const JoyAxis& p_value) {
+
+	_THREAD_SAFE_METHOD_;
+
+	Joystick& joy = joy_names[p_device];
+
+	if (joy.last_axis[p_axis] == p_value.value) {
+		return p_last_id;
+	}
+
+	if (p_value.value > joy.last_axis[p_axis]) {
+
+		if (p_value.value < joy.last_axis[p_axis] + joy.filter ) {
+
+			return p_last_id;
+		}
+	}
+	else if (p_value.value > joy.last_axis[p_axis] - joy.filter) {
+
+		return p_last_id;
+	}
+
+
+	joy.last_axis[p_axis] = p_value.value;
+	if (joy.mapping == -1) {
+		float val = p_value.min == 0 ? -1.0f + 2.0f * p_value.value : p_value.value;
+		return _axis_event(p_last_id, p_device, p_axis, val);
+	};
+
+	Map<int,JoyEvent>::Element* el = map_db[joy.mapping].axis.find(p_axis);
+	if (!el) {
+		//return _axis_event(p_last_id, p_device, p_axis, p_value);
+		return p_last_id;
+	};
+
+
+	JoyEvent map = el->get();
+
+	if (map.type == TYPE_BUTTON) {
+		float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
+		bool pressed = p_value.value > deadzone ? true : false;
+		if (pressed == joy_buttons_pressed.has(_combine_device(map.index,p_device))) {
+			// button already pressed or released, this is an axis bounce value
+			return p_last_id;
+		};
+		return _button_event(p_last_id, p_device, map.index, pressed);
+	};
+
+	if (map.type == TYPE_AXIS) {
+
+		float val = p_value.min == 0 ? -1.0f + 2.0f * p_value.value : p_value.value;
+		return _axis_event(p_last_id, p_device, map.index, val );
+	};
+	//printf("invalid mapping\n");
+	return p_last_id;
+};
+
+uint32_t InputDefault::joy_hat(uint32_t p_last_id, int p_device, int p_val) {
+
+	_THREAD_SAFE_METHOD_;
+	const Joystick& joy = joy_names[p_device];
+
+	JoyEvent* map;
+
+	if (joy.mapping == -1) {
+		map = hat_map_default;
+	} else {
+		map = map_db[joy.mapping].hat;
+	};
+
+	int cur_val = joy_names[p_device].hat_current;
+
+	if ( (p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP) ) {
+		p_last_id = _button_event(p_last_id, p_device, map[HAT_UP].index, p_val & HAT_MASK_UP);
+	};
+
+	if ( (p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT) ) {
+		p_last_id = _button_event(p_last_id, p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT);
+	};
+	if ( (p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN) ) {
+		p_last_id = _button_event(p_last_id, p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN);
+	};
+	if ( (p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT) ) {
+		p_last_id = _button_event(p_last_id, p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT);
+	};
+
+	joy_names[p_device].hat_current = p_val;
+
+	return p_last_id;
+};
+
+uint32_t InputDefault::_button_event(uint32_t p_last_id, int p_device, int p_index, bool p_pressed) {
+
+	InputEvent ievent;
+	ievent.type = InputEvent::JOYSTICK_BUTTON;
+	ievent.device = p_device;
+	ievent.ID = ++p_last_id;
+	ievent.joy_button.button_index = p_index;
+	ievent.joy_button.pressed = p_pressed;
+
+	parse_input_event(ievent);
+
+	return p_last_id;
+};
+
+uint32_t InputDefault::_axis_event(uint32_t p_last_id, int p_device, int p_axis, float p_value) {
+
+	InputEvent ievent;
+	ievent.type = InputEvent::JOYSTICK_MOTION;
+	ievent.device = p_device;
+	ievent.ID = ++p_last_id;
+	ievent.joy_motion.axis = p_axis;
+	ievent.joy_motion.axis_value = p_value;
+
+	parse_input_event( ievent );
+
+	return p_last_id;
+};
+
+InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
+
+	// string names of the SDL buttons in the same order as input_event.h godot buttons
+	static const char* buttons[] = {"a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", NULL };
+
+	static const char* axis[] = {"leftx", "lefty", "rightx", "righty", NULL };
+
+	JoyEvent ret;
+	ret.type = -1;
+
+	int i=0;
+	while (buttons[i]) {
+
+		if (p_to == buttons[i]) {
+			//printf("mapping button %s\n", buttons[i]);
+			ret.type = TYPE_BUTTON;
+			ret.index = i;
+			ret.value = 0;
+			return ret;
+		};
+		++i;
+	};
+
+	i = 0;
+	while (axis[i]) {
+
+		if (p_to == axis[i]) {
+			ret.type = TYPE_AXIS;
+			ret.index = i;
+			ret.value = 0;
+			return ret;
+		};
+		++i;
+	};
+
+	return ret;
+};
+
+void InputDefault::parse_mapping(String p_mapping) {
+
+	_THREAD_SAFE_METHOD_;
+	JoyDeviceMapping mapping;
+
+	Vector<String> entry = p_mapping.split(",");
+	CharString uid;
+	uid.resize(17);
+
+	mapping.uid = entry[0];
+
+	int idx = 1;
+	while (++idx < entry.size()) {
+
+		if (entry[idx] == "")
+			continue;
+
+		String from = entry[idx].get_slice(":", 1);
+		String to = entry[idx].get_slice(":", 0);
+
+		JoyEvent to_event = _find_to_event(to);
+		if (to_event.type == -1)
+			continue;
+
+		String etype = from.substr(0, 1);
+		if (etype == "a") {
+
+			int aid = from.substr(1, from.length()-1).to_int();
+			mapping.axis[aid] = to_event;
+
+		} else if (etype == "b") {
+
+			int bid = from.substr(1, from.length()-1).to_int();
+			mapping.buttons[bid] = to_event;
+
+		} else if (etype == "h") {
+
+			int hat_value = from.get_slice(".", 1).to_int();
+			switch (hat_value) {
+			case 1:
+				mapping.hat[HAT_UP] = to_event;
+				break;
+			case 2:
+				mapping.hat[HAT_RIGHT] = to_event;
+				break;
+			case 4:
+				mapping.hat[HAT_DOWN] = to_event;
+				break;
+			case 8:
+				mapping.hat[HAT_LEFT] = to_event;
+				break;
+			};
+		};
+	};
+	map_db.push_back(mapping);
+	//printf("added mapping with uuid %ls\n", mapping.uid.c_str());
+};

+ 89 - 5
main/input_default.h

@@ -11,9 +11,8 @@ class InputDefault : public Input {
 	int mouse_button_mask;
 	Set<int> keys_pressed;
 	Set<int> joy_buttons_pressed;
-	Map<int,float> joy_axis;
+	Map<int,float> _joy_axis;
 	Map<StringName,int> custom_action_press;
-	Map<int, String> joy_names;
 	Vector3 accelerometer;
 	Vector2 mouse_pos;
 	MainLoop *main_loop;
@@ -34,12 +33,92 @@ class InputDefault : public Input {
 		SpeedTrack();
 	};
 
-	SpeedTrack mouse_speed_track;
+	struct Joystick {
+		StringName name;
+		StringName uid;
+		bool last_buttons[JOY_BUTTON_MAX];
+		float last_axis[JOY_AXIS_MAX];
+		float filter;
+		int last_hat;
+		int mapping;
+		int hat_current;
+
+		Joystick() {
+
+			for (int i = 0; i < JOY_AXIS_MAX; i++) {
+
+				last_axis[i] = 0.0f;
+
+			}
+			for (int i = 0; i < JOY_BUTTON_MAX; i++) {
+
+				last_buttons[i] = false;
+			}
+			last_hat = HAT_MASK_CENTER;
+			filter = 0.01f;
+		}
+	};
 
+	SpeedTrack mouse_speed_track;
+	Map<int, Joystick> joy_names;
 	RES custom_cursor;
+public:
+	enum HatMask {
+		HAT_MASK_CENTER = 0,
+		HAT_MASK_UP = 1,
+		HAT_MASK_RIGHT = 2,
+		HAT_MASK_DOWN = 4,
+		HAT_MASK_LEFT = 8,
+	};
+
+	enum HatDir {
+		HAT_UP,
+		HAT_RIGHT,
+		HAT_DOWN,
+		HAT_LEFT,
+		HAT_MAX,
+	};
+	struct JoyAxis {
+		int min;
+		float value;
+	};
+
+private:
+
+	enum JoyType {
+		TYPE_BUTTON,
+		TYPE_AXIS,
+		TYPE_HAT,
+		TYPE_MAX,
+	};
+
+	struct JoyEvent {
+		int type;
+		int index;
+		int value;
+	};
+
+	struct JoyDeviceMapping {
+
+		String uid;
+		Map<int,JoyEvent> buttons;
+		Map<int,JoyEvent> axis;
+		JoyEvent hat[HAT_MAX];
+	};
+
+	JoyEvent hat_map_default[HAT_MAX];
+
+	Vector<JoyDeviceMapping> map_db;
+
+	JoyEvent _find_to_event(String p_to);
+	uint32_t _button_event(uint32_t p_last_id, int p_device, int p_index, bool p_pressed);
+	uint32_t _axis_event(uint32_t p_last_id, int p_device, int p_axis, float p_value);
+	float _handle_deadzone(int p_device, int p_axis, float p_value);
 
 public:
 
+
+
 	virtual bool is_key_pressed(int p_scancode);
 	virtual bool is_mouse_button_pressed(int p_button);
 	virtual bool is_joy_button_pressed(int p_device, int p_button);
@@ -47,7 +126,8 @@ public:
 
 	virtual float get_joy_axis(int p_device,int p_axis);
 	String get_joy_name(int p_idx);
-	void joy_connection_changed(int p_idx, bool p_connected, String p_name);
+	void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
+	void parse_joystick_mapping(String p_mapping, bool p_update_existing);
 
 	virtual Vector3 get_accelerometer();
 
@@ -76,8 +156,12 @@ public:
 	virtual void set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_hotspot=Vector2());
 	virtual void set_mouse_in_window(bool p_in_window);
 
-	InputDefault();
+	void parse_mapping(String p_mapping);
+	uint32_t joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed);
+	uint32_t joy_axis(uint32_t p_last_id, int p_device, int p_axis, const JoyAxis& p_value);
+	uint32_t joy_hat(uint32_t p_last_id, int p_device, int p_val);
 
+	InputDefault();
 };
 
 #endif // INPUT_DEFAULT_H

+ 2 - 0
platform/iphone/platform_config.h

@@ -31,3 +31,5 @@
 
 
 #define PLATFORM_REFCOUNT
+
+#define PTHREAD_RENAME_SELF

+ 1 - 0
platform/osx/platform_config.h

@@ -29,3 +29,4 @@
 #include <alloca.h>
 #define GLES2_INCLUDE_H "gl_context/glew.h"
 #define GLES1_INCLUDE_H "gl_context/glew.h"
+#define PTHREAD_RENAME_SELF

+ 1 - 0
platform/windows/SCsub

@@ -9,6 +9,7 @@ common_win=[
 	"tcp_server_winsock.cpp",
 	"packet_peer_udp_winsock.cpp",
 	"stream_peer_winsock.cpp",
+	"joystick.cpp",
 ]
 
 restarget="godot_res"+env["OBJSUFFIX"]

+ 2 - 2
platform/windows/detect.py

@@ -243,7 +243,7 @@ def configure(env):
 		env.Append(CCFLAGS=['/DGLES2_ENABLED'])
 
 		env.Append(CCFLAGS=['/DGLEW_ENABLED'])
-		LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32']
+		LIBS=['winmm','opengl32','dsound','kernel32','ole32','oleaut32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32','dinput8','dxguid']
 		env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
 		
 		env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
@@ -369,7 +369,7 @@ def configure(env):
 		env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
 		env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
 		env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
-		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
+		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32', 'oleaut32', 'dinput8', 'dxguid'])
 
 		# if (env["bits"]=="32"):
 			# env.Append(LIBS=['gcc_s'])

+ 3 - 3
platform/windows/godot_res.rc

@@ -7,8 +7,8 @@
 GODOT_ICON ICON platform/windows/godot.ico
 
 1 VERSIONINFO
-FILEVERSION    	VERSION_MAJOR,VERSION_MINOR,0
-PRODUCTVERSION 	VERSION_MAJOR,VERSION_MINOR,0
+FILEVERSION    	VERSION_MAJOR,VERSION_MINOR,0,0
+PRODUCTVERSION 	VERSION_MAJOR,VERSION_MINOR,0,0
 FILEOS         	4
 FILETYPE       	1
 BEGIN
@@ -30,4 +30,4 @@ BEGIN
     BEGIN
         VALUE "Translation", 0x409, 1200
     END
-END
+END

+ 528 - 0
platform/windows/joystick.cpp

@@ -0,0 +1,528 @@
+/*************************************************************************/
+/*  joystick.cpp                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+//author: Andreas Haas <hondres,  [email protected]>
+#include "joystick.h"
+#include <iostream>
+#include <wbemidl.h>
+#include <oleauto.h>
+
+#ifndef __GNUC__
+#define __builtin_bswap32 _byteswap_ulong
+#endif
+
+DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE* pState) { return ERROR_DEVICE_NOT_CONNECTED; }
+
+joystick_windows::joystick_windows() {
+
+}
+
+joystick_windows::joystick_windows(InputDefault* _input, HWND* hwnd) {
+
+	input = _input;
+	hWnd = hwnd;
+	joystick_count = 0;
+	dinput = NULL;
+	xinput_dll = NULL;
+	xinput_get_state = NULL;
+
+	load_xinput();
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++)
+		attached_joysticks[i] = false;
+
+
+	HRESULT result;
+	result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinput, NULL);
+	if (FAILED(result)) {
+		printf("failed init DINPUT: %ld\n", result);
+	}
+	probe_joysticks();
+}
+
+joystick_windows::~joystick_windows() {
+
+	close_joystick();
+	dinput->Release();
+	unload_xinput();
+}
+
+
+bool joystick_windows::have_device(const GUID &p_guid) {
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+		if (d_joysticks[i].guid == p_guid) {
+
+			d_joysticks[i].confirmed = true;
+			return true;
+		}
+	}
+	return false;
+}
+
+int joystick_windows::check_free_joy_slot() const {
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+		if (!attached_joysticks[i])
+			return i;
+	}
+	return -1;
+}
+
+
+// adapted from SDL2, works a lot better than the MSDN version
+bool joystick_windows::is_xinput_device(const GUID *p_guid) {
+
+	PRAWINPUTDEVICELIST dev_list = NULL;
+	unsigned int dev_list_count = 0;
+
+	if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
+		return false;
+	}
+	dev_list = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
+	if (!dev_list) return false;
+
+	if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
+		free(dev_list);
+		return false;
+	}
+	for (int i = 0; i < dev_list_count; i++) {
+
+		RID_DEVICE_INFO rdi;
+		char dev_name[128];
+		UINT rdiSize = sizeof(rdi);
+		UINT nameSize = sizeof(dev_name);
+
+		rdi.cbSize = rdiSize;
+		if ( (dev_list[i].dwType == RIM_TYPEHID) &&
+				(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) &&
+				(MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) &&
+				(GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) &&
+				(strstr(dev_name, "IG_") != NULL)) {
+
+			free(dev_list);
+			return true;
+		}
+	}
+	free(dev_list);
+	return false;
+}
+
+bool joystick_windows::setup_dinput_joystick(const DIDEVICEINSTANCE* instance) {
+
+	HRESULT hr;
+	int num = check_free_joy_slot();
+
+	if (have_device(instance->guidInstance) || num == -1)
+		return false;
+
+	d_joysticks[joystick_count] = dinput_gamepad();
+	dinput_gamepad* joy = &d_joysticks[num];
+
+	const DWORD devtype = (instance->dwDevType & 0xFF);
+
+	if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) {
+		//printf("ignore device %s, type %x\n", instance->tszProductName, devtype);
+		return false;
+	}
+
+	hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL);
+
+	if (FAILED(hr)) {
+
+		//std::wcout << "failed to create device: " << instance->tszProductName << std::endl;
+		return false;
+	}
+
+	const GUID &guid = instance->guidProduct;
+	char uid[128];
+	sprintf(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+		 __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
+		 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
+			guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
+
+	id_to_change = num;
+	joy->di_joy->SetDataFormat(&c_dfDIJoystick2);
+	joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND);
+	joy->di_joy->EnumObjects(objectsCallback, this, NULL);
+	joy->joy_axis.sort();
+
+	joy->guid = instance->guidInstance;
+	input->joy_connection_changed(num, true, instance->tszProductName, uid);
+	joy->attached = true;
+	joy->id = num;
+	attached_joysticks[num] = true;
+	joy->confirmed = true;
+	joystick_count++;
+	return true;
+}
+
+void joystick_windows::setup_joystick_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
+
+	if (ob->dwType & DIDFT_AXIS) {
+
+		HRESULT res;
+		DIPROPRANGE prop_range;
+		DIPROPDWORD dilong;
+		DWORD ofs;
+		if (ob->guidType == GUID_XAxis)
+			ofs = DIJOFS_X;
+		else if (ob->guidType == GUID_YAxis)
+			ofs = DIJOFS_Y;
+		else if (ob->guidType == GUID_ZAxis)
+			ofs = DIJOFS_Z;
+		else if (ob->guidType == GUID_RxAxis)
+			ofs = DIJOFS_RX;
+		else if (ob->guidType == GUID_RyAxis)
+			ofs = DIJOFS_RY;
+		else if (ob->guidType == GUID_RzAxis)
+			ofs = DIJOFS_RZ;
+		else if (ob->guidType == GUID_Slider)
+			ofs = DIJOFS_SLIDER(0);
+		else
+			return;
+		prop_range.diph.dwSize = sizeof(DIPROPRANGE);
+		prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+		prop_range.diph.dwObj = ob->dwType;
+		prop_range.diph.dwHow = DIPH_BYID;
+		prop_range.lMin = -MAX_JOY_AXIS;
+		prop_range.lMax = +MAX_JOY_AXIS;
+
+		dinput_gamepad &joy = d_joysticks[p_joy_id];
+
+
+		res = joy.di_joy->SetProperty(DIPROP_RANGE, &prop_range.diph);
+		if (FAILED(res))
+			return;
+
+		dilong.diph.dwSize = sizeof(dilong);
+		dilong.diph.dwHeaderSize = sizeof(dilong.diph);
+		dilong.diph.dwObj = ob->dwType;
+		dilong.diph.dwHow = DIPH_BYID;
+		dilong.dwData = 0;
+
+		res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_DEADZONE, &dilong.diph);
+		if (FAILED(res))
+			return;
+
+		joy.joy_axis.push_back(ofs);
+	}
+}
+
+BOOL CALLBACK joystick_windows::enumCallback(const DIDEVICEINSTANCE* instance, void* pContext) {
+
+
+	joystick_windows* self = (joystick_windows*)pContext;
+	if (self->is_xinput_device(&instance->guidProduct)) {;
+		return DIENUM_CONTINUE;
+	}
+	self->setup_dinput_joystick(instance);
+	return DIENUM_CONTINUE;
+}
+
+BOOL CALLBACK joystick_windows::objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context) {
+
+	joystick_windows* self = (joystick_windows*)context;
+	self->setup_joystick_object(instance, self->id_to_change);
+
+	return DIENUM_CONTINUE;
+}
+
+void joystick_windows::close_joystick(int id) {
+
+	if (id == -1) {
+
+		for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+			close_joystick(i);
+		}
+		return;
+	}
+
+	if (!d_joysticks[id].attached) return;
+
+	d_joysticks[id].di_joy->Unacquire();
+	d_joysticks[id].di_joy->Release();
+	d_joysticks[id].attached = false;
+	attached_joysticks[d_joysticks[id].id] = false;
+	d_joysticks[id].guid.Data1 = d_joysticks[id].guid.Data2 = d_joysticks[id].guid.Data3 = 0;
+	input->joy_connection_changed(id, false, "");
+	joystick_count--;
+}
+
+void joystick_windows::probe_joysticks() {
+
+	DWORD dwResult;
+	for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
+
+		ZeroMemory(&x_joysticks[i].state, sizeof(XINPUT_STATE));
+
+		dwResult = xinput_get_state(i, &x_joysticks[i].state);
+		if ( dwResult == ERROR_SUCCESS) {
+
+			int id = check_free_joy_slot();
+			if (id != -1 && !x_joysticks[i].attached) {
+
+				x_joysticks[i].attached = true;
+				x_joysticks[i].id = id;
+				attached_joysticks[id] = true;
+				input->joy_connection_changed(id, true, "XInput Gamepad","__XINPUT_DEVICE__");
+			}
+		}
+		else if (x_joysticks[i].attached) {
+
+			x_joysticks[i].attached = false;
+			attached_joysticks[x_joysticks[i].id] = false;
+			input->joy_connection_changed(x_joysticks[i].id, false, "");
+		}
+	}
+
+	for (int i = 0; i < joystick_count; i++) {
+
+		d_joysticks[i].confirmed = false;
+	}
+
+	dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
+
+	for (int i = 0; i < joystick_count; i++) {
+
+		if (!d_joysticks[i].confirmed) {
+
+			close_joystick(i);
+		}
+	}
+}
+
+unsigned int joystick_windows::process_joysticks(unsigned int p_last_id) {
+
+	HRESULT hr;
+
+	for (int i = 0; i < XUSER_MAX_COUNT; i++) {
+
+		xinput_gamepad &joy = x_joysticks[i];
+		if (!joy.attached) {
+			continue;
+		}
+		ZeroMemory(&joy.state, sizeof(XINPUT_STATE));
+
+		xinput_get_state(i, &joy.state);
+		if (joy.state.dwPacketNumber != joy.last_packet) {
+
+			int button_mask = XINPUT_GAMEPAD_DPAD_UP;
+			for (int i = 0; i <= 16; i++) {
+
+				p_last_id = input->joy_button(p_last_id, joy.id, i, joy.state.Gamepad.wButtons & button_mask);
+				button_mask = button_mask * 2;
+			}
+
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_0,  axis_correct(joy.state.Gamepad.sThumbLX, true));
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_1,  axis_correct(joy.state.Gamepad.sThumbLY, true, false, true));
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_2,  axis_correct(joy.state.Gamepad.sThumbRX, true));
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_3,  axis_correct(joy.state.Gamepad.sThumbRY, true, false, true));
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_4,  axis_correct(joy.state.Gamepad.bLeftTrigger, true, true));
+			p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_5,  axis_correct(joy.state.Gamepad.bRightTrigger, true, true));
+			joy.last_packet = joy.state.dwPacketNumber;
+		}
+	}
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+		dinput_gamepad* joy = &d_joysticks[i];
+
+		if (!joy->attached)
+			continue;
+
+		DIJOYSTATE2 js;
+		hr = joy->di_joy->Poll();
+		if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {
+			IDirectInputDevice8_Acquire(joy->di_joy);
+			joy->di_joy->Poll();
+		}
+		if (FAILED(hr = d_joysticks[i].di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js))) {
+
+			//printf("failed to read joy #%d\n", i);
+			continue;
+		}
+
+		p_last_id = post_hat(p_last_id, i, js.rgdwPOV[0]);
+
+		for (int j = 0; j < 128; j++) {
+
+			if (js.rgbButtons[j] & 0x80) {
+
+				if (!joy->last_buttons[j]) {
+
+					p_last_id = input->joy_button(p_last_id, i, j, true);
+					joy->last_buttons[j] = true;
+				}
+			}
+			else {
+
+				if (joy->last_buttons[j]) {
+
+					p_last_id = input->joy_button(p_last_id, i, j, false);
+					joy->last_buttons[j] = false;
+				}
+			}
+		}
+
+        // on mingw, these constants are not constants
+		int count = 6;
+		int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ };
+		int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz };
+
+		for (int j = 0; j < joy->joy_axis.size(); j++) {
+
+			for (int k=0; k<count; k++) {
+				if (joy->joy_axis[j] == axes[k]) {
+					p_last_id = input->joy_axis(p_last_id, i, j, axis_correct(values[k]));
+					break;
+				};
+			};
+		};
+	}
+	return p_last_id;
+}
+
+unsigned int joystick_windows::post_hat(unsigned int p_last_id, int p_device, DWORD p_dpad) {
+
+	int dpad_val = 0;
+
+	if (p_dpad == -1) {
+		dpad_val = InputDefault::HAT_MASK_CENTER;
+	}
+	if (p_dpad == 0) {
+
+		dpad_val = InputDefault::HAT_MASK_UP;
+
+	}
+	else if (p_dpad == 4500) {
+
+		dpad_val = (InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT);
+
+	}
+	else if (p_dpad == 9000) {
+
+		dpad_val = InputDefault::HAT_MASK_RIGHT;
+
+	}
+	else if (p_dpad == 13500) {
+
+		dpad_val = (InputDefault::HAT_MASK_RIGHT | InputDefault::HAT_MASK_DOWN);
+
+	}
+	else if (p_dpad == 18000) {
+
+		dpad_val = InputDefault::HAT_MASK_DOWN;
+
+	}
+	else if (p_dpad == 22500) {
+
+		dpad_val = (InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT);
+
+	}
+	else if (p_dpad == 27000) {
+
+		dpad_val = InputDefault::HAT_MASK_LEFT;
+
+	}
+	else if (p_dpad == 31500) {
+
+		dpad_val = (InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_UP);
+	}
+	return input->joy_hat(p_last_id, p_device, dpad_val);
+};
+
+InputDefault::JoyAxis joystick_windows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+
+	InputDefault::JoyAxis jx;
+	if (Math::abs(p_val) < MIN_JOY_AXIS) {
+		jx.min = -1;
+		jx.value = 0.0f;
+		return jx;
+	}
+	if (p_xinput) {
+
+		if (p_trigger) {
+			jx.min = 0;
+			jx.value = (float)p_val / MAX_TRIGGER;
+			return jx;
+		}
+		jx.min = -1;
+		if (p_val < 0) {
+			jx.value = (float)p_val / MAX_JOY_AXIS;
+		}
+		else {
+			jx.value = (float)p_val / (MAX_JOY_AXIS - 1);
+		}
+		if (p_negate) {
+			jx.value = -jx.value;
+		}
+		return jx;
+	}
+	jx.min = -1;
+	jx.value = (float)p_val / MAX_JOY_AXIS;
+	return jx;
+}
+
+void joystick_windows::load_xinput() {
+
+	xinput_get_state = &_xinput_get_state;
+	xinput_dll = LoadLibrary( "XInput1_4.dll" );
+	if (!xinput_dll) {
+		xinput_dll = LoadLibrary("XInput1_3.dll");
+		if (!xinput_dll) {
+			xinput_dll = LoadLibrary("XInput9_1_0.dll");
+		}
+	}
+
+	if (!xinput_dll) {
+		if (OS::get_singleton()->is_stdout_verbose()) {
+			print_line("Could not find XInput, using DirectInput only");
+		}
+		return;
+	}
+
+	XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState");
+	if (!func) {
+		unload_xinput();
+		return;
+	}
+	xinput_get_state = func;
+	return;
+}
+
+void joystick_windows::unload_xinput() {
+
+	if (xinput_dll) {
+
+		FreeLibrary((HMODULE)xinput_dll);
+	}
+}

+ 139 - 0
platform/windows/joystick.h

@@ -0,0 +1,139 @@
+/*************************************************************************/
+/*  joystick.h                                                           */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+//author: Andreas Haas <hondres,  [email protected]>
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+#include "os_windows.h"
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+#include <xinput.h> // on unix the file is called "xinput.h", on windows I'm sure it won't mind
+
+#ifndef SAFE_RELEASE            // when Windows Media Device M? is not present
+#define SAFE_RELEASE(x) \
+if(x != NULL)           \
+{                       \
+    x->Release();       \
+    x = NULL;           \
+}
+#endif
+
+
+class joystick_windows
+{
+public:
+	joystick_windows();
+	joystick_windows(InputDefault* _input, HWND* hwnd);
+	~joystick_windows();
+
+	void probe_joysticks();
+	unsigned int process_joysticks(unsigned int p_last_id);
+private:
+
+	enum {
+		JOYSTICKS_MAX = 16,
+		JOY_AXIS_COUNT = 6,
+		MIN_JOY_AXIS = 10,
+		MAX_JOY_AXIS = 32768,
+		MAX_JOY_BUTTONS = 128,
+		KEY_EVENT_BUFFER_SIZE = 512,
+		MAX_TRIGGER = 255
+	};
+
+	struct dinput_gamepad {
+
+		int id;
+		bool attached;
+		bool confirmed;
+		bool last_buttons[MAX_JOY_BUTTONS];
+		DWORD last_pad;
+
+		LPDIRECTINPUTDEVICE8 di_joy;
+		List<DWORD> joy_axis;
+		GUID guid;
+
+		dinput_gamepad() {
+			id = -1;
+			last_pad = -1;
+			attached = false;
+			confirmed = false;
+
+			for (int i = 0; i < MAX_JOY_BUTTONS; i++)
+				last_buttons[i] = false;
+		}
+	};
+
+	struct xinput_gamepad {
+
+		int id;
+		bool attached;
+		DWORD last_packet;
+		XINPUT_STATE state;
+
+		xinput_gamepad() {
+			attached = false;
+			last_packet = 0;
+		}
+	};
+
+	typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState);
+
+	HWND* hWnd;
+	HANDLE xinput_dll;
+	LPDIRECTINPUT8 dinput;
+	InputDefault* input;
+
+	int id_to_change;
+	int joystick_count;
+	bool attached_joysticks[JOYSTICKS_MAX];
+	dinput_gamepad d_joysticks[JOYSTICKS_MAX];
+	xinput_gamepad x_joysticks[XUSER_MAX_COUNT];
+
+	static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE* p_instance, void* p_context);
+	static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE* instance, void* context);
+
+	void setup_joystick_object(const DIDEVICEOBJECTINSTANCE* ob, int p_joy_id);
+	void close_joystick(int id = -1);
+	void load_xinput();
+	void unload_xinput();
+
+	int check_free_joy_slot() const;
+	unsigned int post_hat(unsigned int p_last_id, int p_device, DWORD p_dpad);
+
+	bool have_device(const GUID &p_guid);
+	bool is_xinput_device(const GUID* p_guid);
+	bool setup_dinput_joystick(const DIDEVICEINSTANCE* instance);
+
+	InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
+	XInputGetState_t xinput_get_state;
+};
+
+#endif
+
+

+ 8 - 260
platform/windows/os_windows.cpp

@@ -52,6 +52,7 @@
 #include "os/memory_pool_dynamic_prealloc.h"
 #include "globals.h"
 #include "io/marshalls.h"
+#include "joystick.h"
 
 #include "shlobj.h"
 #include <regstr.h>
@@ -682,6 +683,10 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM	wParam,	LPARAM	lParam) {
 		} break;
 
 		#endif
+		case WM_DEVICECHANGE: {
+
+			joystick->probe_joysticks();
+		} break;
 
 		default: {
 
@@ -706,108 +711,6 @@ LRESULT CALLBACK WndProc(HWND	hWnd,UINT uMsg,	WPARAM	wParam,	LPARAM	lParam)	{
 
 }
 
-
-String OS_Windows::get_joystick_name(int id, JOYCAPS jcaps)
-{
-	char buffer [256];
-	char OEM [256];
-	HKEY hKey;
-	DWORD sz;
-	int res;
-
-	_snprintf(buffer, sizeof(buffer), "%s\\%s\\%s",
-				REGSTR_PATH_JOYCONFIG, jcaps.szRegKey,
-				REGSTR_KEY_JOYCURR );
-	res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
-	if (res != ERROR_SUCCESS)
-	{
-		res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
-		if (res != ERROR_SUCCESS) 
-			return "";
-	}
-
-	sz = sizeof(OEM);
-	_snprintf( buffer, sizeof(buffer), "Joystick%d%s", id + 1, REGSTR_VAL_JOYOEMNAME);
-	res = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEM, &sz);
-	RegCloseKey ( hKey );
-	if (res != ERROR_SUCCESS) 
-		return "";
-
-	_snprintf( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEM);
-	res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
-	if (res != ERROR_SUCCESS)
-	{
-		res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
-		if (res != ERROR_SUCCESS)
-			return "";
-	}
-		
-
-	sz = sizeof(buffer);
-	res = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buffer,
-						  &sz);
-	RegCloseKey(hKey);
-	if (res != ERROR_SUCCESS) 
-		return "";
-
-	return String(buffer);
-}
-
-void OS_Windows::probe_joysticks() {
-
-	static uint32_t last_attached = 0;
-
-	int device_count = joyGetNumDevs();
-
-	JOYINFOEX jinfo;
-	jinfo.dwSize = sizeof(JOYINFOEX);
-	jinfo.dwFlags = JOY_RETURNALL;
-
-	for (int i=0; i<JOYSTICKS_MAX; i++) {
-
-		Joystick joy;
-		joy.id = i;
-		joy.attached = (device_count > 0) && (joyGetPosEx(JOYSTICKID1 + i, &jinfo) == JOYERR_NOERROR);
-
-		if (joy.attached == (last_attached & (1 << i) != 0)) {
-			continue;
-		};
-
-		// there's been a change since last call
-
-		if (joy.attached)
-			last_attached = last_attached | (1 << i);
-		else
-			last_attached &= ~(1 << i);
-
-		if (joy.attached) {
-
-			joy.last_buttons = jinfo.dwButtons;
-
-			joy.last_axis[0] = jinfo.dwXpos;
-			joy.last_axis[1] = jinfo.dwYpos;
-			joy.last_axis[2] = jinfo.dwZpos;
-			joy.last_axis[3] = jinfo.dwRpos;
-			joy.last_axis[4] = jinfo.dwUpos;
-			joy.last_axis[5] = jinfo.dwVpos;
-
-			JOYCAPS jcaps;
-			MMRESULT res = joyGetDevCaps(JOYSTICKID1 + i, &jcaps, sizeof(jcaps));
-			if (res == JOYERR_NOERROR) {
-				String name = get_joystick_name(JOYSTICKID1 + i, jcaps);
-				if ( name == "")
-					joy.name = jcaps.szPname;
-				else
-					joy.name = name;
-				
-					
-			};
-		};
-
-		joystick_change_queue.push_back(joy);
-	};
-};
-
 void OS_Windows::process_key_events() {
 
 	for(int i=0;i<key_event_pos;i++) {
@@ -879,154 +782,6 @@ void OS_Windows::process_key_events() {
 	key_event_pos=0;
 }
 
-void OS_Windows::_post_dpad(DWORD p_dpad, int p_device, bool p_pressed) {
-
-	InputEvent ievent;
-	ievent.device = p_device;
-	ievent.type = InputEvent::JOYSTICK_BUTTON;
-	ievent.joy_button.pressed = p_pressed;
-	ievent.joy_button.pressure = p_pressed ? 1.0 : 0.0;
-
-	if (p_dpad == 0) {
-
-		ievent.joy_button.button_index = JOY_DPAD_UP;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 4500) {
-
-		ievent.joy_button.button_index = JOY_DPAD_UP;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-		ievent.joy_button.button_index = JOY_DPAD_RIGHT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 9000) {
-
-		ievent.joy_button.button_index = JOY_DPAD_RIGHT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 13500) {
-
-		ievent.joy_button.button_index = JOY_DPAD_RIGHT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-		ievent.joy_button.button_index = JOY_DPAD_DOWN;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 18000) {
-
-		ievent.joy_button.button_index = JOY_DPAD_DOWN;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 22500) {
-
-		ievent.joy_button.button_index = JOY_DPAD_DOWN;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-		ievent.joy_button.button_index = JOY_DPAD_LEFT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 27000) {
-
-		ievent.joy_button.button_index = JOY_DPAD_LEFT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-	} else if (p_dpad == 31500) {
-
-		ievent.joy_button.button_index = JOY_DPAD_LEFT;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-
-		ievent.joy_button.button_index = JOY_DPAD_UP;
-		ievent.ID = ++last_id;
-		input->parse_input_event(ievent);
-	};
-};
-
-void OS_Windows::process_joysticks() {
-
-	if (!main_loop) {
-		return;
-	};
-
-	InputEvent ievent;
-
-	JOYINFOEX jinfo;
-	jinfo.dwSize = sizeof(JOYINFOEX);
-	jinfo.dwFlags = JOY_RETURNALL;
-
-	for (int i=0; i<JOYSTICKS_MAX; i++) {
-
-		if (!joysticks[i].attached) {
-			continue;
-		};
-
-		if (joyGetPosEx(JOYSTICKID1 + i, &jinfo) != JOYERR_NOERROR) {
-
-			continue;
-		};
-
-		ievent.device = i;
-
-		#define CHECK_AXIS(n, var) \
-			if (joysticks[i].last_axis[n] != var) {\
-				ievent.type = InputEvent::JOYSTICK_MOTION;\
-				ievent.ID = ++last_id;\
-				ievent.joy_motion.axis = n;\
-				ievent.joy_motion.axis_value = (float)((int)var - MAX_JOY_AXIS) / (float)MAX_JOY_AXIS;\
-				joysticks[i].last_axis[n] = var;\
-				input->parse_input_event(ievent);\
-			};
-
-		CHECK_AXIS(0, jinfo.dwXpos);
-		CHECK_AXIS(1, jinfo.dwYpos);
-		CHECK_AXIS(2, jinfo.dwZpos);
-		CHECK_AXIS(3, jinfo.dwRpos);
-		CHECK_AXIS(4, jinfo.dwUpos);
-		CHECK_AXIS(5, jinfo.dwVpos);
-
-		if (joysticks[i].last_pov != jinfo.dwPOV) {
-
-			if (joysticks[i].last_pov != JOY_POVCENTERED)
-				_post_dpad(joysticks[i].last_pov, i, false);
-
-			if (jinfo.dwPOV != JOY_POVCENTERED)
-				_post_dpad(jinfo.dwPOV, i, true);
-
-			joysticks[i].last_pov = jinfo.dwPOV;
-		};
-
-		if (joysticks[i].last_buttons == jinfo.dwButtons) {
-			continue;
-		};
-
-		ievent.type = InputEvent::JOYSTICK_BUTTON;
-		for (int j=0; j<32; j++) {
-
-			if ( (joysticks[i].last_buttons & (1<<j)) != (jinfo.dwButtons & (1<<j)) ) {
-
-				ievent.joy_button.button_index = j; //_pc_joystick_get_native_button(j);
-				ievent.joy_button.pressed = jinfo.dwButtons & 1<<j;
-				ievent.ID = ++last_id;
-				input->parse_input_event(ievent);
-			};
-		};
-
-		joysticks[i].last_buttons = jinfo.dwButtons;
-	};
-};
-
-
 BOOL CALLBACK OS_Windows::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor,  LPARAM dwData) {
 	OS_Windows *self=(OS_Windows*)OS::get_singleton();
 	MonitorInfo minfo;
@@ -1213,6 +968,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
 	visual_server->init();	
 
 	input = memnew( InputDefault );
+	joystick = memnew (joystick_windows(input, &hWnd));
 
 	AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
 
@@ -1231,14 +987,6 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
 	spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
 	spatial_sound_2d_server->init();
 
-	probe_joysticks(); // todo: move this to a thread
-	while (joystick_change_queue.size() > 0) {
-		Joystick joy = joystick_change_queue.front()->get();
-		joystick_change_queue.pop_front();
-		joysticks[joy.id] = joy;
-		input->joy_connection_changed(joy.id, joy.attached, joy.name);
-	};
-
 	TRACKMOUSEEVENT tme;
 	tme.cbSize=sizeof(TRACKMOUSEEVENT);
 	tme.dwFlags=TME_LEAVE;
@@ -1351,6 +1099,7 @@ void OS_Windows::finalize() {
 
 	main_loop=NULL;
 
+	memdelete(joystick);
 	memdelete(input);
 
 	visual_server->finish();
@@ -1386,7 +1135,6 @@ void OS_Windows::finalize() {
 	physics_2d_server->finish();
 	memdelete(physics_2d_server);
 
-	joystick_change_queue.clear();
 	monitor_info.clear();
 
 }
@@ -1967,7 +1715,7 @@ void OS_Windows::process_events() {
 
 	MSG msg;
 
-	process_joysticks();
+	last_id = joystick->process_joysticks(last_id);
 	
 	while(PeekMessageW(&msg,NULL,0,0,PM_REMOVE)) {
 

+ 4 - 37
platform/windows/os_windows.h

@@ -60,13 +60,11 @@
 /**
 	@author Juan Linietsky <[email protected]>
 */
+class joystick_windows;
 class OS_Windows : public OS {
 
-	enum {
-		JOYSTICKS_MAX = 8,
-		JOY_AXIS_COUNT = 6,
-		MAX_JOY_AXIS = 32768, // I've no idea
-		KEY_EVENT_BUFFER_SIZE=512
+        enum {
+            KEY_EVENT_BUFFER_SIZE=512
 	};
 
 	FILE *stdo;
@@ -106,32 +104,6 @@ class OS_Windows : public OS {
 	HINSTANCE	hInstance;		// Holds The Instance Of The Application
 	HWND hWnd;
 
-	struct Joystick {
-
-		int id;
-		bool attached;
-
-		DWORD last_axis[JOY_AXIS_COUNT];
-		DWORD last_buttons;
-		DWORD last_pov;
-		String name;
-
-		Joystick() {
-			id = -1;
-			attached = false;
-			for (int i=0; i<JOY_AXIS_COUNT; i++) {
-
-				last_axis[i] = 0;
-			};
-			last_buttons = 0;
-			last_pov = 0;
-		};
-	};
-
-	List<Joystick> joystick_change_queue;
-	int joystick_count;
-	Joystick joysticks[JOYSTICKS_MAX];
-	
 	Size2 window_rect;
 	VideoMode video_mode;
 
@@ -156,13 +128,12 @@ class OS_Windows : public OS {
 	CursorShape cursor_shape;
 
 	InputDefault *input;
+	joystick_windows *joystick;
 
 #ifdef RTAUDIO_ENABLED
 	AudioDriverRtAudio driver_rtaudio;
 #endif
 
-	void _post_dpad(DWORD p_dpad, int p_device, bool p_pressed);
-
 	void _drag_event(int p_x, int p_y, int idx);
 	void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
 
@@ -186,11 +157,7 @@ protected:
 	virtual void finalize_core();
 	
 	void process_events();
-
-	void probe_joysticks();
-	void process_joysticks();
 	void process_key_events();
-	String get_joystick_name( int id, JOYCAPS jcaps);
 	
 	struct ProcessInfo {
 

+ 1 - 0
platform/x11/SCsub

@@ -5,6 +5,7 @@ common_x11=[\
 	"context_gl_x11.cpp",\
 	"os_x11.cpp",\
 	"key_mapping_x11.cpp",\
+	"joystick_linux.cpp",\
 ]
 
 env.Program('#bin/godot',['godot_x11.cpp']+common_x11)

+ 1 - 1
platform/x11/detect.py

@@ -150,7 +150,7 @@ def configure(env):
 	env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
 	if platform.system() == 'Linux':
 		env.Append(CPPFLAGS=["-DALSA_ENABLED"])
-		env.Append(LIBS=['asound'])
+		env.Append(LIBS=['asound', 'evdev', 'udev'])
 
 	if (env["pulseaudio"]=="yes"):
 		if not os.system("pkg-config --exists libpulse-simple"):

+ 402 - 0
platform/x11/joystick_linux.cpp

@@ -0,0 +1,402 @@
+/*************************************************************************/
+/*  joystick_linux.cpp                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+//author: Andreas Haas <hondres,  [email protected]>
+#ifdef __linux__
+
+#include "joystick_linux.h"
+#include "print_string.h"
+
+#include <libevdev-1.0/libevdev/libevdev.h>
+#include <libudev.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cstring>
+
+static const char* ignore_str = "/dev/input/js";
+
+joystick_linux::Joystick::Joystick() {
+	fd = -1;
+	dpad = 0;
+}
+
+void joystick_linux::Joystick::reset() {
+	num_buttons = 0;
+	num_axes    = 0;
+	dpad        = 0;
+	fd          = -1;
+	for (int i=0; i < MAX_ABS; i++) {
+		abs_map[i] = -1;
+	}
+}
+
+joystick_linux::joystick_linux(InputDefault *in)
+{
+	exit_udev = false;
+	input = in;
+	joy_mutex = Mutex::create();
+	joy_thread = Thread::create(joy_thread_func, this);
+}
+
+joystick_linux::~joystick_linux() {
+	exit_udev = true;
+	Thread::wait_to_finish(joy_thread);
+	close_joystick();
+}
+
+void joystick_linux::joy_thread_func(void *p_user) {
+
+	if (p_user) {
+		joystick_linux* joy = (joystick_linux*) p_user;
+		joy->run_joystick_thread();
+	}
+	return;
+}
+
+void joystick_linux::run_joystick_thread() {
+
+	udev *_udev = udev_new();
+	ERR_FAIL_COND(!_udev);
+	enumerate_joysticks(_udev);
+	monitor_joysticks(_udev);
+	udev_unref(_udev);
+}
+
+void joystick_linux::enumerate_joysticks(udev *p_udev) {
+
+	udev_enumerate *enumerate;
+	udev_list_entry *devices, *dev_list_entry;
+	udev_device *dev;
+
+	enumerate = udev_enumerate_new(p_udev);
+	udev_enumerate_add_match_subsystem(enumerate,"input");
+	udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");
+
+	udev_enumerate_scan_devices(enumerate);
+	devices = udev_enumerate_get_list_entry(enumerate);
+	udev_list_entry_foreach(dev_list_entry, devices) {
+
+		const char* path = udev_list_entry_get_name(dev_list_entry);
+		dev = udev_device_new_from_syspath(p_udev, path);
+		const char* devnode = udev_device_get_devnode(dev);
+
+		if (devnode != NULL && strstr(devnode, ignore_str) == NULL) {
+			joy_mutex->lock();
+			open_joystick(devnode);
+			joy_mutex->unlock();
+		}
+		udev_device_unref(dev);
+	}
+	udev_enumerate_unref(enumerate);
+}
+
+void joystick_linux::monitor_joysticks(udev *p_udev) {
+
+	udev_device *dev = NULL;
+	udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
+	udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
+	udev_monitor_enable_receiving(mon);
+	int fd = udev_monitor_get_fd(mon);
+
+	while (!exit_udev) {
+
+		fd_set fds;
+		struct timeval tv;
+		int ret;
+
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds);
+		tv.tv_sec = 0;
+		tv.tv_usec = 0;
+
+		ret = select(fd+1, &fds, NULL, NULL, &tv);
+
+		/* Check if our file descriptor has received data. */
+		if (ret > 0 && FD_ISSET(fd, &fds)) {
+			/* Make the call to receive the device.
+					   select() ensured that this will not block. */
+			dev = udev_monitor_receive_device(mon);
+
+			if (dev && udev_device_get_devnode(dev) != 0) {
+
+				joy_mutex->lock();
+				const char* action = udev_device_get_action(dev);
+				const char* devnode = udev_device_get_devnode(dev);
+
+				if (strstr(devnode, ignore_str) == NULL) {
+
+					if (strcmp(action, "add") == 0)
+						open_joystick(devnode);
+
+					else if (strcmp(action, "remove") == 0)
+						close_joystick(get_joy_from_path(devnode));
+				}
+
+				udev_device_unref(dev);
+				joy_mutex->unlock();
+			}
+		}
+		usleep(50000);
+	}
+	//printf("exit udev\n");
+	udev_monitor_unref(mon);
+}
+
+int joystick_linux::get_free_joy_slot() const {
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+		if (joysticks[i].fd == -1) return i;
+	}
+	return -1;
+}
+
+int joystick_linux::get_joy_from_path(String p_path) const {
+
+	for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+		if (joysticks[i].devpath == p_path) {
+			return i;
+		}
+	}
+	return -2;
+}
+
+void joystick_linux::close_joystick(int p_id) {
+	if (p_id == -1) {
+		for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+			close_joystick(i);
+		};
+		return;
+	}
+	else if (p_id < 0) return;
+
+	Joystick &joy = joysticks[p_id];
+
+	if (joy.fd != -1) {
+
+		libevdev_free(joy.dev);
+		close(joy.fd);
+		joy.fd = -1;
+		input->joy_connection_changed(p_id, false, "");
+	};
+};
+
+static String _hex_str(uint8_t p_byte) {
+
+	static const char* dict = "0123456789abcdef";
+	char ret[3];
+	ret[2] = 0;
+
+	ret[0] = dict[p_byte>>4];
+	ret[1] = dict[p_byte & 0xF];
+
+	return ret;
+};
+
+void joystick_linux::setup_joystick_properties(int p_id) {
+
+	Joystick* joy = &joysticks[p_id];
+
+	libevdev* dev = joy->dev;
+	for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
+
+		if (libevdev_has_event_code(dev, EV_KEY, i)) {
+
+			joy->key_map[i] = joy->num_buttons++;
+		}
+	}
+	for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
+
+		if (libevdev_has_event_code(dev, EV_KEY, i)) {
+
+			joy->key_map[i] = joy->num_buttons++;
+		}
+	}
+	for (int i = 0; i < ABS_MISC; ++i) {
+		/* Skip hats */
+		if (i == ABS_HAT0X) {
+			i = ABS_HAT3Y;
+			continue;
+		}
+		if (libevdev_has_event_code(dev, EV_ABS, i)) {
+
+			joy->abs_map[i] = joy->num_axes++;
+		}
+	}
+}
+
+void joystick_linux::open_joystick(const char *p_path) {
+
+	int joy_num = get_free_joy_slot();
+	int fd = open(p_path, O_RDONLY | O_NONBLOCK);
+	if (fd != -1 && joy_num != -1) {
+
+		int rc = libevdev_new_from_fd(fd, &joysticks[joy_num].dev);
+		if (rc < 0) {
+
+			fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
+			return;
+		}
+
+		libevdev *dev = joysticks[joy_num].dev;
+
+		//check if the device supports basic gamepad events, prevents certain keyboards from
+		//being detected as joysticks
+		if (libevdev_has_event_type(dev, EV_ABS) && libevdev_has_event_type(dev, EV_KEY) &&
+				(libevdev_has_event_code(dev, EV_KEY, BTN_A) || libevdev_has_event_code(dev, EV_KEY, BTN_THUMBL) || libevdev_has_event_code(dev, EV_KEY, BTN_TOP))) {
+
+			char uid[128];
+			String name = libevdev_get_name(dev);
+			uint16_t bus = __bswap_16(libevdev_get_id_bustype(dev));
+			uint16_t vendor = __bswap_16(libevdev_get_id_vendor(dev));
+			uint16_t product = __bswap_16(libevdev_get_id_product(dev));
+			uint16_t version = __bswap_16(libevdev_get_id_version(dev));
+
+			joysticks[joy_num].reset();
+
+			Joystick &joy = joysticks[joy_num];
+			joy.fd = fd;
+			joy.devpath = String(p_path);
+			setup_joystick_properties(joy_num);
+			sprintf(uid, "%04x%04x", bus, 0);
+			if (vendor && product && version) {
+
+				sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor,0,product,0,version,0);
+				input->joy_connection_changed(joy_num, true, name, uid);
+			}
+			else {
+				String uidname = uid;
+				int uidlen = MIN(name.length(), 11);
+				for (int i=0; i<uidlen; i++) {
+
+					uidname = uidname + _hex_str(name[i]);
+				}
+				uidname += "00";
+				input->joy_connection_changed(joy_num, true, name, uidname);
+
+			}
+		}
+		else {
+			//device is not a gamepad, clean up
+			libevdev_free(dev);
+			close(fd);
+		}
+	}
+}
+
+InputDefault::JoyAxis joystick_linux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+
+	int min = p_abs->minimum;
+	int max = p_abs->maximum;
+	InputDefault::JoyAxis jx;
+
+	if (min < 0) {
+		jx.min = -1;
+		if (p_value < 0) {
+			jx.value = (float) -p_value / min;
+		}
+		jx.value = (float) p_value / max;
+	}
+	if (min == 0) {
+		jx.min = 0;
+		jx.value = 0.0f + (float) p_value / max;
+	}
+	return jx;
+}
+
+uint32_t joystick_linux::process_joysticks(uint32_t p_event_id) {
+
+	if (joy_mutex->try_lock() != OK) {
+		return p_event_id;
+	}
+	for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+		if (joysticks[i].fd == -1) continue;
+
+		input_event ev;
+		Joystick* joy = &joysticks[i];
+		libevdev* dev = joy->dev;
+		int rc = 1;
+
+		rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+
+		if (rc < 0 && rc != -EAGAIN) {
+			continue;
+		}
+
+		while (rc == LIBEVDEV_READ_STATUS_SYNC || rc == LIBEVDEV_READ_STATUS_SUCCESS) {
+
+			switch (ev.type) {
+			case EV_KEY:
+				p_event_id = input->joy_button(p_event_id, i, joy->key_map[ev.code], ev.value);
+				break;
+
+			case EV_ABS:
+
+				switch (ev.code) {
+				case ABS_HAT0X:
+					if (ev.value != 0) {
+						if (ev.value < 0) joy->dpad |= InputDefault::HAT_MASK_LEFT;
+						else              joy->dpad |= InputDefault::HAT_MASK_RIGHT;
+
+					}
+					else joy->dpad &= ~(InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_RIGHT);
+
+					p_event_id = input->joy_hat(p_event_id, i, joy->dpad);
+					break;
+
+				case ABS_HAT0Y:
+					if (ev.value != 0) {
+						if (ev.value < 0) joy->dpad |= InputDefault::HAT_MASK_UP;
+						else              joy->dpad |= InputDefault::HAT_MASK_DOWN;
+					}
+					else joy->dpad &= ~(InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_DOWN);
+
+					p_event_id = input->joy_hat(p_event_id, i, joy->dpad);
+					break;
+
+				default:
+					if (joy->abs_map[ev.code] != -1) {
+						InputDefault::JoyAxis value = axis_correct(libevdev_get_abs_info(dev, ev.code), ev.value);
+						p_event_id = input->joy_axis(p_event_id, i, joy->abs_map[ev.code], value);
+					}
+					break;
+				}
+				break;
+			}
+			rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+		}
+	}
+	joy_mutex->unlock();
+	return p_event_id;
+}
+#endif

+ 93 - 0
platform/x11/joystick_linux.h

@@ -0,0 +1,93 @@
+/*************************************************************************/
+/*  joystick_linux.h                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+//author: Andreas Haas <hondres,  [email protected]>
+#ifndef JOYSTICK_LINUX_H
+#define JOYSTICK_LINUX_H
+#ifdef __linux__
+#include "main/input_default.h"
+#include "os/thread.h"
+#include "os/mutex.h"
+
+struct input_absinfo;
+
+class joystick_linux
+{
+public:
+	joystick_linux(InputDefault *in);
+	~joystick_linux();
+	uint32_t process_joysticks(uint32_t p_event_id);
+private:
+
+	enum {
+		JOYSTICKS_MAX = 16,
+		MAX_ABS = 63,
+		MAX_KEY = 767,   // Hack because <linux/input.h> can't be included here
+		BT_MISC = 256,
+		HAT_MAX = 4,
+	};
+
+	struct Joystick {
+		int key_map[MAX_KEY - BT_MISC];
+		int abs_map[MAX_ABS];
+		int num_buttons;
+		int num_axes;
+		int dpad;
+		int fd;
+
+		String devpath;
+		struct libevdev *dev;
+
+		Joystick();
+		void reset();
+	};
+
+	bool exit_udev;
+	Mutex *joy_mutex;
+	Thread *joy_thread;
+	InputDefault *input;
+	Joystick joysticks[JOYSTICKS_MAX];
+
+	static void joy_thread_func(void *p_user);
+
+	int get_joy_from_path(String path) const;
+	int get_free_joy_slot() const;
+
+	void setup_joystick_properties(int p_id);
+	void close_joystick(int p_id = -1);
+	void enumerate_joysticks(struct udev *_udev);
+	void monitor_joysticks(struct udev *_udev);
+	void run_joystick_thread();
+	void open_joystick(const char* path);
+
+	InputDefault::JoyAxis axis_correct(const input_absinfo *abs, int value) const;
+};
+
+#endif
+#endif // JOYSTICK_LINUX_H

+ 9 - 193
platform/x11/os_x11.cpp

@@ -58,10 +58,6 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#ifdef __linux__
-#include <linux/joystick.h>
-#endif
-
 //stupid linux.h
 #ifdef KEY_TAB
 #undef KEY_TAB
@@ -99,8 +95,6 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
 void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
 
 	last_button_state=0;
-	dpad_last[0]=0;
-	dpad_last[1]=0;
 
 	xmbstring=NULL;
 	event_id=0;
@@ -432,9 +426,9 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 	physics_2d_server->init();
 
 	input = memnew( InputDefault );
-
-	probe_joystick();
-
+#ifdef __linux__
+	joystick = memnew( joystick_linux(input));
+#endif
 	_ensure_data_dir();
 }
 
@@ -467,7 +461,9 @@ void OS_X11::finalize() {
 
 	physics_2d_server->finish();
 	memdelete(physics_2d_server);
-
+#ifdef __linux__
+	memdelete(joystick);
+#endif
 	memdelete(input);
 
 	XUnmapWindow( x11_display, x11_window );
@@ -1653,193 +1649,11 @@ String OS_X11::get_system_dir(SystemDir p_dir) const {
 	return pipe.strip_edges();
 }
 
-
-void OS_X11::close_joystick(int p_id) {
-
-	if (p_id == -1) {
-		for (int i=0; i<JOYSTICKS_MAX; i++) {
-
-			close_joystick(i);
-		};
-		return;
-	};
-
-
-	if (joysticks[p_id].fd != -1) {
-		close(joysticks[p_id].fd);
-		joysticks[p_id].fd = -1;
-	};
-	input->joy_connection_changed(p_id, false, "");
-};
-
-void OS_X11::probe_joystick(int p_id) {
-	#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
-
-	if (p_id == -1) {
-
-		for (int i=0; i<JOYSTICKS_MAX; i++) {
-
-			probe_joystick(i);
-		};
-		return;
-	};
-
-	if (joysticks[p_id].fd != -1)
-		close_joystick(p_id);
-
-	const char *joy_names[] = {
-		"/dev/input/js%d",
-		"/dev/js%d",
-		NULL
-	};
-
-	int i=0;
-	while(joy_names[i]) {
-
-		char fname[64];
-		sprintf(fname, joy_names[i], p_id);
-		int fd = open(fname, O_RDONLY|O_NONBLOCK);
-		if (fd != -1) {
-
-			//fcntl( fd, F_SETFL, O_NONBLOCK );
-			joysticks[p_id] = Joystick(); // this will reset the axis array
-			joysticks[p_id].fd = fd;
-
-			String name;
-			char namebuf[255] = {0};
-			if (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) >= 0) {
-				name = namebuf;
-			} else {
-				name = "error";
-			};
-
-			input->joy_connection_changed(p_id, true, name);
-			break; // don't try the next name
-		};
-
-		++i;
-	};
-	#endif
-};
-
 void OS_X11::move_window_to_foreground() {
 
 	XRaiseWindow(x11_display,x11_window);
 }
 
-void OS_X11::process_joysticks() {
-	#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
-	int bytes;
-	js_event events[32];
-	InputEvent ievent;
-	for (int i=0; i<JOYSTICKS_MAX; i++) {
-
-		if (joysticks[i].fd == -1) {
-			probe_joystick(i);
-			if (joysticks[i].fd == -1)
-				continue;
-		};
-		ievent.device = i;
-
-		while ( (bytes = read(joysticks[i].fd, &events, sizeof(events))) > 0) {
-
-			int ev_count = bytes / sizeof(js_event);
-			for (int j=0; j<ev_count; j++) {
-
-				js_event& event = events[j];
-
-				//printf("got event on joystick %i, %i, %i, %i, %i\n", i, joysticks[i].fd, event.type, event.number, event.value);
-				if (event.type & JS_EVENT_INIT)
-					continue;
-
-				switch (event.type & ~JS_EVENT_INIT) {
-
-				case JS_EVENT_AXIS:
-
-					//if (joysticks[i].last_axis[event.number] != event.value) {
-
-						/*
-						if (event.number==5 || event.number==6) {
-
-							int axis=event.number-5;
-							int val = event.value;
-							if (val<0)
-								val=-1;
-							if (val>0)
-								val=+1;
-
-							InputEvent ev;
-							ev.type = InputEvent::JOYSTICK_BUTTON;
-							ev.ID = ++event_id;
-
-
-							if (val!=dpad_last[axis]) {
-
-								int prev_val = dpad_last[axis];
-								if (prev_val!=0) {
-
-									ev.joy_button.pressed=false;
-									ev.joy_button.pressure=0.0;
-									if (event.number==5)
-										ev.joy_button.button_index=JOY_DPAD_LEFT+(prev_val+1)/2;
-									if (event.number==6)
-										ev.joy_button.button_index=JOY_DPAD_UP+(prev_val+1)/2;
-
-									input->parse_input_event( ev );
-								}
-							}
-
-							if (val!=0) {
-
-								ev.joy_button.pressed=true;
-								ev.joy_button.pressure=1.0;
-								if (event.number==5)
-									ev.joy_button.button_index=JOY_DPAD_LEFT+(val+1)/2;
-								if (event.number==6)
-									ev.joy_button.button_index=JOY_DPAD_UP+(val+1)/2;
-
-								input->parse_input_event( ev );
-							}
-
-
-							dpad_last[axis]=val;
-
-						}
-						*/
-						//print_line("ev: "+itos(event.number)+" val: "+ rtos((float)event.value / (float)MAX_JOY_AXIS));
-						//if (event.number >= JOY_AXIS_MAX)
-						//	break;
-						//ERR_FAIL_COND(event.number >= JOY_AXIS_MAX);
-						ievent.type = InputEvent::JOYSTICK_MOTION;
-						ievent.ID = ++event_id;
-						ievent.joy_motion.axis = event.number; //_pc_joystick_get_native_axis(event.number);
-						ievent.joy_motion.axis_value = (float)event.value / (float)MAX_JOY_AXIS;
-						if (event.number < JOY_AXIS_MAX)
-							joysticks[i].last_axis[event.number] = event.value;
-						input->parse_input_event( ievent );
-					//};
-					break;
-
-				case JS_EVENT_BUTTON:
-
-
-					ievent.type = InputEvent::JOYSTICK_BUTTON;
-					ievent.ID = ++event_id;
-					ievent.joy_button.button_index = event.number; // _pc_joystick_get_native_button(event.number);
-					ievent.joy_button.pressed = event.value;
-					input->parse_input_event( ievent );
-					break;
-				};
-			};
-		};
-		if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
-			close_joystick(i);
-		};
-	};
-	#endif
-};
-
-
 void OS_X11::set_cursor_shape(CursorShape p_shape) {
 
 	ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
@@ -1939,7 +1753,9 @@ void OS_X11::run() {
 	while (!force_quit) {
 	
 		process_xevents(); // get rid of pending events
-		process_joysticks();
+#ifdef __linux__
+		event_id = joystick->process_joysticks(event_id);
+#endif
 		if (Main::iteration()==true)
 			break;
 	};

+ 6 - 25
platform/x11/os_x11.h

@@ -47,6 +47,7 @@
 #include "servers/physics_2d/physics_2d_server_sw.h"
 #include "servers/physics_2d/physics_2d_server_wrap_mt.h"
 #include "main/input_default.h"
+#include "joystick_linux.h"
 
 #include <X11/keysym.h>
 #include <X11/Xlib.h>
@@ -113,7 +114,6 @@ class OS_X11 : public OS_Unix {
 
 	bool force_quit;
 	bool minimized;
-	int dpad_last[2];
 
 	bool do_mouse_warp;
 
@@ -126,6 +126,10 @@ class OS_X11 : public OS_Unix {
 
 	InputDefault *input;
 
+#ifdef __linux__
+	joystick_linux *joystick;
+#endif
+
 #ifdef RTAUDIO_ENABLED
 	AudioDriverRtAudio driver_rtaudio;
 #endif
@@ -138,26 +142,7 @@ class OS_X11 : public OS_Unix {
 	AudioDriverPulseAudio driver_pulseaudio;
 #endif
 
-	enum {
-		JOYSTICKS_MAX = 8,
-		MAX_JOY_AXIS = 32768, // I've no idea
-	};
-
-	struct Joystick {
-
-		int fd;
-		int last_axis[JOY_AXIS_MAX];
-
-		Joystick() {
-			fd = -1;
-			for (int i=0; i<JOY_AXIS_MAX; i++) {
-
-				last_axis[i] = 0;
-			};
-		};
-	};
-	int joystick_count;
-	Joystick joysticks[JOYSTICKS_MAX];
+	Atom net_wm_icon;
 
 	int audio_driver_index;
 	unsigned int capture_idle;
@@ -180,10 +165,6 @@ protected:
 
 	virtual void set_main_loop( MainLoop * p_main_loop );    
 
-	void probe_joystick(int p_id = -1);
-	void process_joysticks();
-	void close_joystick(int p_id = -1);
-
 
 public:
 

+ 2 - 1
servers/audio/audio_server_sw.cpp

@@ -763,9 +763,10 @@ void AudioServerSW::free(RID p_id) {
 
 void AudioServerSW::_thread_func(void *self) {
 
-
 	AudioServerSW *as=(AudioServerSW *)self;
 
+	as->thread->set_name("AudioServerSW");
+
 	while (!as->exit_update_thread) {
 		as->_update_streams(true);
 		OS::get_singleton()->delay_usec(5000);

+ 1 - 4
tools/editor/editor_import_export.cpp

@@ -1128,10 +1128,7 @@ Error EditorExportPlatform::save_zip(const String& p_path, bool p_make_bundles)
 
 	zipClose(zip,NULL);
 
-	if (err)
-		return err;
-
-
+	return err;
 }
 
 Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles, int p_alignment) {

+ 1 - 1
tools/editor/plugins/script_editor_plugin.cpp

@@ -1773,7 +1773,7 @@ void ScriptEditor::_update_script_colors() {
 		if (h>hist_size) {
 			continue;
 		}
-		float v = Math::ease((edit_pass-pass)/float_t(hist_size),0.4);
+		float v = Math::ease((edit_pass-pass)/float(hist_size),0.4);
 
 
 		script_list->set_item_custom_bg_color(i,hot_color.linear_interpolate(cold_color,v));