Detect and report invalid stream earlier.

PiperOrigin-RevId: 876128553
diff --git a/c/dec/decode.c b/c/dec/decode.c
index e87e7f5..19c7e02 100644
--- a/c/dec/decode.c
+++ b/c/dec/decode.c
@@ -1176,7 +1176,7 @@
 
 /* Decodes a command or literal and updates block type ring-buffer.
    Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeBlockTypeAndLength(
     int safe, BrotliDecoderState* s, int tree_type) {
   brotli_reg_t max_block_type = s->num_block_types[tree_type];
   const HuffmanCode* type_tree = &s->block_type_trees[
@@ -1187,7 +1187,7 @@
   brotli_reg_t* ringbuffer = &s->block_type_rb[tree_type * 2];
   brotli_reg_t block_type;
   if (max_block_type <= 1) {
-    return BROTLI_FALSE;
+    return BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH;
   }
 
   /* Read 0..15 + 3..39 bits. */
@@ -1197,11 +1197,13 @@
   } else {
     BrotliBitReaderState memento;
     BrotliBitReaderSaveState(br, &memento);
-    if (!SafeReadSymbol(type_tree, br, &block_type)) return BROTLI_FALSE;
+    if (!SafeReadSymbol(type_tree, br, &block_type)) {
+      return BROTLI_DECODER_NEEDS_MORE_INPUT;
+    }
     if (!SafeReadBlockLength(s, &s->block_length[tree_type], len_tree, br)) {
       s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE;
       BrotliBitReaderRestoreState(br, &memento);
-      return BROTLI_FALSE;
+      return BROTLI_DECODER_NEEDS_MORE_INPUT;
     }
   }
 
@@ -1217,7 +1219,7 @@
   }
   ringbuffer[0] = ringbuffer[1];
   ringbuffer[1] = block_type;
