// 结构解析层。
//
// 这一层的职责不是「找字节」,而是「按格式规范解析字节」:
//   - ZIP:从 EOCD 定位中央目录,逐条解析条目名与压缩方法;
//   - OLE2:读 FAT 与目录扇区,取出真实的流名;
//   - ISO-BMFF:按 box 树遍历,读 ftyp brand 与 hdlr handler;
//   - RIFF:遍历 chunk,校验必需块是否存在;
//   - EBML:按 vint 解析 DocType;
//   - TAR:校验 header 的八进制 checksum;
//   - PE:读 COFF / Optional Header,校验机器类型与子系统。
//
// 所有解析都先做边界检查;任何结构不一致都返回 `None`,由上层决定是否降级,
// 绝不把「看起来像」当成「结构成立」。

// ---------------------------------------------------------------------------
// 基础读取
// ---------------------------------------------------------------------------

///|
/// 比对 `offset` 处的 `magic`,越界或长度不足返回 `false`。
fn match_at(data : Bytes, offset : Int, magic : Bytes) -> Bool {
  let n = data.length()
  let m = magic.length()
  if offset < 0 || m == 0 || offset + m > n {
    return false
  }
  let mut i = 0
  while i < m {
    if data[offset + i].to_int() != magic[i].to_int() {
      return false
    }
    i = i + 1
  }
  true
}

///|
fn byte_at(data : Bytes, offset : Int) -> Int? {
  if offset < 0 || offset >= data.length() {
    return None
  }
  Some(data[offset].to_int())
}

///|
/// 读小端 16 位。
fn u16_le(data : Bytes, offset : Int) -> Int? {
  if offset < 0 || offset + 2 > data.length() {
    return None
  }
  Some(data[offset].to_int() + data[offset + 1].to_int() * 256)
}

///|
/// 读大端 16 位。
fn u16_be(data : Bytes, offset : Int) -> Int? {
  if offset < 0 || offset + 2 > data.length() {
    return None
  }
  Some(data[offset].to_int() * 256 + data[offset + 1].to_int())
}

///|
/// 读小端 32 位。
///
/// 最高字节 ≥ 0x80 时数值超出内存缓冲区的可寻址范围,按越界处理返回 `None`,
/// 这样所有调用点都不需要再单独防溢出。
fn u32_le(data : Bytes, offset : Int) -> Int? {
  if offset < 0 || offset + 4 > data.length() {
    return None
  }
  let high = data[offset + 3].to_int()
  if high >= 128 {
    return None
  }
  Some(
    high * 16777216 +
    data[offset + 2].to_int() * 65536 +
    data[offset + 1].to_int() * 256 +
    data[offset].to_int(),
  )
}

///|
/// 读大端 32 位(同上,超出范围返回 `None`)。
fn u32_be(data : Bytes, offset : Int) -> Int? {
  if offset < 0 || offset + 4 > data.length() {
    return None
  }
  let high = data[offset].to_int()
  if high >= 128 {
    return None
  }
  Some(
    high * 16777216 +
    data[offset + 1].to_int() * 65536 +
    data[offset + 2].to_int() * 256 +
    data[offset + 3].to_int(),
  )
}

///|
fn slice_bytes(data : Bytes, start : Int, end : Int) -> Bytes? {
  if start < 0 || end < start || end > data.length() {
    return None
  }
  let out : Array[Byte] = []
  let mut i = start
  while i < end {
    out.push(data[i])
    i = i + 1
  }
  Some(Bytes::from_array(out.exact_view()))
}

///|
/// 写一个码点,越界时退化为 `?`。
fn write_code(builder : StringBuilder, code : Int) -> Unit {
  match code.to_char() {
    Some(c) => builder.write_char(c)
    None => builder.write_char('?')
  }
}

