use crate::io::BufferReader;
use crate::format::{RecordType, SstTable};
use crate::api::{CellData, RowHandler};
use crate::error::Result;
use bytes::Bytes;
pub struct SheetReader<'a> {
reader: BufferReader,
sst: Option<&'a SstTable>,
}
impl<'a> SheetReader<'a> {
pub fn new(data: Bytes, sst: Option<&'a SstTable>) -> Self {
Self {
reader: BufferReader::new(data),
sst,
}
}
pub fn for_each_row(&mut self, mut handler: impl RowHandler) -> Result<()> {
let mut current_row: u32 = 0;
let mut cells: Vec<CellData> = vec![];
while self.reader.has_remaining() {
let record_type_code = self.reader.read_varint()?;
let size = self.reader.read_varsize()?;
let record_type = RecordType::from_u32(record_type_code);
match record_type {
Some(RecordType::BrtRowHdr) => {
if size < 17 {
return Err(crate::error::XlsbError::InvalidFormat(
format!("BrtRowHdr has invalid size: {}", size)
));
}
if !cells.is_empty() {
handler.on_row(current_row as usize, &cells);
cells.clear();
}
current_row = self.reader.read_u32_le()?;
self.reader.skip(size as usize - 4)?;
}
Some(RecordType::BrtCellReal) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let value = self.reader.read_f64_le()?;
cells.push(CellData::number(value));
}
Some(RecordType::BrtCellRk) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let rk_bytes = self.reader.read_u32_le()?;
let value = Self::decode_rk(rk_bytes);
cells.push(CellData::number(value));
}
Some(RecordType::BrtCellSt) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let text = self.reader.read_wide_string_u32()?;
cells.push(CellData::text(text));
}
Some(RecordType::BrtCellIsst) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let sst_idx = self.reader.read_u32_le()?;
let text = self.sst.and_then(|s| s.get_string(sst_idx))
.unwrap_or("");
cells.push(CellData::text(text));
}
Some(RecordType::BrtCellBool) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(3)?;
let value = self.reader.read_u8()? != 0;
cells.push(CellData::bool(value));
}
Some(RecordType::BrtCellBlank) => {
self.reader.skip(8)?;
cells.push(CellData::blank());
}
Some(RecordType::BrtEndSheetData) => {
if !cells.is_empty() {
handler.on_row(current_row as usize, &cells);
}
break;
}
_ => {
self.reader.skip(size as usize)?;
}
}
}
Ok(())
}
pub fn read_rows(&mut self, start_row: usize, row_count: usize) -> Result<Vec<Vec<CellData>>> {
let end_row = start_row + row_count;
let mut result: Vec<Vec<CellData>> = vec![];
let mut cells: Vec<CellData> = vec![];
let mut current_row: u32;
let mut in_range = false;
while self.reader.has_remaining() {
let record_type_code = self.reader.read_varint()?;
let size = self.reader.read_varsize()?;
let record_type = RecordType::from_u32(record_type_code);
match record_type {
Some(RecordType::BrtRowHdr) => {
if size < 17 {
return Err(crate::error::XlsbError::InvalidFormat(
format!("BrtRowHdr has invalid size: {}", size)
));
}
if in_range && !cells.is_empty() {
result.push(cells);
cells = Vec::new();
}
current_row = self.reader.read_u32_le()?;
self.reader.skip(size as usize - 4)?;
let row_idx = current_row as usize;
in_range = row_idx >= start_row && row_idx < end_row;
}
Some(RecordType::BrtCellReal) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let value = self.reader.read_f64_le()?;
if in_range {
cells.push(CellData::number(value));
}
}
Some(RecordType::BrtCellRk) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let rk_bytes = self.reader.read_u32_le()?;
let value = Self::decode_rk(rk_bytes);
if in_range {
cells.push(CellData::number(value));
}
}
Some(RecordType::BrtCellSt) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let text = self.reader.read_wide_string_u32()?;
if in_range {
cells.push(CellData::text(text));
}
}
Some(RecordType::BrtCellIsst) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(4)?;
let sst_idx = self.reader.read_u32_le()?;
let text = self.sst.and_then(|s| s.get_string(sst_idx))
.unwrap_or("");
if in_range {
cells.push(CellData::text(text));
}
}
Some(RecordType::BrtCellBool) => {
let _col = self.reader.read_u32_le()?;
self.reader.skip(3)?;
let value = self.reader.read_u8()? != 0;
if in_range {
cells.push(CellData::bool(value));
}
}
Some(RecordType::BrtCellBlank) => {
self.reader.skip(8)?;
if in_range {
cells.push(CellData::blank());
}
}
Some(RecordType::BrtEndSheetData) => {
if in_range && !cells.is_empty() {
result.push(cells);
}
break;
}
_ => {
self.reader.skip(size as usize)?;
}
}
}
Ok(result)
}
fn decode_rk(rk: u32) -> f64 {
let is_int = (rk & 0x02) != 0;
let div_100 = (rk & 0x01) != 0;
if is_int {
let value = ((rk as i32) >> 2) as f64;
if div_100 {
value / 100.0
} else {
value
}
} else {
let bits = ((rk as u64 & 0xFFFFFFFC) as u64) << 32;
let value = f64::from_bits(bits);
if div_100 {
value / 100.0
} else {
value
}
}
}
}