mirror of https://github.com/python/cpython
690 lines
15 KiB
C
690 lines
15 KiB
C
/***********************************************************
|
|
Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
|
|
Netherlands.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the names of Stichting Mathematisch
|
|
Centrum or CWI not be used in advertising or publicity pertaining to
|
|
distribution of the software without specific, written prior permission.
|
|
|
|
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
|
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
******************************************************************/
|
|
|
|
|
|
/* Cl objects */
|
|
|
|
#include <stdarg.h>
|
|
#include <cl.h>
|
|
#include "allobjects.h"
|
|
#include "modsupport.h" /* For getargs() etc. */
|
|
#include "ceval.h" /* For call_object() */
|
|
|
|
typedef struct {
|
|
OB_HEAD
|
|
int ob_isCompressor; /* Compressor or Decompressor */
|
|
CL_Handle ob_compressorHdl;
|
|
} clobject;
|
|
|
|
static object *ClError; /* exception cl.error */
|
|
|
|
static int error_handler_called = 0;
|
|
|
|
/********************************************************************
|
|
Utility routines.
|
|
********************************************************************/
|
|
static void
|
|
cl_ErrorHandler(long errnum, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char errbuf[BUFSIZ]; /* hopefully big enough */
|
|
char *p;
|
|
|
|
if (err_occurred()) /* don't change existing error */
|
|
return;
|
|
error_handler_called = 1;
|
|
va_start(ap, fmt);
|
|
vsprintf(errbuf, fmt, ap);
|
|
va_end(ap);
|
|
p = &errbuf[strlen(errbuf) - 1]; /* swat the line feed */
|
|
if (*p == '\n')
|
|
*p = 0;
|
|
err_setstr(ClError, errbuf);
|
|
}
|
|
|
|
/*
|
|
* This assumes that params are always in the range 0 to some maximum.
|
|
* This is not very efficient.
|
|
*/
|
|
static int
|
|
param_type_is_float(CL_Handle comp, long param)
|
|
{
|
|
long bufferlength;
|
|
long *PVbuffer;
|
|
int ret;
|
|
|
|
error_handler_called = 0;
|
|
bufferlength = clQueryParams(comp, 0, 0);
|
|
if (error_handler_called)
|
|
return -1;
|
|
|
|
if (param < 0 || param >= bufferlength / 2)
|
|
return -1;
|
|
|
|
PVbuffer = NEW(long, bufferlength);
|
|
if (PVbuffer == NULL)
|
|
return -1;
|
|
|
|
bufferlength = clQueryParams(comp, PVbuffer, bufferlength);
|
|
if (error_handler_called) {
|
|
DEL(PVbuffer);
|
|
return -1;
|
|
}
|
|
|
|
if (PVbuffer[param*2 + 1] == CL_FLOATING_ENUM_VALUE ||
|
|
PVbuffer[param*2 + 1] == CL_FLOATING_RANGE_VALUE)
|
|
ret = 1;
|
|
else
|
|
ret = 0;
|
|
|
|
DEL(PVbuffer);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/********************************************************************
|
|
Single image compression/decompression.
|
|
********************************************************************/
|
|
static object *
|
|
cl_CompressImage(self, args)
|
|
object *self, *args;
|
|
{
|
|
long compressionScheme, width, height, originalFormat;
|
|
float compressionRatio;
|
|
long frameBufferSize, compressedBufferSize;
|
|
char *frameBuffer;
|
|
object *compressedBuffer;
|
|
|
|
if (!getargs(args, "(iiiifs#)", &compressionScheme, &width, &height,
|
|
&originalFormat, &compressionRatio, &frameBuffer,
|
|
&frameBufferSize))
|
|
return NULL;
|
|
|
|
retry:
|
|
compressedBuffer = newsizedstringobject(NULL, frameBufferSize);
|
|
if (compressedBuffer == NULL)
|
|
return NULL;
|
|
|
|
compressedBufferSize = frameBufferSize;
|
|
error_handler_called = 0;
|
|
if (clCompressImage(compressionScheme, width, height, originalFormat,
|
|
compressionRatio, (void *) frameBuffer,
|
|
&compressedBufferSize,
|
|
(void *) getstringvalue(compressedBuffer))
|
|
== FAILURE) {
|
|
DECREF(compressedBuffer);
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "clCompressImage failed");
|
|
return NULL;
|
|
}
|
|
|
|
if (compressedBufferSize > frameBufferSize) {
|
|
frameBufferSize = compressedBufferSize;
|
|
DECREF(compressedBuffer);
|
|
goto retry;
|
|
}
|
|
|
|
if (compressedBufferSize < frameBufferSize)
|
|
if (resizestring(&compressedBuffer, compressedBufferSize))
|
|
return NULL;
|
|
|
|
return compressedBuffer;
|
|
}
|
|
|
|
static object *
|
|
cl_DecompressImage(self, args)
|
|
object *self, *args;
|
|
{
|
|
long compressionScheme, width, height, originalFormat;
|
|
char *compressedBuffer;
|
|
long compressedBufferSize, frameBufferSize;
|
|
object *frameBuffer;
|
|
|
|
if (!getargs(args, "(iiiis#i)", &compressionScheme, &width, &height,
|
|
&originalFormat, &compressedBuffer, &compressedBufferSize,
|
|
&frameBufferSize))
|
|
return NULL;
|
|
|
|
frameBuffer = newsizedstringobject(NULL, frameBufferSize);
|
|
if (frameBuffer == NULL)
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
if (clDecompressImage(compressionScheme, width, height, originalFormat,
|
|
compressedBufferSize, compressedBuffer,
|
|
(void *) getstringvalue(frameBuffer)) == FAILURE) {
|
|
DECREF(frameBuffer);
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "clDecompressImage failed");
|
|
return NULL;
|
|
}
|
|
|
|
return frameBuffer;
|
|
}
|
|
|
|
/********************************************************************
|
|
Sequential compression/decompression.
|
|
********************************************************************/
|
|
extern typeobject Cltype; /* Really static, forward */
|
|
|
|
#define CheckCompressor(self) if ((self)->ob_compressorHdl == NULL) { \
|
|
err_setstr(RuntimeError, "(de)compressor not active"); \
|
|
return NULL; \
|
|
}
|
|
|
|
static object *
|
|
doClose(self, args, close_func)
|
|
clobject *self;
|
|
object *args;
|
|
long (*close_func) PROTO((CL_Handle));
|
|
{
|
|
CheckCompressor(self);
|
|
|
|
if (!getnoarg(args))
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
if ((*close_func)(self->ob_compressorHdl) == FAILURE) {
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "close failed");
|
|
return NULL;
|
|
}
|
|
|
|
self->ob_compressorHdl = NULL;
|
|
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
clm_CloseCompressor(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
return doClose(self, args, clCloseCompressor);
|
|
}
|
|
|
|
static object *
|
|
clm_CloseDecompressor(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
return doClose(self, args, clCloseDecompressor);
|
|
}
|
|
|
|
static object *
|
|
clm_Compress(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long numberOfFrames;
|
|
long frameBufferSize, compressedBufferSize;
|
|
char *frameBuffer;
|
|
long PVbuf[2];
|
|
object *data;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "(is#)", &numberOfFrames, &frameBuffer, &frameBufferSize))
|
|
return NULL;
|
|
|
|
PVbuf[0] = CL_COMPRESSED_BUFFER_SIZE;
|
|
PVbuf[1] = 0;
|
|
error_handler_called = 0;
|
|
clGetParams(self->ob_compressorHdl, PVbuf, 2L);
|
|
if (error_handler_called)
|
|
return NULL;
|
|
|
|
data = newsizedstringobject(NULL, PVbuf[1]);
|
|
if (data == NULL)
|
|
return NULL;
|
|
|
|
compressedBufferSize = PVbuf[1];
|
|
|
|
error_handler_called = 0;
|
|
if (clCompress(self->ob_compressorHdl, numberOfFrames,
|
|
(void *) frameBuffer, &compressedBufferSize,
|
|
(void *) getstringvalue(data)) == FAILURE) {
|
|
DECREF(data);
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "compress failed");
|
|
return NULL;
|
|
}
|
|
|
|
if (compressedBufferSize < PVbuf[1])
|
|
if (resizestring(&data, compressedBufferSize))
|
|
return NULL;
|
|
|
|
if (compressedBufferSize > PVbuf[1]) {
|
|
/* we didn't get all "compressed" data */
|
|
DECREF(data);
|
|
err_setstr(ClError, "compressed data is more than fitted");
|
|
return NULL;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static object *
|
|
clm_Decompress(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long PVbuf[2];
|
|
object *data;
|
|
long numberOfFrames;
|
|
char *compressedData;
|
|
long compressedDataSize;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "(is#)", &numberOfFrames, &compressedData,
|
|
&compressedDataSize))
|
|
return NULL;
|
|
|
|
PVbuf[0] = CL_FRAME_BUFFER_SIZE;
|
|
PVbuf[1] = 0;
|
|
error_handler_called = 0;
|
|
clGetParams(self->ob_compressorHdl, PVbuf, 2L);
|
|
if (error_handler_called)
|
|
return NULL;
|
|
|
|
data = newsizedstringobject(NULL, PVbuf[1]);
|
|
if (data == NULL)
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
if (clDecompress(self->ob_compressorHdl, numberOfFrames,
|
|
compressedDataSize, (void *) compressedData,
|
|
(void *) getstringvalue(data)) == FAILURE) {
|
|
DECREF(data);
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "decompress failed");
|
|
return NULL;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static object *
|
|
doParams(self, args, func, modified)
|
|
clobject *self;
|
|
object *args;
|
|
void (*func)(CL_Handle, long *, long);
|
|
int modified;
|
|
{
|
|
object *list, *v;
|
|
long *PVbuffer;
|
|
long length;
|
|
int i;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "O", &list))
|
|
return NULL;
|
|
if (!is_listobject(list)) {
|
|
err_badarg();
|
|
return NULL;
|
|
}
|
|
length = getlistsize(list);
|
|
PVbuffer = NEW(long, length);
|
|
if (PVbuffer == NULL)
|
|
return err_nomem();
|
|
for (i = 0; i < length; i++) {
|
|
v = getlistitem(list, i);
|
|
if (is_floatobject(v))
|
|
PVbuffer[i] = clFloatToRatio(getfloatvalue(v));
|
|
else if (is_intobject(v))
|
|
PVbuffer[i] = getintvalue(v);
|
|
else {
|
|
DEL(PVbuffer);
|
|
err_badarg();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
error_handler_called = 0;
|
|
(*func)(self->ob_compressorHdl, PVbuffer, length);
|
|
if (error_handler_called)
|
|
return NULL;
|
|
|
|
if (modified) {
|
|
for (i = 0; i < length; i++) {
|
|
v = getlistitem(list, i);
|
|
if (is_floatobject(v))
|
|
v = newfloatobject(clRatioToFloat(PVbuffer[i]));
|
|
else
|
|
v = newintobject(PVbuffer[i]);
|
|
setlistitem(list, i, v);
|
|
}
|
|
}
|
|
|
|
DEL(PVbuffer);
|
|
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
clm_GetParams(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
return doParams(self, args, clGetParams, 1);
|
|
}
|
|
|
|
static object *
|
|
clm_SetParams(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
return doParams(self, args, clSetParams, 1);
|
|
}
|
|
|
|
static object *
|
|
clm_GetParamID(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
char *name;
|
|
long value;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "s", &name))
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
value = clGetParamID(self->ob_compressorHdl, name);
|
|
if (value == FAILURE) {
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "getparamid failed");
|
|
return NULL;
|
|
}
|
|
|
|
return newintobject(value);
|
|
}
|
|
|
|
static object *
|
|
clm_QueryParams(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long bufferlength;
|
|
long *PVbuffer;
|
|
object *list;
|
|
int i;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getnoarg(args))
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
bufferlength = clQueryParams(self->ob_compressorHdl, 0, 0);
|
|
if (error_handler_called)
|
|
return NULL;
|
|
|
|
PVbuffer = NEW(long, bufferlength);
|
|
if (PVbuffer == NULL)
|
|
return err_nomem();
|
|
|
|
bufferlength = clQueryParams(self->ob_compressorHdl, PVbuffer,
|
|
bufferlength);
|
|
if (error_handler_called) {
|
|
DEL(PVbuffer);
|
|
return NULL;
|
|
}
|
|
|
|
list = newlistobject(bufferlength);
|
|
if (list == NULL) {
|
|
DEL(PVbuffer);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < bufferlength; i++) {
|
|
if (i & 1)
|
|
setlistitem(list, i, newintobject(PVbuffer[i]));
|
|
else if (PVbuffer[i] == 0) {
|
|
INCREF(None);
|
|
setlistitem(list, i, None);
|
|
} else
|
|
setlistitem(list, i, newstringobject((char *) PVbuffer[i]));
|
|
}
|
|
|
|
DEL(PVbuffer);
|
|
|
|
return list;
|
|
}
|
|
|
|
static object *
|
|
clm_GetMinMax(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long param, min, max;
|
|
double fmin, fmax;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "i", ¶m))
|
|
return NULL;
|
|
|
|
clGetMinMax(self->ob_compressorHdl, param, &min, &max);
|
|
|
|
if (param_type_is_float(self->ob_compressorHdl, param) > 0) {
|
|
fmin = clRatioToFloat(min);
|
|
fmax = clRatioToFloat(max);
|
|
return mkvalue("(ff)", fmin, fmax);
|
|
}
|
|
|
|
return mkvalue("(ii)", min, max);
|
|
}
|
|
|
|
static object *
|
|
clm_GetName(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long param;
|
|
char *name;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "i", ¶m))
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
name = clGetName(self->ob_compressorHdl, param);
|
|
if (name == NULL || error_handler_called) {
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "getname failed");
|
|
return NULL;
|
|
}
|
|
|
|
return newstringobject(name);
|
|
}
|
|
|
|
static object *
|
|
clm_GetDefault(self, args)
|
|
clobject *self;
|
|
object *args;
|
|
{
|
|
long param, value;
|
|
double fvalue;
|
|
|
|
CheckCompressor(self);
|
|
|
|
if (!getargs(args, "i", ¶m))
|
|
return NULL;
|
|
|
|
error_handler_called = 0;
|
|
value = clGetDefault(self->ob_compressorHdl, param);
|
|
if (error_handler_called)
|
|
return NULL;
|
|
|
|
if (param_type_is_float(self->ob_compressorHdl, param) > 0) {
|
|
fvalue = clRatioToFloat(value);
|
|
return newfloatobject(fvalue);
|
|
}
|
|
|
|
return newintobject(value);
|
|
}
|
|
|
|
static struct methodlist compressor_methods[] = {
|
|
{"close", clm_CloseCompressor}, /* alias */
|
|
{"CloseCompressor", clm_CloseCompressor},
|
|
{"Compress", clm_Compress},
|
|
{"GetDefault", clm_GetDefault},
|
|
{"GetMinMax", clm_GetMinMax},
|
|
{"GetName", clm_GetName},
|
|
{"GetParamID", clm_GetParamID},
|
|
{"GetParams", clm_GetParams},
|
|
{"QueryParams", clm_QueryParams},
|
|
{"SetParams", clm_SetParams},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static struct methodlist decompressor_methods[] = {
|
|
{"close", clm_CloseDecompressor}, /* alias */
|
|
{"CloseDecompressor", clm_CloseDecompressor},
|
|
{"Decompress", clm_Decompress},
|
|
{"GetDefault", clm_GetDefault},
|
|
{"GetMinMax", clm_GetMinMax},
|
|
{"GetName", clm_GetName},
|
|
{"GetParamID", clm_GetParamID},
|
|
{"GetParams", clm_GetParams},
|
|
{"QueryParams", clm_QueryParams},
|
|
{"SetParams", clm_SetParams},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static void
|
|
cl_dealloc(self)
|
|
clobject *self;
|
|
{
|
|
if (self->ob_compressorHdl) {
|
|
if (self->ob_isCompressor)
|
|
clCloseCompressor(self->ob_compressorHdl);
|
|
else
|
|
clCloseDecompressor(self->ob_compressorHdl);
|
|
}
|
|
DEL(self);
|
|
}
|
|
|
|
static object *
|
|
cl_getattr(self, name)
|
|
clobject *self;
|
|
char *name;
|
|
{
|
|
if (self->ob_isCompressor)
|
|
return findmethod(compressor_methods, (object *)self, name);
|
|
else
|
|
return findmethod(decompressor_methods, (object *) self, name);
|
|
}
|
|
|
|
static typeobject Cltype = {
|
|
OB_HEAD_INIT(&Typetype)
|
|
0, /*ob_size*/
|
|
"cl", /*tp_name*/
|
|
sizeof(clobject), /*tp_size*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
cl_dealloc, /*tp_dealloc*/
|
|
0, /*tp_print*/
|
|
cl_getattr, /*tp_getattr*/
|
|
0, /*tp_setattr*/
|
|
0, /*tp_compare*/
|
|
0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
};
|
|
|
|
static object *
|
|
doOpen(self, args, open_func, iscompressor)
|
|
object *self, *args;
|
|
long (*open_func) PROTO((long, CL_Handle *));
|
|
int iscompressor;
|
|
{
|
|
long scheme;
|
|
clobject *new;
|
|
|
|
if (!getargs(args, "i", &scheme))
|
|
return NULL;
|
|
|
|
new = NEWOBJ(clobject, &Cltype);
|
|
if (new == NULL)
|
|
return NULL;
|
|
|
|
new->ob_compressorHdl = NULL;
|
|
new->ob_isCompressor = iscompressor;
|
|
|
|
error_handler_called = 0;
|
|
if ((*open_func)(scheme, &new->ob_compressorHdl) == FAILURE) {
|
|
DECREF(new);
|
|
if (!error_handler_called)
|
|
err_setstr(ClError, "Open(De)Compressor failed");
|
|
return NULL;
|
|
}
|
|
return new;
|
|
}
|
|
|
|
static object *
|
|
cl_OpenCompressor(self, args)
|
|
object *self, *args;
|
|
{
|
|
return doOpen(self, args, clOpenCompressor, 1);
|
|
}
|
|
|
|
static object *
|
|
cl_OpenDecompressor(self, args)
|
|
object *self, *args;
|
|
{
|
|
return doOpen(self, args, clOpenDecompressor, 0);
|
|
}
|
|
|
|
static struct methodlist cl_methods[] = {
|
|
{"CompressImage", cl_CompressImage},
|
|
{"DecompressImage", cl_DecompressImage},
|
|
{"OpenCompressor", cl_OpenCompressor},
|
|
{"OpenDecompressor", cl_OpenDecompressor},
|
|
{NULL, NULL} /* Sentinel */
|
|
};
|
|
|
|
void
|
|
initcl()
|
|
{
|
|
object *m, *d;
|
|
|
|
m = initmodule("cl", cl_methods);
|
|
d = getmoduledict(m);
|
|
|
|
ClError = newstringobject("cl.error");
|
|
if (ClError == NULL || dictinsert(d, "error", ClError) != 0)
|
|
fatal("can't define cl.error");
|
|
|
|
(void) clSetErrorHandler(cl_ErrorHandler);
|
|
}
|