///|
/// 把一段原始字节按 UTF-8 解码为字符串。
///
/// 不能用 `Bytes::to_unchecked_string`(它按 UTF-16 重新解释字节),
/// 也不能用 `Bytes::to_string`(它返回 `b"..."` 调试形式),
/// 所以这里显式做 UTF-8 解码。
fn raw_string(data : Bytes, offset : Int, length : Int) -> String {
  if offset < 0 || length <= 0 || offset + length > data.length() {
    return ""
  }
  let builder = StringBuilder()
  let mut i = 0
  while i < length {
    let b = data[offset + i].to_int()
    if b < 128 {
      builder.write_char(data[offset + i].to_char())
      i = i + 1
    } else {
      let needed = if b >= 194 && b <= 223 {
        1
      } else if b >= 224 && b <= 239 {
        2
      } else if b >= 240 && b <= 244 {
        3
      } else {
        0
      }
      if needed == 0 || i + needed >= length {
        builder.write_char('?')
        i = i + 1
      } else {
        let base = if needed == 1 {
          192
        } else if needed == 2 {
          224
        } else {
          240
        }
        let mut code = b - base
        let mut j = 1
        while j <= needed {
          code = code * 64 + (data[offset + i + j].to_int() - 128)
          j = j + 1
        }
        write_code(builder, code)
        i = i + needed + 1
      }
    }
  }
  builder.to_string()
}

///|
fn contains_name(names : Array[String], wanted : String) -> Bool {
  for name in names {
    if name == wanted {
      return true
    }
  }
  false
}

// ---------------------------------------------------------------------------
// ZIP:中央目录
// ---------------------------------------------------------------------------

///|
pub struct ZipEntry {
  name : String
  /// 压缩方法:0 = stored,8 = deflate
  compression : Int
  compressed_size : Int
  uncompressed_size : Int
  /// 条目数据在输入中的起始偏移
  data_offset : Int
  local_offset : Int
}

///|
pub struct ZipArchive {
  entries : Array[ZipEntry]
  /// EOCD 中声明的条目总数
  declared_entries : Int
  /// 是否完整解析了声明的全部条目
  complete : Bool
}

///|
fn find_eocd(data : Bytes) -> Int? {
  let len = data.length()
  if len < 22 {
    return None
  }
  let mut pos = len - 22
  let floor = if len > 65557 { len - 65557 } else { 0 }
  while pos >= floor {
    if match_at(data, pos, b"PK\x05\x06") {
      return Some(pos)
    }
    pos = pos - 1
  }
  None
}

///|
fn zip_data_offset(data : Bytes, local_offset : Int) -> Int? {
  if !match_at(data, local_offset, b"PK\x03\x04") {
    return None
  }
  let name_len = match u16_le(data, local_offset + 26) {
    Some(v) => v
    None => return None
  }
  let extra_len = match u16_le(data, local_offset + 28) {
    Some(v) => v
    None => return None
  }
  let start = local_offset + 30 + name_len + extra_len
  if start > data.length() {
    return None
  }
  Some(start)
}

///|
/// 解析 ZIP 中央目录。返回 `None` 表示这不是结构完整的 ZIP。
pub fn parse_zip(data : Bytes) -> ZipArchive? {
  let eocd = match find_eocd(data) {
    Some(v) => v
    None => return None
  }
  let declared = match u16_le(data, eocd + 10) {
    Some(v) => v
    None => return None
  }
  let cd_offset = match u32_le(data, eocd + 16) {
    Some(v) => v
    None => return None
  }
  if declared == 0 || cd_offset >= data.length() {
    return None
  }
  let entries : Array[ZipEntry] = []
  let mut pos = cd_offset
  let mut count = 0
  while count < declared && count < 100000 {
    if !match_at(data, pos, b"PK\x01\x02") {
      break
    }
    let compression = match u16_le(data, pos + 10) {
      Some(v) => v
      None => break
    }
    // 注意:不要读 CRC32。真实 ZIP 的 CRC 经常 > 0x7FFFFFFF,
    // 会被 u32_le 的溢出保护判为越界,导致整份中央目录解析中断。
    let compressed = match u32_le(data, pos + 20) {
      Some(v) => v
      None => break
    }
    let uncompressed = match u32_le(data, pos + 24) {
      Some(v) => v
      None => break
    }
    let name_len = match u16_le(data, pos + 28) {
      Some(v) => v
      None => break
    }
    let extra_len = match u16_le(data, pos + 30) {
      Some(v) => v
      None => break
    }
    let comment_len = match u16_le(data, pos + 32) {
      Some(v) => v
      None => break
    }
    let local_offset = match u32_le(data, pos + 42) {
      Some(v) => v
      None => break
    }
    if pos + 46 + name_len > data.length() {
      break
    }
    let name = raw_string(data, pos + 46, name_len)
    let start = match zip_data_offset(data, local_offset) {
      Some(v) => v
      None => break
    }
    entries.push({
      name,
      compression,
      compressed_size: compressed,
      uncompressed_size: uncompressed,
      data_offset: start,
      local_offset,
    })
    pos = pos + 46 + name_len + extra_len + comment_len
    count = count + 1
  }
  if entries.length() == 0 {
    return None
  }
  Some({
    entries,
    declared_entries: declared,
    complete: entries.length() == declared,
  })
}

