Simpler itemID finding for alpha. (#1967)

Also better handle the case where there is no possible value
and newItemID wraps around.
diff --git a/src/read.c b/src/read.c
index 97206a6..43e8687 100644
--- a/src/read.c
+++ b/src/read.c
@@ -787,7 +787,7 @@
     return AVIF_RESULT_OK;
 }
 
-static avifResult avifMetaFindOrCreateItem(avifMeta * meta, uint32_t itemID, avifDecoderItem ** item)
+static avifResult avifMetaFindOrCreateItem(avifMeta * meta, uint32_t itemID, avifDecoderItem ** item, avifDiagnostics * diag)
 {
     *item = NULL;
     assert(itemID != 0);
@@ -799,6 +799,18 @@
         }
     }
 
+    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) {
+            avifBreakOnError();
+            avifDiagnosticsPrintf(diag, "The added itemID [%u] does not preserve the itemID order", itemID);
+            return AVIF_RESULT_BMFF_PARSE_FAILED;
+        }
+    }
+
     avifDecoderItem ** itemPtr = (avifDecoderItem **)avifArrayPush(&meta->items);
     AVIF_CHECKERR(itemPtr != NULL, AVIF_RESULT_OUT_OF_MEMORY);
     *item = (avifDecoderItem *)avifAlloc(sizeof(avifDecoderItem));
@@ -1768,7 +1780,7 @@
 #endif // AVIF_ENABLE_EXPERIMENTAL_AVIR
 
         avifDecoderItem * item;
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item, diag));
         if (item->extents.count > 0) {
             // This item has already been given extents via this iloc box. This is invalid.
             avifDiagnosticsPrintf(diag, "Item ID [%u] contains duplicate sets of extents", itemID);
@@ -2382,7 +2394,7 @@
         prevItemID = itemID;
 
         avifDecoderItem * item;
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item, diag));
         if (item->ipmaSeen) {
             avifDiagnosticsPrintf(diag, "Duplicate Box[ipma] for item ID [%u]", itemID);
             return AVIF_RESULT_BMFF_PARSE_FAILED;
@@ -2658,7 +2670,7 @@
     }
 #endif // AVIF_ENABLE_EXPERIMENTAL_AVIR
     avifDecoderItem * item;
-    AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item));
+    AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, itemID, &item, diag));
 
     memcpy(item->type, itemType, sizeof(itemType));
     item->contentType = contentType;
@@ -2727,7 +2739,7 @@
         AVIF_CHECKRES(avifCheckItemID("iref", fromID, diag));
 
         avifDecoderItem * item;
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, fromID, &item));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, fromID, &item, diag));
         if (!memcmp(irefHeader.type, "dimg", 4)) {
             if (item->hasDimgFrom) {
                 // ISO/IEC 23008-12 (HEIF) 6.6.1: The number of SingleItemTypeReferenceBoxes with the box type 'dimg'
@@ -2765,7 +2777,7 @@
             } else if (!memcmp(irefHeader.type, "dimg", 4)) {
                 // derived images refer in the opposite direction
                 avifDecoderItem * dimg;
-                AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, toID, &dimg));
+                AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, toID, &dimg, diag));
 
                 dimg->dimgForID = fromID;
                 dimg->dimgIdx = refIndex;
@@ -3565,7 +3577,7 @@
 
     meta->primaryItemID = 1;
     avifDecoderItem * colorItem;
-    AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, meta->primaryItemID, &colorItem));
+    AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, meta->primaryItemID, &colorItem, diag));
     memcpy(colorItem->type, "av01", 4);
     colorItem->width = width;
     colorItem->height = height;
@@ -3574,7 +3586,7 @@
 
     avifDecoderItem * alphaItem = NULL;
     if (hasAlpha) {
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/2, &alphaItem));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/2, &alphaItem, diag));
         memcpy(alphaItem->type, "av01", 4);
         alphaItem->width = width;
         alphaItem->height = height;
@@ -3679,7 +3691,7 @@
 
     if (hasExif) {
         avifDecoderItem * exifItem;
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/3, &exifItem));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/3, &exifItem, diag));
         memcpy(exifItem->type, "Exif", 4);
         exifItem->descForID = colorItem->id;
         colorItem->premByID = alphaIsPremultiplied;
