1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Variable length records, both extended and regular.

use std::io::{Read, Write};
use Result;

/// A raw variable length record.
#[derive(Debug, Default, PartialEq)]
pub struct Vlr {
    /// This value must be set to zero
    pub reserved: u16,

    /// The User ID field is ASCII character data that identifies the user which created the
    /// variable length record.
    ///
    /// It is possible to have many Variable Length Records from different sources with different
    /// User IDs. If the character data is less than 16 characters, the remaining data must be
    /// null. The User ID must be registered with the LAS specification managing body. The
    /// management of these User IDs ensures that no two individuals accidentally use the same User
    /// ID.
    pub user_id: [u8; 16],

    /// The Record ID is dependent upon the User ID.
    ///
    /// There can be 0 to 65,535 Record IDs for every User ID. The LAS specification manages its
    /// own Record IDs (User IDs owned by the specification), otherwise Record IDs will be managed
    /// by the owner of the given User ID. Thus each User ID is allowed to assign 0 to 65,535
    /// Record IDs in any manner they desire. Publicizing the meaning of a given Record ID is left
    /// to the owner of the given User ID. Unknown User ID/Record ID combinations should be
    /// ignored.
    pub record_id: u16,

    /// The record length is the number of bytes for the record after the end of the standard part
    /// of the header.
    ///
    /// Thus the entire record length is 54 bytes (the header size of the VLR) plus the number of
    /// bytes in the variable length portion of the record.
    pub record_length_after_header: RecordLength,

    /// Optional, null terminated text description of the data.
    ///
    /// Any remaining characters not used must be null.
    pub description: [u8; 32],

    #[allow(missing_docs)]
    pub data: Vec<u8>,
}

/// The length of the data in the vlr.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RecordLength {
    /// Vlrs use u16.
    Vlr(u16),
    /// Evlrs use u64.
    Evlr(u64),
}

impl Vlr {
    /// Reads a raw VLR or EVLR.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Seek, SeekFrom};
    /// use std::fs::File;
    /// use las::raw::Vlr;
    /// let mut file = File::open("tests/data/autzen.las").unwrap();
    /// file.seek(SeekFrom::Start(227));
    /// // If the second parameter were true, it would be read as an extended vlr.
    /// let vlr = Vlr::read_from(file, false).unwrap();
    /// ```
    pub fn read_from<R: Read>(mut read: R, extended: bool) -> Result<Vlr> {
        use byteorder::{LittleEndian, ReadBytesExt};

        let mut vlr = Vlr::default();
        vlr.reserved = read.read_u16::<LittleEndian>()?;
        read.read_exact(&mut vlr.user_id)?;
        vlr.record_id = read.read_u16::<LittleEndian>()?;
        vlr.record_length_after_header = if extended {
            RecordLength::Evlr(read.read_u64::<LittleEndian>()?)
        } else {
            RecordLength::Vlr(read.read_u16::<LittleEndian>()?)
        };
        read.read_exact(&mut vlr.description)?;
        vlr.data
            .resize(usize::from(vlr.record_length_after_header), 0);
        read.read_exact(&mut vlr.data)?;
        Ok(vlr)
    }

    /// Writes a raw VLR.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::Cursor;
    /// use las::raw::Vlr;
    /// let mut cursor = Cursor::new(Vec::new());
    /// let vlr = Vlr::default();
    /// vlr.write_to(cursor).unwrap();
    /// ```
    pub fn write_to<W: Write>(&self, mut write: W) -> Result<()> {
        use byteorder::{LittleEndian, WriteBytesExt};
        write.write_u16::<LittleEndian>(self.reserved)?;
        write.write_all(&self.user_id)?;
        write.write_u16::<LittleEndian>(self.record_id)?;
        match self.record_length_after_header {
            RecordLength::Vlr(n) => write.write_u16::<LittleEndian>(n)?,
            RecordLength::Evlr(n) => write.write_u64::<LittleEndian>(n)?,
        }
        write.write_all(&self.description)?;
        write.write_all(&self.data)?;
        Ok(())
    }
}

impl From<RecordLength> for u64 {
    fn from(record_length: RecordLength) -> u64 {
        match record_length {
            RecordLength::Vlr(n) => u64::from(n),
            RecordLength::Evlr(n) => n,
        }
    }
}

impl From<RecordLength> for usize {
    fn from(record_length: RecordLength) -> usize {
        u64::from(record_length) as usize
    }
}

impl Default for RecordLength {
    fn default() -> RecordLength {
        RecordLength::Vlr(0)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn roundtrip() {
        let vlr = Vlr::default();
        let mut cursor = Cursor::new(Vec::new());
        vlr.write_to(&mut cursor).unwrap();
        cursor.set_position(0);
        assert_eq!(vlr, Vlr::read_from(cursor, false).unwrap());
    }

    #[test]
    fn roundtrip_evlr() {
        let evlr = Vlr {
            record_length_after_header: RecordLength::Evlr(0),
            ..Default::default()
        };
        let mut cursor = Cursor::new(Vec::new());
        evlr.write_to(&mut cursor).unwrap();
        cursor.set_position(0);
        assert_eq!(evlr, Vlr::read_from(cursor, true).unwrap());
    }
}