Graphics-MNG
view release on metacpan or search on metacpan
static char * _MNG_TEMP = "_my_scratchpad";
// keys for callback functions (text is also used in warning messages)
static char * _MNG_MEMALLOC = "memalloc";
static char * _MNG_MEMFREE = "memfree";
static char * _MNG_OPENSTREAM = "openstream";
static char * _MNG_CLOSESTREAM = "closestream";
static char * _MNG_READDATA = "readdata";
static char * _MNG_WRITEDATA = "writedata";
static char * _MNG_ERRORPROC = "errorproc";
static char * _MNG_TRACEPROC = "traceproc";
static char * _MNG_PROCESSHEADER = "processheader";
static char * _MNG_PROCESSTEXT = "processtext";
static char * _MNG_PROCESSSAVE = "processsave";
static char * _MNG_PROCESSSEEK = "processseek";
static char * _MNG_PROCESSNEED = "processneed";
static char * _MNG_PROCESSMEND = "processmend";
static char * _MNG_PROCESSUNKNOWN = "processunknown";
static char * _MNG_PROCESSTERM = "processterm";
static char * _MNG_GETCANVASLINE = "getcanvasline";
static char * _MNG_GETBKGDLINE = "getbkgdline";
static char * _MNG_GETALPHALINE = "getalphaline";
static char * _MNG_REFRESH = "refresh";
static char * _MNG_GETTICKCOUNT = "gettickcount";
static char * _MNG_SETTIMER = "settimer";
static char * _MNG_PROCESSGAMMA = "processgamma";
static char * _MNG_PROCESSCHROMA = "processchroma";
static char * _MNG_PROCESSSRGB = "processsrgb";
static char * _MNG_PROCESSICCP = "processiccp";
static char * _MNG_PROCESSAROW = "processarow";
static char * _MNG_ITERATECHUNK = "iteratechunk";
// this one is special because I made it up for those functions
// that take a callback function. I'm calling them one-shot callbacks,
// because we're really not supposed to store them anywhere.
static char * _MNG_GETCANVASLINE_ONESHOT = "getcanvasline_oneshot";
// typedef to replace mng_handle when we don't want to treat it as an object (i.e. hChunks)
typedef void * mng_chunkhandle;
//==============================================================================
// I/F functions that are version dependent
//==============================================================================
// new functions for v1.0.3
#if ( ((MNG_VERSION_MAJOR > 1)) \
|| ((MNG_VERSION_MAJOR == 1) && (MNG_VERSION_MINOR > 0)) \
|| ((MNG_VERSION_MAJOR == 1) && (MNG_VERSION_MINOR == 0) && (MNG_VERSION_RELEASE >= 3)) \
)
#define _MNG_GET_LASTBACKCHUNK(hndl,red,green,blue,mand) (mng_get_lastbackchunk((hndl),(red),(green),(blue),(mand)))
#else
#define _MNG_GET_LASTBACKCHUNK(hndl,red,green,blue,mand) \
(warn("mng_get_lastbackchunk() is not implemented in this version of libmng\n" \
"Please update your version of libmng to at least 1.0.3\n"), \
MNG_FUNCTIONINVALID)
#endif
//==============================================================================
// Min / Max Macros
//==============================================================================
#ifndef min
#define min(x,y) ((x)<(y)?(x):(y))
#endif
#ifndef max
#define max(x,y) ((x)>(y)?(x):(y))
#endif
//==============================================================================
// Convenience Macros
//==============================================================================
// this is used in the typemap file
#define _MNG_GET_HANDLE(arg) (*(hv_fetch((HV*)SvRV((arg)), _MNG_HANDLE, strlen(_MNG_HANDLE), 0)))
// this gives us an element of the hash in the userdata from the MNG handle
// it will create the entry if it doesn't already exist
#define _MNG_GETPRIVATE(hndl,field) (*hv_fetch((HV*)mng_get_userdata(hndl), field, strlen(field), 1))
// this will get us a reference to our object, given the handle
#define _MNG_GETOBJREF(hndl) newRV_inc((SV*)mng_get_userdata(hndl))
// every place that uses this should be changed to construct a PERL array
// in memory and return that array as a reference.
#define CHAR_PTR_CAST(x) ((char*)x)
//==============================================================================
// Macros for writing callback functionality
//==============================================================================
static void my_warn( const char *pat, ... )
{
// do warnings if:
// 1. (PL_dowarn & G_WARN_ALL_OFF) is false and
// 2. (PL_dowarn & G_WARN_ALL_ON) is true or
// 3. ckWARN(warn_category) is true
// bool do_ckWarn_d = ckWARN_d(warn_category);
bool do_ckWarn = ckWARN(warn_category);
bool do_warn = !(PL_dowarn & G_WARN_ALL_OFF) && ( PL_dowarn & G_WARN_ALL_ON || do_ckWarn );
va_list marker;
va_start( marker, pat );
if ( do_warn ) warn(pat, marker);
// warn("Warnings are %s (PL_dowarn=0x%x)(do_ckWarn=%d,do_ckWarn_d=%d)\n", do_warn ? "on":"off", PL_dowarn,do_ckWarn,do_ckWarn_d);
va_end(marker);
}
//==============================================================================
// Macros for writing callback functionality
//==============================================================================
#define VERIFY_CBFN_OR_RETURN( hHandle, error, fnname ) \
SV * cbfn = _MNG_GETPRIVATE(hHandle, fnname); \
\
while ( cbfn != NULL && SvROK(cbfn) ) { cbfn=SvRV(cbfn); } \
\
/* The first case doesn't seem to work. \
The second case is an empirical hack. \
Return if they've assigned 'undef' to the callback function */ \
if ( cbfn == &PL_sv_undef ) return error; \
if ( !SvROK(cbfn) && SvTYPE(cbfn)==SVt_RV ) return error; \
\
if ( cbfn == NULL ) \
{ \
my_warn( "%s: callback function not registered", fnname ); \
return error; \
} \
\
if ( SvTYPE(cbfn) != SVt_PVCV ) \
{ \
int t=SvTYPE(cbfn); \
my_warn( "%s: wrong type registered for callback function", fnname ); \
return error; \
} \
// this space intentionally left blank
#define PREPARE_PERL_STACK() \
/* dSP; */ \
int count; \
ENTER; \
SAVETMPS; \
PUSHMARK(SP); \
// this space intentionally left blank
#define CALL_CBFN_SET_RETVAL(retval,op) \
PUTBACK; \
count = perl_call_sv( cbfn, G_SCALAR ); \
SPAGAIN; \
while (count-- > 0) retval = op; /* eat the return stack */ \
FREETMPS; \
LEAVE; \
// this space intentionally left blank
//==============================================================================
// Function and Macro for writing Perl XS code
//==============================================================================
int check_cbfn( mng_handle hHandle, const char * fnname )
{
VERIFY_CBFN_OR_RETURN( hHandle, 0, fnname );
return 1;
}
int store_cbfn( mng_handle hHandle, const char * fnname, SV *cbfn )
{
// store the callback as it is given to us, but put it in a temporary slot
sv_setsv( _MNG_GETPRIVATE(hHandle, _MNG_TEMP), cbfn );
// now verify that it's OK. This will return 0 if something went wrong
if ( ! check_cbfn( hHandle, _MNG_TEMP ) )
{
return 0;
}
// set the callback function in the correct place now
sv_setsv( _MNG_GETPRIVATE(hHandle, fnname), cbfn );
return 1;
}
// use some preprocessor string concatination to make happy magic
#define IF_STORE_THEN_SET_CBFN( hHandle, key, procname, fProc ) \
if ( store_cbfn( hHandle, key, fProc ) ) \
{ \
RETVAL=mng_setcb_##procname( hHandle, &_mng_##procname ); \
} \
else \
{ \
RETVAL=mng_setcb_##procname( hHandle, NULL ); \
} \
// this space intentionally left blank
//==============================================================================
// Macro to fix NULL return pointers that will be represented as PERL strings
//==============================================================================
// We often make a PERL string by specifying the pointer and length.
// if that length is zero, PERL will go off and call strlen() on the string.
// That's bad. Make sure that PERL gets a NUL terminated empty string in this
// case.
#define FIX_NULL_PTR(ptr,len) \
if ( ptr == NULL || len == 0 ) { \
len = 0; \
((char*)ptr) = "\0\0\0\0"; \
} \
// this space intentionally left blank
// we always pass in a zero length for strings, so PERL can determine their
// length. A NULL pointer is always bad in this case
#define FIX_NULL_STRING(ptr) \
if ( ptr == NULL ) ((char*)ptr) = "\0\0\0\0"; \
// this space intentionally left blank
//==============================================================================
// MNG HIGH-LEVEL CALLBACK FUNCTIONS (C code)
//==============================================================================
/* memory management callbacks */
static mng_ptr MNG_DECL _mng_memalloc (mng_size_t iLen)
{
mng_ptr rv = (mng_ptr) malloc( iLen );
// my_warn("mng_memalloc: called for %d bytes, returning 0x%p\n", iLen, rv);
memset( rv, 0, iLen );
return rv;
}
static void MNG_DECL _mng_memfree (mng_ptr iPtr,
mng_size_t iLen)
{
// my_warn("mng_memfree: releasing %d bytes from 0x%p\n", iLen, iPtr);
free( iPtr );
return;
}
/* I/O management callbacks */
static mng_bool MNG_DECL _mng_openstream (mng_handle hHandle)
{
mng_bool rv = MNG_FALSE;
VERIFY_CBFN_OR_RETURN( hHandle, rv, _MNG_OPENSTREAM )
{
dSP;
PREPARE_PERL_STACK()
XPUSHs( sv_2mortal( _MNG_GETOBJREF(hHandle) ) );
CALL_CBFN_SET_RETVAL(rv,POPi)
}
return rv;
}
static mng_bool MNG_DECL _mng_closestream (mng_handle hHandle)
{
mng_bool rv = MNG_FALSE;
VERIFY_CBFN_OR_RETURN( hHandle, rv, _MNG_CLOSESTREAM )
( run in 0.423 second using v1.01-cache-2.11-cpan-df04353d9ac )