///|
/// 取出 stored 条目的原始内容(deflate 条目不解压,返回 `None`)。
pub fn zip_entry_content(data : Bytes, entry : ZipEntry) -> Bytes? {
  if entry.compression != 0 {
    return None
  }
  slice_bytes(
    data,
    entry.data_offset,
    entry.data_offset + entry.compressed_size,
  )
}

///|
/// 按名字精确查找条目(不是子串搜索)。
pub fn zip_find_entry(archive : ZipArchive, name : String) -> ZipEntry? {
  for entry in archive.entries {
    if entry.name == name {
      return Some(entry)
    }
  }
  None
}

///|
/// 条目名快照,用于算法判定与证据输出。
pub fn zip_entry_names(archive : ZipArchive) -> Array[String] {
  let out : Array[String] = []
  for entry in archive.entries {
    out.push(entry.name)
  }
  out
}

// ---------------------------------------------------------------------------
// OLE2:FAT 与目录项
// ---------------------------------------------------------------------------

///|
fn ole_sector_offset(sector : Int, sector_size : Int) -> Int {
  // 扇区号 + 1 才是文件偏移(头部占第 0 个扇区的位置)
  if sector < 0 || sector > 1048576 {
    return -1
  }
  (sector + 1) * sector_size
}

///|
fn utf16le_name(data : Bytes, offset : Int, byte_len : Int) -> String {
  let builder = StringBuilder()
  let mut i = 0
  while i + 1 < byte_len {
    let low = data[offset + i].to_int()
    let high = data[offset + i + 1].to_int()
    let code = high * 256 + low
    if code == 0 {
      break
    }
    write_code(builder, code)
    i = i + 2
  }
  builder.to_string()
}

///|
/// 解析 OLE2 复合文档的目录项名称(WordDocument / Workbook / PowerPoint Document …)。
///
/// 返回 `None` 表示头部或 FAT 结构不成立;返回空数组表示结构成立但没有可读流名。
pub fn parse_ole2_streams(data : Bytes) -> Array[String]? {
  if data.length() < 512 {
    return None
  }
  if !match_at(data, 0, b"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1") {
    return None
  }
  let shift = match u16_le(data, 30) {
    Some(v) => v
    None => return None
  }
  if shift < 7 || shift > 16 {
    return None
  }
  let sector_size = 1 << shift
  let fat_count = match u32_le(data, 44) {
    Some(v) => v
    None => return None
  }
  let dir_start = match u32_le(data, 48) {
    Some(v) => v
    None => return None
  }
  if fat_count == 0 || fat_count > 4096 {
    return None
  }
  // 头部 DIFAT 的前 109 项就是 FAT 扇区号
  let fat_sectors : Array[Int] = []
  let mut i = 0
  while i < 109 && i < fat_count {
    match u32_le(data, 76 + i * 4) {
      Some(sector) => fat_sectors.push(sector)
      None => break
    }
    i = i + 1
  }
  if fat_sectors.length() == 0 {
    return None
  }
  let fat : Array[Int] = []
  for sector in fat_sectors {
    let base = ole_sector_offset(sector, sector_size)
    if base >= 0 && base + sector_size <= data.length() {
      let mut j = 0
      while j < sector_size {
        match u32_le(data, base + j) {
          Some(v) => fat.push(v)
          None => fat.push(-1)
        }
        j = j + 4
      }
    }
  }
  if fat.length() == 0 {
    return None
  }
  let names : Array[String] = []
  let mut sector = dir_start
  let mut steps = 0
  while sector >= 0 && steps < 4096 {
    let base = ole_sector_offset(sector, sector_size)
    if base < 0 || base + sector_size > data.length() {
      break
    }
    let mut off = 0
    while off + 128 <= sector_size {
      let pos = base + off
      let name_len = match u16_le(data, pos + 64) {
        Some(v) => v
        None => 0
      }
      let etype = match byte_at(data, pos + 66) {
        Some(v) => v
        None => 0
      }
      if (etype == 1 || etype == 2 || etype == 5) &&
        name_len >= 2 && name_len <= 64 {
        let name = utf16le_name(data, pos, name_len)
        if !name.is_empty() {
          names.push(name)
        }
      }
      off = off + 128
    }
    let next = if sector < fat.length() { fat[sector] } else { -1 }
    sector = next
    steps = steps + 1
  }
  Some(names)
}

