Add std/json quirk_allow_leading_etc
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 247cba6..aa6a9a2 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -5944,6 +5944,11 @@
 
 // ---------------- Public Function Prototypes
 
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct  //
+wuffs_json__decoder__set_quirk_enabled(wuffs_json__decoder* self,
+                                       uint32_t a_quirk,
+                                       bool a_enabled);
+
 WUFFS_BASE__MAYBE_STATIC wuffs_base__status  //
 wuffs_json__decoder__decode_tokens(wuffs_json__decoder* self,
                                    wuffs_base__token_buffer* a_dst,
@@ -5972,9 +5977,28 @@
     wuffs_base__vtable vtable_for__wuffs_base__token_decoder;
     wuffs_base__vtable null_vtable;
 
+    bool f_quirk_enabled_allow_backslash_a;
+    bool f_quirk_enabled_allow_backslash_capital_u;
+    bool f_quirk_enabled_allow_backslash_e;
+    bool f_quirk_enabled_allow_backslash_question_mark;
+    bool f_quirk_enabled_allow_backslash_single_quote;
+    bool f_quirk_enabled_allow_backslash_v;
+    bool f_quirk_enabled_allow_backslash_x;
+    bool f_quirk_enabled_allow_backslash_zero;
+    bool f_quirk_enabled_allow_comment_block;
+    bool f_quirk_enabled_allow_comment_line;
+    bool f_quirk_enabled_allow_final_comma;
+    bool f_quirk_enabled_allow_inf_nan_numbers;
+    bool f_quirk_enabled_allow_leading_ascii_record_separator;
+    bool f_quirk_enabled_allow_leading_unicode_byte_order_mark;
+    bool f_quirk_enabled_allow_trailing_new_line;
+    bool f_quirk_enabled_replace_invalid_utf_8;
+    bool f_allow_leading_ars;
+    bool f_allow_leading_ubom;
     bool f_end_of_data;
 
     uint32_t p_decode_tokens[1];
+    uint32_t p_decode_leading[1];
   } private_impl;
 
   struct {
@@ -6029,6 +6053,11 @@
     return (wuffs_base__token_decoder*)this;
   }
 
+  inline wuffs_base__empty_struct  //
+  set_quirk_enabled(uint32_t a_quirk, bool a_enabled) {
+    return wuffs_json__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+  }
+
   inline wuffs_base__status  //
   decode_tokens(wuffs_base__token_buffer* a_dst, wuffs_base__io_buffer* a_src) {
     return wuffs_json__decoder__decode_tokens(this, a_dst, a_src);
@@ -20262,6 +20291,11 @@
                                    wuffs_base__io_buffer* a_src,
                                    uint32_t a_n);
 
+static wuffs_base__status  //
+wuffs_json__decoder__decode_leading(wuffs_json__decoder* self,
+                                    wuffs_base__token_buffer* a_dst,
+                                    wuffs_base__io_buffer* a_src);
+
 // ---------------- VTables
 
 const wuffs_base__token_decoder__func_ptrs
@@ -20329,6 +20363,58 @@
 
 // ---------------- Function Implementations
 
