Merge pull request #1005 from sullis:enum-values

PiperOrigin-RevId: 506138469
diff --git a/bootstrap b/bootstrap
old mode 100644
new mode 100755
index 1da6d60..d4325b2
--- a/bootstrap
+++ b/bootstrap
@@ -9,7 +9,8 @@
 # -E is POSIX. -r is for GNU sed older than 4.2.
 echo hello | sed -E s/hello/world/ >/dev/null 2>&1 && SED_ERE=-E || SED_ERE=-r
 
-# If libtool is not installed -> "error: Libtool library used but 'LIBTOOL' is undefined"
+# If libtool is not installed ->
+# "error: Libtool library used but 'LIBTOOL' is undefined"
 
 if [ ! -e "./m4" ]; then
 mkdir m4 2>/dev/null
diff --git a/c/dec/bit_reader.h b/c/dec/bit_reader.h
index c737bda..64701ec 100644
--- a/c/dec/bit_reader.h
+++ b/c/dec/bit_reader.h
@@ -341,6 +341,11 @@
   return TO_BROTLI_BOOL(pad_bits == 0);
 }
 
+static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) {
+  br->avail_in -= num;
+  br->next_in += num;
+}
+
 /* Copies remaining input bytes stored in the bit reader to the output. Value
    |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
    warmed up again after this. */
@@ -352,9 +357,10 @@
     ++dest;
     --num;
   }
-  memcpy(dest, br->next_in, num);
-  br->avail_in -= num;
-  br->next_in += num;
+  if (num > 0) {
+    memcpy(dest, br->next_in, num);
+    BrotliDropBytes(br, num);
+  }
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/dec/decode.c b/c/dec/decode.c
index 845f556..3ee1963 100644
--- a/c/dec/decode.c
+++ b/c/dec/decode.c
@@ -1354,6 +1354,57 @@
   return BROTLI_TRUE;
 }
 
+static BrotliDecoderErrorCode BROTLI_NOINLINE
+SkipMetadataBlock(BrotliDecoderState* s) {
+  BrotliBitReader* br = &s->br;
+
+  if (s->meta_block_remaining_len == 0) {
+    return BROTLI_DECODER_SUCCESS;
+  }
+
+  BROTLI_DCHECK((BrotliGetAvailableBits(br) & 7) == 0);
+
+  /* Drain accumulator. */
+  if (BrotliGetAvailableBits(br) >= 8) {
+    uint8_t buffer[8];
+    int nbytes = (int)(BrotliGetAvailableBits(br)) >> 3;
+    BROTLI_DCHECK(nbytes <= 8);
+    if (nbytes > s->meta_block_remaining_len) {
+      nbytes = s->meta_block_remaining_len;
+    }
+    BrotliCopyBytes(buffer, br, (size_t)nbytes);
+    if (s->metadata_chunk_func) {
+      s->metadata_chunk_func(s->metadata_callback_opaque, buffer,
+                             (size_t)nbytes);
+    }
+    s->meta_block_remaining_len -= nbytes;
+    if (s->meta_block_remaining_len == 0) {
+      return BROTLI_DECODER_SUCCESS;
+    }
+  }
+
+  /* Direct access to metadata is possible. */
+  int nbytes = (int)BrotliGetRemainingBytes(br);
+  if (nbytes > s->meta_block_remaining_len) {
+    nbytes = s->meta_block_remaining_len;
+  }
+  if (nbytes > 0) {
+    if (s->metadata_chunk_func) {
+      s->metadata_chunk_func(s->metadata_callback_opaque, br->next_in,
+                             (size_t)nbytes);
+    }
+    BrotliDropBytes(br, (size_t)nbytes);
+    s->meta_block_remaining_len -= nbytes;
+    if (s->meta_block_remaining_len == 0) {
+      return BROTLI_DECODER_SUCCESS;
+    }
+  }
+
+  BROTLI_DCHECK(BrotliGetRemainingBytes(br) == 0);
+
+  return BROTLI_DECODER_NEEDS_MORE_INPUT;
+}
+
 static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
     size_t* available_out, uint8_t** next_out, size_t* total_out,
     BrotliDecoderState* s) {
@@ -2414,6 +2465,10 @@
         }
         if (s->is_metadata) {
           s->state = BROTLI_STATE_METADATA;
+          if (s->metadata_start_func) {
+            s->metadata_start_func(s->metadata_callback_opaque,
+                                   (size_t)s->meta_block_remaining_len);
+          }
           break;
         }
         if (s->meta_block_remaining_len == 0) {
@@ -2506,17 +2561,11 @@
       }
 
       case BROTLI_STATE_METADATA:
