Graphics-MNG

 view release on metacpan or  search on metacpan

MNG.xs  view on Meta::CPAN

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 )