// ---------------------------------------------------------------------------
// ISO-BMFF:box 树
// ---------------------------------------------------------------------------

///|
priv struct BmffBox {
  typ : String
  payload : Int
  end : Int
}

///|
fn read_box(data : Bytes, pos : Int, limit : Int) -> BmffBox? {
  if pos + 8 > limit {
    return None
  }
  let size32 = match u32_be(data, pos) {
    Some(v) => v
    None => return None
  }
  let typ = raw_string(data, pos + 4, 4)
  if size32 == 0 {
    return Some({ typ, payload: pos + 8, end: limit })
  }
  if size32 == 1 {
    // 64 位 largesize:这里只支持高 32 位为 0(< 4 GiB)
    let high = match u32_be(data, pos + 8) {
      Some(v) => v
      None => return None
    }
    let low = match u32_be(data, pos + 12) {
      Some(v) => v
      None => return None
    }
    if high != 0 || low < 16 {
      return None
    }
    let end = pos + low
    if end > limit {
      return None
    }
    return Some({ typ, payload: pos + 16, end })
  }
  if size32 < 8 {
    return None
  }
  let end = pos + size32
  if end > limit {
    return None
  }
  Some({ typ, payload: pos + 8, end })
}

///|
fn child_boxes(data : Bytes, parent : BmffBox) -> Array[BmffBox] {
  let out : Array[BmffBox] = []
  let mut pos = parent.payload
  let mut scanned = 0
  while pos + 8 <= parent.end && scanned < 4096 {
    match read_box(data, pos, parent.end) {
      Some(b) => {
        if b.end <= pos {
          break
        }
        out.push(b)
        pos = b.end
      }
      None => break
    }
    scanned = scanned + 1
  }
  out
}

///|
fn find_top_box(data : Bytes, typ : String) -> BmffBox? {
  let limit = data.length()
  let mut pos = 0
  let mut scanned = 0
  while pos + 8 <= limit && scanned < 4096 {
    match read_box(data, pos, limit) {
      Some(b) => {
        if b.typ == typ {
          return Some(b)
        }
        if b.end <= pos {
          break
        }
        pos = b.end
      }
      None => break
    }
    scanned = scanned + 1
  }
  None
}

///|
/// 收集 handler 类型(`vide` / `soun`),路径为 moov → trak* → mdia → hdlr。
pub fn bmff_handlers(data : Bytes) -> Array[String] {
  let out : Array[String] = []
  let moov = match find_top_box(data, "moov") {
    Some(b) => b
    None => return out
  }
  for trak in child_boxes(data, moov) {
    if trak.typ == "trak" {
      for mdia in child_boxes(data, trak) {
        if mdia.typ == "mdia" {
          for hdlr in child_boxes(data, mdia) {
            if hdlr.typ == "hdlr" && hdlr.payload + 12 <= hdlr.end {
              let handler = raw_string(data, hdlr.payload + 8, 4)
              out.push(handler)
            }
          }
        }
      }
    }
  }
  out
}