+// -------- func json.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct  //
+wuffs_json__decoder__set_quirk_enabled(wuffs_json__decoder* self,
+                                       uint32_t a_quirk,
+                                       bool a_enabled) {
+  if (!self) {
+    return wuffs_base__make_empty_struct();
+  }
+  if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+    return wuffs_base__make_empty_struct();
+  }
+
+  if (a_quirk == 1225364480) {
+    self->private_impl.f_quirk_enabled_allow_backslash_a = a_enabled;
+  } else if (a_quirk == 1225364481) {
+    self->private_impl.f_quirk_enabled_allow_backslash_capital_u = a_enabled;
+  } else if (a_quirk == 1225364482) {
+    self->private_impl.f_quirk_enabled_allow_backslash_e = a_enabled;
+  } else if (a_quirk == 1225364483) {
+    self->private_impl.f_quirk_enabled_allow_backslash_question_mark =
+        a_enabled;
+  } else if (a_quirk == 1225364484) {
+    self->private_impl.f_quirk_enabled_allow_backslash_single_quote = a_enabled;
+  } else if (a_quirk == 1225364485) {
+    self->private_impl.f_quirk_enabled_allow_backslash_v = a_enabled;
+  } else if (a_quirk == 1225364486) {
+    self->private_impl.f_quirk_enabled_allow_backslash_x = a_enabled;
+  } else if (a_quirk == 1225364487) {
+    self->private_impl.f_quirk_enabled_allow_backslash_zero = a_enabled;
+  } else if (a_quirk == 1225364488) {
+    self->private_impl.f_quirk_enabled_allow_comment_block = a_enabled;
+  } else if (a_quirk == 1225364489) {
+    self->private_impl.f_quirk_enabled_allow_comment_line = a_enabled;
+  } else if (a_quirk == 1225364490) {
+    self->private_impl.f_quirk_enabled_allow_final_comma = a_enabled;
+  } else if (a_quirk == 1225364491) {
+    self->private_impl.f_quirk_enabled_allow_inf_nan_numbers = a_enabled;
+  } else if (a_quirk == 1225364492) {
+    self->private_impl.f_quirk_enabled_allow_leading_ascii_record_separator =
+        a_enabled;
+  } else if (a_quirk == 1225364493) {
+    self->private_impl.f_quirk_enabled_allow_leading_unicode_byte_order_mark =
+        a_enabled;
+  } else if (a_quirk == 1225364494) {
+    self->private_impl.f_quirk_enabled_allow_trailing_new_line = a_enabled;
+  } else if (a_quirk == 1225364495) {
+    self->private_impl.f_quirk_enabled_replace_invalid_utf_8 = a_enabled;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
 // -------- func json.decoder.decode_tokens
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__status  //
@@ -20418,13 +20504,35 @@
       status = wuffs_base__make_status(wuffs_base__note__end_of_data);
       goto ok;
     }
+    if (self->private_impl
+            .f_quirk_enabled_allow_leading_ascii_record_separator ||
+        self->private_impl
+            .f_quirk_enabled_allow_leading_unicode_byte_order_mark) {
+      if (a_dst) {
+        a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+      }
+      if (a_src) {
+        a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+      }
+      WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+      status = wuffs_json__decoder__decode_leading(self, a_dst, a_src);
+      if (a_dst) {
+        iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+      }
+      if (a_src) {
+        iop_a_src = a_src->data.ptr + a_src->meta.ri;
+      }
+      if (status.repr) {
+        goto suspend;
+      }
+    }
     v_expect = 3762;
   label__outer__continue:;
     while (true) {
       while (true) {
         if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
           status = wuffs_base__make_status(wuffs_base__suspension__short_write);
-          WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+          WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
           goto label__outer__continue;
         }
         v_whitespace_length = 0;
@@ -20445,7 +20553,7 @@
             }
             status =
                 wuffs_base__make_status(wuffs_base__suspension__short_read);
-            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
             v_whitespace_length = 0;
             goto label__outer__continue;
           }
@@ -20490,7 +20598,7 @@
             if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
               status =
                   wuffs_base__make_status(wuffs_base__suspension__short_write);
-              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
               goto label__string_loop_outer__continue;
             }
             v_string_length = 0;
@@ -20513,7 +20621,7 @@
                 }
                 status =
                     wuffs_base__make_status(wuffs_base__suspension__short_read);
-                WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+                WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
                 v_string_length = 0;
                 goto label__string_loop_outer__continue;
               }
@@ -20587,7 +20695,7 @@
                   }
                   status = wuffs_base__make_status(
                       wuffs_base__suspension__short_read);
-                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(6);
                   v_string_length = 0;
                   v_char = 0;
                   goto label__string_loop_outer__continue;
@@ -20613,7 +20721,7 @@
                     }
                     status = wuffs_base__make_status(
                         wuffs_base__suspension__short_read);
-                    WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(6);
+                    WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7);
                     v_string_length = 0;
                     v_char = 0;
                     goto label__string_loop_outer__continue;
@@ -20659,7 +20767,7 @@
                       }
                       status = wuffs_base__make_status(
                           wuffs_base__suspension__short_read);
