summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2022-03-08 12:14:51 +0000
committerMichael Drake <tlsa@netsurf-browser.org>2022-03-08 12:17:34 +0000
commit61934ff70402ffff91fbea9238cb1833ffa6cec6 (patch)
tree8bc6e980a3bb445f2a2bb7a01a9471137d9be25e
parentc77c518aa14ed14ca1424cfa635ca8bf95cb0814 (diff)
downloadlibnsgif-61934ff70402ffff91fbea9238cb1833ffa6cec6.tar.gz
libnsgif-61934ff70402ffff91fbea9238cb1833ffa6cec6.tar.bz2
GIF: Support AnimExts Looping Application Extension.
The the NETSCAPE2.0 and ANIMEXTS1.0 extensions are identical.
-rw-r--r--src/gif.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/src/gif.c b/src/gif.c
index d49cfe0..287b632 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -771,6 +771,34 @@ static nsgif_error nsgif__parse_extension_graphic_control(
}
/**
+ * Check an app ext identifier and authentication code for loop count extension.
+ *
+ * \param[in] data The data to decode.
+ * \param[in] len Byte length of data.
+ * \return true if extension is a loop count extension.
+ */
+static bool nsgif__app_ext_is_loop_count(
+ const uint8_t *data,
+ size_t len)
+{
+ enum {
+ EXT_LOOP_COUNT_BLOCK_SIZE = 0x0b,
+ };
+
+ assert(len > 13);
+ (void)(len);
+
+ if (data[1] == EXT_LOOP_COUNT_BLOCK_SIZE) {
+ if (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0 ||
+ strncmp((const char *)data + 2, "ANIMEXTS1.0", 11) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
* Parse the application extension
*
* \param[in] gif The gif object we're decoding.
@@ -796,12 +824,23 @@ static nsgif_error nsgif__parse_extension_application(
return NSGIF_ERR_END_OF_DATA;
}
- if ((data[1] == 0x0b) &&
- (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0) &&
- (data[13] == 0x03) && (data[14] == 0x01)) {
- gif->info.loop_max = data[15] | (data[16] << 8);
- if (gif->info.loop_max > 0) {
- gif->info.loop_max++;
+ if (nsgif__app_ext_is_loop_count(data, len)) {
+ enum {
+ EXT_LOOP_COUNT_SUB_BLOCK_SIZE = 0x03,
+ EXT_LOOP_COUNT_SUB_BLOCK_ID = 0x01,
+ };
+ if ((data[13] == EXT_LOOP_COUNT_SUB_BLOCK_SIZE) &&
+ (data[14] == EXT_LOOP_COUNT_SUB_BLOCK_ID)) {
+ gif->info.loop_max = data[15] | (data[16] << 8);
+
+ /* The value in the source data means repeat N times
+ * after the first implied play. A value of zero has
+ * the special meaning of loop forever. (The only way
+ * to play the animation once is not to have this
+ * extension at all. */
+ if (gif->info.loop_max > 0) {
+ gif->info.loop_max++;
+ }
}
}