require 3 or 4 B2A output channels

We'd been requiring 1-4 in one place and 0-4 in another,
while asserting it was 3-4 in the CLUT transform code.
This should make everyone agree on 3-4.

Add a profile with 2 output mBA tag,
which we should now fail to parse.

Bug: oss-fuzz:33281
Change-Id: Ia9db10805e4b046dc4adf112e7f8679c0e6b96c3
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/397075
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/profiles/fuzz/b2a_too_few_output_channels.icc b/profiles/fuzz/b2a_too_few_output_channels.icc
new file mode 100644
index 0000000..b757b03
--- /dev/null
+++ b/profiles/fuzz/b2a_too_few_output_channels.icc
Binary files differ
diff --git a/profiles/fuzz/b2a_too_few_output_channels.icc.txt b/profiles/fuzz/b2a_too_few_output_channels.icc.txt
new file mode 100644
index 0000000..979baac
--- /dev/null
+++ b/profiles/fuzz/b2a_too_few_output_channels.icc.txt
@@ -0,0 +1 @@
+Unable to parse ICC profile
diff --git a/skcms.cc b/skcms.cc
index 21e1c83..0b2c781 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -636,11 +636,11 @@
     b2a->output_channels = mftTag->output_channels[0];
 
 
-    // For B2A, exactly 3 *input* channels and 1-4 *output* channels.
+    // For B2A, exactly 3 input channels (XYZ) and 3 (RGB) or 4 (CMYK) output channels.
     if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) {
         return false;
     }
-    if (b2a->output_channels < 1 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
+    if (b2a->output_channels < 3 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
         return false;
     }
 
@@ -936,11 +936,11 @@
     b2a->input_channels  = mBATag->input_channels[0];
     b2a->output_channels = mBATag->output_channels[0];
 
-    // Input and output arity requirements swapped... |inputs|==3, |outputs|<=4.
+    // Require exactly 3 inputs (XYZ) and 3 (RGB) or 4 (CMYK) outputs.
     if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) {
         return false;
     }
-    if (b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
+    if (b2a->output_channels < 3 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
         return false;
     }
 
@@ -964,7 +964,7 @@
         if (0 == matrix_offset) {
             return false;
         }
-        // Matrix channels is tied to input_channels (3), not output_channels (1-4).
+        // Matrix channels is tied to input_channels (3), not output_channels.
         b2a->matrix_channels = b2a->input_channels;
 
         if (!read_curves(tag->buf, tag->size, m_curve_offset, b2a->matrix_channels,
diff --git a/tests.c b/tests.c
index de44d1d..e6bc1fc 100644
--- a/tests.c
+++ b/tests.c
@@ -650,6 +650,7 @@
     "profiles/fuzz/a2b_too_many_input_channels2.icc", // oss-fuzz:32765
     "profiles/fuzz/mangled_trc_tags.icc",             // chromium:835666
     "profiles/fuzz/negative_g_para.icc",              // chromium:836634
+    "profiles/fuzz/b2a_too_few_output_channels.icc",  // oss-fuzz:33281
 
     // Caused skcms_PolyTF fit to round trip indices outside the range of int.
     "profiles/fuzz/infinite_roundtrip.icc",           // oss-fuzz:8101