-                      WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7);
+                      WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(8);
                       v_string_length = 0;
                       v_uni4_value = 0;
                       v_char = 0;
@@ -20745,7 +20853,7 @@
                   }
                   status = wuffs_base__make_status(
                       wuffs_base__suspension__short_read);
-                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(8);
+                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(9);
                   v_string_length = 0;
                   v_char = 0;
                   goto label__string_loop_outer__continue;
@@ -20787,7 +20895,7 @@
                   }
                   status = wuffs_base__make_status(
                       wuffs_base__suspension__short_read);
-                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(9);
+                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
                   v_string_length = 0;
                   v_char = 0;
                   goto label__string_loop_outer__continue;
@@ -20834,7 +20942,7 @@
                   }
                   status = wuffs_base__make_status(
                       wuffs_base__suspension__short_read);
-                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
+                  WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
                   v_string_length = 0;
                   v_char = 0;
                   goto label__string_loop_outer__continue;
@@ -20892,13 +21000,13 @@
               }
               status =
                   wuffs_base__make_status(wuffs_base__suspension__short_read);
-              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
+              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(12);
               goto label__1__continue;
             }
             if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
               status =
                   wuffs_base__make_status(wuffs_base__suspension__short_write);
-              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(12);
+              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(13);
               goto label__1__continue;
             }
             (iop_a_src += 1, wuffs_base__make_empty_struct());
@@ -20976,11 +21084,11 @@
             } else {
               status =
                   wuffs_base__make_status(wuffs_base__suspension__short_read);
-              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(13);
+              WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(14);
               while (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
                 status = wuffs_base__make_status(
                     wuffs_base__suspension__short_write);
-                WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(14);
+                WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(15);
               }
             }
           }
@@ -21114,7 +21222,7 @@
           } else if (v_match == 1) {
             status =
                 wuffs_base__make_status(wuffs_base__suspension__short_read);
-            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(15);
+            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(16);
             goto label__outer__continue;
           }
         } else if (v_class == 10) {
@@ -21135,7 +21243,7 @@
           } else if (v_match == 1) {
             status =
                 wuffs_base__make_status(wuffs_base__suspension__short_read);
-            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(16);
+            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
             goto label__outer__continue;
           }
         } else if (v_class == 11) {
@@ -21156,7 +21264,7 @@
           } else if (v_match == 1) {
             status =
                 wuffs_base__make_status(wuffs_base__suspension__short_read);
-            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
+            WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(18);
             goto label__outer__continue;
           }
         }
@@ -21387,6 +21495,122 @@
   return v_n;
 }
 
