Merge branch 'upstream' into tizen
[platform/upstream/libpng.git] / pngwrite.c
index 59377a4..8e13163 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -75,10 +75,10 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,
  * library.  If you have a new chunk to add, make a function to write it,
  * and put it in the correct location here.  If you want the chunk written
  * after the image data, put it in png_write_end().  I strongly encourage
- * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
- * the chunk, as that will keep the code from breaking if you want to just
- * write a plain PNG file.  If you have long comments, I suggest writing
- * them in png_write_end(), and compressing them.
+ * you to supply a PNG_INFO_<chunk> flag, and check info_ptr->valid before
+ * writing the chunk, as that will keep the code from breaking if you want
+ * to just write a plain PNG file.  If you have long comments, I suggest
+ * writing them in png_write_end(), and compressing them.
  */
 void PNGAPI
 png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
@@ -128,6 +128,10 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
        * the application continues writing the PNG.  So check the 'invalid'
        * flag here too.
        */
+#ifdef PNG_WRITE_APNG_SUPPORTED
+      if (info_ptr->valid & PNG_INFO_acTL)
+         png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
+#endif
 #ifdef PNG_GAMMA_SUPPORTED
 #  ifdef PNG_WRITE_gAMA_SUPPORTED
       if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
@@ -239,7 +243,10 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
 
 #ifdef PNG_WRITE_eXIf_SUPPORTED
    if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+   {
       png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+      png_ptr->mode |= PNG_WROTE_eXIf;
+   }
 #endif
 
 #ifdef PNG_WRITE_hIST_SUPPORTED
@@ -370,6 +377,11 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
       png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
 #endif
 
+#ifdef PNG_WRITE_APNG_SUPPORTED
+   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
+      png_error(png_ptr, "Not enough frames written");
+#endif
+
    /* See if user wants us to write information chunks */
    if (info_ptr != NULL)
    {
@@ -439,8 +451,9 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
 #endif
 
 #ifdef PNG_WRITE_eXIf_SUPPORTED
-   if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
-      png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+      if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
+          (png_ptr->mode & PNG_WROTE_eXIf) == 0)
+         png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
 #endif
 
 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
@@ -489,6 +502,16 @@ png_convert_from_time_t(png_timep ptime, time_t ttime)
    png_debug(1, "in png_convert_from_time_t");
 
    tbuf = gmtime(&ttime);
+   if (tbuf == NULL)
+   {
+      /* TODO: add a safe function which takes a png_ptr argument and raises
+       * a png_error if the ttime argument is invalid and the call to gmtime
+       * fails as a consequence.
+       */
+      memset(ptime, 0, sizeof(*ptime));
+      return;
+   }
+
    png_convert_from_struct_tm(ptime, tbuf);
 }
 #endif
@@ -1020,10 +1043,38 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
          case 7: png_app_error(png_ptr, "Unknown row filter for method 0");
 #endif /* WRITE_FILTER */
             /* FALLTHROUGH */
+#ifdef __TIZEN__
+            /* 'switch ~ case' is dead code.
+             * If filters is #PNG_FILTER_VALUE_NONE, #PNG_FILTER_VALUE_SUB ...,
+             * filter flag will be assigned to 'png_ptr->do_filter'. But
+             * 'png_ptr->do_filter' is overwritten as 'filters' at below code.
+             * Issue code(#1155) is 'png_ptr->do_filter = (png_byte)filters;'.
+             * So the result of 'switch ~ case' has been lost at the line.
+             * To keep the value of 'switch ~ case', we fixed it to apply
+             * the result into 'filters'.
+             * It will be updated into 'png_ptr->do_filter' at #1155 line.
+             */
+         case PNG_FILTER_VALUE_NONE:
+            filters = PNG_FILTER_NONE; break;
+#else
          case PNG_FILTER_VALUE_NONE:
             png_ptr->do_filter = PNG_FILTER_NONE; break;
+#endif /* __TIZEN__ */
 
 #ifdef PNG_WRITE_FILTER_SUPPORTED
+#ifdef __TIZEN__
+         case PNG_FILTER_VALUE_SUB:
+            filters = PNG_FILTER_SUB; break;
+
+         case PNG_FILTER_VALUE_UP:
+            filters = PNG_FILTER_UP; break;
+
+         case PNG_FILTER_VALUE_AVG:
+            filters = PNG_FILTER_AVG; break;
+
+         case PNG_FILTER_VALUE_PAETH:
+            filters = PNG_FILTER_PAETH; break;
+#else
          case PNG_FILTER_VALUE_SUB:
             png_ptr->do_filter = PNG_FILTER_SUB; break;
 
@@ -1035,7 +1086,7 @@ png_set_filter(png_structrp png_ptr, int method, int filters)
 
          case PNG_FILTER_VALUE_PAETH:
             png_ptr->do_filter = PNG_FILTER_PAETH; break;
-
+#endif /* __TIZEN__ */
          default:
             png_ptr->do_filter = (png_byte)filters; break;
 #else
@@ -1461,6 +1512,43 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
 }
 #endif
 
+#ifdef PNG_WRITE_APNG_SUPPORTED
+void PNGAPI
+png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
+    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
+    png_uint_32 x_offset, png_uint_32 y_offset,
+    png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
+    png_byte blend_op)
+{
+    png_debug(1, "in png_write_frame_head");
+
+    /* there is a chance this has been set after png_write_info was called,
+    * so it would be set but not written. is there a way to be sure? */
+    if (!(info_ptr->valid & PNG_INFO_acTL))
+        png_error(png_ptr, "png_write_frame_head(): acTL not set");
+
+    png_write_reset(png_ptr);
+
+    png_write_reinit(png_ptr, info_ptr, width, height);
+
+    if ( !(png_ptr->num_frames_written == 0 &&
+           (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
+        png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
+                       delay_num, delay_den, dispose_op, blend_op);
+
+    PNG_UNUSED(row_pointers)
+}
+
+void PNGAPI
+png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
+{
+    png_debug(1, "in png_write_frame_tail");
+
+    png_ptr->num_frames_written++;
+
+    PNG_UNUSED(info_ptr)
+}
+#endif /* PNG_WRITE_APNG_SUPPORTED */
 
 #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
 /* Initialize the write structure - general purpose utility. */