char *fontdata;
int fontdata_size;
int fontdata_used;
+
+ // contains bitmap of ReadOrder IDs of all read events
+ uint32_t *read_order_bitmap;
+ int read_order_elems; // size in uint32_t units of read_order_bitmap
};
#define ASS_STYLES_ALLOC 20
int i;
if (track->parser_priv) {
+ free(track->parser_priv->read_order_bitmap);
free(track->parser_priv->fontname);
free(track->parser_priv->fontdata);
free(track->parser_priv);
free(style->FontName);
}
+static int resize_read_order_bitmap(ASS_Track *track, int max_id)
+{
+ // Don't allow malicious files to OOM us easily. Also avoids int overflows.
+ if (max_id < 0 || max_id >= 10 * 1024 * 1024 * 8)
+ goto fail;
+ if (max_id >= track->parser_priv->read_order_elems * 32) {
+ int oldelems = track->parser_priv->read_order_elems;
+ int elems = ((max_id + 31) / 32 + 1) * 2;
+ assert(elems >= oldelems);
+ track->parser_priv->read_order_elems = elems;
+ void *new_bitmap =
+ realloc(track->parser_priv->read_order_bitmap, elems * 4);
+ if (!new_bitmap)
+ goto fail;
+ track->parser_priv->read_order_bitmap = new_bitmap;
+ memset(track->parser_priv->read_order_bitmap + oldelems, 0,
+ (elems - oldelems) * 4);
+ }
+ return 0;
+
+fail:
+ free(track->parser_priv->read_order_bitmap);
+ track->parser_priv->read_order_bitmap = NULL;
+ track->parser_priv->read_order_elems = 0;
+ return -1;
+}
+
+static int test_and_set_read_order_bit(ASS_Track *track, int id)
+{
+ if (resize_read_order_bitmap(track, id) < 0)
+ return -1;
+ int index = id / 32;
+ int bit = 1 << (id % 32);
+ if (track->parser_priv->read_order_bitmap[index] & bit)
+ return 1;
+ track->parser_priv->read_order_bitmap[index] |= bit;
+ return 0;
+}
+
// ==============================================================================================
/**
static int check_duplicate_event(ASS_Track *track, int ReadOrder)
{
- int i;
- for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
+ if (track->parser_priv->read_order_bitmap)
+ return test_and_set_read_order_bit(track, ReadOrder) > 0;
+ // ignoring last event, it is the one we are comparing with
+ for (int i = 0; i < track->n_events - 1; i++)
if (track->events[i].ReadOrder == ReadOrder)
return 1;
return 0;
char *token;
ASS_Event *event;
+ if (!track->parser_priv->read_order_bitmap) {
+ for (int i = 0; i < track->n_events; i++) {
+ if (test_and_set_read_order_bit(track, track->events[i].ReadOrder) < 0)
+ break;
+ }
+ }
+
if (!track->event_format) {
ass_msg(track->library, MSGL_WARN, "Event format header missing");
return;
#include <stdarg.h>
#include "ass_types.h"
-#define LIBASS_VERSION 0x01300000
+#define LIBASS_VERSION 0x01300001
#ifdef __cplusplus
extern "C" {
/**
* \brief Parse a chunk of subtitle stream data. A chunk contains exactly one
* event in Matroska format. See the Matroska specification for details.
+ * In later libass versions (since LIBASS_VERSION==0x01300001), using this
+ * function means you agree not to modify events manually, or using other
+ * functions manipulating the event list like ass_process_data(). If you do
+ * anyway, the internal duplicate checking might break.
* \param track track
* \param data string to parse
* \param size length of data