@@ -3694,7 +3706,7 @@
 
     if (hasXMP) {
         avifDecoderItem * xmpItem;
-        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/4, &xmpItem));
+        AVIF_CHECKRES(avifMetaFindOrCreateItem(meta, /*itemID=*/4, &xmpItem, diag));
         memcpy(xmpItem->type, "mime", 4);
         memcpy(xmpItem->contentType.contentType, xmpContentType, xmpContentTypeSize);
         xmpItem->descForID = colorItem->id;
@@ -4037,7 +4049,7 @@
                 // The data comes from an item. Let avifDecoderItemMaxExtent() do the heavy lifting.
 
                 avifDecoderItem * item;
-                AVIF_CHECKRES(avifMetaFindOrCreateItem(decoder->data->meta, sample->itemID, &item));
+                AVIF_CHECKRES(avifMetaFindOrCreateItem(decoder->data->meta, sample->itemID, &item, decoder->data->diag));
                 avifResult maxExtentResult = avifDecoderItemMaxExtent(item, sample, &sampleExtent);
                 if (maxExtentResult != AVIF_RESULT_OK) {
                     return maxExtentResult;
@@ -4076,7 +4088,7 @@
             // The data comes from an item. Let avifDecoderItemRead() do the heavy lifting.
 
             avifDecoderItem * item;
-            AVIF_CHECKRES(avifMetaFindOrCreateItem(decoder->data->meta, sample->itemID, &item));
+            AVIF_CHECKRES(avifMetaFindOrCreateItem(decoder->data->meta, sample->itemID, &item, decoder->data->diag));
             avifROData itemContents;
             if (sample->offset > SIZE_MAX) {
                 return AVIF_RESULT_BMFF_PARSE_FAILED;
@@ -4341,6 +4353,7 @@
 static avifResult avifMetaFindAlphaItem(avifMeta * meta,
                                         const avifDecoderItem * colorItem,
                                         const avifTileInfo * colorInfo,
+                                        avifDiagnostics * diag,
                                         avifDecoderItem ** alphaItem,
                                         avifTileInfo * alphaInfo,
                                         avifBool * isAlphaItemInInput)
@@ -4401,25 +4414,14 @@
         }
     }
     assert(alphaItemCount == colorItemCount);
-    // Find an unused ID.
+    // Figure out the last used itemID.
     avifResult result;
-    if (meta->items.count >= UINT32_MAX - 1) {
-        // In the improbable case where all IDs are used.
+    const uint32_t lastID = meta->items.item[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.
         result = AVIF_RESULT_DECODE_ALPHA_FAILED;
     } else {
-        uint32_t newItemID = 0;
-        avifBool isUsed;
-        do {
-            ++newItemID;
-            isUsed = AVIF_FALSE;
-            for (uint32_t i = 0; i < meta->items.count; ++i) {
-                if (meta->items.item[i]->id == newItemID) {
-                    isUsed = AVIF_TRUE;
-                    break;
-                }
-            }
-        } while (isUsed && newItemID != 0);
-        result = avifMetaFindOrCreateItem(meta, newItemID, alphaItem); // Create new empty item.
+        result = avifMetaFindOrCreateItem(meta, lastID + 1, alphaItem, diag); // Create new empty item.
     }
     if (result != AVIF_RESULT_OK) {
         avifFree(alphaItemIndices);
@@ -4563,7 +4565,7 @@
 
     assert(gainMapItemID != 0);
     avifDecoderItem * gainMapItemTmp;
-    AVIF_CHECKRES(avifMetaFindOrCreateItem(data->meta, gainMapItemID, &gainMapItemTmp));
+    AVIF_CHECKRES(avifMetaFindOrCreateItem(data->meta, gainMapItemID, &gainMapItemTmp, data->diag));
     if (avifDecoderItemShouldBeSkipped(gainMapItemTmp)) {
         avifDiagnosticsPrintf(data->diag, "Box[tmap] gain map item %d is not a supported image type", gainMapItemID);
         return AVIF_RESULT_INVALID_TONE_MAPPED_IMAGE;
@@ -4887,6 +4889,7 @@
         AVIF_CHECKRES(avifMetaFindAlphaItem(data->meta,
                                             mainItems[AVIF_ITEM_COLOR],
                                             &data->tileInfos[AVIF_ITEM_COLOR],
+                                            data->diag,
                                             &mainItems[AVIF_ITEM_ALPHA],
                                             &data->tileInfos[AVIF_ITEM_ALPHA],
                                             &isAlphaItemInInput));