remove aarch64 for neon check
[platform/upstream/libpng.git] / pngrutil.c
index c190e10..86bc392 100644 (file)
@@ -868,6 +868,11 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
    filter_type = buf[11];
    interlace_type = buf[12];
 
+#ifdef PNG_READ_APNG_SUPPORTED
+   png_ptr->first_frame_width = width;
+   png_ptr->first_frame_height = height;
+#endif
+
    /* Set internal variables */
    png_ptr->width = width;
    png_ptr->height = height;
@@ -2860,6 +2865,179 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 }
 #endif
 
+#ifdef PNG_READ_APNG_SUPPORTED
+void /* PRIVATE */
+png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    png_byte data[8];
+    png_uint_32 num_frames;
+    png_uint_32 num_plays;
+    png_uint_32 didSet;
+
+    png_debug(1, "in png_handle_acTL");
+
+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
+    {
+        png_error(png_ptr, "Missing IHDR before acTL");
+    }
+    else if (png_ptr->mode & PNG_HAVE_IDAT)
+    {
+        png_warning(png_ptr, "Invalid acTL after IDAT skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (png_ptr->mode & PNG_HAVE_acTL)
+    {
+        png_warning(png_ptr, "Duplicate acTL skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+    else if (length != 8)
+    {
+        png_warning(png_ptr, "acTL with invalid length skipped");
+        png_crc_finish(png_ptr, length);
+        return;
+    }
+
+    png_crc_read(png_ptr, data, 8);
+    png_crc_finish(png_ptr, 0);
+
+    num_frames = png_get_uint_31(png_ptr, data);
+    num_plays = png_get_uint_31(png_ptr, data + 4);
+
+    /* the set function will do error checking on num_frames */
+    didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
+    if(didSet)
+        png_ptr->mode |= PNG_HAVE_acTL;
+}
+
+void /* PRIVATE */
+png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    png_byte data[22];
+    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_handle_fcTL");
+
+    png_ensure_sequence_number(png_ptr, length);
+
+    if (!(png_ptr->mode & PNG_HAVE_IHDR))
+    {
+        png_error(png_ptr, "Missing IHDR before fcTL");
+    }
+    else if (png_ptr->mode & PNG_HAVE_IDAT)
+    {
+        /* for any frames other then the first this message may be misleading,
+        * but correct. PNG_HAVE_IDAT is unset before the frame head is read
+        * i can't think of a better message */
+        png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
+        png_crc_finish(png_ptr, length-4);
+        return;
+    }
+    else if (png_ptr->mode & PNG_HAVE_fcTL)
+    {
+        png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
+        png_crc_finish(png_ptr, length-4);
+        return;
+    }
+    else if (length != 26)
+    {
+        png_warning(png_ptr, "fcTL with invalid length skipped");
+        png_crc_finish(png_ptr, length-4);
+        return;
+    }
+
+    png_crc_read(png_ptr, data, 22);
+    png_crc_finish(png_ptr, 0);
+
+    width = png_get_uint_31(png_ptr, data);
+    height = png_get_uint_31(png_ptr, data + 4);
+    x_offset = png_get_uint_31(png_ptr, data + 8);
+    y_offset = png_get_uint_31(png_ptr, data + 12);
+    delay_num = png_get_uint_16(data + 16);
+    delay_den = png_get_uint_16(data + 18);
+    dispose_op = data[20];
+    blend_op = data[21];
+
+    if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
+    {
+        png_warning(png_ptr, "fcTL for the first frame must have zero offset");
+        return;
+    }
+
+    if (info_ptr != NULL)
+    {
+        if (png_ptr->num_frames_read == 0 &&
+            (width != info_ptr->width || height != info_ptr->height))
+        {
+            png_warning(png_ptr, "size in first frame's fcTL must match "
+                               "the size in IHDR");
+            return;
+        }
+
+        /* The set function will do more error checking */
+        png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
+                                x_offset, y_offset, delay_num, delay_den,
+                                dispose_op, blend_op);
+
+        png_read_reinit(png_ptr, info_ptr);
+
+        png_ptr->mode |= PNG_HAVE_fcTL;
+    }
+}
+
+void /* PRIVATE */
+png_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+    if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
+    {
+        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
+        info_ptr->num_frames++;
+    }
+}
+
+void /* PRIVATE */
+png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+    png_ensure_sequence_number(png_ptr, length);
+
+    /* This function is only called from png_read_end(), png_read_info(),
+    * and png_push_read_chunk() which means that:
+    * - the user doesn't want to read this frame
+    * - or this is an out-of-place fdAT
+    * in either case it is safe to ignore the chunk with a warning */
+    png_warning(png_ptr, "ignoring fdAT chunk");
+    png_crc_finish(png_ptr, length - 4);
+    PNG_UNUSED(info_ptr)
+}
+
+void /* PRIVATE */
+png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
+{
+    png_byte data[4];
+    png_uint_32 sequence_number;
+
+    if (length < 4)
+        png_error(png_ptr, "invalid fcTL or fdAT chunk found");
+
+    png_crc_read(png_ptr, data, 4);
+    sequence_number = png_get_uint_31(png_ptr, data);
+
+    if (sequence_number != png_ptr->next_seq_num)
+        png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
+                           "number found");
+
+    png_ptr->next_seq_num++;
+}
+#endif /* PNG_READ_APNG_SUPPORTED */
+
 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
 /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
 static int
