Simpler itemID finding for alpha. (#1974) Backport https://github.com/AOMediaCodec/libavif/commit/4378794207f7a244bc36730c63dcc2bc188b6b3c
diff --git a/src/read.c b/src/read.c index c879024..dfaa20e 100644 --- a/src/read.c +++ b/src/read.c
@@ -770,7 +770,7 @@ avifFree(meta); } -static avifDecoderItem * avifMetaFindItem(avifMeta * meta, uint32_t itemID) +static avifDecoderItem * avifMetaFindItem(avifMeta * meta, uint32_t itemID, avifDiagnostics * diag) { if (itemID == 0) { return NULL; @@ -782,6 +782,17 @@ } } + if (meta->items.count != 0) { + // ISO/IEC 23008-12, First edition, 2017-12, Section 9.3.1: + // Each ItemPropertyAssociation box shall be ordered by increasing item_ID, and there shall + // be at most one association box for each item_ID, in any ItemPropertyAssociation box. + const uint32_t lastID = meta->items.item[meta->items.count - 1]->id; + if (itemID <= lastID) { + avifDiagnosticsPrintf(diag, "The added itemID [%u] does not preserve the itemID order", itemID); + return NULL; + } + } + avifDecoderItem * item = (avifDecoderItem *)avifAlloc(sizeof(avifDecoderItem)); memset(item, 0, sizeof(avifDecoderItem)); if (!avifArrayCreate(&item->properties, sizeof(avifProperty), 16)) { @@ -1683,7 +1694,7 @@ AVIF_CHECK(avifROStreamReadU32(&s, &itemID)); // unsigned int(32) item_ID; } - avifDecoderItem * item = avifMetaFindItem(meta, itemID); + avifDecoderItem * item = avifMetaFindItem(meta, itemID, diag); if (!item) { avifDiagnosticsPrintf(diag, "Box[iloc] has an invalid item ID [%u]", itemID); return AVIF_FALSE; @@ -2146,7 +2157,7 @@ } prevItemID = itemID; - avifDecoderItem * item = avifMetaFindItem(meta, itemID); + avifDecoderItem * item = avifMetaFindItem(meta, itemID, diag); if (!item) { avifDiagnosticsPrintf(diag, "Box[ipma] has an invalid item ID [%u]", itemID); return AVIF_FALSE; @@ -2413,7 +2424,7 @@ memset(&contentType, 0, sizeof(contentType)); } - avifDecoderItem * item = avifMetaFindItem(meta, itemID); + avifDecoderItem * item = avifMetaFindItem(meta, itemID, diag); if (!item) { avifDiagnosticsPrintf(diag, "%s: Box[infe] with item_type %.4s has an invalid item_ID [%u]", s.diagContext, itemType, itemID); return AVIF_FALSE; @@ -2501,7 +2512,7 @@ // Read this reference as "{fromID} is a {irefType} for {toID}" if (fromID && toID) { - avifDecoderItem * item = avifMetaFindItem(meta, fromID); + avifDecoderItem * item = avifMetaFindItem(meta, fromID, diag); if (!item) { avifDiagnosticsPrintf(diag, "Box[iref] has an invalid item ID [%u]", fromID); return AVIF_FALSE; @@ -2515,7 +2526,7 @@ item->descForID = toID; } else if (!memcmp(irefHeader.type, "dimg", 4)) { // derived images refer in the opposite direction - avifDecoderItem * dimg = avifMetaFindItem(meta, toID); + avifDecoderItem * dimg = avifMetaFindItem(meta, toID, diag); if (!dimg) { avifDiagnosticsPrintf(diag, "Box[iref] has an invalid item ID dimg ref [%u]", toID); return AVIF_FALSE; @@ -3355,7 +3366,7 @@ if (sample->itemID) { // The data comes from an item. Let avifDecoderItemMaxExtent() do the heavy lifting. - avifDecoderItem * item = avifMetaFindItem(decoder->data->meta, sample->itemID); + avifDecoderItem * item = avifMetaFindItem(decoder->data->meta, sample->itemID, decoder->data->diag); avifResult maxExtentResult = avifDecoderItemMaxExtent(item, sample, &sampleExtent); if (maxExtentResult != AVIF_RESULT_OK) { return maxExtentResult; @@ -3393,7 +3404,7 @@ if (sample->itemID) { // The data comes from an item. Let avifDecoderItemRead() do the heavy lifting. - avifDecoderItem * item = avifMetaFindItem(decoder->data->meta, sample->itemID); + avifDecoderItem * item = avifMetaFindItem(decoder->data->meta, sample->itemID, decoder->data->diag); avifROData itemContents; if (sample->offset > SIZE_MAX) { return AVIF_RESULT_BMFF_PARSE_FAILED; @@ -3636,7 +3647,8 @@ static avifResult avifDecoderDataFindAlphaItem(avifDecoderData * data, avifDecoderItem * colorItem, avifDecoderItem ** alphaItem, - avifBool * isAlphaItemInInput) + avifBool * isAlphaItemInInput, + avifDiagnostics * diag) { for (uint32_t itemIndex = 0; itemIndex < data->meta->items.count; ++itemIndex) { avifDecoderItem * item = data->meta->items.item[itemIndex]; @@ -3665,12 +3677,8 @@ uint32_t * alphaItemIndices = avifAlloc(colorItemCount * sizeof(uint32_t)); AVIF_CHECKERR(alphaItemIndices, AVIF_RESULT_OUT_OF_MEMORY); uint32_t alphaItemCount = 0; - uint32_t maxItemID = 0; for (uint32_t i = 0; i < colorItem->meta->items.count; ++i) { avifDecoderItem * item = colorItem->meta->items.item[i]; - if (item->id > maxItemID) { - maxItemID = item->id; - } if (item->dimgForID == colorItem->id) { avifBool seenAlphaForCurrentItem = AVIF_FALSE; for (uint32_t j = 0; j < colorItem->meta->items.count; ++j) { @@ -3699,8 +3707,22 @@ } } assert(alphaItemCount == colorItemCount); - *alphaItem = avifMetaFindItem(colorItem->meta, maxItemID + 1); - if (*alphaItem == NULL) { + // Figure out the last used itemID. + avifResult result = AVIF_RESULT_OK; + const uint32_t lastID = colorItem->meta->items.item[colorItem->meta->items.count - 1]->id; + if (lastID == UINT32_MAX) { + // In the improbable case where the last ID is the maximum one, ids cannot be kept ordered. + avifDiagnosticsPrintf(diag, + "Cannot set an itemID for alpha that fits the increasing " + "order as the maximum possible ID is in use."); + result = AVIF_RESULT_DECODE_ALPHA_FAILED; + } else { + *alphaItem = avifMetaFindItem(colorItem->meta, lastID + 1, diag); // Create new empty item. + if (*alphaItem == NULL) { + result = AVIF_RESULT_OUT_OF_MEMORY; + } + } + if (result != AVIF_RESULT_OK) { avifFree(alphaItemIndices); *isAlphaItemInInput = AVIF_FALSE; return AVIF_RESULT_OUT_OF_MEMORY; @@ -3964,7 +3986,7 @@ avifBool isAlphaItemInInput; avifDecoderItem * alphaItem; - AVIF_CHECKRES(avifDecoderDataFindAlphaItem(data, colorItem, &alphaItem, &isAlphaItemInInput)); + AVIF_CHECKRES(avifDecoderDataFindAlphaItem(data, colorItem, &alphaItem, &isAlphaItemInInput, &decoder->diag)); avifCodecType alphaCodecType = AVIF_CODEC_TYPE_UNKNOWN; if (alphaItem) { if (!memcmp(alphaItem->type, "grid", 4)) {