1 //! C API, drop-in replacement for libgif
2 
3 #![allow(non_snake_case)]
4 #![allow(non_camel_case_types)]
5 #![allow(dead_code)]
6 #![allow(missing_docs)] //FIXME
7 
8 use std::cmp;
9 use std::mem;
10 use std::ptr;
11 use std::boxed;
12 use std::fs::File;
13 use std::ffi::CStr;
14 use std::str;
15 use std::slice;
16 
17 use libc::{free, c_int, c_uint, c_char, c_uchar, c_void};
18 
19 use reader::{Decoder, Reader, Decoded};
20 use c_api_utils::{CInterface, CFile, FnInputFile};
21 
22 /// NOTE As of rust issue #954 `bool` is compatible with c_bool.
23 pub type c_bool = bool;
24 
25 pub type GifPixelType = c_uchar;
26 pub type GifRowType = *mut c_uchar;
27 pub type GifByteType = c_uchar;
28 pub type GifPrefixType = c_uint;
29 pub type GifWord = c_int;
30 
31 #[repr(C)]
32 pub struct GifColorType {
33     pub Red: GifByteType,
34     pub Green: GifByteType,
35     pub Blue: GifByteType
36 }
37 
38 #[repr(C)]
39 pub struct ColorMapObject {
40     pub ColorCount: c_int,
41     pub BitsPerPixel: c_int,
42     pub SortFlag: c_bool,
43     /// on malloc(3) heap
44     pub Colors: *mut GifColorType // TODO USE MALLOC for this
45 }
46 
47 #[repr(C)]
48 pub struct ExtensionBlock {
49     pub ByteCount: c_int,
50     /// on malloc(3) heap
51     pub Bytes: *mut GifByteType, // TODO USE MALLOC for this
52     /// The block function code
53     pub Function: c_int
54 //#define CONTINUE_EXT_FUNC_CODE    0x00    /* continuation subblock */
55 //#define COMMENT_EXT_FUNC_CODE     0xfe    /* comment */
56 //#define GRAPHICS_EXT_FUNC_CODE    0xf9    /* graphics control (GIF89) */
57 //#define PLAINTEXT_EXT_FUNC_CODE   0x01    /* plaintext */
58 //#define APPLICATION_EXT_FUNC_CODE 0xff    /* application block */
59 }
60 
61 #[repr(C)]
62 pub struct SavedImage {
63     pub ImageDesc: GifImageDesc,
64     /// on malloc(3) heap
65     pub RasterBits: *mut GifByteType,
66     /// Count of extensions before image
67     pub ExtensionBlockCount: c_int,
68     /// Extensions before image
69     pub ExtensionBlocks: *mut ExtensionBlock
70 }
71 
72 #[repr(C)]
73 pub struct GifImageDesc {
74     /// Current image dimensions. (left)
75     pub Left: GifWord,
76     /// Current image dimensions. (top)
77     pub Top: GifWord,
78     /// Current image dimensions. (width)
79     pub Width: GifWord,
80     /// Current image dimensions. (height)
81     pub Height: GifWord,
82     /// Sequential/Interlaced lines.
83     pub Interlace: c_bool,
84     /// The local color map
85     pub ColorMap: *mut ColorMapObject
86 }
87 
88 #[repr(C)]
89 pub struct GifFileType {
90     /// Size of virtual canvas (width)
91     pub SWidth: GifWord,
92     /// Size of virtual canvas (height)
93     pub SHeight: GifWord,
94     /// How many colors can we generate?
95     pub SColorResolution: GifWord,
96     /// Background color for virtual canvas
97     pub SBackGroundColor: GifWord,
98     /// Used to compute pixel aspect ratio
99     pub AspectByte: GifByteType,
100     /// Global colormap, NULL if nonexistent.
101     pub SColorMap: *mut ColorMapObject,
102     /// Number of current image (both APIs)
103     pub ImageCount: c_int,
104     /// Current image (low-level API)
105     pub Image: GifImageDesc,
106     /// Image sequence (high-level API)
107     pub SavedImages: *mut SavedImage,
108     /// Count extensions past last image
109     pub ExtensionBlockCount: c_int,
110     /// Extensions past last image
111     pub ExtensionBlocks: *mut ExtensionBlock,
112     /// Last error condition reported
113     pub Error: c_int,
114     /// hook to attach user data (TVT)
115     pub UserData: *mut c_void,
116     /// Don't mess with this!
117     pub Private: *mut c_void,
118 }
119 
120 #[repr(C)]
121 pub enum GifRecordType {
122     UNDEFINED_RECORD_TYPE,
123     SCREEN_DESC_RECORD_TYPE,
124     IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
125     EXTENSION_RECORD_TYPE,  /* Begin with '!' */
126     TERMINATE_RECORD_TYPE   /* Begin with ';' */
127 }
128 
129 /// Input callback for DGifOpen. Returns `c_int` bytes input the buffer
130 /// and returns the number of bytes read.
131 pub type InputFunc = extern "C" fn(*mut GifFileType, *mut GifByteType, c_int) -> c_int;
132 
133 const D_GIF_SUCCEEDED         : c_int = 0;
134 const D_GIF_ERR_OPEN_FAILED   : c_int = 101;    /* And DGif possible errors. */
135 const D_GIF_ERR_READ_FAILED   : c_int = 102;
136 const D_GIF_ERR_NOT_GIF_FILE  : c_int = 103;
137 const D_GIF_ERR_NO_SCRN_DSCR  : c_int = 104;
138 const D_GIF_ERR_NO_IMAG_DSCR  : c_int = 105;
139 const D_GIF_ERR_NO_COLOR_MAP  : c_int = 106;
140 const D_GIF_ERR_WRONG_RECORD  : c_int = 107;
141 const D_GIF_ERR_DATA_TOO_BIG  : c_int = 108;
142 const D_GIF_ERR_NOT_ENOUGH_MEM: c_int = 109;
143 const D_GIF_ERR_CLOSE_FAILED  : c_int = 110;
144 const D_GIF_ERR_NOT_READABLE  : c_int = 111;
145 const D_GIF_ERR_IMAGE_DEFECT  : c_int = 112;
146 const D_GIF_ERR_EOF_TOO_SOON  : c_int = 113;
147 
148 const GIF_ERROR: c_int = 0;
149 const GIF_OK   : c_int = 1;
150 
151 macro_rules! try_capi {
152     ($val:expr, $err:expr, $code:expr, $retval:expr) => (
153         match $val {
154             Ok(val) => val,
155             Err(_) => {
156                 if $err != ptr::null_mut() {
157                     *$err = $code
158                 }
159                 return $retval
160             }
161         }
162     );
163     ($val:expr) => (
164         match $val {
165             Ok(val) => val,
166             Err(_) => return GIF_ERROR
167         }
168     );
169 }
170 
171 macro_rules! try_get_decoder {
172     ($this:expr) => (
173         if $this != ptr::null_mut() {
174             let decoder: &mut &mut CInterface = mem::transmute((*$this).Private);
175             decoder
176         } else {
177             return GIF_ERROR
178         }
179     );
180 }
181 
182 #[no_mangle] pub unsafe extern "C"
DGifOpenFileName(gif_file_name: *const c_char, err: *mut c_int) -> *mut GifFileType183 fn DGifOpenFileName(gif_file_name: *const c_char, err: *mut c_int) -> *mut GifFileType {
184     let file = try_capi!(
185         File::open(try_capi!(
186             str::from_utf8(CStr::from_ptr(gif_file_name).to_bytes()),
187             err, D_GIF_ERR_OPEN_FAILED, ptr::null_mut()
188         )),
189         err, D_GIF_ERR_OPEN_FAILED, ptr::null_mut()
190     );
191     let mut decoder = try_capi!(
192         Decoder::new(file).read_info(),
193         err, D_GIF_ERR_READ_FAILED, ptr::null_mut()
194     ).into_c_interface();
195     let this: *mut GifFileType = Box::into_raw(Box::new(mem::zeroed()));
196     decoder.read_screen_desc(&mut *this);
197     let decoder = Box::into_raw(Box::new(Box::into_raw(decoder)));
198     (*this).Private = mem::transmute(decoder);
199     this
200 }
201 
202 #[no_mangle] pub unsafe extern "C"
DGifOpenFileHandle(fp: c_int, err: *mut c_int) -> *mut GifFileType203 fn DGifOpenFileHandle(fp: c_int, err: *mut c_int) -> *mut GifFileType {
204     let mut decoder = try_capi!(
205         Decoder::new(CFile::new(fp)).read_info(),
206         err, D_GIF_ERR_READ_FAILED, ptr::null_mut()
207     ).into_c_interface();
208     let this: *mut GifFileType = Box::into_raw(Box::new(mem::zeroed()));
209     decoder.read_screen_desc(&mut *this);
210     let decoder = Box::into_raw(Box::new(Box::into_raw(decoder)));
211     (*this).Private = mem::transmute(decoder);
212     this
213 }
214 
215 /*
216 #[no_mangle] pub unsafe extern "C"
217 fn DGifSlurp(this: *mut GifFileType) -> c_int {
218     match try_get_decoder!(this).read_to_end(mem::transmute(this)) {
219         Ok(()) => GIF_OK,
220         Err(_) => GIF_ERROR
221     }
222 }
223 */
224 #[no_mangle] pub unsafe extern "C"
DGifOpen(user_data: *mut c_void, read_fn: InputFunc, err: *mut c_int) -> *mut GifFileType225 fn DGifOpen(user_data: *mut c_void, read_fn: InputFunc, err: *mut c_int) -> *mut GifFileType {
226     let this: *mut GifFileType = Box::into_raw(Box::new(mem::zeroed()));
227     (*this).UserData = user_data;
228     let decoder = try_capi!(
229         Decoder::new(FnInputFile::new(read_fn, this)).read_info(),
230         err, D_GIF_ERR_READ_FAILED, {
231             // TODO: check if it is ok and expected to free GifFileType
232             // This is unclear since the API exposes the whole struct to the read
233             // function and not only the user data
234             let _: Box<GifFileType> = Box::from_raw(this);
235             ptr::null_mut()
236         }
237     ).into_c_interface();
238     let decoder = Box::into_raw(Box::new(Box::into_raw(decoder)));
239     (*this).Private = mem::transmute(decoder);
240     this
241 }
242 
243 /// Closes the file and also frees all data structures.
244 #[no_mangle] pub unsafe extern "C"
DGifCloseFile(this: *mut GifFileType, _: *mut c_int) -> c_int245 fn DGifCloseFile(this: *mut GifFileType, _: *mut c_int)
246 -> c_int {
247     if this != ptr::null_mut() {
248         let this: Box<GifFileType> = Box::from_raw(this);
249         let _: Box<Box<CInterface>> = mem::transmute(this.Private);
250         for image in slice::from_raw_parts_mut(this.SavedImages, this.ImageCount as usize) {
251             free(mem::transmute(image.RasterBits));
252             if image.ImageDesc.ColorMap != ptr::null_mut() {
253                 free(mem::transmute((*image.ImageDesc.ColorMap).Colors))
254             }
255             free(mem::transmute(image.ImageDesc.ColorMap));
256             if image.ExtensionBlockCount != 0 {
257                 GifFreeExtensions(&mut image.ExtensionBlockCount, &mut image.ExtensionBlocks)
258             }
259         }
260         free(mem::transmute(this.SavedImages));
261     }
262     GIF_OK
263 }
264 
265 // legacy but needed API
266 #[no_mangle] pub unsafe extern "C"
DGifGetScreenDesc(_: *mut GifFileType) -> c_int267 fn DGifGetScreenDesc(_: *mut GifFileType) -> c_int {
268     GIF_OK
269 }
270 /*
271 #[no_mangle] pub unsafe extern "C"
272 fn DGifGetRecordType(this: *mut GifFileType, record_type: *mut GifRecordType) -> c_int {
273     use common::Block::*;
274     use self::GifRecordType::*;
275     *record_type = match try_capi!(try_get_decoder!(this).next_record_type()) {
276         Image => IMAGE_DESC_RECORD_TYPE,
277         Extension => EXTENSION_RECORD_TYPE,
278         Trailer => TERMINATE_RECORD_TYPE
279     };
280     GIF_OK
281 }
282 */
283 #[no_mangle] pub unsafe extern "C"
DGifGetImageDesc(this: *mut GifFileType) -> c_int284 fn DGifGetImageDesc(this: *mut GifFileType) -> c_int {
285     match try_get_decoder!(this).current_image_buffer() {
286         Ok(_) => GIF_OK,
287         Err(_) => GIF_ERROR
288     }
289 }
290 
291 #[no_mangle] pub unsafe extern "C"
DGifGetLine(this: *mut GifFileType, line: *mut GifPixelType, len: c_int) -> c_int292 fn DGifGetLine(this: *mut GifFileType, line: *mut GifPixelType, len: c_int) -> c_int {
293     let (buffer, offset) = try_capi!(try_get_decoder!(this).current_image_buffer());
294     let buffer = &buffer[*offset..];
295     let len = cmp::min(buffer.len(), len as usize);
296     *offset = *offset + len;
297     let line = slice::from_raw_parts_mut(line, len);
298     line.copy_from_slice(&buffer[..len]);
299     GIF_OK
300 }
301 //int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
302 //int DGifGetComment(GifFi leType *GifFile, char *GifComment);
303 
304 /// Returns the type of the extension and the first extension sub-block `(size, data...)`
305 #[no_mangle] pub unsafe extern "C"
DGifGetExtension(this: *mut GifFileType, ext_type: *mut c_int, ext_block: *mut *const GifByteType) -> c_int306 fn DGifGetExtension(this: *mut GifFileType, ext_type: *mut c_int, ext_block: *mut *const GifByteType) -> c_int {
307     use common::Block::*;
308     let decoder = try_get_decoder!(this);
309     match try_capi!(decoder.next_record_type()) {
310         Image | Trailer => {
311             if ext_block != ptr::null_mut() {
312                 *ext_block = ptr::null_mut();
313             }
314             if ext_type != ptr::null_mut() {
315                 *ext_type = 0;
316             }
317         }
318         Extension => {
319             match try_capi!(decoder.decode_next()) {
320                 Some(Decoded::SubBlockFinished(type_, data))
321                 | Some(Decoded::BlockFinished(type_, data)) => {
322                     if ext_block != ptr::null_mut() {
323                         *ext_block = data.as_ptr();
324                     }
325                     if ext_type != ptr::null_mut() {
326                         *ext_type = type_ as c_int;
327                     }
328                 }
329                 _ => return GIF_ERROR
330             }
331         }
332     }
333     GIF_OK
334 }
335 
336 /// Returns the next extension sub-block `(size, data...)`
337 #[no_mangle] pub unsafe extern "C"
DGifGetExtensionNext(this: *mut GifFileType, ext_block: *mut *const GifByteType) -> c_int338 fn DGifGetExtensionNext(this: *mut GifFileType, ext_block: *mut *const GifByteType) -> c_int {
339     // TODO extract next sub block
340     let mut decoder = try_get_decoder!(this);
341     if decoder.last_ext().2 {
342         if ext_block != ptr::null_mut() {
343             *ext_block = ptr::null_mut();
344         }
345         GIF_OK
346     } else {
347         match try_capi!(decoder.decode_next()) {
348             Some(Decoded::SubBlockFinished(_, data))
349             | Some(Decoded::BlockFinished(_, data)) => {
350                 if ext_block != ptr::null_mut() {
351                     *ext_block = data.as_ptr();
352                 }
353                 GIF_OK
354             }
355             _ => GIF_ERROR
356         }
357     }
358 }
359 /*
360 /// This function reallocs `ext_blocks` and copies `data`
361 #[no_mangle] pub unsafe extern "C"
362 fn GifAddExtensionBlock(block_count: *mut c_int, ext_blocks: *mut *const ExtensionBlock,
363                         ext_type: c_int, len: c_uint, data: *const c_uchar) -> c_int {
364     GIF_OK
365 }
366 */
367 #[no_mangle] pub unsafe extern "C"
GifFreeExtensions(block_count: *mut c_int, ext_blocks: *mut *mut ExtensionBlock)368 fn GifFreeExtensions(block_count: *mut c_int, ext_blocks: *mut *mut ExtensionBlock) {
369     if ext_blocks == ptr::null_mut() || block_count ==  ptr::null_mut() {
370         return
371     }
372     for i in 0..(*block_count) as isize {
373         let block = (*ext_blocks).offset(i);
374         free(mem::transmute((*block).Bytes));
375     }
376     free(mem::transmute(ext_blocks));
377     *ext_blocks = ptr::null_mut();
378     *block_count = 0;
379 }
380