///|
/// 读 ftyp:major brand + compatible brands。
pub fn bmff_brands(data : Bytes) -> Array[String] {
  let out : Array[String] = []
  let ftyp = match find_top_box(data, "ftyp") {
    Some(b) => b
    None => return out
  }
  if ftyp.payload + 8 > ftyp.end {
    return out
  }
  out.push(raw_string(data, ftyp.payload, 4))
  let mut pos = ftyp.payload + 8
  while pos + 4 <= ftyp.end {
    out.push(raw_string(data, pos, 4))
    pos = pos + 4
  }
  out
}

// ---------------------------------------------------------------------------
// RIFF:chunk 遍历
// ---------------------------------------------------------------------------

///|
pub struct RiffInfo {
  /// 容器子类型,例如 `WAVE` / `AVI ` / `WEBP`
  form : String
  /// 实际遍历到的 chunk id
  chunks : Array[String]
  /// chunk 遍历是否走到预期结尾
  complete : Bool
}

///|
fn parse_chunk_container(data : Bytes, tag : Bytes) -> RiffInfo? {
  if data.length() < 12 || !match_at(data, 0, tag) {
    return None
  }
  let declared = match u32_le(data, 4) {
    Some(v) => v
    None => return None
  }
  let form = raw_string(data, 8, 4)
  let limit = if 8 + declared < data.length() {
    8 + declared
  } else {
    data.length()
  }
  let chunks : Array[String] = []
  let mut pos = 12
  let mut scanned = 0
  while pos + 8 <= limit && scanned < 4096 {
    let id = raw_string(data, pos, 4)
    let size = match u32_le(data, pos + 4) {
      Some(v) => v
      None => break
    }
    chunks.push(id)
    let advance = 8 + size + (size % 2)
    if advance <= 8 {
      break
    }
    pos = pos + advance
    scanned = scanned + 1
  }
  Some({
    form,
    chunks,
    complete: chunks.length() > 0 && pos >= limit - 1,
  })
}

///|
pub fn parse_riff(data : Bytes) -> RiffInfo? {
  parse_chunk_container(data, b"RIFF")
}

///|
/// IFF(AIFF/AIFC 等)用的是 `FORM` 容器标记,chunk 布局与 RIFF 相同。
pub fn parse_iff(data : Bytes) -> RiffInfo? {
  parse_chunk_container(data, b"FORM")
}

// ---------------------------------------------------------------------------
// EBML:vint 与 DocType
// ---------------------------------------------------------------------------

///|
fn vint_length(first : Int) -> Int {
  if first >= 128 {
    1
  } else if first >= 64 {
    2
  } else if first >= 32 {
    3
  } else if first >= 16 {
    4
  } else if first >= 8 {
    5
  } else if first >= 4 {
    6
  } else if first >= 2 {
    7
  } else if first >= 1 {
    8
  } else {
    0
  }
}

///|
/// 读变长整数,返回 (原始值, 字节数)。原始值保留 marker 位。
fn read_vint(data : Bytes, offset : Int, limit : Int) -> (Int, Int)? {
  if offset < 0 || offset >= limit {
    return None
  }
  let first = data[offset].to_int()
  let n = vint_length(first)
  if n == 0 || n > 4 || offset + n > limit {
    return None
  }
  let mut value = first
  let mut i = 1
  while i < n {
    value = value * 256 + data[offset + i].to_int()
    i = i + 1
  }
  Some((value, n))
}

///|
/// 去掉 vint 的 marker 位,得到实际长度值。
fn vint_payload(value : Int, n : Int) -> Int {
  let marker = 1 << ((n - 1) * 8 + (8 - n))
  value - marker
}

