#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use std::cmp;
use std::mem;
use std::ptr;
use std::boxed;
use std::fs::File;
use std::ffi::CStr;
use std::str;
use std::slice;
use libc::{free, c_int, c_uint, c_char, c_uchar, c_void};
use reader::{Decoder, Reader, Decoded};
use c_api_utils::{CInterface, CFile, FnInputFile};
use util;
#[repr(u8)]
enum_from_primitive!{
pub enum _Bool { False = 0, True = 1 }
}
pub type c_bool = _Bool;
pub type GifPixelType = c_uchar;
pub type GifRowType = *mut c_uchar;
pub type GifByteType = c_uchar;
pub type GifPrefixType = c_uint;
pub type GifWord = c_int;
#[repr(C)]
pub struct GifColorType {
pub Red: GifByteType,
pub Green: GifByteType,
pub Blue: GifByteType
}
#[repr(C)]
pub struct ColorMapObject {
pub ColorCount: c_int,
pub BitsPerPixel: c_int,
pub SortFlag: c_bool,
pub Colors: *mut GifColorType }
#[repr(C)]
pub struct ExtensionBlock {
pub ByteCount: c_int,
pub Bytes: *mut GifByteType, pub Function: c_int
}
#[repr(C)]
pub struct SavedImage {
pub ImageDesc: GifImageDesc,
pub RasterBits: *mut GifByteType,
pub ExtensionBlockCount: c_int,
pub ExtensionBlocks: *mut ExtensionBlock
}
#[repr(C)]
pub struct GifImageDesc {
pub Left: GifWord,
pub Top: GifWord,
pub Width: GifWord,
pub Height: GifWord,
pub Interlace: c_bool,
pub ColorMap: *mut ColorMapObject
}
#[repr(C)]
pub struct GifFileType {
pub SWidth: GifWord,
pub SHeight: GifWord,
pub SColorResolution: GifWord,
pub SBackGroundColor: GifWord,
pub AspectByte: GifByteType,
pub SColorMap: *mut ColorMapObject,
pub ImageCount: c_int,
pub Image: GifImageDesc,
pub SavedImages: *mut SavedImage,
pub ExtensionBlockCount: c_int,
pub ExtensionBlocks: *mut ExtensionBlock,
pub Error: c_int,
pub UserData: *mut c_void,
pub Private: *mut c_void,
}
#[repr(C)]
pub enum GifRecordType {
UNDEFINED_RECORD_TYPE,
SCREEN_DESC_RECORD_TYPE,
IMAGE_DESC_RECORD_TYPE,
EXTENSION_RECORD_TYPE,
TERMINATE_RECORD_TYPE
}
pub type InputFunc = extern "C" fn(*mut GifFileType, *mut GifByteType, c_int) -> c_int;
const D_GIF_SUCCEEDED : c_int = 0;
const D_GIF_ERR_OPEN_FAILED : c_int = 101;
const D_GIF_ERR_READ_FAILED : c_int = 102;
const D_GIF_ERR_NOT_GIF_FILE : c_int = 103;
const D_GIF_ERR_NO_SCRN_DSCR : c_int = 104;
const D_GIF_ERR_NO_IMAG_DSCR : c_int = 105;
const D_GIF_ERR_NO_COLOR_MAP : c_int = 106;
const D_GIF_ERR_WRONG_RECORD : c_int = 107;
const D_GIF_ERR_DATA_TOO_BIG : c_int = 108;
const D_GIF_ERR_NOT_ENOUGH_MEM: c_int = 109;
const D_GIF_ERR_CLOSE_FAILED : c_int = 110;
const D_GIF_ERR_NOT_READABLE : c_int = 111;
const D_GIF_ERR_IMAGE_DEFECT : c_int = 112;
const D_GIF_ERR_EOF_TOO_SOON : c_int = 113;
const GIF_ERROR: c_int = 0;
const GIF_OK : c_int = 1;
macro_rules! try_capi {
($val:expr, $err:expr, $code:expr, $retval:expr) => (
match $val {
Ok(val) => val,
Err(_) => {
if $err != ptr::null_mut() {
*$err = $code
}
return $retval
}
}
);
($val:expr) => (
match $val {
Ok(val) => val,
Err(_) => return GIF_ERROR
}
);
}
macro_rules! try_get_decoder {
($this:expr) => (
if $this != ptr::null_mut() {
let decoder: &mut &mut CInterface = mem::transmute((*$this).Private);
decoder
} else {
return GIF_ERROR
}
);
}
#[no_mangle] pub unsafe extern "C"
fn DGifOpenFileName(gif_file_name: *const c_char, err: *mut c_int) -> *mut GifFileType {
let file = try_capi!(
File::open(try_capi!(
str::from_utf8(CStr::from_ptr(gif_file_name).to_bytes()),
err, D_GIF_ERR_OPEN_FAILED, ptr::null_mut()
)),
err, D_GIF_ERR_OPEN_FAILED, ptr::null_mut()
);
let mut decoder = try_capi!(
Decoder::new(file).read_info(),
err, D_GIF_ERR_READ_FAILED, ptr::null_mut()
).into_c_interface();
let this: *mut GifFileType = boxed::into_raw(Box::new(mem::zeroed()));
decoder.read_screen_desc(&mut *this);
let decoder = boxed::into_raw(Box::new(boxed::into_raw(decoder)));
(*this).Private = mem::transmute(decoder);
this
}
#[no_mangle] pub unsafe extern "C"
fn DGifOpenFileHandle(fp: c_int, err: *mut c_int) -> *mut GifFileType {
let mut decoder = try_capi!(
Decoder::new(CFile::new(fp)).read_info(),
err, D_GIF_ERR_READ_FAILED, ptr::null_mut()
).into_c_interface();
let this: *mut GifFileType = boxed::into_raw(Box::new(mem::zeroed()));
decoder.read_screen_desc(&mut *this);
let decoder = boxed::into_raw(Box::new(boxed::into_raw(decoder)));
(*this).Private = mem::transmute(decoder);
this
}
#[no_mangle] pub unsafe extern "C"
fn DGifOpen(user_data: *mut c_void, read_fn: InputFunc, err: *mut c_int) -> *mut GifFileType {
let this: *mut GifFileType = boxed::into_raw(Box::new(mem::zeroed()));
(*this).UserData = user_data;
let decoder = try_capi!(
Decoder::new(FnInputFile::new(read_fn, this)).read_info(),
err, D_GIF_ERR_READ_FAILED, {
let _: Box<GifFileType> = Box::from_raw(this);
ptr::null_mut()
}
).into_c_interface();
let decoder = boxed::into_raw(Box::new(boxed::into_raw(decoder)));
(*this).Private = mem::transmute(decoder);
this
}
#[no_mangle] pub unsafe extern "C"
fn DGifCloseFile(this: *mut GifFileType, _: *mut c_int)
-> c_int {
if this != ptr::null_mut() {
let this: Box<GifFileType> = Box::from_raw(this);
let _: Box<Box<CInterface>> = mem::transmute(this.Private);
for image in slice::from_raw_parts_mut(this.SavedImages, this.ImageCount as usize) {
free(mem::transmute(image.RasterBits));
if image.ImageDesc.ColorMap != ptr::null_mut() {
free(mem::transmute((*image.ImageDesc.ColorMap).Colors))
}
free(mem::transmute(image.ImageDesc.ColorMap));
if image.ExtensionBlockCount != 0 {
GifFreeExtensions(&mut image.ExtensionBlockCount, &mut image.ExtensionBlocks)
}
}
free(mem::transmute(this.SavedImages));
}
GIF_OK
}
#[no_mangle] pub unsafe extern "C"
fn DGifGetScreenDesc(_: *mut GifFileType) -> c_int {
GIF_OK
}
#[no_mangle] pub unsafe extern "C"
fn DGifGetImageDesc(this: *mut GifFileType) -> c_int {
match try_get_decoder!(this).current_image_buffer() {
Ok(_) => GIF_OK,
Err(_) => GIF_ERROR
}
}
#[no_mangle] pub unsafe extern "C"
fn DGifGetLine(this: *mut GifFileType, line: *mut GifPixelType, len: c_int) -> c_int {
let (buffer, offset) = try_capi!(try_get_decoder!(this).current_image_buffer());
let buffer = &buffer[*offset..];
let len = cmp::min(buffer.len(), len as usize);
*offset = *offset + len;
let line = slice::from_raw_parts_mut(line, len);
util::copy_memory(buffer, line);
GIF_OK
}
#[no_mangle] pub unsafe extern "C"
fn DGifGetExtension(this: *mut GifFileType, ext_type: *mut c_int, ext_block: *mut *const GifByteType) -> c_int {
use common::Block::*;
let decoder = try_get_decoder!(this);
match try_capi!(decoder.next_record_type()) {
Image | Trailer => {
if ext_block != ptr::null_mut() {
*ext_block = ptr::null_mut();
}
if ext_type != ptr::null_mut() {
*ext_type = 0;
}
}
Extension => {
match try_capi!(decoder.decode_next()) {
Some(Decoded::SubBlockFinished(type_, data))
| Some(Decoded::BlockFinished(type_, data)) => {
if ext_block != ptr::null_mut() {
*ext_block = data.as_ptr();
}
if ext_type != ptr::null_mut() {
*ext_type = type_ as c_int;
}
}
_ => return GIF_ERROR
}
}
}
GIF_OK
}
#[no_mangle] pub unsafe extern "C"
fn DGifGetExtensionNext(this: *mut GifFileType, ext_block: *mut *const GifByteType) -> c_int {
let mut decoder = try_get_decoder!(this);
if decoder.last_ext().2 {
if ext_block != ptr::null_mut() {
*ext_block = ptr::null_mut();
}
GIF_OK
} else {
match try_capi!(decoder.decode_next()) {
Some(Decoded::SubBlockFinished(_, data))
| Some(Decoded::BlockFinished(_, data)) => {
if ext_block != ptr::null_mut() {
*ext_block = data.as_ptr();
}
GIF_OK
}
_ => GIF_ERROR
}
}
}
#[no_mangle] pub unsafe extern "C"
fn GifFreeExtensions(block_count: *mut c_int, ext_blocks: *mut *mut ExtensionBlock) {
if ext_blocks == ptr::null_mut() || block_count == ptr::null_mut() {
return
}
for i in 0..(*block_count) as isize {
let block = (*ext_blocks).offset(i);
free(mem::transmute((*block).Bytes));
}
free(mem::transmute(ext_blocks));
*ext_blocks = ptr::null_mut();
*block_count = 0;
}