Recognize extensions with capital letters / capslock, print which format was written in "Wrote:" prints

Fixes: #144
diff --git a/apps/avifdec.c b/apps/avifdec.c
index 9880000..8f3a266 100644
--- a/apps/avifdec.c
+++ b/apps/avifdec.c
@@ -140,24 +140,22 @@
         printf("Image details:\n");
         avifImageDump(avif);
 
-        const char * fileExt = strrchr(outputFilename, '.');
-        if (!fileExt) {
-            fprintf(stderr, "Cannot determine output file extension: %s\n", outputFilename);
-            returnCode = 1;
-        } else if (!strcmp(fileExt, ".y4m")) {
+        avifAppFileFormat outputFormat = avifGuessFileFormat(outputFilename);
+        if (outputFormat == AVIF_APP_FILE_FORMAT_UNKNOWN) {
+        } else if (outputFormat == AVIF_APP_FILE_FORMAT_Y4M) {
             if (!y4mWrite(avif, outputFilename)) {
                 returnCode = 1;
             }
-        } else if (!strcmp(fileExt, ".jpg") || !strcmp(fileExt, ".jpeg")) {
+        } else if (outputFormat == AVIF_APP_FILE_FORMAT_JPEG) {
             if (!avifJPEGWrite(avif, outputFilename, jpegQuality)) {
                 returnCode = 1;
             }
-        } else if (!strcmp(fileExt, ".png")) {
+        } else if (outputFormat == AVIF_APP_FILE_FORMAT_PNG) {
             if (!avifPNGWrite(avif, outputFilename, requestedDepth)) {
                 returnCode = 1;
             }
         } else {
-            fprintf(stderr, "Unrecognized file extension: %s\n", fileExt + 1);
+            fprintf(stderr, "Unrecognized file extension: %s\n", inputFilename);
             returnCode = 1;
         }
     } else {
diff --git a/apps/avifenc.c b/apps/avifenc.c
index 6a6722a..357596c 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -334,13 +334,13 @@
         avifImageSetProfileNCLX(avif, &nclx);
     }
 
-    const char * fileExt = strrchr(inputFilename, '.');
-    if (!fileExt) {
+    avifAppFileFormat inputFormat = avifGuessFileFormat(inputFilename);
+    if (inputFormat == AVIF_APP_FILE_FORMAT_UNKNOWN) {
         fprintf(stderr, "Cannot determine input file extension: %s\n", inputFilename);
         returnCode = 1;
         goto cleanup;
     }
-    if (!strcmp(fileExt, ".y4m")) {
+    if (inputFormat == AVIF_APP_FILE_FORMAT_Y4M) {
         if (requestedRangeSet) {
             fprintf(stderr, "WARNING: Ignoring range (-r) value when encoding from y4m content.\n");
         }
@@ -353,18 +353,18 @@
             nclx.range = avif->yuvRange;
             avifImageSetProfileNCLX(avif, &nclx);
         }
-    } else if (!strcmp(fileExt, ".jpg") || !strcmp(fileExt, ".jpeg")) {
+    } else if (inputFormat == AVIF_APP_FILE_FORMAT_JPEG) {
         if (!avifJPEGRead(avif, inputFilename, requestedFormat, requestedDepth)) {
             returnCode = 1;
             goto cleanup;
         }
-    } else if (!strcmp(fileExt, ".png")) {
+    } else if (inputFormat == AVIF_APP_FILE_FORMAT_PNG) {
         if (!avifPNGRead(avif, inputFilename, requestedFormat, requestedDepth)) {
             returnCode = 1;
             goto cleanup;
         }
     } else {
-        fprintf(stderr, "Unrecognized file extension: %s\n", fileExt + 1);
+        fprintf(stderr, "Unrecognized file extension: %s\n", inputFilename);
         returnCode = 1;
         goto cleanup;
     }
@@ -436,7 +436,7 @@
         fprintf(stderr, "Failed to write %zu bytes: %s\n", raw.size, outputFilename);
         returnCode = 1;
     } else {
-        printf("Wrote: %s\n", outputFilename);
+        printf("Wrote AVIF: %s\n", outputFilename);
     }
     fclose(f);
 
