// extract.mbt
//
// 解包流水线:Folder 解码 → 子流切分 → 逐级 CRC 校验 → 按条目表取文件。
//
// F3 只实现 COPY(stored)coder。7z 允许一个 Folder 里串联多个 coder
// (BCJ/delta 之类的前置过滤)以及一个 Folder 对应多个 pack stream,
// 这两种情况都显式报 `Unsupported`,留到 LZMA/LZMA2 之外的后续增量。

///|
/// 解包出的一个文件。
pub struct ArchiveFile {
  /// 归档内路径。
  name : String
  /// 文件内容。
  data : Bytes
}

///|
/// 解出归档中的所有文件。
///
/// 目录条目会被跳过;"空文件"条目产出长度 0 的 `Bytes`。
/// 每个 Folder 与子流声明的 CRC-32 都会被校验,不符即报 `BadCrc`。
pub fn SevenZ::extract_all(
  self : SevenZ,
) -> Array[ArchiveFile] raise SevenZError {
  let plan = self.parse_plan()
  let streams = plan.streams
  if streams.pack_sizes.length() != streams.folders.length() {
    raise Unsupported(what="一个 Folder 对应多个 pack stream")
  }
  // 1) 解码每个 Folder(含 folder 级 CRC 校验)
  let decoded : Array[Bytes] = []
  let mut cursor = 32L + streams.pack_pos
  for i in 0.. {
          let actual = crc32(data, 0, data.length())
          if actual != expected {
            raise BadCrc(what="folder " + i.to_string(), expected~, actual~)
          }
        }
        None => ()
      }
    }
    decoded.push(data)
    cursor += packed_size
  }
  // 2) 按声明的子流大小切分,并校验子流 CRC
  let sub_data : Array[Bytes] = []
  for i in 0.. data.length() {
        raise Malformed(
          reason="子流大小超出 Folder 解压数据(folder " +
            i.to_string() +
            ",子流 " +
            j.to_string() +
            ")",
        )
      }
      let piece = copy_range(data, pos, end)
      if j < folder.sub_crcs.length() {
        match folder.sub_crcs[j] {
          Some(expected) => {
            let actual = crc32(piece, 0, piece.length())
            if actual != expected {
              raise BadCrc(
                what="substream " + i.to_string() + "/" + j.to_string(),
                expected~,
                actual~,
              )
            }
          }
          None => ()
        }
      }
      sub_data.push(piece)
      pos = end
    }
    if pos != data.length() {
      raise Malformed(reason="子流大小之和与 Folder 解压大小不符")
    }
  }
  // 3) 按条目表装配:目录跳过;"空文件"(无数据流但 is_dir=false)产出空 Bytes
  let out : Array[ArchiveFile] = []
  for i in 0.. if !entry.is_dir { out.push({ name: entry.name, data: b"", }) }
      Some(owner) => {
        let flat = flat_index(streams, owner.0, owner.1)
        out.push({ name: entry.name, data: sub_data[flat], })
      }
    }
  }
  out
}

///|
/// 解出指定名字的文件。找不到时报 `Malformed`。
pub fn SevenZ::extract(self : SevenZ, name : String) -> Bytes raise SevenZError {
  for file in self.extract_all() {
    if file.name == name {
      return file.data
    }
  }
  raise Malformed(reason="归档中没有文件 " + name)
}

///|
/// 解码一个 Folder(F3 只支持单个 COPY coder)。
///
/// 输入:`cursor` 是该 Folder 的 packed 数据在文件中的绝对起点。
fn SevenZ::decode_folder(
  self : SevenZ,
  folder : Folder,
  cursor : Int64,
  packed_size : Int64,
) -> Bytes raise SevenZError {
  let start = cursor.to_int()
  let end = start + packed_size.to_int()
  if packed_size < 0L || end > self.data.length() {
    raise Malformed(reason="packed 数据区间越界")
  }
  decode_folder_bytes(folder, copy_range(self.data, start, end))
}

///|
/// 用 Folder 的 coder 解码 `packed` 数据。
///
/// 支持单 coder 的三种形态:COPY(0x0)、LZMA1(0x030101)、LZMA2(0x21)。
/// 多 coder 串联(例如 BCJ + LZMA2,可执行文件常见)留待后续增量。
fn decode_folder_bytes(
  folder : Folder,
  packed : Bytes,
) -> Bytes raise SevenZError {
  if folder.coders.length() != 1 {
    raise Unsupported(
      what="由多个 coder 串联组成的 Folder(过滤器链)",
    )
  }
  if folder.unpack_sizes.length() != 1 {
    raise Unsupported(what="Folder 有多个输出流")
  }
  let coder = folder.coders[0]
  let unpack_size = folder.unpack_sizes[0]
  if coder.id == 0L {
    if packed.length().to_int64() != unpack_size {
      raise Malformed(
        reason="COPY coder 的打包大小与解压大小不一致",
      )
    }
    packed
  } else if coder.id == 0x030101L {
    lzma1_decode(coder.props, packed, unpack_size)
  } else if coder.id == 0x21L {
    lzma2_decode(coder.props, packed, unpack_size)
  } else {
    raise Unsupported(what="coder " + hex_id(coder.id))
  }
}

///|
/// `(folder, 子流)` → 展平后的子流下标(与条目映射同序)。
fn flat_index(streams : Streams, folder : Int32, sub : Int32) -> Int32 {
  let mut n = 0
  for k in 0..