-        for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
-          uint32_t bits;
-          /* Read one byte and ignore it. */
-          if (!BrotliSafeReadBits(br, 8, &bits)) {
-            result = BROTLI_DECODER_NEEDS_MORE_INPUT;
-            break;
-          }
+        result = SkipMetadataBlock(s);
+        if (result != BROTLI_DECODER_SUCCESS) {
+          break;
         }
-        if (result == BROTLI_DECODER_SUCCESS) {
-          s->state = BROTLI_STATE_METABLOCK_DONE;
-        }
+        s->state = BROTLI_STATE_METABLOCK_DONE;
         break;
 
       case BROTLI_STATE_METABLOCK_HEADER_2: {
@@ -2785,6 +2834,15 @@
   return BROTLI_VERSION;
 }
 
+void BrotliDecoderSetMetadataCallbacks(
+    BrotliDecoderState* state,
+    brotli_decoder_metadata_start_func start_func,
+    brotli_decoder_metadata_chunk_func chunk_func, void* opaque) {
+  state->metadata_start_func = start_func;
+  state->metadata_chunk_func = chunk_func;
+  state->metadata_callback_opaque = opaque;
+}
+
 /* Escalate internal functions visibility; for testing purposes only. */
 #if defined(BROTLI_TEST)
 BROTLI_BOOL SafeReadSymbolForTest(
diff --git a/c/dec/state.c b/c/dec/state.c
index 08d4c8b..a3baf37 100644
--- a/c/dec/state.c
+++ b/c/dec/state.c
@@ -89,6 +89,10 @@
       BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque);
   if (!s->dictionary) return BROTLI_FALSE;
 
+  s->metadata_start_func = NULL;
+  s->metadata_chunk_func = NULL;
+  s->metadata_callback_opaque = 0;
+
   return BROTLI_TRUE;
 }
 
diff --git a/c/dec/state.h b/c/dec/state.h
index 6ec5c8f..84fddc8 100644
--- a/c/dec/state.h
+++ b/c/dec/state.h
@@ -9,6 +9,7 @@
 #ifndef BROTLI_DEC_STATE_H_
 #define BROTLI_DEC_STATE_H_
 
+#include <brotli/decode.h>
 #include <brotli/shared_dictionary.h>
 #include <brotli/types.h>
 
@@ -322,6 +323,10 @@
 
   /* Less used attributes are at the end of this struct. */
 
+  brotli_decoder_metadata_start_func metadata_start_func;
+  brotli_decoder_metadata_chunk_func metadata_chunk_func;
+  void* metadata_callback_opaque;
+
   /* For reporting. */
   uint64_t used_input;  /* how many bytes of input are consumed */
 