///|
/// 解析 EBML 头部里的 DocType(`webm` / `matroska`)。
pub fn ebml_doctype(data : Bytes) -> String? {
  let limit = data.length()
  if limit < 4 || !match_at(data, 0, b"\x1a\x45\xdf\xa3") {
    return None
  }
  let element_id_len = match read_vint(data, 0, limit) {
    Some((_, n)) => n
    None => return None
  }
  let header_size = match read_vint(data, element_id_len, limit) {
    Some((value, n)) => vint_payload(value, n)
    None => return None
  }
  let header_size_len = match read_vint(data, element_id_len, limit) {
    Some((_, n)) => n
    None => return None
  }
  let mut pos = element_id_len + header_size_len
  let end = if pos + header_size < limit { pos + header_size } else { limit }
  let mut scanned = 0
  while pos < end && scanned < 256 {
    let (id_value, element_id_len) = match read_vint(data, pos, end) {
      Some(v) => v
      None => break
    }
    let size_pos = pos + element_id_len
    let (size_value, size_len) = match read_vint(data, size_pos, end) {
      Some(v) => v
      None => break
    }
    let payload_len = vint_payload(size_value, size_len)
    let payload = size_pos + size_len
    if payload + payload_len > end {
      break
    }
    if id_value == 0x4282 {
      return Some(raw_string(data, payload, payload_len))
    }
    pos = payload + payload_len
    scanned = scanned + 1
  }
  None
}

// ---------------------------------------------------------------------------
// TAR:header checksum
// ---------------------------------------------------------------------------

///|
/// 校验 POSIX tar header 的八进制 checksum(字段 148..155,计算时按空格处理)。
pub fn tar_checksum_ok(data : Bytes) -> Bool {
  if data.length() < 512 {
    return false
  }
  let mut stored = 0
  let mut digits = 0
  let mut i = 0
  while i < 8 {
    let b = data[148 + i].to_int()
    if b >= 48 && b <= 55 {
      stored = stored * 8 + (b - 48)
      digits = digits + 1
    } else if b != 0 && b != 32 {
      return false
    }
    i = i + 1
  }
  if digits == 0 {
    return false
  }
  let mut sum = 0
  let mut j = 0
  while j < 512 {
    if j >= 148 && j < 156 {
      sum = sum + 32
    } else {
      sum = sum + data[j].to_int()
    }
    j = j + 1
  }
  stored == sum
}

// ---------------------------------------------------------------------------
// PE:COFF / Optional Header
// ---------------------------------------------------------------------------

///|
pub struct PeInfo {
  machine : Int
  is_64 : Bool
  is_dll : Bool
  subsystem : Int
  sections : Int
}

///|
fn machine_name(machine : Int) -> String {
  match machine {
    0x014c => "i386"
    0x8664 => "x86-64"
    0x01c0 => "ARM"
    0xaa64 => "ARM64"
    _ => "unknown"
  }
}

///|
/// 解析 PE 结构。返回 `None` 表示 `e_lfanew` 指向的位置没有合法的 PE 头。
pub fn parse_pe(data : Bytes) -> PeInfo? {
  if data.length() < 64 || !match_at(data, 0, b"MZ") {
    return None
  }
  let pe_offset = match u32_le(data, 60) {
    Some(v) => v
    None => return None
  }
  if !match_at(data, pe_offset, b"PE\x00\x00") {
    return None
  }
  let machine = match u16_le(data, pe_offset + 4) {
    Some(v) => v
    None => return None
  }
  if machine_name(machine) == "unknown" {
    return None
  }
  let sections = match u16_le(data, pe_offset + 6) {
    Some(v) => v
    None => return None
  }
  let characteristics = match u16_le(data, pe_offset + 22) {
    Some(v) => v
    None => return None
  }
  let optional = pe_offset + 24
  let magic = match u16_le(data, optional) {
    Some(v) => v
    None => return None
  }
  if magic != 0x10b && magic != 0x20b {
    return None
  }
  let subsystem = match u16_le(data, optional + 68) {
    Some(v) => v
    None => return None
  }
  Some({
    machine,
    is_64: magic == 0x20b,
    is_dll: (characteristics / 8192) % 2 == 1,
    subsystem,
    sections,
  })
}

///|
pub fn pe_machine_name(info : PeInfo) -> String {
  machine_name(info.machine)
}