exif/
writer.rs

1//
2// Copyright (c) 2017 KAMADA Ken'ichi.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions
7// are met:
8// 1. Redistributions of source code must retain the above copyright
9//    notice, this list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11//    notice, this list of conditions and the following disclaimer in the
12//    documentation and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24// SUCH DAMAGE.
25//
26
27use std::io;
28use std::io::{Seek, SeekFrom, Write};
29
30use crate::endian::{Endian, BigEndian, LittleEndian};
31use crate::error::Error;
32use crate::tag::{Context, Tag};
33use crate::tiff::{Field, In, TIFF_BE_SIG, TIFF_LE_SIG};
34use crate::value::Value;
35
36/// The `Writer` struct is used to encode and write Exif data.
37///
38/// # Examples
39///
40/// ```
41/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
42/// use exif::{Field, In, Tag, Value};
43/// use exif::experimental::Writer;
44/// let image_desc = Field {
45///     tag: Tag::ImageDescription,
46///     ifd_num: In::PRIMARY,
47///     value: Value::Ascii(vec![b"Sample".to_vec()]),
48/// };
49/// let mut writer = Writer::new();
50/// let mut buf = std::io::Cursor::new(Vec::new());
51/// writer.push_field(&image_desc);
52/// writer.write(&mut buf, false)?;
53/// static expected: &[u8] =
54///     b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
55///       \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x07\x00\x00\x00\x1a\
56///       \x00\x00\x00\x00\
57///       Sample\0";
58/// assert_eq!(buf.into_inner(), expected);
59/// # Ok(()) }
60/// ```
61#[derive(Debug)]
62pub struct Writer<'a> {
63    ifd_list: Vec<Ifd<'a>>,
64}
65
66#[derive(Debug, Default)]
67struct Ifd<'a> {
68    tiff_fields: Vec<&'a Field>,
69    exif_fields: Vec<&'a Field>,
70    gps_fields: Vec<&'a Field>,
71    interop_fields: Vec<&'a Field>,
72    strips: Option<&'a [&'a [u8]]>,
73    tiles: Option<&'a [&'a [u8]]>,
74    jpeg: Option<&'a [u8]>,
75}
76
77impl<'a> Ifd<'a> {
78    fn is_empty(&self) -> bool {
79        self.tiff_fields.is_empty() &&
80            self.exif_fields.is_empty() &&
81            self.gps_fields.is_empty() &&
82            self.interop_fields.is_empty() &&
83            self.strips.is_none() &&
84            self.tiles.is_none() &&
85            self.jpeg.is_none()
86    }
87}
88
89struct WriterState<'a> {
90    tiff_fields: Vec<&'a Field>,
91    exif_fields: Vec<&'a Field>,
92    gps_fields: Vec<&'a Field>,
93    interop_fields: Vec<&'a Field>,
94    tiff_ifd_offset: u32,
95    exif_ifd_offset: u32,
96    gps_ifd_offset: u32,
97    interop_ifd_offset: u32,
98}
99
100impl<'a> Writer<'a> {
101    /// Constructs an empty `Writer`.
102    pub fn new() -> Writer<'a> {
103        Writer {
104            ifd_list: Vec::new(),
105        }
106    }
107
108    /// Appends a field to be written.
109    ///
110    /// The fields can be appended in any order.
111    /// Duplicate fields must not be appended.
112    ///
113    /// The following fields are ignored and synthesized when needed:
114    /// ExifIFDPointer, GPSInfoIFDPointer, InteropIFDPointer,
115    /// StripOffsets, StripByteCounts, TileOffsets, TileByteCounts,
116    /// JPEGInterchangeFormat, and JPEGInterchangeFormatLength.
117    pub fn push_field(&mut self, field: &'a Field) {
118        match *field {
119            // Ignore the tags for the internal data structure.
120            Field { tag: Tag::ExifIFDPointer, .. } |
121            Field { tag: Tag::GPSInfoIFDPointer, .. } |
122            Field { tag: Tag::InteropIFDPointer, .. } => {},
123            // These tags are synthesized from the actual strip/tile data.
124            Field { tag: Tag::StripOffsets, .. } |
125            Field { tag: Tag::StripByteCounts, .. } |
126            Field { tag: Tag::TileOffsets, .. } |
127            Field { tag: Tag::TileByteCounts, .. } => {},
128            // These tags are synthesized from the actual JPEG thumbnail.
129            Field { tag: Tag::JPEGInterchangeFormat, .. } |
130            Field { tag: Tag::JPEGInterchangeFormatLength, .. } => {},
131            // Other normal tags.
132            Field { tag: Tag(ctx, _), ifd_num, .. } => {
133                let ifd = self.pick_ifd(ifd_num);
134                match ctx {
135                    Context::Tiff => ifd.tiff_fields.push(field),
136                    Context::Exif => ifd.exif_fields.push(field),
137                    Context::Gps => ifd.gps_fields.push(field),
138                    Context::Interop => ifd.interop_fields.push(field),
139                }
140            },
141        }
142    }
143
144    /// Sets TIFF strips for the specified IFD.
145    /// If this method is called multiple times, the last one is used.
146    pub fn set_strips(&mut self, strips: &'a [&'a [u8]], ifd_num: In) {
147        self.pick_ifd(ifd_num).strips = Some(strips);
148    }
149
150    /// Sets TIFF tiles for the specified IFD.
151    /// If this method is called multiple times, the last one is used.
152    pub fn set_tiles(&mut self, tiles: &'a [&'a [u8]], ifd_num: In) {
153        self.pick_ifd(ifd_num).tiles = Some(tiles);
154    }
155
156    /// Sets JPEG data for the specified IFD.
157    /// If this method is called multiple times, the last one is used.
158    pub fn set_jpeg(&mut self, jpeg: &'a [u8], ifd_num: In) {
159        self.pick_ifd(ifd_num).jpeg = Some(jpeg);
160    }
161
162    /// Encodes Exif data and writes it into `w`.
163    ///
164    /// The write position of `w` must be set to zero before calling
165    /// this method.
166    pub fn write<W>(&mut self, w: &mut W, little_endian: bool)
167                    -> Result<(), Error> where W: Write + Seek {
168        // TIFF signature and the offset of the 0th IFD.
169        if little_endian {
170            w.write_all(&TIFF_LE_SIG)?;
171            LittleEndian::writeu32(w, 8)?;
172        } else {
173            w.write_all(&TIFF_BE_SIG)?;
174            BigEndian::writeu32(w, 8)?;
175        }
176
177        // There must be at least 1 IFD in a TIFF file [TIFF6, Section 2,
178        // Image File Directory].
179        if self.ifd_list.is_empty() {
180            return Err(Error::InvalidFormat("At least one IFD must exist"));
181        }
182        let mut ifd_num_ck = Some(0);
183        let mut next_ifd_offset_offset = 4;
184        for ifd in &self.ifd_list {
185            // Each IFD must have at least one entry [TIFF6, Section 2,
186            // Image File Directory].
187            if ifd.is_empty() {
188                return Err(Error::InvalidFormat("IFD must not be empty"));
189            }
190            let ifd_num =
191                ifd_num_ck.ok_or(Error::InvalidFormat("Too many IFDs"))?;
192            if ifd_num > 0 {
193                let next_ifd_offset = pad_and_get_offset(w)?;
194                let origpos = w.seek(SeekFrom::Current(0))?;
195                w.seek(SeekFrom::Start(next_ifd_offset_offset as u64))?;
196                match little_endian {
197                    false => BigEndian::writeu32(w, next_ifd_offset)?,
198                    true => LittleEndian::writeu32(w, next_ifd_offset)?,
199                }
200                w.seek(SeekFrom::Start(origpos))?;
201            }
202            next_ifd_offset_offset =
203                synthesize_fields(w, ifd, In(ifd_num), little_endian)?;
204            ifd_num_ck = ifd_num.checked_add(1);
205        }
206        w.flush()?;
207        Ok(())
208    }
209
210    fn pick_ifd(&mut self, ifd_num: In) -> &mut Ifd<'a> {
211        let ifd_num = ifd_num.index() as usize;
212        if self.ifd_list.len() <= ifd_num {
213            self.ifd_list.resize_with(ifd_num + 1, Default::default);
214        }
215        &mut self.ifd_list[ifd_num]
216    }
217}
218
219// Synthesizes special fields, writes an image, and returns the offset
220// of the next IFD offset.
221fn synthesize_fields<W>(w: &mut W, ifd: &Ifd, ifd_num: In,
222                        little_endian: bool)
223                        -> Result<u32, Error> where W: Write + Seek {
224    let exif_in_tiff;
225    let gps_in_tiff;
226    let interop_in_exif;
227    let strip_offsets;
228    let strip_byte_counts;
229    let tile_offsets;
230    let tile_byte_counts;
231    let jpeg_offset;
232    let jpeg_length;
233    let mut ws = WriterState {
234        tiff_fields: ifd.tiff_fields.clone(),
235        exif_fields: ifd.exif_fields.clone(),
236        gps_fields: ifd.gps_fields.clone(),
237        interop_fields: ifd.interop_fields.clone(),
238        tiff_ifd_offset: 0,
239        exif_ifd_offset: 0,
240        gps_ifd_offset: 0,
241        interop_ifd_offset: 0,
242    };
243
244    if let Some(strips) = ifd.strips {
245        strip_offsets = Field {
246            tag: Tag::StripOffsets,
247            ifd_num: ifd_num,
248            value: Value::Long(vec![0; strips.len()]),
249        };
250        ws.tiff_fields.push(&strip_offsets);
251        strip_byte_counts = Field {
252            tag: Tag::StripByteCounts,
253            ifd_num: ifd_num,
254            value: Value::Long(
255                strips.iter().map(|s| s.len() as u32).collect()),
256        };
257        ws.tiff_fields.push(&strip_byte_counts);
258    }
259    if let Some(tiles) = ifd.tiles {
260        tile_offsets = Field {
261            tag: Tag::TileOffsets,
262            ifd_num: ifd_num,
263            value: Value::Long(vec![0; tiles.len()]),
264        };
265        ws.tiff_fields.push(&tile_offsets);
266        tile_byte_counts = Field {
267            tag: Tag::TileByteCounts,
268            ifd_num: ifd_num,
269            value: Value::Long(
270                tiles.iter().map(|s| s.len() as u32).collect()),
271        };
272        ws.tiff_fields.push(&tile_byte_counts);
273    }
274    if let Some(jpeg) = ifd.jpeg {
275        jpeg_offset = Field {
276            tag: Tag::JPEGInterchangeFormat,
277            ifd_num: ifd_num,
278            value: Value::Long(vec![0]),
279        };
280        ws.tiff_fields.push(&jpeg_offset);
281        jpeg_length = Field {
282            tag: Tag::JPEGInterchangeFormatLength,
283            ifd_num: ifd_num,
284            value: Value::Long(vec![jpeg.len() as u32]),
285        };
286        ws.tiff_fields.push(&jpeg_length);
287    }
288
289    let interop_fields_len = ws.interop_fields.len();
290    let gps_fields_len = ws.gps_fields.len();
291    let exif_fields_len = ws.exif_fields.len() +
292        match interop_fields_len { 0 => 0, _ => 1 };
293    let tiff_fields_len = ws.tiff_fields.len() +
294        match gps_fields_len { 0 => 0, _ => 1 } +
295        match exif_fields_len { 0 => 0, _ => 1 };
296    assert_ne!(tiff_fields_len, 0);
297
298    ws.tiff_ifd_offset = reserve_ifd(w, tiff_fields_len)?;
299    if exif_fields_len > 0 {
300        ws.exif_ifd_offset = reserve_ifd(w, exif_fields_len)?;
301        exif_in_tiff = Field {
302            tag: Tag::ExifIFDPointer,
303            ifd_num: ifd_num,
304            value: Value::Long(vec![ws.exif_ifd_offset]),
305        };
306        ws.tiff_fields.push(&exif_in_tiff);
307    }
308    if gps_fields_len > 0 {
309        ws.gps_ifd_offset = reserve_ifd(w, gps_fields_len)?;
310        gps_in_tiff = Field {
311            tag: Tag::GPSInfoIFDPointer,
312            ifd_num: ifd_num,
313            value: Value::Long(vec![ws.gps_ifd_offset]),
314        };
315        ws.tiff_fields.push(&gps_in_tiff);
316    }
317    if interop_fields_len > 0 {
318        ws.interop_ifd_offset = reserve_ifd(w, interop_fields_len)?;
319        interop_in_exif = Field {
320            tag: Tag::InteropIFDPointer,
321            ifd_num: ifd_num,
322            value: Value::Long(vec![ws.interop_ifd_offset]),
323        };
324        ws.exif_fields.push(&interop_in_exif);
325    }
326
327    ws.tiff_fields.sort_by_key(|f| f.tag.number());
328    ws.exif_fields.sort_by_key(|f| f.tag.number());
329    ws.gps_fields.sort_by_key(|f| f.tag.number());
330    ws.interop_fields.sort_by_key(|f| f.tag.number());
331
332    match little_endian {
333        false => write_image::<_, BigEndian>(w, &ws, ifd),
334        true => write_image::<_, LittleEndian>(w, &ws, ifd),
335    }
336}
337
338// Writes an image and returns the offset of the next IFD offset.
339fn write_image<W, E>(w: &mut W, ws: &WriterState, ifd: &Ifd)
340                     -> Result<u32, Error> where W: Write + Seek, E: Endian {
341    let (next_ifd_offset_offset,
342         strip_offsets_offset, tile_offsets_offset, jpeg_offset) =
343        write_ifd_and_fields::<_, E>(
344            w, &ws.tiff_fields, ws.tiff_ifd_offset)?;
345    if ws.exif_fields.len() > 0 {
346        write_ifd_and_fields::<_, E>(
347            w, &ws.exif_fields, ws.exif_ifd_offset)?;
348    }
349    if ws.gps_fields.len() > 0 {
350        write_ifd_and_fields::<_, E>(
351            w, &ws.gps_fields, ws.gps_ifd_offset)?;
352    }
353    if ws.interop_fields.len() > 0 {
354        write_ifd_and_fields::<_, E>(
355            w, &ws.interop_fields, ws.interop_ifd_offset)?;
356    }
357
358    if let Some(strips) = ifd.strips {
359        let mut strip_offsets = Vec::new();
360        for strip in strips {
361            strip_offsets.push(get_offset(w)?);
362            w.write_all(strip)?;
363        }
364        let origpos = w.seek(SeekFrom::Current(0))?;
365        w.seek(SeekFrom::Start(strip_offsets_offset as u64))?;
366        for ofs in strip_offsets {
367            E::writeu32(w, ofs)?;
368        }
369        w.seek(SeekFrom::Start(origpos))?;
370    }
371    if let Some(tiles) = ifd.tiles {
372        let mut tile_offsets = Vec::new();
373        for tile in tiles {
374            tile_offsets.push(get_offset(w)?);
375            w.write_all(tile)?;
376        }
377        let origpos = w.seek(SeekFrom::Current(0))?;
378        w.seek(SeekFrom::Start(tile_offsets_offset as u64))?;
379        for ofs in tile_offsets {
380            E::writeu32(w, ofs)?;
381        }
382        w.seek(SeekFrom::Start(origpos))?;
383    }
384    if let Some(jpeg) = ifd.jpeg {
385        let offset = get_offset(w)?;
386        w.write_all(jpeg)?;
387        let origpos = w.seek(SeekFrom::Current(0))?;
388        w.seek(SeekFrom::Start(jpeg_offset as u64))?;
389        E::writeu32(w, offset)?;
390        w.seek(SeekFrom::Start(origpos))?;
391    }
392
393    Ok(next_ifd_offset_offset)
394}
395
396// Advances the write position to make a space for a new IFD and
397// returns the offset of the IFD.
398fn reserve_ifd<W>(w: &mut W, count: usize)
399                  -> Result<u32, Error> where W: Write + Seek {
400    let ifdpos = get_offset(w)?;
401    assert!(ifdpos % 2 == 0);
402    // The number of entries (2) + array of entries (12 * n) +
403    // the next IFD pointer (4).
404    w.seek(SeekFrom::Current(2 + count as i64 * 12 + 4))?;
405    Ok(ifdpos)
406}
407
408// Writes an IFD and its fields, and
409// returns the offsets of the next IFD offset, StripOffsets value,
410// TileOffsets value, and JPEGInterchangeFormat value.
411fn write_ifd_and_fields<W, E>(
412    w: &mut W, fields: &Vec<&Field>, ifd_offset: u32)
413    -> Result<(u32, u32, u32, u32), Error> where W: Write + Seek, E: Endian
414{
415    let mut strip_offsets_offset = 0;
416    let mut tile_offsets_offset = 0;
417    let mut jpeg_offset = 0;
418    let mut ifd = Vec::new();
419
420    // Write the number of entries.
421    E::writeu16(&mut ifd, fields.len() as u16)?;
422    // Write the fields.
423    for f in fields {
424        let (typ, cnt, mut valbuf) = compose_value::<E>(&f.value)?;
425        if cnt as u32 as usize != cnt {
426            return Err(Error::TooBig("Too long array"));
427        }
428        E::writeu16(&mut ifd, f.tag.number())?;
429        E::writeu16(&mut ifd, typ)?;
430        E::writeu32(&mut ifd, cnt as u32)?;
431        // Embed the value itself into the offset, or
432        // encode as an offset and the value.
433        if valbuf.len() <= 4 {
434            valbuf.resize(4, 0);
435            ifd.write_all(&valbuf)?;
436        } else {
437            // The value must begin on a word boundary. [TIFF6, Section 2:
438            // TIFF Structure, Image File Directory, IFD Entry, p. 15]
439            let valofs = pad_and_get_offset(w)?;
440            E::writeu32(&mut ifd, valofs)?;
441            w.write_all(&valbuf)?;
442        }
443        if f.tag == Tag::StripOffsets {
444            strip_offsets_offset = match valbuf.len() {
445                0..=4 => ifd_offset + ifd.len() as u32 - 4,
446                _ => get_offset(w)? - valbuf.len() as u32,
447            };
448        }
449        if f.tag == Tag::TileOffsets {
450            tile_offsets_offset = match valbuf.len() {
451                0..=4 => ifd_offset + ifd.len() as u32 - 4,
452                _ => get_offset(w)? - valbuf.len() as u32,
453            };
454        }
455        if f.tag == Tag::JPEGInterchangeFormat {
456            jpeg_offset = ifd_offset + ifd.len() as u32 - 4;
457        }
458    }
459    // Write the next IFD pointer.
460    let next_ifd_offset_offset = ifd_offset + ifd.len() as u32;
461    E::writeu32(&mut ifd, 0)?;
462
463    // Write the IFD.
464    write_at(w, &ifd, ifd_offset)?;
465
466    Ok((next_ifd_offset_offset,
467        strip_offsets_offset, tile_offsets_offset, jpeg_offset))
468}
469
470// Returns the type, count, and encoded value.
471fn compose_value<E>(value: &Value)
472                    -> Result<(u16, usize, Vec<u8>), Error> where E: Endian {
473    match *value {
474        Value::Byte(ref vec) =>
475            Ok((1, vec.len(), vec.clone())),
476        Value::Ascii(ref vec) => {
477            let mut buf = Vec::new();
478            for x in vec {
479                buf.extend_from_slice(x);
480                buf.push(0);
481            }
482            Ok((2, buf.len(), buf))
483        },
484        Value::Short(ref vec) => {
485            let mut buf = Vec::new();
486            for &v in vec {
487                E::writeu16(&mut buf, v)?;
488            }
489            Ok((3, vec.len(), buf))
490        },
491        Value::Long(ref vec) => {
492            let mut buf = Vec::new();
493            for &v in vec {
494                E::writeu32(&mut buf, v)?;
495            }
496            Ok((4, vec.len(), buf))
497        },
498        Value::Rational(ref vec) => {
499            let mut buf = Vec::new();
500            for v in vec {
501                E::writeu32(&mut buf, v.num)?;
502                E::writeu32(&mut buf, v.denom)?;
503            }
504            Ok((5, vec.len(), buf))
505        },
506        Value::SByte(ref vec) => {
507            let bytes = vec.iter().map(|x| *x as u8).collect();
508            Ok((6, vec.len(), bytes))
509        },
510        Value::Undefined(ref s, _) =>
511            Ok((7, s.len(), s.to_vec())),
512        Value::SShort(ref vec) => {
513            let mut buf = Vec::new();
514            for &v in vec {
515                E::writeu16(&mut buf, v as u16)?;
516            }
517            Ok((8, vec.len(), buf))
518        },
519        Value::SLong(ref vec) => {
520            let mut buf = Vec::new();
521            for &v in vec {
522                E::writeu32(&mut buf, v as u32)?;
523            }
524            Ok((9, vec.len(), buf))
525        },
526        Value::SRational(ref vec) => {
527            let mut buf = Vec::new();
528            for v in vec {
529                E::writeu32(&mut buf, v.num as u32)?;
530                E::writeu32(&mut buf, v.denom as u32)?;
531            }
532            Ok((10, vec.len(), buf))
533        },
534        Value::Float(ref vec) => {
535            let mut buf = Vec::new();
536            for &v in vec {
537                E::writeu32(&mut buf, v.to_bits())?;
538            }
539            Ok((11, vec.len(), buf))
540        },
541        Value::Double(ref vec) => {
542            let mut buf = Vec::new();
543            for &v in vec {
544                E::writeu64(&mut buf, v.to_bits())?;
545            }
546            Ok((12, vec.len(), buf))
547        },
548        Value::Unknown(_, _, _) =>
549            Err(Error::NotSupported("Cannot write unknown field types")),
550    }
551}
552
553fn write_at<W>(w: &mut W, buf: &[u8], offset: u32)
554               -> io::Result<()> where W: Write + Seek {
555    let orig = w.seek(SeekFrom::Current(0))?;
556    w.seek(SeekFrom::Start(offset as u64))?;
557    w.write_all(buf)?;
558    w.seek(SeekFrom::Start(orig))?;
559    Ok(())
560}
561
562// Aligns `w` to the two-byte (word) boundary and returns the new offset.
563fn pad_and_get_offset<W>(w: &mut W)
564                         -> Result<u32, Error> where W: Write + Seek {
565    let mut pos = w.seek(SeekFrom::Current(0))?;
566    if pos >= (1 << 32) - 1 {
567        return Err(Error::TooBig("Offset too large"));
568    }
569    if pos % 2 != 0 {
570        w.write_all(&[0])?;
571        pos += 1;
572    }
573    Ok(pos as u32)
574}
575
576fn get_offset<W>(w: &mut W)
577                 -> Result<u32, Error> where W: Write + Seek {
578    let pos = w.seek(SeekFrom::Current(0))?;
579    if pos as u32 as u64 != pos {
580        return Err(Error::TooBig("Offset too large"));
581    }
582    Ok(pos as u32)
583}
584
585#[cfg(test)]
586mod tests {
587    use std::io::Cursor;
588    use super::*;
589
590    #[test]
591    fn primary() {
592        let image_desc = Field {
593            tag: Tag::ImageDescription,
594            ifd_num: In::PRIMARY,
595            value: Value::Ascii(vec![b"Sample".to_vec()]),
596        };
597        let mut writer = Writer::new();
598        let mut buf = Cursor::new(Vec::new());
599        writer.push_field(&image_desc);
600        writer.write(&mut buf, false).unwrap();
601        let expected: &[u8] =
602            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
603              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x07\x00\x00\x00\x1a\
604              \x00\x00\x00\x00\
605              Sample\0";
606        assert_eq!(buf.into_inner(), expected);
607    }
608
609    #[test]
610    fn primary_exif_only() {
611        let exif_ver = Field {
612            tag: Tag::ExifVersion,
613            ifd_num: In::PRIMARY,
614            value: Value::Undefined(b"0231".to_vec(), 0),
615        };
616        let mut writer = Writer::new();
617        let mut buf = Cursor::new(Vec::new());
618        writer.push_field(&exif_ver);
619        writer.write(&mut buf, false).unwrap();
620        let expected: &[u8] =
621            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
622              \x00\x01\x87\x69\x00\x04\x00\x00\x00\x01\x00\x00\x00\x1a\
623              \x00\x00\x00\x00\
624              \x00\x01\x90\x00\x00\x07\x00\x00\x00\x040231\
625              \x00\x00\x00\x00";
626        assert_eq!(buf.into_inner(), expected);
627    }
628
629    #[test]
630    fn primary_tiff_tiled() {
631        // This is not a valid TIFF tile (only for testing).
632        let tiles: &[&[u8]] = &[b"TILE"];
633        let mut writer = Writer::new();
634        let mut buf = Cursor::new(Vec::new());
635        writer.set_tiles(tiles, In::PRIMARY);
636        writer.write(&mut buf, false).unwrap();
637        let expected: &[u8] =
638            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
639              \x00\x02\x01\x44\x00\x04\x00\x00\x00\x01\x00\x00\x00\x26\
640                      \x01\x45\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
641              \x00\x00\x00\x00\
642              TILE";
643        assert_eq!(buf.into_inner(), expected);
644    }
645
646    #[test]
647    fn thumbnail_jpeg() {
648        // This is not a valid JPEG data (only for testing).
649        let jpeg = b"JPEG";
650        let desc = Field {
651            tag: Tag::ImageDescription,
652            ifd_num: In::PRIMARY,
653            value: Value::Ascii(vec![b"jpg".to_vec()]),
654        };
655        let mut writer = Writer::new();
656        let mut buf = Cursor::new(Vec::new());
657        writer.push_field(&desc);
658        writer.set_jpeg(jpeg, In::THUMBNAIL);
659        writer.write(&mut buf, false).unwrap();
660        let expected: &[u8] =
661            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
662              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x04jpg\x00\
663              \x00\x00\x00\x1a\
664              \x00\x02\x02\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00\x38\
665                      \x02\x02\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
666              \x00\x00\x00\x00\
667              JPEG";
668        assert_eq!(buf.into_inner(), expected);
669    }
670
671    #[test]
672    fn thumbnail_tiff() {
673        // This is not a valid TIFF strip (only for testing).
674        let desc = Field {
675            tag: Tag::ImageDescription,
676            ifd_num: In::PRIMARY,
677            value: Value::Ascii(vec![b"tif".to_vec()]),
678        };
679        let strips: &[&[u8]] = &[b"STRIP"];
680        let mut writer = Writer::new();
681        let mut buf = Cursor::new(Vec::new());
682        writer.push_field(&desc);
683        writer.set_strips(strips, In::THUMBNAIL);
684        writer.write(&mut buf, false).unwrap();
685        let expected: &[u8] =
686            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
687              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x04tif\x00\
688              \x00\x00\x00\x1a\
689              \x00\x02\x01\x11\x00\x04\x00\x00\x00\x01\x00\x00\x00\x38\
690                      \x01\x17\x00\x04\x00\x00\x00\x01\x00\x00\x00\x05\
691              \x00\x00\x00\x00\
692              STRIP";
693        assert_eq!(buf.into_inner(), expected);
694    }
695
696    #[test]
697    fn primary_and_thumbnail() {
698        let image_desc = Field {
699            tag: Tag::ImageDescription,
700            ifd_num: In::PRIMARY,
701            value: Value::Ascii(vec![b"Sample".to_vec()]),
702        };
703        let exif_ver = Field {
704            tag: Tag::ExifVersion,
705            ifd_num: In::PRIMARY,
706            value: Value::Undefined(b"0231".to_vec(), 0),
707        };
708        let gps_ver = Field {
709            tag: Tag::GPSVersionID,
710            ifd_num: In::PRIMARY,
711            value: Value::Byte(vec![2, 3, 0, 0]),
712        };
713        let interop_index = Field {
714            tag: Tag::InteroperabilityIndex,
715            ifd_num: In::PRIMARY,
716            value: Value::Ascii(vec![b"ABC".to_vec()]),
717        };
718        let jpeg = b"JPEG";
719        let mut writer = Writer::new();
720        let mut buf = Cursor::new(Vec::new());
721        writer.push_field(&image_desc);
722        writer.push_field(&exif_ver);
723        writer.push_field(&gps_ver);
724        writer.push_field(&interop_index);
725        writer.set_jpeg(jpeg, In::THUMBNAIL);
726        writer.write(&mut buf, false).unwrap();
727        let expected: &[u8] =
728            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
729              \x00\x03\x01\x0e\x00\x02\x00\x00\x00\x07\x00\x00\x00\x74\
730                      \x87\x69\x00\x04\x00\x00\x00\x01\x00\x00\x00\x32\
731                      \x88\x25\x00\x04\x00\x00\x00\x01\x00\x00\x00\x50\
732              \x00\x00\x00\x7c\
733              \x00\x02\x90\x00\x00\x07\x00\x00\x00\x040231\
734                      \xa0\x05\x00\x04\x00\x00\x00\x01\x00\x00\x00\x62\
735              \x00\x00\x00\x00\
736              \x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x02\x03\x00\x00\
737              \x00\x00\x00\x00\
738              \x00\x01\x00\x01\x00\x02\x00\x00\x00\x04ABC\0\
739              \x00\x00\x00\x00\
740              Sample\0\0\
741              \x00\x02\x02\x01\x00\x04\x00\x00\x00\x01\x00\x00\x00\x9a\
742                      \x02\x02\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\
743              \x00\x00\x00\x00\
744              JPEG";
745        assert_eq!(buf.into_inner(), expected);
746    }
747
748    #[test]
749    fn primary_thumbnail_and_2nd() {
750        let desc0 = Field {
751            tag: Tag::ImageDescription,
752            ifd_num: In::PRIMARY,
753            value: Value::Ascii(vec![b"p".to_vec()]),
754        };
755        let desc1 = Field {
756            tag: Tag::ImageDescription,
757            ifd_num: In::THUMBNAIL,
758            value: Value::Ascii(vec![b"t".to_vec()]),
759        };
760        let desc2 = Field {
761            tag: Tag::ImageDescription,
762            ifd_num: In(2),
763            value: Value::Ascii(vec![b"2".to_vec()]),
764        };
765        let mut writer = Writer::new();
766        let mut buf = Cursor::new(Vec::new());
767        writer.push_field(&desc0);
768        writer.push_field(&desc1);
769        writer.push_field(&desc2);
770        writer.write(&mut buf, false).unwrap();
771        let expected: &[u8] =
772            b"\x4d\x4d\x00\x2a\x00\x00\x00\x08\
773              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x02p\x00\x00\x00\
774              \x00\x00\x00\x1a\
775              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x02t\x00\x00\x00\
776              \x00\x00\x00\x2c\
777              \x00\x01\x01\x0e\x00\x02\x00\x00\x00\x022\x00\x00\x00\
778              \x00\x00\x00\x00";
779        assert_eq!(buf.into_inner(), expected);
780    }
781
782    #[test]
783    fn empty_file() {
784        let mut writer = Writer::new();
785        let mut buf = Cursor::new(Vec::new());
786        assert_pat!(writer.write(&mut buf, false),
787                    Err(Error::InvalidFormat("At least one IFD must exist")));
788    }
789
790    #[test]
791    fn missing_primary() {
792        let jpeg = b"JPEG";
793        let mut writer = Writer::new();
794        let mut buf = Cursor::new(Vec::new());
795        writer.set_jpeg(jpeg, In::THUMBNAIL);
796        assert_pat!(writer.write(&mut buf, false),
797                    Err(Error::InvalidFormat("IFD must not be empty")));
798    }
799
800    #[test]
801    fn write_twice() {
802        let image_desc = Field {
803            tag: Tag::ImageDescription,
804            ifd_num: In::PRIMARY,
805            value: Value::Ascii(vec![b"Sample".to_vec()]),
806        };
807        let mut writer = Writer::new();
808        writer.push_field(&image_desc);
809        let mut buf1 = Cursor::new(Vec::new());
810        writer.write(&mut buf1, false).unwrap();
811        let mut buf2 = Cursor::new(Vec::new());
812        writer.write(&mut buf2, false).unwrap();
813        assert_eq!(buf1.into_inner(), buf2.into_inner());
814    }
815
816    #[test]
817    fn compose_field_value() {
818        let patterns = vec![
819            (Value::Byte(vec![1, 2]),
820             (1, 2, vec![1, 2]),
821             (1, 2, vec![1, 2])),
822            (Value::Ascii(vec![b"a".to_vec(), b"b".to_vec()]),
823             (2, 4, b"a\0b\0".to_vec()),
824             (2, 4, b"a\0b\0".to_vec())),
825            (Value::Short(vec![0x0102, 0x0304]),
826             (3, 2, b"\x01\x02\x03\x04".to_vec()),
827             (3, 2, b"\x02\x01\x04\x03".to_vec())),
828            (Value::Long(vec![0x01020304, 0x05060708]),
829             (4, 2, b"\x01\x02\x03\x04\x05\x06\x07\x08".to_vec()),
830             (4, 2, b"\x04\x03\x02\x01\x08\x07\x06\x05".to_vec())),
831            (Value::Rational(vec![(1, 2).into(), (3, 4).into()]),
832             (5, 2, b"\0\0\0\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04".to_vec()),
833             (5, 2, b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0".to_vec())),
834            (Value::SByte(vec![-2, -128]),
835             (6, 2, b"\xfe\x80".to_vec()),
836             (6, 2, b"\xfe\x80".to_vec())),
837            (Value::Undefined(b"abc".to_vec(), 0),
838             (7, 3, b"abc".to_vec()),
839             (7, 3, b"abc".to_vec())),
840            (Value::SShort(vec![-2, -0x8000]),
841             (8, 2, b"\xff\xfe\x80\x00".to_vec()),
842             (8, 2, b"\xfe\xff\x00\x80".to_vec())),
843            (Value::SLong(vec![-2, -0x80000000]),
844             (9, 2, b"\xff\xff\xff\xfe\x80\x00\x00\x00".to_vec()),
845             (9, 2, b"\xfe\xff\xff\xff\x00\x00\x00\x80".to_vec())),
846            (Value::SRational(vec![(-1, -2).into(), (-3, -4).into()]),
847             (10, 2, b"\xff\xff\xff\xff\xff\xff\xff\xfe\
848                       \xff\xff\xff\xfd\xff\xff\xff\xfc".to_vec()),
849             (10, 2, b"\xff\xff\xff\xff\xfe\xff\xff\xff\
850                       \xfd\xff\xff\xff\xfc\xff\xff\xff".to_vec())),
851            (Value::Float(vec![2.5, -0.5]),
852             (11, 2, b"\x40\x20\x00\x00\xbf\x00\x00\x00".to_vec()),
853             (11, 2, b"\x00\x00\x20\x40\x00\x00\x00\xbf".to_vec())),
854            (Value::Double(vec![2.5, -0.5]),
855             (12, 2, b"\x40\x04\x00\x00\x00\x00\x00\x00\
856                       \xbf\xe0\x00\x00\x00\x00\x00\x00".to_vec()),
857             (12, 2, b"\x00\x00\x00\x00\x00\x00\x04\x40\
858                       \x00\x00\x00\x00\x00\x00\xe0\xbf".to_vec())),
859        ];
860        for (val, be, le) in patterns {
861            assert_eq!(compose_value::<BigEndian>(&val).unwrap(), be);
862            assert_eq!(compose_value::<LittleEndian>(&val).unwrap(), le);
863        }
864    }
865}