1use std::{cmp::max, collections::{HashMap, HashSet}, fs::File, io::BufReader, path::Path};
2use anyhow::{anyhow, Result};
3use zip::{ZipArchive, read::ZipFile};
4use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
5use quick_xml::{events::Event, reader::Reader};
6
7use lazy_static::lazy_static;
8use crate::{get_num_from_ord, get_tuple_from_ord, CellValue, ColNum, Date32, MergedRange, RowNum, Timesecond, Timestamp, MAX_COL_NUM};
9
10#[cfg(feature = "cached")]
11use crate::is_merged_cell;
12
13macro_rules! get_attr_val {
16 ($e:expr, $tag:expr) => {
17 match $e.try_get_attribute($tag)? {
18 Some(v) => {v.unescape_value()?},
19 None => return Err(anyhow!("attribute {} not exist", $tag))
20 }
21 };
22 ($e:expr, $tag:expr, parse) => {
23 match $e.try_get_attribute($tag)? {
24 Some(v) => {v.unescape_value()?.parse()?},
25 None => return Err(anyhow!("attribute {} not exist", $tag))
26 }
27 };
28 ($e:expr, $tag:expr, to_string) => {
29 match $e.try_get_attribute($tag)? {
30 Some(v) => {v.unescape_value()?.to_string()},
31 None => return Err(anyhow!("attribute {} not exist", $tag))
32 }
33 };
34}
35
36fn is_matched_row(row: &Vec<CellValue<'_>>, checks: &HashMap<usize, HashSet<String>>, check_by_and: bool) -> (bool, String) {
38 if check_by_and {
39 for (i, v) in checks {
40 if let Some(cell) = row.get(*i) {
41 if let Ok(Some(s)) = cell.get::<String>() {
42 if !v.contains(&s) {
43 return (false, format!("{:?}", v));
44 }
45 } else {
46 return (false, format!("{:?}", v));
47 }
48 } else {
49 return (false, format!("{:?}", v));
50 }
51 }
52 (true, "".to_string())
53 } else {
54 for (i, v) in checks {
55 if let Some(cell) = row.get(*i) {
56 if let Ok(Some(s)) = cell.get::<String>() {
57 if v.contains(&s) {
58 return (true, format!("{:?}", v));
59 }
60 }
61 }
62 }
63 (false, "".to_string())
64 }
65}
66
67pub struct XlsxBook {
69 ini_share: bool,
70 str_share: Vec<String>,
71 shts_hidden: Vec<String>,
72 shts_visible: Vec<String>,
73 map_style: HashMap<u32, u32>,
74 map_sheet: HashMap<String, String>,
75 zip_archive: ZipArchive<BufReader<File>>,
76 datetime_fmts: HashMap<u32, u8>,
77}
78
79impl XlsxBook {
80 pub fn new<T: AsRef<Path>>(path: T, load_share: bool) -> Result<XlsxBook> {
82 let mut zip_archive = {
84 let file = File::open(path)?;
85 let zipreader = BufReader::new(file);
86 ZipArchive::new(zipreader)?
87 };
88
89 let book_refs = {
90 let file = zip_archive.by_name("xl/_rels/workbook.xml.rels")?;
91
92 let mut buf = Vec::new();
93 let mut refs = HashMap::new();
94 let mut reader = Reader::from_reader(BufReader::new(file));
95 loop {
96 match reader.read_event_into(&mut buf) {
97 Ok(Event::Empty(ref e)) => {
98 if e.name().as_ref() == b"Relationship"{
99 refs.insert(get_attr_val!(e, "Id", to_string), get_attr_val!(e, "Target", to_string));
100 };
101 },
102 Ok(Event::Start(ref e)) => { if e.name().as_ref() == b"Relationship"{
104 refs.insert(get_attr_val!(e, "Id", to_string), get_attr_val!(e, "Target", to_string));
105 };
106 },
107 Ok(Event::Eof) => break, Err(e) => return Err(anyhow!("workbook.xml.refs broken: {:?}", e)),
109 _ => () }
111 buf.clear();
112 };
113 refs
114 };
115
116
117 let mut shts_hidden = Vec::<String>::new();
119 let mut shts_visible = Vec::<String>::new();
120 let map_sheet = {
121 let file = zip_archive.by_name("xl/workbook.xml")?;
122 let mut reader = Reader::from_reader(BufReader::new(file));
123 let mut buf = Vec::new();
126 let mut map_share: HashMap<String, String> = HashMap::new();
127 loop {
128 match reader.read_event_into(&mut buf) {
129 Ok(Event::Empty(ref e)) => {
130 if e.name().as_ref() == b"sheet"{
131 let name = get_attr_val!(e, "name", to_string);
132 let rid = get_attr_val!(e, "r:id", to_string);
133 let sheet = if book_refs.contains_key(&rid) {
134 if book_refs[&rid].starts_with('/') {
135 format!("{}", book_refs[&rid].trim_start_matches('/'))
136 } else {
137 format!("xl/{}", book_refs[&rid])
138 }
139 } else {
140 return Err(anyhow!("Relationship of sheet-{rid} not found"))
141 };
142 match e.try_get_attribute("state").unwrap_or(None) {
143 Some(attr) => {
144 if attr.unescape_value()?.as_bytes() == b"hidden" {
145 shts_hidden.push(name.clone());
146 } else {
147 shts_visible.push(name.clone());
148 };
149 },
150 _ => {shts_visible.push(name.clone());}
151 };
152 map_share.insert(name, sheet); };
154 },
155 Ok(Event::Start(ref e)) => { if e.name().as_ref() == b"sheet"{
157 let name = get_attr_val!(e, "name", to_string);
158 let rid = get_attr_val!(e, "r:id", to_string);
159 let sheet = if book_refs.contains_key(&rid) {
160 if book_refs[&rid].starts_with('/') {
161 format!("{}", book_refs[&rid].trim_start_matches('/'))
162 } else {
163 format!("/xl/{}", book_refs[&rid])
164 }
165 } else {
166 return Err(anyhow!("Relationship of sheet-rid not found!"))
167 };
168 match e.try_get_attribute("state").unwrap_or(None) {
169 Some(attr) => {
170 if attr.unescape_value()?.as_bytes() != b"hidden" {
171 shts_visible.push(name.clone());
172 };
173 },
174 _ => {shts_visible.push(name.clone());}
175 };
176 map_share.insert(name, sheet); };
178 },
179 Ok(Event::Eof) => break, Err(e) => return Err(anyhow!("workbook.xml is broken: {:?}", e)),
181 _ => () }
183 buf.clear();
184 };
185 map_share
186 };
187
188 let mut datetime_fmts = DATETIME_FMTS.clone();
190 let map_style = {
191 match zip_archive.by_name("xl/styles.xml") {
192 Ok(file) => {
193 let mut reader = Reader::from_reader(BufReader::new(file));
194 let mut inx: u32 = 0;
197 let mut act = false;
198 let mut buf = Vec::new();
199 let mut map_style: HashMap<u32, u32> = HashMap::new();
200 loop {
201 match reader.read_event_into(&mut buf) {
202 Ok(Event::Start(ref e)) => {
203 if e.name().as_ref() == b"cellXfs" || e.name().as_ref() == b"numFmts" {
204 act = true;
205 } else if act && (e.name().as_ref() == b"numFmt"){
206 let code = get_attr_val!(e, "formatCode", to_string);
207 if code.contains("yy") {
208 if code.contains("h") || code.contains("ss") {
209 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_DATETIME);
210 } else {
211 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_DATE);
212 }
213 } else if code.contains("ss") {
214 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_TIME);
215 };
216 } else if act && (e.name().as_ref() == b"xf"){
217 map_style.insert(inx, get_attr_val!(e, "numFmtId", parse));
218 inx += 1;
219 };
220 },
221 Ok(Event::Empty(ref e)) => {
222 if act && (e.name().as_ref() == b"numFmt"){
223 let code = get_attr_val!(e, "formatCode", to_string);
224 if code.contains("yy") {
225 if code.contains("h") || code.contains("ss") {
226 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_DATETIME);
227 } else {
228 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_DATE);
229 }
230 } else if code.contains("ss") {
231 datetime_fmts.insert(get_attr_val!(e, "numFmtId", parse), FMT_TIME);
232 };
233 } else if act && (e.name().as_ref() == b"xf"){
234 map_style.insert(inx, get_attr_val!(e, "numFmtId", parse));
235 inx += 1;
236 };
237 },
238 Ok(Event::End(ref e)) => {
239 if e.name().as_ref() == b"numFmts" {
240 act = false;
241 } else if e.name().as_ref() == b"cellXfs" {
242 break;
243 };
244 },
245 Ok(Event::Eof) => break, Err(e) => return Err(anyhow!("styles.xml is broken: {:?}", e)),
247 _ => () }
249 buf.clear();
250 };
251 map_style
252 },
253 Err(_) => {
254 HashMap::new()
255 }
256 }
257 };
258
259 let mut book = XlsxBook{
260 ini_share: false,
261 str_share: Vec::new(),
262 map_style,
263 map_sheet,
264 shts_hidden,
265 shts_visible,
266 zip_archive,
267 datetime_fmts,
268 };
269 if load_share {
270 book.load_share_strings()?;
271 };
272 Ok(book)
273 }
274 pub fn get_hidden_sheets(&self) -> &Vec<String> {
276 &self.shts_hidden
277 }
278 pub fn get_visible_sheets(&self) -> &Vec<String> {
280 &self.shts_visible
281 }
282 pub fn load_share_strings(&mut self) -> Result<()>{
284 if self.ini_share {
285 return Ok(());
286 };
287 let str_share = {
288 match self.zip_archive.by_name("xl/sharedStrings.xml") {
289 Ok(file) => {
290 let mut reader = Reader::from_reader(BufReader::new(file));
291 let mut buf = Vec::with_capacity(3069);
294 let cap = loop { match reader.read_event_into(&mut buf) {
296 Ok(Event::Start(ref e)) => {
297 if e.name().as_ref() == b"sst"{
298 let cnt: usize = {
299 match e.try_get_attribute("uniqueCount")? {
300 Some(a) => {a.unescape_value()?.parse()?},
301 None => {get_attr_val!(e, "count", parse)}
302 }
303 };
304 break cnt
305 }
306 }
307 Ok(Event::Eof) => {return Ok(())}, Err(e) => return Err(anyhow!("sharedStrings.xml is broken: {:?}", e)),
309 _ => (), }
311 };
312
313 let mut insert = false;
314 let mut shstring = String::new();
315 let mut vec_share: Vec<String> = Vec::with_capacity(cap);
316 loop {
317 match reader.read_event_into(&mut buf) {
318 Ok(Event::Start(ref e)) => {
319 match e.name().as_ref() {
320 b"si" => {shstring.clear()},
321 b"t" => {insert = true},
322 _ => {insert = false},
323 }
324 },
325 Ok(Event::Text(ref t)) => {
326 if insert {
327 shstring += &String::from_utf8(t.to_vec())?;
328 }
329 },
330 Ok(Event::End(ref e)) => {
331 if e.name().as_ref() == b"si" {
332 vec_share.push(shstring.clone());
333 }
334 },
335 Ok(Event::Eof) => break, Err(e) => return Err(anyhow!("sharedStrings.xml is broken: {:?}", e)),
337 _ => () }
339 buf.clear();
340 };
341 if cap != vec_share.len() {
342 return Err(anyhow!("shareString-lenth check error!!"));
343 };
344 vec_share
345 },
346 Err(_) => {
347 Vec::<String>::new()
348 }
349 }
350 };
351 self.ini_share = true;
352 self.str_share = str_share;
353 Ok(())
354 }
355 pub fn get_sheet_by_name<'a, 'b>(&'a mut self, sht_name: &'b String, iter_batch: usize, skip_rows: u32, left_ncol: ColNum, right_ncol: ColNum, first_row_is_header: bool) -> Result<XlsxSheet<'a>> {
361 for (k, v) in self.map_sheet.clone() {
362 if k.eq(sht_name) {
363 if !self.ini_share {
364 self.load_share_strings()?;
365 };
366
367 match self.zip_archive.by_name(v.as_str()) {
368 Ok(file) => {
369 let reader = Reader::from_reader(BufReader::new(file));
370 return Ok(XlsxSheet {
373 reader,
374 skip_rows,
375 left_ncol: left_ncol-1,
376 right_ncol,
377 iter_batch,
378 first_row_is_header,
379 first_row: None,
380 key: k,
381 buf: Vec::with_capacity(8*1024),
382 status: 1,
383 currow: 0,
384 str_share: &self.str_share,
385 map_style: &self.map_style,
386 datetime_fmts: &self.datetime_fmts,
387 max_size: None,
388 merged_rects: None,
389 skip_until: None,
390 skip_matched: None,
391 skip_matched_check_by_and: true,
392 read_before: None,
393 header_check: None,
394 addr_captures: None,
395 vals_captures: HashMap::new(),
396 });
397 },
398 Err(_) => {
399 return Err(anyhow!("sheet {} - {} lost!", k.as_str(), v.as_str()));
400 }
401 };
402 };
403 };
404 Err(anyhow!(format!("{} sheet not found!", sht_name)))
405 }
406 #[cfg(feature = "cached")]
408 pub fn get_cached_sheet_by_name<'a>(&'a mut self, sht_name: &String, iter_batch: usize, skip_rows: u32, left_ncol: ColNum, right_ncol: ColNum, first_row_is_header: bool) -> Result<CachedSheet<'a>> {
409 Ok(self.get_sheet_by_name(sht_name, iter_batch, skip_rows, left_ncol, right_ncol, first_row_is_header)?.into_cached_sheet()?)
410 }
411 pub fn get_sheets_maps(&self) -> &HashMap<String, String> {
413 &self.map_sheet
414 }
415}
416
417pub struct XlsxSheet<'a> {
419 key: String,
420 str_share: &'a Vec<String>,
421 map_style: &'a HashMap<u32, u32>,
422 buf: Vec<u8>,
423 status: u8, currow: RowNum, reader: Reader<BufReader<ZipFile<'a, BufReader<File>>>>,
426 iter_batch: usize,
427 skip_rows: u32,
428 max_size: Option<(RowNum, ColNum)>,
429 left_ncol: ColNum,
430 right_ncol: ColNum,
431 first_row_is_header: bool, first_row: Option<(u32, Vec<CellValue<'a>>)>,
433 datetime_fmts: &'a HashMap<u32, u8>,
434 merged_rects: Option<Vec<((RowNum, ColNum), (RowNum, ColNum))>>,
435 skip_until: Option<HashMap<usize, HashSet<String>>>,
436 skip_matched: Option<HashMap<usize, HashSet<String>>>,
437 skip_matched_check_by_and: bool,
438 read_before: Option<HashMap<usize, HashSet<String>>>,
439 header_check: Option<HashMap<usize, HashSet<String>>>,
440 addr_captures: Option<HashSet<String>>,
441 vals_captures: HashMap<String, CellValue<'a>>
442}
443
444impl<'a> XlsxSheet<'a> {
445 #[cfg(feature = "cached")]
447 fn into_cached_sheet(mut self) -> Result<CachedSheet<'a>> {
448 let top_nrow = if self.first_row_is_header {self.skip_rows+2} else {self.skip_rows+1};
449 if self.first_row_is_header {
450 self.get_header_row()?;
451 }
452 let (data, bottom_nrow) = match self.get_next_row() {
453 Ok(Some((r, d))) => {
454 let mut data = if let Some((rn, _)) = self.max_size {
455 HashMap::with_capacity(rn as usize)
456 } else {
457 HashMap::new()
458 };
459 data.insert(r, d);
460 let mut last_nrow = r;
461 loop {
462 match self.get_next_row() {
463 Ok(Some((r, d))) => {
464 last_nrow = r;
465 data.insert(r, d);
466 },
467 Ok(None) => {
468 break;
469 },
470 Err(e) => {
471 return Err(e);
472 }
473 };
474 };
475 (data, last_nrow)
476 },
477 Ok(None) => {(HashMap::new(), 0)},
478 Err(e) => {return Err(e);}
479 };
480 let merged_rects = self.get_merged_ranges()?.to_owned();
481 let right_ncol = if self.right_ncol == MAX_COL_NUM {
482 if let Some((_mr, mc)) = self.max_size {
483 mc
484 } else {
485 self.right_ncol
486 }
487 } else {
488 self.right_ncol
489 };
490 let empty = self.is_empty()?;
491 Ok(CachedSheet {
492 data,
493 merged_rects,
494 key: self.key,
495 current: top_nrow,
496 empty,
497 keep_empty: false,
498 iter_batch: self.iter_batch,
499 top_nrow,
500 bottom_nrow,
501 left_ncol: self.left_ncol + 1,
502 right_ncol,
503 header_row: self.first_row,
504 })
505 }
506 pub fn sheet_name(&self) -> &String {
508 &self.key
509 }
510 pub fn with_skip_until(&mut self, checks: &HashMap<String, String>) {
512 let mut maps = HashMap::new();
513 for (c, v) in checks {
514 let col = get_num_from_ord(c.as_bytes()).unwrap_or(0);
515 if col > self.left_ncol && col <= self.right_ncol {
516 maps.insert((col-self.left_ncol-1) as usize, v.split('|').map(|s| s.to_string()).collect());
517 }
518 }
519 if maps.len() > 0 {
520 self.skip_until = Some(maps);
521 } else {
522 self.skip_until = None;
523 }
524 }
525 pub fn with_skip_matched(&mut self, checks: &HashMap<String, String>, check_by_and: bool) {
529 let mut maps = HashMap::new();
530 for (c, v) in checks {
531 let col = get_num_from_ord(c.as_bytes()).unwrap_or(0);
532 if col > self.left_ncol && col <= self.right_ncol {
533 maps.insert((col-self.left_ncol-1) as usize, v.split('|').map(|s| s.to_string()).collect());
534 }
535 }
536 if maps.len() > 0 {
537 self.skip_matched = Some(maps);
538 self.skip_matched_check_by_and = check_by_and;
539 } else {
540 self.skip_matched = None;
541 }
542 }
543 pub fn with_read_before(&mut self, checks: &HashMap<String, String>) {
545 let mut maps = HashMap::new();
546 for (c, v) in checks {
547 let col = get_num_from_ord(c.as_bytes()).unwrap_or(0);
548 if col > self.left_ncol && col <= self.right_ncol {
549 maps.insert((col-self.left_ncol-1) as usize, v.split('|').map(|s| s.to_string()).collect());
550 }
551 }
552 if maps.len() > 0 {
553 self.read_before = Some(maps);
554 } else {
555 self.read_before = None;
556 }
557 }
558 pub fn with_header_check(&mut self, checks: &HashMap<String, String>) {
560 let mut maps = HashMap::new();
561 for (c, v) in checks {
562 let col = get_num_from_ord(c.as_bytes()).unwrap_or(0);
563 if col > self.left_ncol && col <= self.right_ncol {
564 maps.insert((col-self.left_ncol-1) as usize, v.split('|').map(|s| s.to_string()).collect());
565 }
566 }
567 if maps.len() > 0 {
568 self.header_check = Some(maps);
569 } else {
570 self.header_check = None;
571 }
572 }
573 pub fn with_capture_vals(&mut self, captures: HashSet<String>) {
575 if captures.len() > 0 {
576 self.addr_captures = Some(captures);
577 } else {
578 self.addr_captures = None;
579 };
580 self.vals_captures = HashMap::new();
581 }
582 pub fn get_captured_vals(&mut self) -> Result<&HashMap<String, CellValue<'a>>> {
587 if self.addr_captures.is_none() {
588 Ok(&self.vals_captures)
589 } else if self.first_row_is_header {
590 self.get_header_row()?;
591 Ok(&self.vals_captures)
592 } else {
593 Err(anyhow!("get_captured_vals error: first_row_is_header must be true"))
594 }
595 }
596 pub fn is_empty(&self) -> Result<bool> {
598 if self.currow > 0 {
599 Ok(false)
600 } else if self.status == 0 {
601 Ok(true)
602 } else {
603 Err(anyhow!("is_empty should be called after at least one row has been read"))
604 }
605 }
606 pub fn column_range(&self) -> (ColNum, ColNum) {
608 (self.left_ncol+1, self.right_ncol)
609 }
610 fn get_next_row(&mut self) -> Result<Option<(u32, Vec<CellValue<'a>>)>> {
612 let mut col: ColNum = 0;
613 let mut cell_addr = "".into();
614 let mut cell_type = vec![];
615 let mut prev_head = vec![];
616 let mut col_index: ColNum = 1; let mut row_value: Vec<CellValue<'_>> = Vec::new();
619 let mut num_fmt_id: u32 = 0;
620 if self.status == 0 {
621 return Ok(None)
622 } loop {
624 match self.reader.read_event_into(&mut self.buf) {
625 Ok(Event::Start(ref e)) => {
626 prev_head = e.name().as_ref().to_vec();
627 if self.status == 0 {
628 break Ok(None)
629 } else if self.status == 1 {
630 if prev_head == b"dimension" {
631 let attr = get_attr_val!(e, "ref", to_string);
632 let dim: Vec<&str> = attr.split(':').collect();
633 if let Some(x) = dim.get(1) {
634 self.max_size = Some(get_tuple_from_ord(x.as_bytes())?);
635 };
636 } else if prev_head == b"sheetData" {
637 self.status = 2;
638 } else if prev_head == b"mergeCells" {
639 let cnt: usize = get_attr_val!(e, "count", parse);
640 self.process_merged_cells(cnt)?;
641 };
642 } else {
643 if prev_head == b"c" {
644 match e.try_get_attribute("t")? {
645 Some(attr) => {
646 cell_type = attr.unescape_value()?.as_bytes().to_owned();
647 },
648 _ => {
649 cell_type = b"n".to_vec();
650 }
651 };
652 match e.try_get_attribute("s")? {
653 Some(attr) => {
654 num_fmt_id = self.map_style[&attr.unescape_value()?.parse::<u32>()?];
655 },
656 _ => {
657 num_fmt_id = 0;
658 }
659 };
660 cell_addr = get_attr_val!(e, "r").to_string(); col = get_num_from_ord(cell_addr.as_bytes()).unwrap_or(0);
662
663 if self.currow > self.skip_rows && col > self.left_ncol && col <= self.right_ncol {
664 self.status = 3; } else {
666 self.status = 4; }
668 } else if prev_head == b"row" {
669 self.currow = get_attr_val!(e, "r", parse);
670 let cap = {
671 if self.right_ncol == MAX_COL_NUM {
672 match e.try_get_attribute("spans") {
673 Ok(Some(spans)) => {
674 if let Some(x) = spans.unescape_value()?.as_ref().split(":").last() {
675 x.parse()?
676 } else {
677 1
678 }
679 },
680 _ => {
681 1
682 }
683 }
684 } else {
690 self.right_ncol
691 }
692 } - self.left_ncol;
693 row_value = Vec::with_capacity(cap.into());
694 col_index = 1; };
697 };
698 },
699 Ok(Event::Empty(ref e)) => {
700 prev_head = e.name().as_ref().to_vec();
701 if self.status == 1 && prev_head == b"dimension" {
702 let attr = get_attr_val!(e, "ref", to_string);
703 let dim: Vec<&str> = attr.split(':').collect();
704 if let Some(x) = dim.get(1) {
705 self.max_size = Some(get_tuple_from_ord(x.as_bytes())?);
706 };
707 } else if prev_head == b"sheetData" {
708 self.status = 0;
709 break Ok(None)
710 }
711 },
712 Ok(Event::Text(ref t)) => {
713 if self.status == 3 && (prev_head == b"v" || prev_head == b"t") {
721 while col_index + self.left_ncol < col {
722 row_value.push(CellValue::Blank);
723 col_index += 1;
724 }
725 let cel_val = if cell_type == b"inlineStr" && prev_head == b"t" {
726 CellValue::String(String::from_utf8(t.to_vec())?)
727 } else if prev_head == b"v" {
728 if cell_type == b"s" {
729 CellValue::Shared(&self.str_share[String::from_utf8(t.to_vec())?.parse::<usize>()?])
730 } else if cell_type == b"n" {
731 let fmt = self.datetime_fmts.get(&num_fmt_id).unwrap_or(&FMT_DEFAULT);
732 if *fmt == FMT_DATE {
733 CellValue::Date(String::from_utf8(t.to_vec())?.parse::<f64>()?)
734 } else if *fmt == FMT_DATETIME {
735 CellValue::Datetime(String::from_utf8(t.to_vec())?.parse::<f64>()?)
736 } else if *fmt == FMT_TIME {
737 CellValue::Time(String::from_utf8(t.to_vec())?.parse::<f64>()?)
738 } else {
739 CellValue::Number(String::from_utf8(t.to_vec())?.parse::<f64>()?)
740 }
741 } else if cell_type == b"b" {
742 if String::from_utf8(t.to_vec())?.parse::<usize>() == Ok(1) {
743 CellValue::Bool(true)
744 } else {
745 CellValue::Bool(false)
746 }
747 } else if cell_type == b"d" {
748 CellValue::String(String::from_utf8(t.to_vec())?)
749 } else if cell_type == b"e" {
750 CellValue::Error(String::from_utf8(t.to_vec())?)
751 } else if cell_type == b"str" {
752 CellValue::String(String::from_utf8(t.to_vec())?)
753 } else{
754 CellValue::Blank
755 }
756 } else {
757 CellValue::Error("Unknown cell type".into())
758 };
759 if let Some(addrs) = &mut self.addr_captures {
760 if let Some(key) = addrs.take(&cell_addr) {
761 self.vals_captures.insert(key, cel_val.clone());
762 }
763 }
764 col_index += 1;
765 row_value.push(cel_val);
766 }
767 },
768 Ok(Event::End(ref e)) => {
769 if (e.name().as_ref() == b"row") && self.status > 1 && row_value.len() > 0 {
771 if let Some(skip_until) = &self.skip_until {
772 if is_matched_row(&row_value, skip_until, true).0 {
773 self.skip_until = None;
774 } else {
775 continue;
783 } } else if let Some(read_before) = &self.read_before {
785 if is_matched_row(&row_value, read_before, true).0 {
786 self.status = 0;
787 self.read_before = None;
788 break Ok(None);
789 } };
791 if self.right_ncol != MAX_COL_NUM {
792 while row_value.len() < row_value.capacity() {
793 row_value.push(CellValue::Blank);
794 };
795 }
796 self.addr_captures = None; if !self.first_row_is_header { if let Some(skip_matched) = &self.skip_matched {
801 if is_matched_row(&row_value, skip_matched, self.skip_matched_check_by_and).0 {
802 continue; }
804 }
805 };
806 break Ok(Some((self.currow, row_value)))
807 }else if e.name().as_ref() == b"sheetData" {
808 self.status = 0;
809 break Ok(None)
810 }
811 },
812 Ok(Event::Eof) => {
813 self.status = 0;
814 break Ok(None)
815 }, Err(e) => {
817 return Err(anyhow!("sheet data is broken: {:?}", e));
818 },
819 _ => () }
821 self.buf.clear();
822 }
823 }
824 pub fn get_header_row(&mut self) -> Result<(u32, Vec<CellValue<'a>>)> {
826 if self.first_row_is_header {
827 match self.get_next_row() {
828 Ok(Some(v)) => {
829 if let Some(header_check) = &self.header_check {
830 let matched = is_matched_row(&v.1, header_check, true);
831 if matched.0 {
832 self.first_row = Some(v);
833 self.first_row_is_header = false;
834 } else {
835 return Err(anyhow!("header row check failed: {}", matched.1));
836 }
837 } else {
838 self.first_row = Some(v);
839 self.first_row_is_header = false;
840 }
841 },
842 Ok(None) => {},
843 Err(e) => {return Err(e)}
844 }
845 }
846 match &self.first_row {
847 Some(v) => Ok(v.clone()),
848 None => Err(anyhow!("no header row!"))
849 }
850 }
851 fn process_merged_cells(&mut self, count: usize) -> Result<()> {
852 if self.status == 1 || self.status == 0 {
853 if self.merged_rects.is_none() {
854 self.merged_rects = Some(vec![]);
855 }
856 loop {
857 match self.reader.read_event_into(&mut self.buf) {
858 Ok(Event::Start(ref e)) => {
859 if e.name().as_ref() == b"mergeCell" {
860 let attr = get_attr_val!(e, "ref", to_string);
861 let dim: Vec<&str> = attr.split(':').collect();
862 if let Some(x) = dim.get(0) {
863 let left_top = get_tuple_from_ord(x.as_bytes())?;
864 let right_end = if let Some(x) = dim.get(1) {
865 get_tuple_from_ord(x.as_bytes())?
866 } else {
867 return Err(anyhow!("mergeCell error:{}", attr));
868 };
869 if let Some(ref mut mgs) = self.merged_rects {
870 mgs.push((left_top, right_end))
871 };
872 } else {
873 return Err(anyhow!("mergeCell error:{}", attr));
874 };
875 }
876 },
877 Ok(Event::Empty(ref e)) => {
878 if e.name().as_ref() == b"mergeCell" {
879 let attr = get_attr_val!(e, "ref", to_string);
880 let dim: Vec<&str> = attr.split(':').collect();
881 if let Some(x) = dim.get(0) {
882 let left_top = get_tuple_from_ord(x.as_bytes())?;
883 let right_end = if let Some(x) = dim.get(1) {
884 get_tuple_from_ord(x.as_bytes())?
885 } else {
886 return Err(anyhow!("mergeCell error:{}", attr));
887 };
888 if let Some(ref mut mgs) = self.merged_rects {
889 mgs.push((left_top, right_end))
890 };
891 } else {
892 return Err(anyhow!("mergeCell error:{}", attr));
893 };
894 }
895 },
896 Ok(Event::End(ref e)) => {
897 if e.name().as_ref() != b"mergeCells" {
898 break;
899 }
900 else if e.name().as_ref() != b"mergeCell" {
901 break;
902 }
903 },
904 Ok(Event::Eof) => {
905 break;
906 }, _ => {}
908 }
909 };
910 if let Some(ref rects) = self.merged_rects {
911 if rects.len() != count {
912 self.merged_rects = None;
913 return Err(anyhow!("the number of merged ranges is not equal to the number of rows"));
914 };
915 }
916 }
917 Ok(())
918 }
919 pub fn get_merged_ranges(&mut self) -> Result<&Vec<MergedRange>> {
921 if self.merged_rects.is_none() {
922 if self.status == 0 { loop {
924 match self.reader.read_event_into(&mut self.buf) {
925 Ok(Event::Start(ref e)) => {
926 if e.name().as_ref() == b"mergeCells" {
927 let cnt: usize = get_attr_val!(e, "count", parse);
928 self.process_merged_cells(cnt)?;
929 break;
930 };
931 },
932 _ => {}
933 }
934 };
935 } else {
936 return Err(anyhow!("finish fetching data first"));
937 }
938 };
939 if let Some(ref rects) = self.merged_rects {
940 Ok(rects)
941 } else {
942 return Err(anyhow!("merged_rects error"));
943 }
944 }
945 pub fn get_remaining_cells(&mut self) -> Result<Option<(Vec<u32>, Vec<Vec<CellValue<'_>>>)>> {
947 if self.first_row_is_header {
948 self.get_header_row()?;
949 }
950 match self.get_next_row() {
951 Ok(Some((r, d))) => {
952 let (mut rows, mut data) = if let Some((rn, _)) = self.max_size {
953 (Vec::with_capacity(max(1, rn-r+1) as usize), Vec::with_capacity(rn as usize))
954 } else {
955 (Vec::new(), Vec::new())
956 };
957 rows.push(r);
958 data.push(d);
959 loop {
960 match self.get_next_row() {
961 Ok(Some((r, d))) => {
962 rows.push(r);
963 data.push(d);
964 },
965 Ok(None) => {
966 break Ok(Some((rows, data)));
967 },
968 Err(e) => {
969 break Err(e);
970 }
971 };
972 }
973 },
974 Ok(None) => {
975 Ok(None)
976 },
977 Err(e) => {Err(e)}
978 }
979 }
980}
981
982impl<'a> Iterator for XlsxSheet<'a> {
983 type Item = Result<(Vec<u32>, Vec<Vec<CellValue<'a>>>)>;
984 fn next(&mut self) -> Option<Self::Item> {
985 let mut nums = Vec::with_capacity(self.iter_batch);
986 let mut data = Vec::with_capacity(self.iter_batch);
987 if self.first_row_is_header {
988 match self.get_header_row() {
989 Ok(_) => {},
990 Err(e) => {
991 return Some(Err(e));
992 }
993 }
994 }
995 loop {
996 match self.get_next_row() {
997 Ok(Some(v)) => {
998 nums.push(v.0);
999 data.push(v.1);
1000 if nums.len() >= self.iter_batch {
1001 break Some(Ok((nums, data)))
1002 }
1003 },
1004 Ok(None) => {
1005 if nums.len() > 0 {
1006 break Some(Ok((nums, data)))
1007 } else {
1008 break None
1009 }
1010 },
1011 Err(e) => {
1012 break Some(Err(e));
1013 }
1014 }
1015 }
1016
1017 }
1018}
1019
1020#[cfg(feature = "cached")]
1022pub struct CachedSheet<'a> {
1023 data: HashMap<RowNum, Vec<CellValue<'a>>>,
1024 key: String,
1025 current: RowNum,
1026 empty: bool,
1027 keep_empty: bool,
1028 iter_batch: usize,
1029 top_nrow: RowNum,
1030 bottom_nrow: RowNum,
1031 left_ncol: ColNum,
1032 right_ncol: ColNum,
1033 header_row: Option<(u32, Vec<CellValue<'a>>)>,
1034 merged_rects: Vec<((RowNum, ColNum), (RowNum, ColNum))>
1035}
1036
1037#[cfg(feature = "cached")]
1038impl <'a> CachedSheet<'a> {
1039 pub fn with_empty_rows(mut self, keep_empty: bool) -> Self {
1041 self.keep_empty = keep_empty;
1042 self
1043 }
1044 pub fn sheet_name(&self) -> &String {
1046 &self.key
1047 }
1048 pub fn is_empty(&self) -> bool {
1050 self.empty
1051 }
1052 pub fn row_range(&self) -> (RowNum, RowNum) {
1054 (self.top_nrow, self.bottom_nrow)
1055 }
1056 pub fn column_range(&self) -> (ColNum, ColNum) {
1058 (self.left_ncol, self.right_ncol)
1059 }
1060 pub fn get_header_row(&self) -> Result<(u32, Vec<CellValue<'a>>)> {
1062 match &self.header_row {
1063 Some(v) => Ok(v.clone()),
1064 None => Err(anyhow!("no header row!"))
1065 }
1066 }
1067 pub fn get_merged_ranges(&self) -> &Vec<MergedRange> {
1069 &self.merged_rects
1070 }
1071 pub fn get_all_cells(&self) -> &HashMap<RowNum, Vec<CellValue<'_>>> {
1073 &self.data
1074 }
1075 pub fn get_cell_value<A: AsRef<str>>(&self, addr: A) -> Result<&CellValue<'a>> {
1077 let (row, col) = get_tuple_from_ord(addr.as_ref().as_bytes())?;
1078 if row >= self.top_nrow && row <= self.bottom_nrow
1079 && col >= self.left_ncol && col <= self.right_ncol {
1080 if self.data.contains_key(&row) {
1081 Ok(self.data[&row].get((col-1) as usize).unwrap_or(&CellValue::Blank))
1082 } else {
1083 Ok(&CellValue::Blank)
1084 }
1085 } else {
1086 Err(anyhow!("Invalid address - out of range"))
1087 }
1088 }
1089 pub fn get_cell_value_with_merge_info<A: AsRef<str>>(&self, addr: A) -> Result<(&CellValue<'a>, (bool, Option<(RowNum, ColNum)>))> {
1091 let (row, col) = get_tuple_from_ord(addr.as_ref().as_bytes())?;
1092 if row >= self.top_nrow && row <= self.bottom_nrow
1093 && col >= self.left_ncol && col <= self.right_ncol {
1094 let (merge, spans) = is_merged_cell(&self.merged_rects, row, col);
1095 if self.data.contains_key(&row) {
1096 Ok((self.data[&row].get((col-1) as usize).unwrap_or(&CellValue::Blank), (merge, spans)))
1097 } else {
1098 Ok((&CellValue::Blank, (merge, spans)))
1099 }
1100 } else {
1101 Err(anyhow!("Invalid address - out of range"))
1102 }
1103 }
1104}
1105
1106#[cfg(feature = "cached")]
1107impl<'a> Iterator for CachedSheet<'a> {
1108 type Item = (Vec<u32>, Vec<Vec<CellValue<'a>>>);
1109 fn next(&mut self) -> Option<Self::Item> {
1110 let mut nrow = Vec::with_capacity(self.iter_batch);
1111 let mut data = Vec::with_capacity(self.iter_batch);
1112 while nrow.len() < self.iter_batch && self.current <= self.bottom_nrow {
1113 if self.data.contains_key(&self.current) {
1114 nrow.push(self.current);
1115 data.push(self.data[&self.current].to_owned());
1116 } else if self.keep_empty {
1117 nrow.push(self.current);
1118 data.push(vec![]);
1119 };
1120 self.current += 1;
1121 }
1122 Some((nrow, data))
1123 }
1124}
1125
1126pub trait FromCellValue {
1128 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>>
1129 where Self: Sized;
1130}
1131
1132impl FromCellValue for String {
1133 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1134 match val {
1135 CellValue::Number(n) => Ok(Some(n.to_string())),
1136 CellValue::Date(n) => {
1137 Ok(Some((BASE_DATE.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)).to_string()))
1138 },
1139 CellValue::Time(n) => {
1140 Ok(Some(NaiveTime::from_num_seconds_from_midnight_opt(((*n-n.trunc()) * 86400.0) as u32, 0).unwrap().format("%H:%M:%S").to_string()))
1141 }
1142 CellValue::Datetime(n) => {
1143 Ok(Some((BASE_DATETIME.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)+(Duration::try_seconds(((*n-n.trunc()) * 86400.0) as i64).ok_or(anyhow!("invalid date"))?)).to_string()))
1144 },
1145 CellValue::Shared(s) => Ok(Some((**s).to_owned())),
1146 CellValue::String(s) => Ok(Some((*s).to_owned())),
1147 CellValue::Error(s) => Ok(Some((*s).to_string())),
1148 CellValue::Bool(b) => Ok(Some(if *b {"true".to_string()}else{"false".to_string()})),
1149 CellValue::Blank => Ok(Some("".to_string())),
1150 }
1151 }
1152}
1153
1154impl FromCellValue for f64 {
1155 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1156 match val {
1157 CellValue::Number(n) => Ok(Some(*n)),
1158 CellValue::Date(n) => Ok(Some(*n)),
1159 CellValue::Time(n) => Ok(Some(*n)),
1160 CellValue::Datetime(n) => Ok(Some(*n)),
1161 CellValue::Shared(s) => {
1162 match s.parse::<f64>() {
1163 Ok(n) => Ok(Some(n)),
1164 Err(_) => {
1165 if NULL_STRING.contains(*s) {
1166 Ok(None)
1167 } else if let Ok(n) = s.replace(',', "").parse::<f64>() {
1168 Ok(Some(n))
1169 } else {
1170 Err(anyhow!(format!("invalid value-{:?}", val)))
1171 }
1172 }
1173 }
1174 },
1175 CellValue::String(s) => {
1176 match s.parse::<f64>() {
1177 Ok(n) => Ok(Some(n)),
1178 Err(_) => {
1179 if NULL_STRING.contains(s) {
1180 Ok(None)
1181 } else if let Ok(n) = s.replace(',', "").parse::<f64>() {
1182 Ok(Some(n))
1183 } else {
1184 Err(anyhow!(format!("invalid value-{:?}", val)))
1185 }
1186 }
1187 }
1188 },
1189 CellValue::Error(_) => Err(anyhow!(format!("invalid value-{:?}", val))),
1190 CellValue::Bool(b) => Ok(Some(if *b {1.0}else{0.0})),
1191 CellValue::Blank => Ok(None),
1192 }
1193 }
1194}
1195
1196impl FromCellValue for i64 {
1197 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1198 match val {
1199 CellValue::Number(n) => Ok(Some(*n as i64)),
1200 CellValue::Date(n) => Ok(Some(*n as i64)),
1201 CellValue::Time(n) => Ok(Some(*n as i64)),
1202 CellValue::Datetime(n) => Ok(Some(*n as i64)),
1203 CellValue::Shared(s) => {
1204 match s.parse::<i64>() {
1205 Ok(n) => Ok(Some(n)),
1206 Err(_) => {
1207 if NULL_STRING.contains(*s) {
1208 Ok(None)
1209 } else if let Ok(n) = s.replace(',', "").parse::<i64>() {
1210 Ok(Some(n))
1211 } else {
1212 Err(anyhow!(format!("invalid value-{:?}", val)))
1213 }
1214 }
1215 }
1216 },
1217 CellValue::String(s) => {
1218 match s.parse::<i64>() {
1219 Ok(n) => Ok(Some(n)),
1220 Err(_) => {
1221 if NULL_STRING.contains(s) {
1222 Ok(None)
1223 } else if let Ok(n) = s.replace(',', "").parse::<i64>() {
1224 Ok(Some(n))
1225 } else {
1226 Err(anyhow!(format!("invalid value-{:?}", val)))
1227 }
1228 }
1229 }
1230 },
1231 CellValue::Error(_) => Err(anyhow!(format!("invalid value-{:?}", val))),
1232 CellValue::Bool(b) => Ok(Some(if *b {1}else{0})),
1233 CellValue::Blank => Ok(None),
1234 }
1235 }
1236}
1237
1238impl FromCellValue for bool {
1239 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1240 match val {
1241 CellValue::Number(n) => {if (*n).abs() > 0.009 {Ok(Some(true))} else {Ok(Some(false))}},
1242 CellValue::Date(n) => {if (*n).abs() > 0.009 {Ok(Some(true))} else {Ok(Some(false))}},
1243 CellValue::Time(n) => {if (*n).abs() > 0.009 {Ok(Some(true))} else {Ok(Some(false))}},
1244 CellValue::Datetime(n) => {if (*n).abs() > 0.009 {Ok(Some(true))} else {Ok(Some(false))}},
1245 CellValue::Shared(s) => {
1246 match s.parse::<bool>() {
1247 Ok(n) => Ok(Some(n)),
1248 Err(_) => {
1249 if NULL_STRING.contains(*s) {
1250 Ok(None)
1251 } else {
1252 Err(anyhow!(format!("invalid value-{:?}", val)))
1253 }
1254 }
1255 }
1256 },
1257 CellValue::String(s) => {
1258 match s.parse::<bool>() {
1259 Ok(n) => Ok(Some(n)),
1260 Err(_) => {
1261 if NULL_STRING.contains(s) {
1262 Ok(None)
1263 } else {
1264 Err(anyhow!(format!("invalid value-{:?}", val)))
1265 }
1266 }
1267 }
1268 },
1269 CellValue::Error(_) => Err(anyhow!(format!("invalid value-{:?}", val))),
1270 CellValue::Bool(b) => Ok(Some(*b)),
1271 CellValue::Blank => Ok(None),
1272 }
1273 }
1274}
1275
1276impl FromCellValue for NaiveDate {
1277 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1278 match val {
1279 CellValue::Number(n) => Ok(Some(BASE_DATE.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid datetime"))?))),
1280 CellValue::Date(n) => Ok(Some(BASE_DATE.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid datetime"))?))),
1281 CellValue::Time(n) => Ok(Some(BASE_DATE.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid datetime"))?))),
1282 CellValue::Datetime(n) => Ok(Some(BASE_DATE.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid datetime"))?))),
1283 CellValue::Shared(s) => {
1284 match NaiveDate::parse_from_str(*s, "%Y-%m-%d") {
1285 Ok(v) => Ok(Some(v)),
1286 Err(_) => {
1287 match NaiveDate::parse_from_str(*s, "%Y/%m/%d") {
1288 Ok(v) => Ok(Some(v)),
1289 Err(_) => {
1290 if NULL_STRING.contains(*s) {
1291 Ok(None)
1292 } else {
1293 Err(anyhow!(format!("invalid value-{:?}", val)))
1294 }
1295 }
1296 }
1297 }
1298 }
1299 },
1300 CellValue::String(s) => {
1301 match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
1302 Ok(v) => Ok(Some(v)),
1303 Err(_) => {
1304 match NaiveDate::parse_from_str(s, "%Y/%m/%d") {
1305 Ok(v) => Ok(Some(v)),
1306 Err(_) => {
1307 if NULL_STRING.contains(s) {
1308 Ok(None)
1309 } else {
1310 Err(anyhow!(format!("invalid value-{:?}", val)))
1311 }
1312 }
1313 }
1314 }
1315 }
1316 },
1317 CellValue::Error(_) => Err(anyhow!(format!("invalid datetime{:?}", val))),
1318 CellValue::Bool(_) => Err(anyhow!(format!("invalid datetime{:?}", val))),
1319 CellValue::Blank => Ok(None),
1320 }
1321 }
1322}
1323
1324impl FromCellValue for NaiveDateTime {
1325 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1326 match val {
1327 CellValue::Number(n) => {
1328 Ok(Some(BASE_DATETIME.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)+(Duration::try_seconds(((*n-n.trunc()) * 86400.0) as i64).ok_or(anyhow!("invalid date"))?)))
1329 },
1330 CellValue::Date(n) => {
1331 Ok(Some(BASE_DATETIME.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)+(Duration::try_seconds(((*n-n.trunc()) * 86400.0) as i64).ok_or(anyhow!("invalid date"))?)))
1332 },
1333 CellValue::Time(n) => {
1334 Ok(Some(BASE_DATETIME.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)+(Duration::try_seconds(((*n-n.trunc()) * 86400.0) as i64).ok_or(anyhow!("invalid date"))?)))
1335 },
1336 CellValue::Datetime(n) => {
1337 Ok(Some(BASE_DATETIME.clone()+(Duration::try_days(*n as i64).ok_or(anyhow!("invalid date"))?)+(Duration::try_seconds(((*n-n.trunc()) * 86400.0) as i64).ok_or(anyhow!("invalid date"))?)))
1338 },
1339 CellValue::Shared(s) => {
1340 match NaiveDateTime::parse_from_str(*s, "%Y-%m-%d %H:%M:%S") {
1341 Ok(v) => Ok(Some(v)),
1342 Err(_) => {
1343 match NaiveDateTime::parse_from_str(*s, "%Y/%m/%d %H:%M:%S") {
1344 Ok(v) => Ok(Some(v)),
1345 Err(_) => {
1346 if NULL_STRING.contains(*s) {
1347 Ok(None)
1348 } else {
1349 Err(anyhow!(format!("invalid value-{:?}", val)))
1350 }
1351 }
1352 }
1353 }
1354 }
1355 },
1356 CellValue::String(s) => {
1357 match NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
1358 Ok(v) => Ok(Some(v)),
1359 Err(_) => {
1360 match NaiveDateTime::parse_from_str(s, "%Y/%m/%d %H:%M:%S") {
1361 Ok(v) => Ok(Some(v)),
1362 Err(_) => {
1363 if NULL_STRING.contains(s) {
1364 Ok(None)
1365 } else {
1366 Err(anyhow!(format!("invalid value-{:?}", val)))
1367 }
1368 }
1369 }
1370 }
1371 }
1372 },
1373 CellValue::Error(_) => Err(anyhow!(format!("invalid datetime{:?}", val))),
1374 CellValue::Bool(_) => Err(anyhow!(format!("invalid datetime{:?}", val))),
1375 CellValue::Blank => Ok(None),
1376 }
1377 }
1378}
1379
1380impl FromCellValue for NaiveTime {
1381 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1382 match val {
1383 CellValue::Number(n) => {
1384 Ok(Some(NaiveTime::from_num_seconds_from_midnight_opt(((*n-n.trunc()) * 86400.0) as u32, 0).ok_or(anyhow!("invalid time"))?))
1385 },
1386 CellValue::Date(n) => {
1387 Ok(Some(NaiveTime::from_num_seconds_from_midnight_opt(((*n-n.trunc()) * 86400.0) as u32, 0).ok_or(anyhow!("invalid time"))?))
1388 },
1389 CellValue::Time(n) => {
1390 Ok(Some(NaiveTime::from_num_seconds_from_midnight_opt(((*n-n.trunc()) * 86400.0) as u32, 0).ok_or(anyhow!("invalid time"))?))
1391 },
1392 CellValue::Datetime(n) => {
1393 Ok(Some(NaiveTime::from_num_seconds_from_midnight_opt(((*n-n.trunc()) * 86400.0) as u32, 0).ok_or(anyhow!("invalid time"))?))
1394 },
1395 CellValue::Shared(s) => {
1396 match NaiveTime::parse_from_str(*s, "%H:%M:%S") {
1397 Ok(v) => Ok(Some(v)),
1398 Err(_) => {
1399 match NaiveTime::parse_from_str(*s, "%H:%M:%S") {
1400 Ok(v) => Ok(Some(v)),
1401 Err(_) => {
1402 if NULL_STRING.contains(*s) {
1403 Ok(None)
1404 } else {
1405 Err(anyhow!(format!("invalid value-{:?}", val)))
1406 }
1407 }
1408 }
1409 }
1410 }
1411 },
1412 CellValue::String(s) => {
1413 match NaiveTime::parse_from_str(s, "%H:%M:%S") {
1414 Ok(v) => Ok(Some(v)),
1415 Err(_) => {
1416 match NaiveTime::parse_from_str(s, "%H:%M:%S") {
1417 Ok(v) => Ok(Some(v)),
1418 Err(_) => {
1419 if NULL_STRING.contains(s) {
1420 Ok(None)
1421 } else {
1422 Err(anyhow!(format!("invalid value-{:?}", val)))
1423 }
1424 }
1425 }
1426 }
1427 }
1428 },
1429 CellValue::Error(_) => Err(anyhow!(format!("invalid time{:?}", val))),
1430 CellValue::Bool(_) => Err(anyhow!(format!("invalid time{:?}", val))),
1431 CellValue::Blank => Ok(None),
1432 }
1433 }
1434}
1435
1436impl FromCellValue for Date32 {
1437 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1438 match val {
1439 CellValue::Number(n) => Ok(Some((*n as i32)-25569)),
1441 CellValue::Date(n) => Ok(Some((*n as i32)-25569)),
1442 CellValue::Time(n) => Ok(Some((*n as i32)-25569)),
1443 CellValue::Datetime(n) => Ok(Some((*n as i32)-25569)),
1444 CellValue::Shared(s) => {
1445 match NaiveDate::parse_from_str(*s, "%Y-%m-%d") {
1446 Ok(v) => Ok(Some((v - UNIX_DATE.clone()).num_days() as i32)),
1447 Err(_) => {
1448 match NaiveDate::parse_from_str(*s, "%Y/%m/%d") {
1449 Ok(v) => Ok(Some((v - UNIX_DATE.clone()).num_days() as i32)),
1450 Err(_) => {
1451 if NULL_STRING.contains(*s) {
1452 Ok(None)
1453 } else {
1454 Err(anyhow!(format!("invalid value-{:?}", val)))
1455 }
1456 }
1457 }
1458 }
1459 }
1460 },
1461 CellValue::String(s) => {
1462 match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
1463 Ok(v) => Ok(Some((v - UNIX_DATE.clone()).num_days() as i32)),
1464 Err(_) => {
1465 match NaiveDate::parse_from_str(s, "%Y/%m/%d") {
1466 Ok(v) => Ok(Some((v - UNIX_DATE.clone()).num_days() as i32)),
1467 Err(_) => {
1468 if NULL_STRING.contains(s) {
1469 Ok(None)
1470 } else {
1471 Err(anyhow!(format!("invalid value-{:?}", val)))
1472 }
1473 }
1474 }
1475 }
1476 }
1477 },
1478 CellValue::Error(_) => Err(anyhow!(format!("invalid date32-{:?}", val))),
1479 CellValue::Bool(_) => Err(anyhow!(format!("invalid date32-{:?}", val))),
1480 CellValue::Blank => Ok(None),
1481 }
1482 }
1483}
1484
1485impl FromCellValue for Timestamp {
1486 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1487 match val {
1488 CellValue::Number(n) => Ok(Some(((*n - 25569.0) * 86400.0).into())),
1490 CellValue::Date(n) => Ok(Some(((*n - 25569.0) * 86400.0).into())),
1491 CellValue::Time(n) => Ok(Some(((*n - 25569.0) * 86400.0).into())),
1492 CellValue::Datetime(n) => Ok(Some(((*n - 25569.0) * 86400.0).into())),
1493 CellValue::Shared(s) => {
1494 match NaiveDateTime::parse_from_str(*s, "%Y-%m-%d %H:%M:%S") {
1495 Ok(v) => Ok(Some(v.and_utc().timestamp().into())),
1496 Err(_) => {
1497 match NaiveDateTime::parse_from_str(*s, "%Y-%m-%d %H:%M:%S") {
1498 Ok(v) => Ok(Some(v.and_utc().timestamp().into())),
1499 Err(_) => {
1500 if NULL_STRING.contains(*s) {
1501 Ok(None)
1502 } else {
1503 Err(anyhow!(format!("invalid value-{:?}", val)))
1504 }
1505 }
1506 }
1507 }
1508 }
1509 },
1510 CellValue::String(s) => {
1511 match NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
1512 Ok(v) => Ok(Some(v.and_utc().timestamp().into())),
1513 Err(_) => {
1514 match NaiveDateTime::parse_from_str(s, "%Y/%m/%d %H:%M:%S") {
1515 Ok(v) => Ok(Some(v.and_utc().timestamp().into())),
1516 Err(_) => {
1517 if NULL_STRING.contains(s) {
1518 Ok(None)
1519 } else {
1520 Err(anyhow!(format!("invalid value-{:?}", val)))
1521 }
1522 }
1523 }
1524 }
1525 }
1526 },
1527 CellValue::Error(_) => Err(anyhow!(format!("invalid timestamp-{:?}", val))),
1528 CellValue::Bool(_) => Err(anyhow!(format!("invalid timestamp-{:?}", val))),
1529 CellValue::Blank => Ok(None),
1530 }
1531 }
1532}
1533
1534impl FromCellValue for Timesecond {
1535 fn try_from_cval(val: &CellValue<'_>) -> Result<Option<Self>> {
1536 match val {
1537 CellValue::Number(n) => {
1538 Ok(Some((((*n-n.trunc()) * 86400.0) as i32).into()))
1539 },
1540 CellValue::Date(n) => {
1541 Ok(Some((((*n-n.trunc()) * 86400.0) as i32).into()))
1542 },
1543 CellValue::Time(n) => {
1544 Ok(Some((((*n-n.trunc()) * 86400.0) as i32).into()))
1545 },
1546 CellValue::Datetime(n) => {
1547 Ok(Some((((*n-n.trunc()) * 86400.0) as i32).into()))
1548 },
1549 CellValue::Shared(s) => {
1550 match NaiveTime::parse_from_str(*s, "%H:%M:%S") {
1551 Ok(v) => {Ok(Some((v.num_seconds_from_midnight() as i32).into()))},
1552 Err(_) => {
1553 match NaiveTime::parse_from_str(*s, "%H:%M:%S") {
1554 Ok(v) =>Ok(Some((v.num_seconds_from_midnight() as i32).into())),
1555 Err(_) => {
1556 if NULL_STRING.contains(*s) {
1557 Ok(None)
1558 } else {
1559 Err(anyhow!(format!("invalid value-{:?}", val)))
1560 }
1561 }
1562 }
1563 }
1564 }
1565 },
1566 CellValue::String(s) => {
1567 match NaiveTime::parse_from_str(s, "%H:%M:%S") {
1568 Ok(v) => {Ok(Some((v.num_seconds_from_midnight() as i32).into()))},
1569 Err(_) => {
1570 match NaiveTime::parse_from_str(s, "%H:%M:%S") {
1571 Ok(v) =>Ok(Some((v.num_seconds_from_midnight() as i32).into())),
1572 Err(_) => {
1573 if NULL_STRING.contains(s) {
1574 Ok(None)
1575 } else {
1576 Err(anyhow!(format!("invalid value-{:?}", val)))
1577 }
1578 }
1579 }
1580 }
1581 }
1582 },
1583 CellValue::Error(_) => Err(anyhow!(format!("invalid time{:?}", val))),
1584 CellValue::Bool(_) => Err(anyhow!(format!("invalid time{:?}", val))),
1585 CellValue::Blank => Ok(None),
1586 }
1587 }
1588}
1589
1590impl Into<CellValue<'_>> for String {
1592 fn into(self) -> CellValue<'static> {
1593 CellValue::String(self)
1594 }
1595}
1596
1597impl Into<CellValue<'_>> for f64 {
1598 fn into(self) -> CellValue<'static> {
1599 CellValue::Number(self)
1600 }
1601}
1602
1603impl Into<CellValue<'_>> for i64 {
1604 fn into(self) -> CellValue<'static> {
1605 CellValue::Number(self as f64)
1606 }
1607}
1608
1609impl Into<CellValue<'_>> for bool {
1610 fn into(self) -> CellValue<'static> {
1611 CellValue::Bool(self)
1612 }
1613}
1614
1615pub trait IntoCellValue {
1617 fn try_into_cval(self) -> Result<CellValue<'static>>;
1618}
1619
1620impl IntoCellValue for NaiveDate {
1621 fn try_into_cval(self) -> Result<CellValue<'static>> {
1622 Ok(CellValue::Date((self.signed_duration_since(*BASE_DATE).num_days()) as f64))
1623 }
1624}
1625
1626impl IntoCellValue for NaiveDateTime {
1627 fn try_into_cval(self) -> Result<CellValue<'static>> {
1628 let (dt, tm) = (self.date(), self.time());
1629 Ok(CellValue::Datetime(((dt.signed_duration_since(*BASE_DATE).num_days()) as f64) + ((tm.num_seconds_from_midnight() as f64) / 86400.0)))
1630 }
1631}
1632
1633impl IntoCellValue for NaiveTime {
1634 fn try_into_cval(self) -> Result<CellValue<'static>> {
1635 Ok(CellValue::Time((self.num_seconds_from_midnight() as f64) / 86400.0))
1636 }
1637}
1638
1639impl IntoCellValue for Date32 {
1640 fn try_into_cval(self) -> Result<CellValue<'static>> {
1641 Ok(CellValue::Date((self + 25569) as f64))
1642 }
1643}
1644
1645impl IntoCellValue for Timestamp {
1647 fn try_into_cval(self) -> Result<CellValue<'static>> {
1648 if let Some(v) = BASE_DATETIME.checked_add_signed(Duration::seconds(self.0)) {
1649 v.try_into_cval()
1650 } else {
1651 Ok(CellValue::Error(format!("Invalid Timestamp-{}", self.0)))
1652 }
1653 }
1654}
1655
1656impl IntoCellValue for Timesecond {
1657 fn try_into_cval(self) -> Result<CellValue<'static>> {
1658 Ok(CellValue::Time(self.0 as f64 / 86400.0))
1659 }
1660}
1661
1662static FMT_DATE: u8 = 0;
1664static FMT_TIME: u8 = 1;
1665static FMT_DATETIME: u8 = 2;
1666static FMT_DEFAULT: u8 = 255;
1667
1668lazy_static! {
1669 static ref BASE_DATE: NaiveDate = NaiveDate::from_ymd_opt(1899, 12,30).unwrap();
1670 static ref BASE_DATETIME: NaiveDateTime = BASE_DATE.and_hms_opt(0, 0, 0).unwrap();
1671 static ref BASE_TIME: NaiveTime = NaiveTime::from_num_seconds_from_midnight_opt(0, 0).unwrap();
1672 static ref UNIX_DATE: NaiveDate = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
1673 static ref NULL_STRING: HashSet<String> = {
1674 let mut v = HashSet::new();
1675 v.insert("".into());
1676 v.insert("-".into());
1677 v.insert("--".into());
1678 v.insert("#N/A".into());
1679 v
1680 };
1681 static ref DATETIME_FMTS: HashMap<u32, u8> = {
1682 let mut v = HashMap::new();
1683 v.extend((14..18).map(|n| (n, FMT_DATE)));
1684 v.extend((27..32).map(|n| (n, FMT_DATE)));
1685 v.extend((34..37).map(|n| (n, FMT_DATE)));
1686 v.extend((50..59).map(|n| (n, FMT_DATE))); v.extend((18..22).map(|n| (n, FMT_TIME)));
1688 v.extend((32..34).map(|n| (n, FMT_TIME)));
1689 v.extend((45..48).map(|n| (n, FMT_TIME))); v.insert(22, FMT_DATETIME); v
1692 };
1693 static ref NUM_FMTS: HashMap<u32, String> = {
1694 let mut map: HashMap<u32, String> = HashMap::new();
1695 map.insert(0, "General".to_string());
1697 map.insert(1, "0".to_string());
1698 map.insert(2, "0.00".to_string());
1699 map.insert(3, "#,##0".to_string());
1700 map.insert(4, "#,##0.00".to_string());
1701
1702 map.insert(9, "0%".to_string());
1703 map.insert(10, "0.00%".to_string());
1704 map.insert(11, "0.00E+00".to_string());
1705 map.insert(12, "# ?/?".to_string());
1706 map.insert(13, "# ??/??".to_string());
1707 map.insert(14, "m/d/yyyy".to_string()); map.insert(15, "d-mmm-yy".to_string());
1709 map.insert(16, "d-mmm".to_string());
1710 map.insert(17, "mmm-yy".to_string());
1711 map.insert(18, "h:mm AM/PM".to_string());
1712 map.insert(19, "h:mm:ss AM/PM".to_string());
1713 map.insert(20, "h:mm".to_string());
1714 map.insert(21, "h:mm:ss".to_string());
1715 map.insert(22, "m/d/yyyy h:mm".to_string()); map.insert(37, "#,##0_);(#,##0)".to_string()); map.insert(38, "#,##0_);[Red](#,##0)".to_string()); map.insert(39, "#,##0.00_);(#,##0.00)".to_string()); map.insert(40, "#,##0.00_);[Red](#,##0.00)".to_string()); map.insert(44, r###"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"###.to_string());
1723 map.insert(45, "mm:ss".to_string());
1724 map.insert(46, "[h]:mm:ss".to_string());
1725 map.insert(47, "mm:ss.0".to_string()); map.insert(48, "##0.0E+0".to_string());
1727 map.insert(49, "@".to_string());
1728
1729 map.insert(27, "[$-404]e/m/d".to_string());
1731 map.insert(30, "m/d/yy".to_string());
1732 map.insert(36, "[$-404]e/m/d".to_string());
1733 map.insert(50, "[$-404]e/m/d".to_string());
1734 map.insert(57, "[$-404]e/m/d".to_string());
1735
1736 map.insert(59, "t0".to_string());
1738 map.insert(60, "t0.00".to_string());
1739 map.insert(61, "t#,##0".to_string());
1740 map.insert(62, "t#,##0.00".to_string());
1741 map.insert(67, "t0%".to_string());
1742 map.insert(68, "t0.00%".to_string());
1743 map.insert(69, "t# ?/?".to_string());
1744 map.insert(70, "t# ??/??".to_string());
1745
1746 map.insert(28, r###"[$-411]ggge"年"m"月"d"日""###.to_string());
1748 map.insert(29, r###"[$-411]ggge"年"m"月"d"日""###.to_string());
1749 map.insert(31, r###"yyyy"年"m"月"d"日""###.to_string());
1750 map.insert(32, r###"h"時"mm"分""###.to_string());
1751 map.insert(33, r###"h"時"mm"分"ss"秒""###.to_string());
1752 map.insert(34, r###"yyyy"年"m"月""###.to_string());
1753 map.insert(35, r###"m"月"d"日""###.to_string());
1754 map.insert(51, r###"[$-411]ggge"年"m"月"d"日""###.to_string());
1755 map.insert(52, r###"yyyy"年"m"月""###.to_string());
1756 map.insert(53, r###"m"月"d"日""###.to_string());
1757 map.insert(54, r###"[$-411]ggge"年"m"月"d"日""###.to_string());
1758 map.insert(55, r###"yyyy"年"m"月""###.to_string());
1759 map.insert(56, r###"m"月"d"日""###.to_string());
1760 map.insert(58, r###"[$-411]ggge"年"m"月"d"日""###.to_string());
1761
1762 map
1763 };
1764 static ref EMP_CELLS: Vec<CellValue<'static>> = vec![];
1765}