1
1
use std:: collections:: HashMap ;
2
2
use std:: io:: Read ;
3
3
use std:: ops:: Range ;
4
+ use std:: sync:: Arc ;
4
5
5
6
use bytes:: { buf:: Buf , Bytes } ;
6
7
use num_enum:: TryFromPrimitive ;
@@ -195,26 +196,24 @@ impl ImageFileDirectory {
195
196
} else {
196
197
cursor. read_u16 ( ) . await ?. into ( )
197
198
} ;
198
- let mut tags = HashMap :: with_capacity ( tag_count as usize ) ;
199
- for _ in 0 ..tag_count {
200
- let ( tag_name, tag_value) = read_tag ( cursor, bigtiff) . await ?;
201
- tags. insert ( tag_name, tag_value) ;
202
- }
203
-
204
199
// Tag 2 bytes
205
200
// Type 2 bytes
206
201
// Count:
207
202
// - bigtiff: 8 bytes
208
203
// - else: 4 bytes
209
204
// Value:
210
- // - bigtiff: 8 bytes either a pointer the value itself
211
- // - else: 4 bytes either a pointer the value itself
205
+ // - bigtiff: 8 bytes either a pointer or the value itself
206
+ // - else: 4 bytes either a pointer or the value itself
212
207
let ifd_entry_byte_size = if bigtiff { 20 } else { 12 } ;
213
- // The size of `tag_count` that we read above
214
- let tag_count_byte_size = if bigtiff { 8 } else { 2 } ;
215
208
216
- // Reset the cursor position before reading the next ifd offset
217
- cursor. seek ( ifd_start + ( ifd_entry_byte_size * tag_count) + tag_count_byte_size) ;
209
+ // read all tag data into an EndianAwareReader
210
+ let mut reader = cursor. read ( ifd_entry_byte_size * tag_count) . await ?;
211
+
212
+ let mut tags = HashMap :: with_capacity ( tag_count as usize ) ;
213
+ for _ in 0 ..tag_count {
214
+ let ( tag_name, tag_value) = read_tag ( & mut reader, cursor. reader ( ) , bigtiff) . await ?;
215
+ tags. insert ( tag_name, tag_value) ;
216
+ }
218
217
219
218
let next_ifd_offset = if bigtiff {
220
219
cursor. read_u64 ( ) . await ?
@@ -838,22 +837,50 @@ impl ImageFileDirectory {
838
837
}
839
838
840
839
/// Read a single tag from the cursor
841
- async fn read_tag ( cursor : & mut AsyncCursor , bigtiff : bool ) -> AsyncTiffResult < ( Tag , Value ) > {
840
+ async fn read_tag ( cursor : & mut EndianAwareReader , file_reader : & Arc < dyn AsyncFileReader > , bigtiff : bool ) -> AsyncTiffResult < ( Tag , Value ) > {
842
841
// let start_cursor_position = cursor.position();
843
842
844
- let tag_name = Tag :: from_u16_exhaustive ( cursor. read_u16 ( ) . await ?) ;
843
+ let tag_name = Tag :: from_u16_exhaustive ( cursor. read_u16 ( ) ?) ;
845
844
846
- let tag_type_code = cursor. read_u16 ( ) . await ?;
845
+ let tag_type_code = cursor. read_u16 ( ) ?;
847
846
let tag_type = Type :: from_u16 ( tag_type_code) . expect (
848
847
"Unknown tag type {tag_type_code}. TODO: we should skip entries with unknown tag types." ,
849
848
) ;
850
849
let count = if bigtiff {
851
- cursor. read_u64 ( ) . await ?
850
+ cursor. read_u64 ( ) ?
852
851
} else {
853
- cursor. read_u32 ( ) . await ?. into ( )
852
+ cursor. read_u32 ( ) ?. into ( )
854
853
} ;
855
854
856
- let tag_value = read_tag_value ( cursor, tag_type, count, bigtiff) . await ?;
855
+ let tag_size = tag_type. size ( ) ;
856
+
857
+ let value_byte_length = count. checked_mul ( tag_size) . unwrap ( ) ;
858
+
859
+ // prefetch all tag data
860
+ let mut data = if ( bigtiff && value_byte_length <= 8 ) || value_byte_length <= 4 {
861
+ // value fits in offset field
862
+ let mut res = vec ! [ 0u8 ; value_byte_length as usize ] ;
863
+ cursor. read_exact ( & mut res) ?;
864
+ if bigtiff {
865
+ cursor. advance ( 8 -value_byte_length) ?;
866
+ } else {
867
+ cursor. advance ( 4 -value_byte_length) ?;
868
+ }
869
+ EndianAwareReader :: new ( Bytes :: from_owner ( res) . reader ( ) , cursor. endianness ( ) )
870
+ } else {
871
+ // fetch using file_reader
872
+ let offset = if bigtiff {
873
+ cursor. read_u64 ( ) ?
874
+ } else {
875
+ cursor. read_u32 ( ) ?. into ( )
876
+ } ;
877
+ let reader = file_reader. get_bytes ( offset..offset+value_byte_length) . await ?. reader ( ) ;
878
+ EndianAwareReader :: new ( reader, cursor. endianness ( ) )
879
+ // cursor.seek(offset);
880
+ // cursor.read(value_byte_length).await?
881
+ } ;
882
+
883
+ let tag_value = read_tag_value ( & mut data, tag_type, count) ?;
857
884
858
885
// TODO: better handle management of cursor state <- should be done now
859
886
// let ifd_entry_size = if bigtiff { 20 } else { 12 };
@@ -867,43 +894,16 @@ async fn read_tag(cursor: &mut AsyncCursor, bigtiff: bool) -> AsyncTiffResult<(T
867
894
/// NOTE: this does not maintain cursor state
868
895
// This is derived from the upstream tiff crate:
869
896
// https://github.com/image-rs/image-tiff/blob/6dc7a266d30291db1e706c8133357931f9e2a053/src/decoder/ifd.rs#L369-L639
870
- async fn read_tag_value (
871
- cursor : & mut AsyncCursor ,
897
+ fn read_tag_value (
898
+ data : & mut EndianAwareReader ,
872
899
tag_type : Type ,
873
900
count : u64 ,
874
- bigtiff : bool ,
875
901
) -> AsyncTiffResult < Value > {
876
902
// Case 1: there are no values so we can return immediately.
877
903
if count == 0 {
878
904
return Ok ( Value :: List ( vec ! [ ] ) ) ;
879
905
}
880
906
881
- let tag_size = tag_type. size ( ) ;
882
-
883
- let value_byte_length = count. checked_mul ( tag_size) . unwrap ( ) ;
884
-
885
- // prefetch all tag data
886
- let mut data = if ( bigtiff && value_byte_length <= 8 ) || value_byte_length <= 4 {
887
- // value fits in offset field
888
- let res = cursor. read ( value_byte_length) . await ?;
889
- if bigtiff {
890
- cursor. advance ( 8 -value_byte_length) ;
891
- } else {
892
- cursor. advance ( 4 -value_byte_length) ;
893
- }
894
- res
895
- } else {
896
- // Seek cursor
897
- let offset = if bigtiff {
898
- cursor. read_u64 ( ) . await ?
899
- } else {
900
- cursor. read_u32 ( ) . await ?. into ( )
901
- } ;
902
- let reader = cursor. reader ( ) . get_bytes ( offset..offset+value_byte_length) . await ?. reader ( ) ;
903
- EndianAwareReader :: new ( reader, cursor. endianness ( ) )
904
- // cursor.seek(offset);
905
- // cursor.read(value_byte_length).await?
906
- } ;
907
907
// Case 2: there is one value.
908
908
if count == 1 {
909
909
return Ok ( match tag_type {
0 commit comments