diff --git a/c/enc/encode.c b/c/enc/encode.c
index 1d22525..4627ea0 100644
--- a/c/enc/encode.c
+++ b/c/enc/encode.c
@@ -1188,7 +1188,7 @@
   if (block_size == 0) {
     BrotliWriteBits(2, 0, &storage_ix, header);
   } else {
-    uint32_t nbits = (block_size == 1) ? 0 :
+    uint32_t nbits = (block_size == 1) ? 1 :
         (Log2FloorNonZero((uint32_t)block_size - 1) + 1);
     uint32_t nbytes = (nbits + 7) / 8;
     BrotliWriteBits(2, nbytes, &storage_ix, header);
diff --git a/c/enc/find_match_length.h b/c/enc/find_match_length.h
index dee0414..f3de0bd 100644
--- a/c/enc/find_match_length.h
+++ b/c/enc/find_match_length.h
@@ -22,31 +22,23 @@
 static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
                                                      const uint8_t* s2,
                                                      size_t limit) {
-  size_t matched = 0;
-  size_t limit2 = (limit >> 3) + 1;  /* + 1 is for pre-decrement in while */
-  while (BROTLI_PREDICT_TRUE(--limit2)) {
-    if (BROTLI_PREDICT_FALSE(BROTLI_UNALIGNED_LOAD64LE(s2) ==
-                      BROTLI_UNALIGNED_LOAD64LE(s1 + matched))) {
-      s2 += 8;
-      matched += 8;
-    } else {
-      uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
-          BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
+  const uint8_t *s1_orig = s1;
+  for (; limit >= 8; limit -= 8) {
+    uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
+                 BROTLI_UNALIGNED_LOAD64LE(s1);
+    s2 += 8;
+    if (x != 0) {
       size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
-      matched += matching_bits >> 3;
-      return matched;
+      return (size_t)(s1 - s1_orig) + (matching_bits >> 3);
     }
+    s1 += 8;
   }
-  limit = (limit & 7) + 1;  /* + 1 is for pre-decrement in while */
-  while (--limit) {
-    if (BROTLI_PREDICT_TRUE(s1[matched] == *s2)) {
-      ++s2;
-      ++matched;
-    } else {
-      return matched;
-    }
+  while (limit && *s1 == *s2) {
+    limit--;
+    ++s2;
+    ++s1;
   }
-  return matched;
+  return (size_t)(s1 - s1_orig);
 }
 #else
 static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
diff --git a/c/include/brotli/decode.h b/c/include/brotli/decode.h
index 9b580d2..3c473d6 100644
--- a/c/include/brotli/decode.h
+++ b/c/include/brotli/decode.h
@@ -361,6 +361,47 @@
  */
 BROTLI_DEC_API uint32_t BrotliDecoderVersion(void);
 
+/**
+ * Callback to fire on metadata block start.
+ *
+ * After this callback is fired, if @p size is not @c 0, it is followed by
+ * ::brotli_decoder_metadata_chunk_func as more metadata block contents become
+ * accessible.
+ *
+ * @param opaque callback handle
+ * @param size size of metadata block
+ */
+typedef void (*brotli_decoder_metadata_start_func)(void* opaque, size_t size);
+
+/**
+ * Callback to fire on metadata block chunk becomes available.
+ *
+ * This function can be invoked multiple times per metadata block; block should
+ * be considered finished when sum of @p size matches the announced metadata
+ * block size. Chunks contents pointed by @p data are transient and shouln not
+ * be accessed after leaving the callback.
+ *
+ * @param opaque callback handle
+ * @param data pointer to metadata contents
+ * @param size size of metadata block chunk, at least @c 1
+ */
+typedef void (*brotli_decoder_metadata_chunk_func)(void* opaque,
+                                                   const uint8_t* data,
+                                                   size_t size);
+
+/**
+ * Sets callback for receiving metadata blocks.
+ *
+ * @param state decoder instance
+ * @param start_func callback on metadata block start
+ * @param chunk_func callback on metadata block chunk
+ * @param opaque callback handle
+ */
+BROTLI_DEC_API void BrotliDecoderSetMetadataCallbacks(
+    BrotliDecoderState* state,
+    brotli_decoder_metadata_start_func start_func,
+    brotli_decoder_metadata_chunk_func chunk_func, void* opaque);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 } /* extern "C" */
 #endif
diff --git a/configure-cmake b/configure-cmake
old mode 100644
new mode 100755
index 6dfb92c..929300b
--- a/configure-cmake
+++ b/configure-cmake
@@ -315,4 +315,8 @@
     done
 fi
 
-eval "${CMAKE_CMD}" "${TOP_SRCDIR}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DCMAKE_INSTALL_LIBDIR="${LIBDIR}" ${CMAKE_ARGS}
+eval "${CMAKE_CMD}" "${TOP_SRCDIR}" \
+    -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
+    -DCMAKE_INSTALL_PREFIX="${PREFIX}" \
+    -DCMAKE_INSTALL_LIBDIR="${LIBDIR}" \
+    ${CMAKE_ARGS}
diff --git a/docs/decode.h.3 b/docs/decode.h.3
index 3d4e538..320663c 100644
--- a/docs/decode.h.3
+++ b/docs/decode.h.3
@@ -23,6 +23,14 @@
 
 .in +1c
 .ti -1c
+.RI "typedef void(* \fBbrotli_decoder_metadata_chunk_func\fP) (void *opaque, const uint8_t *data, size_t size)"
+.br
+.RI "\fICallback to fire on metadata block chunk becomes available\&. \fP"
+.ti -1c
+.RI "typedef void(* \fBbrotli_decoder_metadata_start_func\fP) (void *opaque, size_t size)"
+.br
+.RI "\fICallback to fire on metadata block start\&. \fP"
+.ti -1c
 .RI "typedef enum \fBBrotliDecoderParameter\fP \fBBrotliDecoderParameter\fP"
 .br
 .RI "\fIOptions to be used with \fBBrotliDecoderSetParameter\fP\&. \fP"
@@ -76,6 +84,10 @@
 .br
 .RI "\fIChecks if instance has already consumed input\&. \fP"
 .ti -1c
+.RI "void \fBBrotliDecoderSetMetadataCallbacks\fP (\fBBrotliDecoderState\fP *state, \fBbrotli_decoder_metadata_start_func\fP start_func, \fBbrotli_decoder_metadata_chunk_func\fP chunk_func, void *opaque)"
+.br
+.RI "\fISets callback for receiving metadata blocks\&. \fP"
+.ti -1c
 .RI "\fBBROTLI_BOOL\fP \fBBrotliDecoderSetParameter\fP (\fBBrotliDecoderState\fP *state, \fBBrotliDecoderParameter\fP param, uint32_t value)"
 .br
 .RI "\fISets the specified parameter to the given decoder instance\&. \fP"
@@ -123,6 +135,34 @@
 The value of the last error code, negative integer\&. All other error code values are in the range from \fBBROTLI_LAST_ERROR_CODE\fP to \fC-1\fP\&. There are also 4 other possible non-error codes \fC0\fP \&.\&. \fC3\fP in \fBBrotliDecoderErrorCode\fP enumeration\&. 
 .SH "Typedef Documentation"
 .PP 
+.SS "typedef void(* brotli_decoder_metadata_chunk_func) (void *opaque, const uint8_t *data, size_t size)"
+
+.PP
+Callback to fire on metadata block chunk becomes available\&. This function can be invoked multiple times per metadata block; block should be considered finished when sum of \fCsize\fP matches the announced metadata block size\&. Chunks contents pointed by \fCdata\fP are transient and shouln not be accessed after leaving the callback\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIopaque\fP callback handle 
+.br
+\fIdata\fP pointer to metadata contents 
+.br
+\fIsize\fP size of metadata block chunk, at least \fC1\fP 
+.RE
+.PP
+
+.SS "typedef void(* brotli_decoder_metadata_start_func) (void *opaque, size_t size)"
+
+.PP
+Callback to fire on metadata block start\&. After this callback is fired, if \fCsize\fP is not \fC0\fP, it is followed by \fBbrotli_decoder_metadata_chunk_func\fP as more metadata block contents become accessible\&.
+.PP
+\fBParameters:\fP
+.RS 4
+\fIopaque\fP callback handle 
+.br
+\fIsize\fP size of metadata block 
+.RE
+.PP
+
 .SS "typedef enum \fBBrotliDecoderParameter\fP  \fBBrotliDecoderParameter\fP"
 
 .PP
@@ -378,6 +418,23 @@
 .RE
 .PP
 
+.SS "void BrotliDecoderSetMetadataCallbacks (\fBBrotliDecoderState\fP * state, \fBbrotli_decoder_metadata_start_func\fP start_func, \fBbrotli_decoder_metadata_chunk_func\fP chunk_func, void * opaque)"
+
+.PP
+Sets callback for receiving metadata blocks\&. 
+.PP
+\fBParameters:\fP
+.RS 4
+\fIstate\fP decoder instance 
+.br
+\fIstart_func\fP callback on metadata block start 
+.br
+\fIchunk_func\fP callback on metadata block chunk 
+.br
+\fIopaque\fP callback handle 
+.RE
+.PP
+
 .SS "\fBBROTLI_BOOL\fP BrotliDecoderSetParameter (\fBBrotliDecoderState\fP * state, \fBBrotliDecoderParameter\fP param, uint32_t value)"
 
 .PP
diff --git a/python/bro.py b/python/bro.py
index 6d71549..b742fd7 100755
--- a/python/bro.py
+++ b/python/bro.py
@@ -3,9 +3,9 @@
 
 from __future__ import print_function
 import argparse
-import sys
 import os
 import platform
+import sys
 
 import brotli