1use std::io;
20use std::marker::PhantomData;
21
22use crate::ifd::types::{BIGIFD, IFD, LONG, LONG8, TiffType};
23use crate::ifd::{AllocatedIfdChain, IfdChain};
24use crate::write::{Cursor, Datablock, EndianFile, OffsetSize};
25
26pub trait FieldValues<O: OffsetSize = u32>: private::Sealed<O> {
48 #[doc(hidden)]
50 fn count(&self) -> O;
51 #[doc(hidden)]
55 fn size(&self) -> O;
56 #[doc(hidden)]
59 fn allocate(self: Box<Self>, c: &mut Cursor<O>) -> Box<dyn AllocatedFieldValues<O>>;
60}
61
62#[doc(hidden)]
66pub trait AllocatedFieldValues<O: OffsetSize = u32> {
67 fn count(&self) -> O;
69 fn size(&self) -> O;
73 fn position(&self) -> Option<O>;
77 fn type_id(&self) -> u16;
79 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()>;
82}
83
84mod private {
88 use crate::write::OffsetSize;
89
90 pub trait Sealed<O: OffsetSize> {}
91 impl<T: super::Datablock, O: OffsetSize> Sealed<O> for super::Offsets<T, O> {}
92 impl<T, O: OffsetSize> Sealed<O> for super::TiffTypeValues<T, O> {}
93 impl<O: OffsetSize> Sealed<O> for super::OffsetsToIfds<O> {}
94}
95
96pub struct Offsets<T: Datablock, O: OffsetSize = u32> {
108 pub data: Vec<T>,
109 _phantom: PhantomData<O>,
110}
111
112impl<T: Datablock + 'static, O: OffsetSize> Offsets<T, O> {
113 pub fn new(datablocks: Vec<T>) -> Self {
117 Offsets {
118 data: datablocks,
119 _phantom: PhantomData,
120 }
121 }
122
123 pub fn single(datablock: T) -> Self {
127 Offsets::new(vec![datablock])
128 }
129}
130
131impl<T: Datablock + 'static> Offsets<T, u32> {
132 pub fn big_new(datablocks: Vec<T>) -> Offsets<T, u64> {
136 Offsets {
137 data: datablocks,
138 _phantom: PhantomData,
139 }
140 }
141
142 pub fn big_single(datablock: T) -> Offsets<T, u64> {
146 Offsets::big_new(vec![datablock])
147 }
148}
149
150impl<T: Datablock + 'static> FieldValues<u32> for Offsets<T, u32> {
151 fn count(&self) -> u32 {
152 self.data.len() as u32
153 }
154
155 fn size(&self) -> u32 {
156 <LONG as TiffType<u32>>::size() * self.count()
157 }
158
159 fn allocate(self: Box<Self>, c: &mut Cursor<u32>) -> Box<dyn AllocatedFieldValues<u32>> {
160 let position = Some(c.allocated_bytes());
161 if self.data.len() == 1 {
162 let offsets = Vec::new();
163 let block_size = self.data.get(0).unwrap().size() as u32;
164
165 c.allocate(if block_size % 2 == 0 {
166 block_size
167 } else {
168 block_size + 1
169 });
170
171 Box::new(AllocatedOffsets {
172 position,
173 offsets,
174 data: self.data,
175 _phantom: PhantomData,
176 })
177 } else {
178 c.allocate(self.size());
179 let mut offsets = Vec::with_capacity(self.data.len());
180
181 for block in self.data.iter() {
182 offsets.push(LONG(c.allocated_bytes()));
183 let block_size = block.size() as u32;
184 c.allocate(if block_size % 2 == 0 {
185 block_size
186 } else {
187 block_size + 1
188 });
189 }
190
191 Box::new(AllocatedOffsets {
192 position,
193 offsets,
194 data: self.data,
195 _phantom: PhantomData,
196 })
197 }
198 }
199}
200
201impl<T: Datablock + 'static> FieldValues<u64> for Offsets<T, u64> {
202 fn count(&self) -> u64 {
203 self.data.len() as u64
204 }
205
206 fn size(&self) -> u64 {
207 <LONG8 as TiffType<u64>>::size() * self.count()
208 }
209
210 fn allocate(self: Box<Self>, c: &mut Cursor<u64>) -> Box<dyn AllocatedFieldValues<u64>> {
211 let position = Some(c.allocated_bytes());
212 if self.data.len() == 1 {
213 let offsets = Vec::new();
214 let block_size = self.data.get(0).unwrap().size() as u64;
215
216 c.allocate(if block_size % 2 == 0 {
217 block_size
218 } else {
219 block_size + 1
220 });
221
222 Box::new(AllocatedOffsets64 {
223 position,
224 offsets,
225 data: self.data,
226 })
227 } else {
228 c.allocate(self.size());
229 let mut offsets = Vec::with_capacity(self.data.len());
230
231 for block in self.data.iter() {
232 offsets.push(LONG8(c.allocated_bytes()));
233 let block_size = block.size() as u64;
234 c.allocate(if block_size % 2 == 0 {
235 block_size
236 } else {
237 block_size + 1
238 });
239 }
240
241 Box::new(AllocatedOffsets64 {
242 position,
243 offsets,
244 data: self.data,
245 })
246 }
247 }
248}
249
250struct AllocatedOffsets<T: Datablock, O: OffsetSize> {
252 position: Option<O>,
253 offsets: Vec<LONG>,
254 data: Vec<T>,
255 _phantom: PhantomData<O>,
256}
257
258impl<T: Datablock> AllocatedFieldValues<u32> for AllocatedOffsets<T, u32> {
259 fn count(&self) -> u32 {
260 self.data.len() as u32
261 }
262
263 fn size(&self) -> u32 {
264 <LONG as TiffType<u32>>::size() * self.count()
265 }
266
267 fn position(&self) -> Option<u32> {
268 self.position
269 }
270
271 fn type_id(&self) -> u16 {
272 <LONG as TiffType<u32>>::id()
273 }
274
275 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()> {
276 let unboxed = *self;
277 let AllocatedOffsets { data, offsets, .. } = unboxed;
278 for offset in offsets {
279 <LONG as TiffType<u32>>::write_to(offset, file)?;
280 }
281 for block in data {
282 let file_initial = file.written_bytes();
283 let block_size = block.size() as u64;
284 block.write_to(file)?;
285 let written_size = file.written_bytes() - file_initial;
286 if written_size % 2 == 1 {
287 file.write_arbitrary_byte()?
288 }
289 if written_size != block_size {
290 panic!(
291 "The number of bytes allocated by the Datablock ({}) is different from the number of bytes written to the file ({}).",
292 block_size, written_size
293 )
294 }
295 }
296 Ok(())
297 }
298}
299
300struct AllocatedOffsets64<T: Datablock> {
302 position: Option<u64>,
303 offsets: Vec<LONG8>,
304 data: Vec<T>,
305}
306
307impl<T: Datablock> AllocatedFieldValues<u64> for AllocatedOffsets64<T> {
308 fn count(&self) -> u64 {
309 self.data.len() as u64
310 }
311
312 fn size(&self) -> u64 {
313 <LONG8 as TiffType<u64>>::size() * self.count()
314 }
315
316 fn position(&self) -> Option<u64> {
317 self.position
318 }
319
320 fn type_id(&self) -> u16 {
321 <LONG8 as TiffType<u64>>::id()
322 }
323
324 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()> {
325 let unboxed = *self;
326 let AllocatedOffsets64 { data, offsets, .. } = unboxed;
327 for offset in offsets {
328 <LONG8 as TiffType<u64>>::write_to(offset, file)?;
329 }
330 for block in data {
331 let file_initial = file.written_bytes();
332 let block_size = block.size() as u64;
333 block.write_to(file)?;
334 let written_size = file.written_bytes() - file_initial;
335 if written_size % 2 == 1 {
336 file.write_arbitrary_byte()?
337 }
338 if written_size != block_size {
339 panic!(
340 "The number of bytes allocated by the Datablock ({}) is different from the number of bytes written to the file ({}).",
341 block_size, written_size
342 )
343 }
344 }
345 Ok(())
346 }
347}
348
349#[derive(Debug, PartialEq)]
355pub struct TiffTypeValues<T, O: OffsetSize = u32> {
356 values: Vec<T>,
357 _phantom: PhantomData<O>,
358}
359
360impl<T, O: OffsetSize> TiffTypeValues<T, O> {
361 pub fn new(values: Vec<T>) -> Self {
366 if values.is_empty() {
367 panic!("Cannot create an empty instance of TiffTypeValues")
368 }
369 TiffTypeValues {
370 values,
371 _phantom: PhantomData,
372 }
373 }
374}
375
376impl<T: TiffType<O> + 'static, O: OffsetSize> FieldValues<O> for TiffTypeValues<T, O> {
377 fn count(&self) -> O {
378 O::from_usize(self.values.len())
379 }
380
381 fn size(&self) -> O {
382 T::size() * self.count()
383 }
384
385 fn allocate(self: Box<Self>, c: &mut Cursor<O>) -> Box<dyn AllocatedFieldValues<O>> {
386 let position = if self.size().to_u64() <= O::INLINE_THRESHOLD.to_u64() {
387 None
388 } else {
389 let size = self.size() + self.size() % O::TWO;
390 let pos = c.allocated_bytes();
391 c.allocate(size);
392 Some(pos)
393 };
394
395 Box::new(AllocatedTiffTypeValues {
396 position,
397 values: self.values,
398 _phantom: PhantomData,
399 })
400 }
401}
402
403struct AllocatedTiffTypeValues<T, O: OffsetSize> {
405 position: Option<O>,
406 values: Vec<T>,
407 _phantom: PhantomData<O>,
408}
409
410impl<T: TiffType<O>, O: OffsetSize> AllocatedFieldValues<O> for AllocatedTiffTypeValues<T, O> {
411 fn count(&self) -> O {
412 O::from_usize(self.values.len())
413 }
414
415 fn size(&self) -> O {
416 T::size() * self.count()
417 }
418
419 fn position(&self) -> Option<O> {
420 self.position
421 }
422
423 fn type_id(&self) -> u16 {
424 T::id()
425 }
426
427 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()> {
428 let size = self.size();
429 for value in self.values {
430 let file_initial = file.written_bytes();
431 value.write_to(file)?;
432 let written_size = file.written_bytes() - file_initial;
433 if written_size != T::size().to_u64() {
434 panic!(
435 "The size indicated ({}) is different from the number of bytes the type has written to the file ({}).",
436 T::size().to_u64(),
437 written_size
438 )
439 }
440 }
441
442 if size.to_u64() % 2 == 1 && size.to_u64() > O::INLINE_THRESHOLD.to_u64() {
443 file.write_arbitrary_byte()?;
444 }
445 Ok(())
446 }
447}
448
449pub struct OffsetsToIfds<O: OffsetSize = u32> {
466 pub data: Vec<IfdChain<O>>,
467}
468
469impl<O: OffsetSize> OffsetsToIfds<O> {
470 pub fn new(ifds: Vec<IfdChain<O>>) -> Self {
474 OffsetsToIfds { data: ifds }
475 }
476}
477
478impl FieldValues<u32> for OffsetsToIfds<u32> {
479 fn count(&self) -> u32 {
480 self.data.len() as u32
481 }
482
483 fn size(&self) -> u32 {
484 <IFD as TiffType<u32>>::size() * self.count()
485 }
486
487 fn allocate(self: Box<Self>, c: &mut Cursor<u32>) -> Box<dyn AllocatedFieldValues<u32>> {
488 let position = Some(c.allocated_bytes());
489 if self.data.len() == 1 {
490 let offsets = Vec::new();
491 let ifd = self.data.into_iter().next().unwrap();
492 let allocated_data = vec![ifd.allocate(c)];
493
494 Box::new(AllocatedOffsetsToIfds {
495 position,
496 offsets,
497 data: allocated_data,
498 })
499 } else {
500 c.allocate(self.size());
501 let mut offsets = Vec::with_capacity(self.data.len());
502 let mut allocated_data = Vec::with_capacity(self.data.len());
503
504 for ifd in self.data {
505 offsets.push(IFD(c.allocated_bytes()));
506 allocated_data.push(ifd.allocate(c));
507 }
508
509 Box::new(AllocatedOffsetsToIfds {
510 position,
511 offsets,
512 data: allocated_data,
513 })
514 }
515 }
516}
517
518impl FieldValues<u64> for OffsetsToIfds<u64> {
519 fn count(&self) -> u64 {
520 self.data.len() as u64
521 }
522
523 fn size(&self) -> u64 {
524 <BIGIFD as TiffType<u64>>::size() * self.count()
525 }
526
527 fn allocate(self: Box<Self>, c: &mut Cursor<u64>) -> Box<dyn AllocatedFieldValues<u64>> {
528 let position = Some(c.allocated_bytes());
529 if self.data.len() == 1 {
530 let offsets = Vec::new();
531 let ifd = self.data.into_iter().next().unwrap();
532 let allocated_data = vec![ifd.allocate(c)];
533
534 Box::new(AllocatedOffsetsToIfds64 {
535 position,
536 offsets,
537 data: allocated_data,
538 })
539 } else {
540 c.allocate(self.size());
541 let mut offsets = Vec::with_capacity(self.data.len());
542 let mut allocated_data = Vec::with_capacity(self.data.len());
543
544 for ifd in self.data {
545 offsets.push(BIGIFD(c.allocated_bytes()));
546 allocated_data.push(ifd.allocate(c));
547 }
548
549 Box::new(AllocatedOffsetsToIfds64 {
550 position,
551 offsets,
552 data: allocated_data,
553 })
554 }
555 }
556}
557
558struct AllocatedOffsetsToIfds {
560 position: Option<u32>,
561 offsets: Vec<IFD>,
562 data: Vec<AllocatedIfdChain<u32>>,
563}
564
565impl AllocatedFieldValues<u32> for AllocatedOffsetsToIfds {
566 fn count(&self) -> u32 {
567 self.data.len() as u32
568 }
569
570 fn size(&self) -> u32 {
571 <IFD as TiffType<u32>>::size() * self.count()
572 }
573
574 fn position(&self) -> Option<u32> {
575 self.position
576 }
577
578 fn type_id(&self) -> u16 {
579 <IFD as TiffType<u32>>::id()
580 }
581
582 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()> {
583 let unboxed = *self;
584 let AllocatedOffsetsToIfds { data, offsets, .. } = unboxed;
585 for offset in offsets {
586 <IFD as TiffType<u32>>::write_to(offset, file)?;
587 }
588 for ifd in data.into_iter() {
589 ifd.write_to(file)?;
590 }
591 Ok(())
592 }
593}
594
595struct AllocatedOffsetsToIfds64 {
597 position: Option<u64>,
598 offsets: Vec<BIGIFD>,
599 data: Vec<AllocatedIfdChain<u64>>,
600}
601
602impl AllocatedFieldValues<u64> for AllocatedOffsetsToIfds64 {
603 fn count(&self) -> u64 {
604 self.data.len() as u64
605 }
606
607 fn size(&self) -> u64 {
608 <BIGIFD as TiffType<u64>>::size() * self.count()
609 }
610
611 fn position(&self) -> Option<u64> {
612 self.position
613 }
614
615 fn type_id(&self) -> u16 {
616 <BIGIFD as TiffType<u64>>::id()
617 }
618
619 fn write_to(self: Box<Self>, file: &mut EndianFile) -> io::Result<()> {
620 let unboxed = *self;
621 let AllocatedOffsetsToIfds64 { data, offsets, .. } = unboxed;
622 for offset in offsets {
623 <BIGIFD as TiffType<u64>>::write_to(offset, file)?;
624 }
625 for ifd in data.into_iter() {
626 ifd.write_to(file)?;
627 }
628 Ok(())
629 }
630}