-  return BROTLI_TRUE;
+  return BROTLI_DECODER_SUCCESS;
 }
 
 static BROTLI_INLINE void DetectTrivialLiteralBlockTypes(
@@ -1254,59 +1256,65 @@
 
 /* Decodes the block type and updates the state for literal context.
    Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeLiteralBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeLiteralBlockSwitchInternal(
     int safe, BrotliDecoderState* s) {
-  if (!DecodeBlockTypeAndLength(safe, s, 0)) {
-    return BROTLI_FALSE;
+  BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 0);
+  if (result != BROTLI_DECODER_SUCCESS) {
+    return result;
   }
   PrepareLiteralDecoding(s);
-  return BROTLI_TRUE;
+  return BROTLI_DECODER_SUCCESS;
 }
 
-static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
-  DecodeLiteralBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
+  return DecodeLiteralBlockSwitchInternal(0, s);
 }
 
-static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch(
+static BROTLI_NOINLINE BrotliDecoderErrorCode SafeDecodeLiteralBlockSwitch(
     BrotliDecoderState* s) {
   return DecodeLiteralBlockSwitchInternal(1, s);
 }
 
 /* Block switch for insert/copy length.
    Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeCommandBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeCommandBlockSwitchInternal(
     int safe, BrotliDecoderState* s) {
-  if (!DecodeBlockTypeAndLength(safe, s, 1)) {
-    return BROTLI_FALSE;
+  BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 1);
+  if (result != BROTLI_DECODER_SUCCESS) {
+    return result;
   }
   s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
-  return BROTLI_TRUE;
+  return BROTLI_DECODER_SUCCESS;
 }
 
-static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s) {
-  DecodeCommandBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeCommandBlockSwitch(BrotliDecoderState* s) {
+  return DecodeCommandBlockSwitchInternal(0, s);
 }
 
-static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeCommandBlockSwitch(
-    BrotliDecoderState* s) {
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+SafeDecodeCommandBlockSwitch(BrotliDecoderState* s) {
   return DecodeCommandBlockSwitchInternal(1, s);
 }
 
 /* Block switch for distance codes.
    Reads 3..54 bits. */
-static BROTLI_INLINE BROTLI_BOOL DecodeDistanceBlockSwitchInternal(
+static BROTLI_INLINE BrotliDecoderErrorCode DecodeDistanceBlockSwitchInternal(
     int safe, BrotliDecoderState* s) {
-  if (!DecodeBlockTypeAndLength(safe, s, 2)) {
-    return BROTLI_FALSE;
+  BrotliDecoderErrorCode result = DecodeBlockTypeAndLength(safe, s, 2);
+  if (result != BROTLI_DECODER_SUCCESS) {
+    return result;
   }
   s->dist_context_map_slice = s->dist_context_map +
       (s->block_type_rb[5] << BROTLI_DISTANCE_CONTEXT_BITS);
   s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
-  return BROTLI_TRUE;
+  return BROTLI_DECODER_SUCCESS;
 }
 
-static void BROTLI_NOINLINE DecodeDistanceBlockSwitch(BrotliDecoderState* s) {
-  DecodeDistanceBlockSwitchInternal(0, s);
+static BROTLI_NOINLINE BrotliDecoderErrorCode
+DecodeDistanceBlockSwitch(BrotliDecoderState* s) {
+  return DecodeDistanceBlockSwitchInternal(0, s);
 }
 
 static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeDistanceBlockSwitch(
@@ -1940,6 +1948,9 @@
   return BrotliCheckInputAmount(br);
 }
 
+/* NB: METHOD should return BROTLI_FALSE only in case there is not enough input;
+       in case of "unsafe" execution, when input is guaranteed to be sufficient,
+       result is ignored. */
 #define BROTLI_SAFE(METHOD)                       \
   {                                               \
     if (safe) {                                   \
@@ -1952,6 +1963,22 @@
     }                                             \
   }
 
+/* NB: METHOD should return BROTLI_DECODER_SUCCESS, BROTLI_DECODER_ERROR_*, or
+   BROTLI_DECODER_NEEDS_MORE_INPUT; the later two break the processing. */
+#define BROTLI_SAFE_WITH_STATUS(METHOD)         \
+  {                                             \
+    BrotliDecoderErrorCode status;              \
+    if (safe) {                                 \
+      status = Safe##METHOD;                    \
+    } else {                                    \
+      status = METHOD;                          \
+    }                                           \
+    if (status != BROTLI_DECODER_SUCCESS) {     \
+      result = status;                          \
+      goto saveStateAndReturn;                  \
+    }                                           \
+  }
+
 static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal(
     int safe, BrotliDecoderState* s) {
   int pos = s->pos;
@@ -1991,7 +2018,7 @@
     goto saveStateAndReturn;
   }
   if (BROTLI_PREDICT_FALSE(s->block_length[1] == 0)) {
-    BROTLI_SAFE(DecodeCommandBlockSwitch(s));
+    BROTLI_SAFE_WITH_STATUS(DecodeCommandBlockSwitch(s));
     goto CommandBegin;
   }
   /* Read the insert/copy length in the command. */
@@ -2136,7 +2163,7 @@
   } else {
     /* Read distance code in the command, unless it was implicitly zero. */
     if (BROTLI_PREDICT_FALSE(s->block_length[2] == 0)) {
-      BROTLI_SAFE(DecodeDistanceBlockSwitch(s));
+      BROTLI_SAFE_WITH_STATUS(DecodeDistanceBlockSwitch(s));
     }
     BROTLI_SAFE(ReadDistance(s, br));
   }
@@ -2330,7 +2357,7 @@
   }
 
 NextLiteralBlock:
-  BROTLI_SAFE(DecodeLiteralBlockSwitch(s));
+  BROTLI_SAFE_WITH_STATUS(DecodeLiteralBlockSwitch(s));
   goto CommandInner;
 
 saveStateAndReturn:
@@ -2552,6 +2579,8 @@
         if (result != BROTLI_DECODER_SUCCESS) {
           break;
         }
+        BROTLI_DCHECK(s->meta_block_remaining_len <=
+                      (int)BROTLI_BLOCK_SIZE_CAP);
         BROTLI_LOG_UINT(s->is_last_metablock);
         BROTLI_LOG_UINT(s->meta_block_remaining_len);
         BROTLI_LOG_UINT(s->is_metadata);
diff --git a/c/include/brotli/decode.h b/c/include/brotli/decode.h
index 8d436db..10d01e3 100644
--- a/c/include/brotli/decode.h
+++ b/c/include/brotli/decode.h
@@ -85,9 +85,7 @@
   BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR              \
   BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR              \
   BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR               \
-                                                                           \
-  /* -17 code is reserved */                                               \
-                                                                           \
+  BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_SWITCH, -17) SEPARATOR           \
   BROTLI_ERROR_CODE(_ERROR_, COMPOUND_DICTIONARY, -18) SEPARATOR           \
   BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR            \
   BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR             \