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)) {