@@ -4329,7 +4507,38 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
       {
          uInt avail_in;
          png_bytep buffer;
+#ifdef PNG_READ_APNG_SUPPORTED
+         png_uint_32 bytes_to_skip = 0;
+
+         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
+         {
+            png_crc_finish(png_ptr, bytes_to_skip);
+            bytes_to_skip = 0;
+
+            png_ptr->idat_size = png_read_chunk_header(png_ptr);
+            if (png_ptr->num_frames_read == 0)
+            {
+               if (png_ptr->chunk_name != png_IDAT)
+                  png_error(png_ptr, "Not enough image data");
+            }
+            else
+            {
+               if (png_ptr->chunk_name == png_IEND)
+                  png_error(png_ptr, "Not enough image data");
+               if (png_ptr->chunk_name != png_fdAT)
+               {
+                  png_warning(png_ptr, "Skipped (ignored) a chunk "
+                                       "between APNG chunks");
+                  bytes_to_skip = png_ptr->idat_size;
+                  continue;
+               }
+
+               png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
 
+               png_ptr->idat_size -= 4;
+            }
+         }
+#else
          while (png_ptr->idat_size == 0)
          {
             png_crc_finish(png_ptr, 0);
@@ -4341,7 +4550,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
             if (png_ptr->chunk_name != png_IDAT)
                png_error(png_ptr, "Not enough image data");
          }
-
+#endif /* PNG_READ_APNG_SUPPORTED */
          avail_in = png_ptr->IDAT_read_size;
 
          if (avail_in > png_ptr->idat_size)
@@ -4404,6 +4613,9 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
 
          png_ptr->mode |= PNG_AFTER_IDAT;
          png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+#ifdef PNG_READ_APNG_SUPPORTED
+         png_ptr->num_frames_read++;
+#endif
 
          if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
             png_chunk_benign_error(png_ptr, "Extra compressed data");
@@ -4842,4 +5054,80 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
 
    png_ptr->flags |= PNG_FLAG_ROW_INIT;
 }
+
+#ifdef PNG_READ_APNG_SUPPORTED
+/* This function is to be called after the main IDAT set has been read and
+ * before a new IDAT is read. It resets some parts of png_ptr
+ * to make them usable by the read functions again */
+void /* PRIVATE */
+png_read_reset(png_structp png_ptr)
+{
+    png_ptr->mode &= ~PNG_HAVE_IDAT;
+    png_ptr->mode &= ~PNG_AFTER_IDAT;
+    png_ptr->row_number = 0;
+    png_ptr->pass = 0;
+}
+
+void /* PRIVATE */
+png_read_reinit(png_structp png_ptr, png_infop info_ptr)
+{
+    png_ptr->width = info_ptr->next_frame_width;
+    png_ptr->height = info_ptr->next_frame_height;
+    png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
+    png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
+        png_ptr->width);
+    if (png_ptr->prev_row)
+        memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+}
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* same as png_read_reset() but for the progressive reader */
+void /* PRIVATE */
+png_progressive_read_reset(png_structp png_ptr)
+{
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+   /* Start of interlace block */
+    const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+    /* Offset to next interlace block */
+    const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+    /* Start of interlace block in the y direction */
+    const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+    /* Offset to next interlace block in the y direction */
+    const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+    if (png_ptr->interlaced)
+    {
+        if (!(png_ptr->transformations & PNG_INTERLACE))
+            png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+                                png_pass_ystart[0]) / png_pass_yinc[0];
+        else
+            png_ptr->num_rows = png_ptr->height;
+
+        png_ptr->iwidth = (png_ptr->width +
+                           png_pass_inc[png_ptr->pass] - 1 -
+                           png_pass_start[png_ptr->pass]) /
+                           png_pass_inc[png_ptr->pass];
+    }
+    else
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+    {
+        png_ptr->num_rows = png_ptr->height;
+        png_ptr->iwidth = png_ptr->width;
+    }
+    png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
+    if (inflateReset(&(png_ptr->zstream)) != Z_OK)
+        png_error(png_ptr, "inflateReset failed");
+    png_ptr->zstream.avail_in = 0;
+    png_ptr->zstream.next_in = 0;
+    png_ptr->zstream.next_out = png_ptr->row_buf;
+    png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
+        png_ptr->iwidth) + 1;
+}
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+#endif /* PNG_READ_APNG_SUPPORTED */
 #endif /* READ */