1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use std::cmp;
3use std::io::{self, Error, ErrorKind, Read, Write};
4
5use super::icontype::{Encoding, IconType, OSType};
6use super::image::{Image, PixelFormat};
7
8const ICON_ELEMENT_HEADER_LENGTH: u32 = 8;
10
11#[cfg(feature = "pngio")]
13const JPEG_2000_FILE_MAGIC_NUMBER: [u8; 12] = [
14 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
15];
16
17pub struct IconElement {
21 pub ostype: OSType,
23 pub data: Vec<u8>,
25}
26
27impl IconElement {
28 pub fn new(ostype: OSType, data: Vec<u8>) -> IconElement {
30 IconElement { ostype, data }
31 }
32
33 pub fn encode_image_with_type(image: &Image, icon_type: IconType) -> io::Result<IconElement> {
46 let width = icon_type.pixel_width();
47 let height = icon_type.pixel_height();
48 if image.width() != width || image.height() != height {
49 let msg = format!(
50 "image has wrong dimensions for {:?} ({}x{} \
51 instead of {}x{}))",
52 icon_type,
53 image.width(),
54 image.height(),
55 width,
56 height
57 );
58 return Err(Error::new(ErrorKind::InvalidInput, msg));
59 }
60 let mut data: Vec<u8>;
61 match icon_type.encoding() {
62 #[cfg(feature = "pngio")]
63 Encoding::JP2PNG => {
64 data = Vec::new();
65 image.write_png(&mut data)?;
66 }
67 #[cfg(not(feature = "pngio"))]
68 Encoding::JP2PNG => unimplemented!(),
69 Encoding::RLE24 => {
70 let num_pixels = (width * height) as usize;
71 match image.pixel_format() {
72 PixelFormat::RGBA => {
73 data = encode_rle(image.data(), 4, num_pixels);
74 }
75 PixelFormat::RGB => {
76 data = encode_rle(image.data(), 3, num_pixels);
77 }
78 _ => {
80 let image = image.convert_to(PixelFormat::RGB);
81 data = encode_rle(image.data(), 3, num_pixels);
82 }
83 }
84 }
85 Encoding::Mask8 => {
86 let image = image.convert_to(PixelFormat::Alpha);
90 data = image.into_data().into_vec();
91 }
92 }
93 Ok(IconElement::new(icon_type.ostype(), data))
94 }
95
96 pub fn decode_image(&self) -> io::Result<Image> {
108 let icon_type = self.icon_type().ok_or_else(|| {
109 Error::new(
110 ErrorKind::InvalidInput,
111 format!("unsupported OSType: {}", self.ostype),
112 )
113 })?;
114 let width = icon_type.pixel_width();
115 let height = icon_type.pixel_width();
116 match icon_type.encoding() {
117 #[cfg(feature = "pngio")]
118 Encoding::JP2PNG => {
119 if self.data.starts_with(&JPEG_2000_FILE_MAGIC_NUMBER) {
120 let msg = "element to be decoded contains JPEG 2000 \
121 data, which is not yet supported";
122 return Err(Error::new(ErrorKind::InvalidInput, msg));
123 }
124 let image = Image::read_png(io::Cursor::new(&self.data))?;
125 if image.width() != width || image.height() != height {
126 let msg = format!(
127 "decoded PNG has wrong dimensions \
128 ({}x{} instead of {}x{})",
129 image.width(),
130 image.height(),
131 width,
132 height
133 );
134 return Err(Error::new(ErrorKind::InvalidData, msg));
135 }
136 Ok(image)
137 }
138 #[cfg(not(feature = "pngio"))]
139 Encoding::JP2PNG => unimplemented!(),
140 Encoding::RLE24 => {
141 let mut image = Image::new(PixelFormat::RGB, width, height);
142 decode_rle(&self.data, 3, image.data_mut())?;
143 Ok(image)
144 }
145 Encoding::Mask8 => {
146 let num_pixels = width * height;
147 if self.data.len() as u32 != num_pixels {
148 let msg = format!(
149 "wrong data payload length ({} \
150 instead of {})",
151 self.data.len(),
152 num_pixels
153 );
154 return Err(Error::new(ErrorKind::InvalidData, msg));
155 }
156 let mut image = Image::new(PixelFormat::Alpha, width, height);
157 image.data_mut().clone_from_slice(&self.data);
158 Ok(image)
159 }
160 }
161 }
162
163 pub fn decode_image_with_mask(&self, mask: &IconElement) -> io::Result<Image> {
173 let icon_type = self.icon_type().ok_or_else(|| {
174 Error::new(
175 ErrorKind::InvalidInput,
176 format!("unsupported OSType: {}", self.ostype),
177 )
178 })?;
179 let mask_type = icon_type.mask_type().ok_or_else(|| {
180 let msg = format!("icon type {:?} does not use a mask", icon_type);
181 Error::new(ErrorKind::InvalidInput, msg)
182 })?;
183 assert_eq!(icon_type.encoding(), Encoding::RLE24);
184 if mask.ostype != mask_type.ostype() {
185 let msg = format!(
186 "wrong OSType for mask ('{}' instead of '{}')",
187 mask.ostype,
188 mask_type.ostype()
189 );
190 return Err(Error::new(ErrorKind::InvalidInput, msg));
191 }
192 let width = icon_type.pixel_width();
193 let height = icon_type.pixel_height();
194 let num_pixels = (width * height) as usize;
195 if mask.data.len() != num_pixels {
196 let msg = format!(
197 "wrong mask data payload length ({} instead \
198 of {})",
199 mask.data.len(),
200 num_pixels
201 );
202 return Err(Error::new(ErrorKind::InvalidInput, msg));
203 }
204 let mut image = Image::new(PixelFormat::RGBA, width, height);
205 decode_rle(&self.data, 4, image.data_mut())?;
206 for (i, &alpha) in mask.data.iter().enumerate() {
207 image.data_mut()[4 * i + 3] = alpha;
208 }
209 Ok(image)
210 }
211
212 pub fn icon_type(&self) -> Option<IconType> {
215 IconType::from_ostype(self.ostype)
216 }
217
218 pub fn read<R: Read>(mut reader: R) -> io::Result<IconElement> {
220 let mut raw_ostype = [0u8; 4];
221 reader.read_exact(&mut raw_ostype)?;
222 let element_length = reader.read_u32::<BigEndian>()?;
223 if element_length < ICON_ELEMENT_HEADER_LENGTH {
224 return Err(Error::new(ErrorKind::InvalidData, "invalid element length"));
225 }
226 let data_length = element_length - ICON_ELEMENT_HEADER_LENGTH;
227 let mut data = vec![0u8; data_length as usize];
228 reader.read_exact(&mut data)?;
229 Ok(IconElement::new(OSType(raw_ostype), data))
230 }
231
232 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
234 let OSType(ref raw_ostype) = self.ostype;
235 writer.write_all(raw_ostype)?;
236 writer.write_u32::<BigEndian>(self.total_length())?;
237 writer.write_all(&self.data)?;
238 Ok(())
239 }
240
241 pub fn total_length(&self) -> u32 {
244 ICON_ELEMENT_HEADER_LENGTH + (self.data.len() as u32)
245 }
246}
247
248fn encode_rle(input: &[u8], num_input_channels: usize, num_pixels: usize) -> Vec<u8> {
249 assert!(num_input_channels == 3 || num_input_channels == 4);
250 let mut output = Vec::new();
251 if num_pixels == 128 * 128 {
252 output.extend_from_slice(&[0, 0, 0, 0]);
254 }
255 for channel in 0..3 {
256 let mut pixel: usize = 0;
257 let mut literal_start: usize = 0;
258 while pixel < num_pixels {
259 let value = input[num_input_channels * pixel + channel];
260 let mut run_length = 1;
261 while pixel + run_length < num_pixels
262 && input[num_input_channels * (pixel + run_length) + channel] == value
263 && run_length < 130
264 {
265 run_length += 1;
266 }
267 if run_length >= 3 {
268 while literal_start < pixel {
269 let literal_length = cmp::min(128, pixel - literal_start);
270 output.push((literal_length - 1) as u8);
271 for i in 0..literal_length {
272 output.push(input[num_input_channels * (literal_start + i) + channel]);
273 }
274 literal_start += literal_length;
275 }
276 output.push((run_length + 125) as u8);
277 output.push(value);
278 pixel += run_length;
279 literal_start = pixel;
280 } else {
281 pixel += run_length;
282 }
283 }
284 while literal_start < pixel {
285 let literal_length = cmp::min(128, pixel - literal_start);
286 output.push((literal_length - 1) as u8);
287 for i in 0..literal_length {
288 output.push(input[num_input_channels * (literal_start + i) + channel]);
289 }
290 literal_start += literal_length;
291 }
292 }
293 output
294}
295
296fn decode_rle(input: &[u8], num_output_channels: usize, output: &mut [u8]) -> io::Result<()> {
297 assert!(num_output_channels == 3 || num_output_channels == 4);
298 assert_eq!(output.len() % num_output_channels, 0);
299 let num_pixels = output.len() / num_output_channels;
300 let skip: usize = if input.starts_with(&[0, 0, 0, 0]) {
303 4
304 } else {
305 0
306 };
307 let input = &input[skip..input.len()];
308 let mut iter = input.iter();
309 let mut remaining: usize = 0;
310 let mut within_run = false;
311 let mut run_value: u8 = 0;
312 for channel in 0..3 {
313 for pixel in 0..num_pixels {
314 if remaining == 0 {
315 let next: u8 = *iter.next().ok_or_else(rle_error)?;
316 if next < 128 {
317 remaining = (next as usize) + 1;
318 within_run = false;
319 } else {
320 remaining = (next as usize) - 125;
321 within_run = true;
322 run_value = *iter.next().ok_or_else(rle_error)?;
323 }
324 }
325 output[num_output_channels * pixel + channel] = if within_run {
326 run_value
327 } else {
328 *iter.next().ok_or_else(rle_error)?
329 };
330 remaining -= 1;
331 }
332 if remaining != 0 {
333 return Err(rle_error());
334 }
335 }
336 if iter.next().is_some() {
337 Err(rle_error())
338 } else {
339 Ok(())
340 }
341}
342
343fn rle_error() -> Error {
344 Error::new(ErrorKind::InvalidData, "invalid RLE-compressed data")
345}
346
347#[cfg(test)]
348mod tests {
349 use super::super::icontype::{IconType, OSType};
350 use super::super::image::{Image, PixelFormat};
351 use super::*;
352
353 #[test]
354 fn encode_rle() {
355 let mut image = Image::new(PixelFormat::Gray, 16, 16);
356 image.data_mut()[0] = 44;
357 image.data_mut()[1] = 55;
358 image.data_mut()[2] = 66;
359 image.data_mut()[3] = 66;
360 image.data_mut()[4] = 66;
361 let element = IconElement::encode_image_with_type(&image, IconType::RGB24_16x16)
362 .expect("failed to encode image");
363 assert_eq!(element.ostype, OSType(*b"is32"));
364 assert_eq!(element.data[0..5], [1, 44, 55, 128, 66]);
365 }
366
367 #[test]
368 fn decode_rle() {
369 let data: Vec<u8> = vec![
370 0, 12, 255, 0, 250, 0, 128, 34, 255, 0, 248, 0, 1, 56, 99, 255, 0, 249, 0,
371 ];
372 let element = IconElement::new(OSType(*b"is32"), data);
373 let image = element.decode_image().expect("failed to decode image");
374 assert_eq!(image.pixel_format(), PixelFormat::RGB);
375 assert_eq!(image.width(), 16);
376 assert_eq!(image.height(), 16);
377 assert_eq!(image.data()[0], 12);
378 assert_eq!(image.data()[1], 34);
379 assert_eq!(image.data()[2], 56);
380 }
381
382 #[test]
383 fn decode_rle_skip_extra_zeros() {
384 let data: Vec<u8> = vec![
385 0, 0, 0, 0, 0, 12, 255, 0, 250, 0, 128, 34, 255, 0, 248, 0, 1, 56, 99, 255, 0, 249, 0,
386 ];
387 let element = IconElement::new(OSType(*b"is32"), data);
388 let image = element.decode_image().expect("failed to decode image");
389 assert_eq!(image.data()[0], 12);
390 assert_eq!(image.data()[1], 34);
391 assert_eq!(image.data()[2], 56);
392 }
393
394 #[test]
395 fn encode_mask() {
396 let mut image = Image::new(PixelFormat::Alpha, 16, 16);
397 image.data_mut()[2] = 127;
398 let element = IconElement::encode_image_with_type(&image, IconType::Mask8_16x16)
399 .expect("failed to encode image");
400 assert_eq!(element.ostype, OSType(*b"s8mk"));
401 assert_eq!(element.data[2], 127);
402 }
403
404 #[test]
405 fn decode_mask() {
406 let mut data = vec![0u8; 256];
407 data[2] = 127;
408 let element = IconElement::new(OSType(*b"s8mk"), data);
409 let image = element.decode_image().expect("failed to decode image");
410 assert_eq!(image.pixel_format(), PixelFormat::Alpha);
411 assert_eq!(image.width(), 16);
412 assert_eq!(image.height(), 16);
413 assert_eq!(image.data()[2], 127);
414 }
415
416 #[test]
417 fn decode_rle_with_mask() {
418 let color_data: Vec<u8> = vec![
419 0, 12, 255, 0, 250, 0, 128, 34, 255, 0, 248, 0, 1, 56, 99, 255, 0, 249, 0,
420 ];
421 let color_element = IconElement::new(OSType(*b"is32"), color_data);
422 let mask_data = vec![78u8; 256];
423 let mask_element = IconElement::new(OSType(*b"s8mk"), mask_data);
424 let image = color_element
425 .decode_image_with_mask(&mask_element)
426 .expect("failed to decode image");
427 assert_eq!(image.pixel_format(), PixelFormat::RGBA);
428 assert_eq!(image.width(), 16);
429 assert_eq!(image.height(), 16);
430 assert_eq!(image.data()[0], 12);
431 assert_eq!(image.data()[1], 34);
432 assert_eq!(image.data()[2], 56);
433 assert_eq!(image.data()[3], 78);
434 }
435}