+// -------- func json.decoder.decode_leading
+
+static wuffs_base__status  //
+wuffs_json__decoder__decode_leading(wuffs_json__decoder* self,
+                                    wuffs_base__token_buffer* a_dst,
+                                    wuffs_base__io_buffer* a_src) {
+  wuffs_base__status status = wuffs_base__make_status(NULL);
+
+  uint8_t v_c = 0;
+  uint32_t v_u = 0;
+
+  wuffs_base__token* iop_a_dst = NULL;
+  wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  wuffs_base__token* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  if (a_dst) {
+    io0_a_dst = a_dst->data.ptr;
+    io1_a_dst = io0_a_dst + a_dst->meta.wi;
+    iop_a_dst = io1_a_dst;
+    io2_a_dst = io0_a_dst + a_dst->data.len;
+    if (a_dst->meta.closed) {
+      io2_a_dst = iop_a_dst;
+    }
+  }
+  uint8_t* iop_a_src = NULL;
+  uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  if (a_src) {
+    io0_a_src = a_src->data.ptr;
+    io1_a_src = io0_a_src + a_src->meta.ri;
+    iop_a_src = io1_a_src;
+    io2_a_src = io0_a_src + a_src->meta.wi;
+  }
+
+  uint32_t coro_susp_point = self->private_impl.p_decode_leading[0];
+  if (coro_susp_point) {
+  }
+  switch (coro_susp_point) {
+    WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+    self->private_impl.f_allow_leading_ars =
+        self->private_impl.f_quirk_enabled_allow_leading_ascii_record_separator;
+    self->private_impl.f_allow_leading_ubom =
+        self->private_impl
+            .f_quirk_enabled_allow_leading_unicode_byte_order_mark;
+  label__0__continue:;
+    while (self->private_impl.f_allow_leading_ars ||
+           self->private_impl.f_allow_leading_ubom) {
+      if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+        status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+        WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+        goto label__0__continue;
+      }
+      if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+        if (a_src && a_src->meta.closed) {
+          goto label__0__break;
+        }
+        status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+        WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+        goto label__0__continue;
+      }
+      v_c = wuffs_base__load_u8be__no_bounds_check(iop_a_src);
+      if ((v_c == 30) && self->private_impl.f_allow_leading_ars) {
+        self->private_impl.f_allow_leading_ars = false;
+        (iop_a_src += 1, wuffs_base__make_empty_struct());
+        *iop_a_dst++ = wuffs_base__make_token(
+            (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+            (((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+        goto label__0__continue;
+      } else if ((v_c == 239) && self->private_impl.f_allow_leading_ubom) {
+        if (((uint64_t)(io2_a_src - iop_a_src)) < 3) {
+          if (a_src && a_src->meta.closed) {
+            goto label__0__break;
+          }
+          status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+          WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+          goto label__0__continue;
+        }
+        v_u = ((uint32_t)(wuffs_base__load_u24le__no_bounds_check(iop_a_src)));
+        if (v_u == 12565487) {
+          self->private_impl.f_allow_leading_ubom = false;
+          (iop_a_src += 3, wuffs_base__make_empty_struct());
+          *iop_a_dst++ = wuffs_base__make_token(
+              (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+              (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+          goto label__0__continue;
+        }
+      }
+      goto label__0__break;
+    }
+  label__0__break:;
+
+    goto ok;
+  ok:
+    self->private_impl.p_decode_leading[0] = 0;
+    goto exit;
+  }
+
+  goto suspend;
+suspend:
+  self->private_impl.p_decode_leading[0] =
+      wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+
+  goto exit;
+exit:
+  if (a_dst) {
+    a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+  }
+  if (a_src) {
+    a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+  }
+
+  return status;
+}
+
 #endif  // !defined(WUFFS_CONFIG__MODULES) ||
         // defined(WUFFS_CONFIG__MODULE__JSON)
 
diff --git a/std/json/decode_json.wuffs b/std/json/decode_json.wuffs
index 1bd524a..44d1678 100644
--- a/std/json/decode_json.wuffs
+++ b/std/json/decode_json.wuffs
@@ -13,6 +13,26 @@
 // limitations under the License.
 
 pub struct decoder? implements base.token_decoder(
+	quirk_enabled_allow_backslash_a                     : base.bool,
+	quirk_enabled_allow_backslash_capital_u             : base.bool,
+	quirk_enabled_allow_backslash_e                     : base.bool,
+	quirk_enabled_allow_backslash_question_mark         : base.bool,
+	quirk_enabled_allow_backslash_single_quote          : base.bool,
+	quirk_enabled_allow_backslash_v                     : base.bool,
+	quirk_enabled_allow_backslash_x                     : base.bool,
+	quirk_enabled_allow_backslash_zero                  : base.bool,
+	quirk_enabled_allow_comment_block                   : base.bool,
+	quirk_enabled_allow_comment_line                    : base.bool,
+	quirk_enabled_allow_final_comma                     : base.bool,
+	quirk_enabled_allow_inf_nan_numbers                 : base.bool,
+	quirk_enabled_allow_leading_ascii_record_separator  : base.bool,
+	quirk_enabled_allow_leading_unicode_byte_order_mark : base.bool,
+	quirk_enabled_allow_trailing_new_line               : base.bool,
+	quirk_enabled_replace_invalid_utf_8                 : base.bool,
+
+	allow_leading_ars  : base.bool,
+	allow_leading_ubom : base.bool,
+
 	end_of_data : base.bool,
 )(
 	// stack is conceptually an array of bits, implemented as an array of u32.
@@ -46,6 +66,42 @@
 	stack : array[1024 / 32] base.u32,
 )
 
+pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
+	if args.quirk == quirk_allow_backslash_a {
+		this.quirk_enabled_allow_backslash_a = args.enabled
+	} else if args.quirk == quirk_allow_backslash_capital_u {
+		this.quirk_enabled_allow_backslash_capital_u = args.enabled
+	} else if args.quirk == quirk_allow_backslash_e {
+		this.quirk_enabled_allow_backslash_e = args.enabled
+	} else if args.quirk == quirk_allow_backslash_question_mark {
+		this.quirk_enabled_allow_backslash_question_mark = args.enabled
+	} else if args.quirk == quirk_allow_backslash_single_quote {
+		this.quirk_enabled_allow_backslash_single_quote = args.enabled
+	} else if args.quirk == quirk_allow_backslash_v {
+		this.quirk_enabled_allow_backslash_v = args.enabled
+	} else if args.quirk == quirk_allow_backslash_x {
+		this.quirk_enabled_allow_backslash_x = args.enabled
+	} else if args.quirk == quirk_allow_backslash_zero {
+		this.quirk_enabled_allow_backslash_zero = args.enabled
+	} else if args.quirk == quirk_allow_comment_block {
+		this.quirk_enabled_allow_comment_block = args.enabled
+	} else if args.quirk == quirk_allow_comment_line {
+		this.quirk_enabled_allow_comment_line = args.enabled
+	} else if args.quirk == quirk_allow_final_comma {
+		this.quirk_enabled_allow_final_comma = args.enabled
+	} else if args.quirk == quirk_allow_inf_nan_numbers {
+		this.quirk_enabled_allow_inf_nan_numbers = args.enabled
+	} else if args.quirk == quirk_allow_leading_ascii_record_separator {
+		this.quirk_enabled_allow_leading_ascii_record_separator = args.enabled
+	} else if args.quirk == quirk_allow_leading_unicode_byte_order_mark {
+		this.quirk_enabled_allow_leading_unicode_byte_order_mark = args.enabled
+	} else if args.quirk == quirk_allow_trailing_new_line {
+		this.quirk_enabled_allow_trailing_new_line = args.enabled
+	} else if args.quirk == quirk_replace_invalid_utf_8 {
+		this.quirk_enabled_replace_invalid_utf_8 = args.enabled
+	}
+}
+
 pub func decoder.decode_tokens?(dst: base.token_writer, src: base.io_reader) {
 	var vminor            : base.u32[..= 0xFF_FFFF]
 	var number_length     : base.u32[..= 0x3FF]
@@ -82,6 +138,11 @@
 		return base."@end of data"
 	}
 
+	if this.quirk_enabled_allow_leading_ascii_record_separator or
+		this.quirk_enabled_allow_leading_unicode_byte_order_mark {
+		this.decode_leading?(dst: args.dst, src: args.src)
+	}
+
 	expect = 0x0EB2  // EXPECT_VALUE
 
 	while.outer true {
@@ -1017,3 +1078,49 @@
 	}
 	return n
 }
+
+pri func decoder.decode_leading?(dst: base.token_writer, src: base.io_reader) {
+	var c : base.u8
+	var u : base.u32
+
+	this.allow_leading_ars = this.quirk_enabled_allow_leading_ascii_record_separator
+	this.allow_leading_ubom = this.quirk_enabled_allow_leading_unicode_byte_order_mark
+	while this.allow_leading_ars or this.allow_leading_ubom {
+		if args.dst.available() <= 0 {
+			yield? base."$short write"
+			continue
+		}
+		if args.src.available() <= 0 {
+			if args.src.is_closed() {
+				break
+			}
+			yield? base."$short read"
+			continue
+		}
+		c = args.src.peek_u8()
+		if (c == 0x1E) and this.allow_leading_ars {
+			this.allow_leading_ars = false
+			args.src.skip32_fast!(actual: 1, worst_case: 1)
+			args.dst.write_fast_token!(
+				value_major: 0, value_minor: 0, link: 0x0, length: 1)
+			continue
+		} else if (c == 0xEF) and this.allow_leading_ubom {
+			if args.src.available() < 3 {
+				if args.src.is_closed() {
+					break
+				}
+				yield? base."$short read"
+				continue
+			}
+			u = args.src.peek_u24le_as_u32()
+			if u == 0xBF_BBEF {
+				this.allow_leading_ubom = false
+				args.src.skip32_fast!(actual: 3, worst_case: 3)
+				args.dst.write_fast_token!(
+					value_major: 0, value_minor: 0, link: 0x0, length: 3)
+				continue
+			}
+		}
+		break
+	}
+}
diff --git a/test/c/std/json.c b/test/c/std/json.c
index cdb91ca..2c1d712 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -1106,6 +1106,72 @@
 }
 
 const char*  //
+test_wuffs_json_decode_quirk_allow_leading_etc() {
+  CHECK_FOCUS(__func__);
+
+  struct {
+    // want has 4 bytes, one for each possible q:
+    //  - q&1 sets WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR.
+    //  - q&2 sets WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK.
+    // A '+' or '-' means that decoding should succeed or fail.
+    const char* want;
+    const char* str;
+  } test_cases[] = {
+      {.want = "-+-+", .str = "\x1Etrue"},
+      {.want = "--++", .str = "\xEF\xBB\xBFtrue"},
+      {.want = "---+", .str = "\x1E\xEF\xBB\xBFtrue"},
+      {.want = "---+", .str = "\xEF\xBB\xBF\x1Etrue"},
+      {.want = "----", .str = " \x1Etrue"},
+      {.want = "----", .str = "\x1E \xEF\xBB\xBFtrue"},
+      {.want = "----", .str = "\x1E\x1Etrue"},
+      {.want = "----", .str = "\xEF\xBB"},
+      {.want = "----", .str = "\xEF\xBB\xBF"},
+      {.want = "----", .str = "\xEF\xBB\xBF$"},
+      {.want = "----", .str = "\xEFtrue"},
+  };
+
+  int tc;
+  for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+    int q;
+    for (q = 0; q < 4; q++) {
+      wuffs_json__decoder dec;
+      CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+                                     &dec, sizeof dec, WUFFS_VERSION,
+                                     WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+      wuffs_json__decoder__set_quirk_enabled(
+          &dec, WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR, q & 1);
+      wuffs_json__decoder__set_quirk_enabled(
+          &dec, WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK, q & 2);
+
+      wuffs_base__token_buffer tok =
+          wuffs_base__make_token_buffer_writer(global_have_token_slice);
+      wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+          wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+                                    strlen(test_cases[tc].str)),
+          true);
+      const char* have =
+          wuffs_json__decoder__decode_tokens(&dec, &tok, &src).repr;
+      const char* want =
+          (test_cases[tc].want[q] == '+') ? NULL : wuffs_json__error__bad_input;
+      if (have != want) {
+        RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+                    q, have, want);
+      }
+
+      size_t total_length = 0;
+      while (tok.meta.ri < tok.meta.wi) {
+        total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+      }
+      if (total_length != src.meta.ri) {
+        RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+                    total_length, src.meta.ri);
+      }
+    }
+  }
+  return NULL;
+}
+
+const char*  //
 test_wuffs_json_decode_unicode4_escapes() {
   CHECK_FOCUS(__func__);
 
@@ -1453,13 +1519,14 @@
     test_strconv_parse_number_u64,     //
     test_strconv_utf_8_next,           //
 
-    test_wuffs_json_decode_end_of_data,           //
-    test_wuffs_json_decode_interface,             //
-    test_wuffs_json_decode_long_numbers,          //
-    test_wuffs_json_decode_prior_valid_utf_8,     //
-    test_wuffs_json_decode_src_io_buffer_length,  //
-    test_wuffs_json_decode_string,                //
-    test_wuffs_json_decode_unicode4_escapes,      //
+    test_wuffs_json_decode_end_of_data,              //
+    test_wuffs_json_decode_interface,                //
+    test_wuffs_json_decode_long_numbers,             //
+    test_wuffs_json_decode_prior_valid_utf_8,        //
+    test_wuffs_json_decode_quirk_allow_leading_etc,  //
+    test_wuffs_json_decode_src_io_buffer_length,     //
+    test_wuffs_json_decode_string,                   //
+    test_wuffs_json_decode_unicode4_escapes,         //
 
 #ifdef WUFFS_MIMIC