// ============================================================
// TAR
// ============================================================

///|
/// 从字节数组读取以 NUL 结尾的字符串字段(tar 头),按 UTF-8 解码(支持中文文件名)
fn tar_field_cstr(arr : Array[Byte], start : Int, len : Int) -> String {
  let mut end = start
  while end < start + len && end < arr.length() && arr[end].to_int() != 0 {
    end = end + 1
  }
  @utf8.decode_lossy(Bytes::from_array(arr.view(start~, end~)))
}

///|
/// 从字节数组直接解析八进制字段(tar 头 size/mode 等)
fn tar_octal_field(arr : Array[Byte], start : Int, len : Int) -> Int {
  let mut v = 0
  let mut i = start
  while i < start + len && i < arr.length() && arr[i].to_int() != 0 {
    let b = arr[i].to_int()
    if b >= 0x30 && b <= 0x37 {
      v = v * 8 + (b - 0x30)
    }
    i = i + 1
  }
  v
}

///|
/// tar 包内的一个条目:文件名 + 原始内容字节
pub(all) struct TarEntry {
  name : String
  content : Bytes
} derive(Eq, @debug.Debug)

///|
/// 把条目内容自动检测编码并解码为字符串(非法字节用 U+FFFD 替换)。
/// encoding 可显式指定解码方式。
pub fn TarEntry::text(self : TarEntry, encoding? : Encoding? = None) -> String {
  match encoding {
    Some(e) => decode(self.content, e)
    None => decode_auto(self.content)
  }
}

///|
/// 把整个 tar 字节流解析为条目数组(一次遍历,每个条目内容独立拷贝)
fn parse_tar(data : Bytes) -> Array[TarEntry] {
  let arr = data.to_array()
  let n = arr.length()
  let entries : Array[TarEntry] = []
  let mut offset = 0
  while offset + 512 <= n {
    let name = tar_field_cstr(arr, offset, 100)
    let size = tar_octal_field(arr, offset + 124, 12)
    if size == 0 && name == "" {
      break
    }
    if name != "" {
      let data_start = offset + 512
      let data_end = if data_start + size <= n { data_start + size } else { n }
      entries.push({
        name,
        content: Bytes::from_array(arr.view(start=data_start, end=data_end)),
      })
    }
    let data_blocks = (size + 511) / 512
    offset = offset + 512 + data_blocks * 512
  }
  entries
}

///|
/// 一次读盘并解析 tar 内所有条目(文件名 + 内容)。
/// 需要多个条目时用这个,避免反复读盘。
pub fn read_tar_entries(
  file_path : String,
) -> Array[TarEntry] raise ReaderError {
  parse_tar(read_txt_by_byte(file_path))
}

///|
/// 列出 tar 包内所有文件名
pub fn list_tar_filenames(
  file_path : String,
) -> Array[String] raise ReaderError {
  parse_tar(read_txt_by_byte(file_path)).map(fn(e) { e.name })
}

///|
/// 读取 tar 包内某个文件的内容,返回原始字节
pub fn read_tar_file(
  file_path : String,
  inner_name : String,
) -> Bytes raise ReaderError {
  let entries = parse_tar(read_txt_by_byte(file_path))
  for e in entries {
    if e.name == inner_name {
      return e.content
    }
  }
  raise ReaderError::Parse("tar 内未找到文件: " + inner_name)
}

///|
/// 读取 tar 包内某个文件的内容,自动检测编码并解码为字符串。
/// encoding 可显式指定解码方式。
pub fn read_tar_text(
  file_path : String,
  inner_name : String,
  encoding? : Encoding? = None,
) -> String raise ReaderError {
  let bytes = read_tar_file(file_path, inner_name)
  match encoding {
    Some(e) => decode(bytes, e)
    None => decode_auto(bytes)
  }
}