diff --git a/apps/shared/avifjpeg.c b/apps/shared/avifjpeg.c
index a5b6e6d..dcefb41 100644
--- a/apps/shared/avifjpeg.c
+++ b/apps/shared/avifjpeg.c
@@ -149,7 +149,7 @@
 
     jpeg_finish_compress(&cinfo);
     ret = AVIF_TRUE;
-    printf("Wrote: %s\n", outputFilename);
+    printf("Wrote JPEG: %s\n", outputFilename);
 cleanup:
     if (f) {
         fclose(f);
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c
index 43f7a98..843d6b0 100644
--- a/apps/shared/avifpng.c
+++ b/apps/shared/avifpng.c
@@ -210,7 +210,7 @@
     png_write_end(png, NULL);
 
     writeResult = AVIF_TRUE;
-    printf("Wrote: %s\n", outputFilename);
+    printf("Wrote PNG: %s\n", outputFilename);
 cleanup:
     if (f) {
         fclose(f);
diff --git a/apps/shared/avifutil.c b/apps/shared/avifutil.c
index 6f26ab0..3856ac8 100644
--- a/apps/shared/avifutil.c
+++ b/apps/shared/avifutil.c
@@ -3,6 +3,7 @@
 
 #include "avifutil.h"
 
+#include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -63,3 +64,34 @@
     avifCodecVersions(codecVersions);
     printf("Version: %s (%s)\n\n", avifVersion(), codecVersions);
 }
+
+avifAppFileFormat avifGuessFileFormat(const char * filename)
+{
+    const char * fileExt = strrchr(filename, '.');
+    if (!fileExt) {
+        return AVIF_APP_FILE_FORMAT_UNKNOWN;
+    }
+    ++fileExt; // skip past the dot
+
+    char lowercaseExt[8]; // This only needs to fit up to "jpeg", so this is plenty
+    const size_t fileExtLen = strlen(fileExt);
+    if (fileExtLen >= sizeof(lowercaseExt)) { // >= accounts for NULL terminator
+        return AVIF_APP_FILE_FORMAT_UNKNOWN;
+    }
+
+    for (size_t i = 0; i < fileExtLen; ++i) {
+        lowercaseExt[i] = (char)tolower(fileExt[i]);
+    }
+    lowercaseExt[fileExtLen] = 0;
+
+    if (!strcmp(lowercaseExt, "avif")) {
+        return AVIF_APP_FILE_FORMAT_AVIF;
+    } else if (!strcmp(lowercaseExt, "y4m")) {
+        return AVIF_APP_FILE_FORMAT_Y4M;
+    } else if (!strcmp(lowercaseExt, "jpg") || !strcmp(lowercaseExt, "jpeg")) {
+        return AVIF_APP_FILE_FORMAT_JPEG;
+    } else if (!strcmp(lowercaseExt, "png")) {
+        return AVIF_APP_FILE_FORMAT_PNG;
+    }
+    return AVIF_APP_FILE_FORMAT_UNKNOWN;
+}
diff --git a/apps/shared/avifutil.h b/apps/shared/avifutil.h
index be02635..83f08ee 100644
--- a/apps/shared/avifutil.h
+++ b/apps/shared/avifutil.h
@@ -9,4 +9,16 @@
 void avifImageDump(avifImage * avif);
 void avifPrintVersions(void);
 
+typedef enum avifAppFileFormat
+{
+    AVIF_APP_FILE_FORMAT_UNKNOWN = 0,
+
+    AVIF_APP_FILE_FORMAT_AVIF,
+    AVIF_APP_FILE_FORMAT_JPEG,
+    AVIF_APP_FILE_FORMAT_PNG,
+    AVIF_APP_FILE_FORMAT_Y4M
+} avifAppFileFormat;
+
+avifAppFileFormat avifGuessFileFormat(const char * filename);
+
 #endif // ifndef LIBAVIF_APPS_SHARED_AVIFUTIL_H
diff --git a/apps/shared/y4m.c b/apps/shared/y4m.c
index 8547642..72e97a2 100644
--- a/apps/shared/y4m.c
+++ b/apps/shared/y4m.c
@@ -422,7 +422,7 @@
 cleanup:
     fclose(f);
     if (success) {
-        printf("Wrote: %s\n", outputFilename);
+        printf("Wrote Y4M: %s\n", outputFilename);
     }
     return success;
 }