blob: 0713aae2ff2bae56bcd34a39928f86cf52010911 [file] [log] [blame]
/* Copyright (C) 1989, 1990 Aladdin Enterprises. All rights reserved.
Distributed by Free Software Foundation, Inc.
This file is part of Ghostscript.
Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing. Refer
to the Ghostscript General Public License for full details.
Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License. A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities. It should be in a file named COPYING. Among other
things, the copyright notice and this notice must be preserved on all
copies. */
/* iutil.c */
/* Utilities for GhostScript interpreter */
#include "memory_.h"
#include "string_.h"
#include "ghost.h"
#include "errors.h"
#include "alloc.h"
#include "oper.h"
#include "store.h"
#include "gsmatrix.h"
#include "gxdevice.h" /* for gx_color_index */
#include "gzcolor.h"
/* Imported from name.c */
extern ref *name_string_ref(P2(ref *, ref *));
/* ------ Object utilities ------ */
/* Copy refs from one place to another. */
void
refcpy(register ref *to, register ref *from, register uint size)
{ while ( size-- ) store_i(to++, from++);
}
/* Compare two objects for equality. Return 1 if equal, 0 if not. */
int
obj_eq(register ref *pref1, register ref *pref2)
{ ref nref;
if ( r_btype(pref1) != r_btype(pref2) )
{ /* Only a few cases need be considered here: */
/* integer/real, name/string, and vice versa. */
switch ( r_type(pref1) )
{
case t_integer:
return (r_type(pref2) == t_real &&
pref2->value.realval == pref1->value.intval);
case t_real:
return (r_type(pref2) == t_integer &&
pref2->value.intval == pref1->value.realval);
case t_name:
if ( r_type(pref2) != t_string ) return 0;
name_string_ref(pref1, &nref);
pref1 = &nref;
break;
case t_string:
if ( r_type(pref2) != t_name ) return 0;
name_string_ref(pref2, &nref);
pref2 = &nref;
break;
default:
return 0;
}
}
/* Now do a type-dependent comparison. */
/* This would be very simple if we always filled in */
/* all 8 bytes of a ref, but we currently don't. */
switch ( r_btype(pref1) )
{
case t_array:
case t_packedarray:
return (pref1->value.refs == pref2->value.refs &&
pref1->size == pref2->size);
case t_boolean:
return (pref1->value.index == pref2->value.index);
case t_dictionary:
return (pref1->value.pdict == pref2->value.pdict);
case t_file:
return (pref1->value.pfile == pref2->value.pfile);
case t_fontID:
return (pref1->value.pfont == pref2->value.pfont);
case t_integer:
return (pref1->value.intval == pref2->value.intval);
case t_mark:
case t_null:
return 1;
case t_name:
return (pref1->value.pname == pref2->value.pname);
case t_operator:
return ((long)pref1->value.opproc ==
(long)pref2->value.opproc);
case t_real:
return (pref1->value.realval == pref2->value.realval);
case t_save:
return (pref1->value.psave == pref2->value.psave);
case t_string:
return (!bytes_compare(pref1->value.bytes, pref1->size,
pref2->value.bytes, pref2->size));
case t_color:
{ struct gs_color_s
*pc1 = pref1->value.pcolor,
*pc2 = pref2->value.pcolor;
return (pc1->red == pc2->red && pc1->green == pc2->green &&
pc1->blue == pc2->blue);
}
case t_device:
return (pref1->value.pdevice == pref2->value.pdevice);
}
return 0; /* shouldn't happen! */
}
/* ------ String utilities ------ */
/* Compare two strings, returning -1 if the first is less, */
/* 0 if they are equal, and 1 if first is greater. */
/* We can't use memcmp, because we always use unsigned characters. */
int
bytes_compare(byte *s1, uint len1, byte *s2, uint len2)
{ register uint len = len1;
if ( len2 < len ) len = len2;
{ register byte *p1 = s1;
register byte *p2 = s2;
while ( len-- )
if ( *p1++ != *p2++ )
return (p1[-1] < p2[-1] ? -1 : 1);
}
/* Now check for differing lengths */
return (len1 == len2 ? 0 : len1 < len2 ? -1 : 1);
}
/* Compute a hash for a string */
uint
string_hash(byte *ptr, uint len)
{ register byte *p = ptr;
register uint hash = 0;
register uint n = len;
while ( n-- ) hash = hash * 19 + *p++;
return hash;
}
/* Convert a C string to a Ghostscript string */
int
string_to_ref(char *cstr, ref *pref, char *cname)
{ uint size = strlen(cstr);
char *str = alloc(size, 1, cname);
if ( str == 0 ) return e_VMerror;
memcpy(str, cstr, size);
make_tasv(pref, t_string, a_all, size, bytes, (byte *)str);
return 0;
}
/* Convert a Ghostscript string to a C string. */
/* Return 0 iff the buffer can't be allocated. */
char *
ref_to_string(ref *pref, char *client_name)
{ uint size = pref->size;
char *str = alloc(size + 1, 1, client_name);
if ( str == 0 ) return 0;
memcpy(str, (char *)pref->value.bytes, size);
str[size] = 0;
return str;
}
/* ------ Operand utilities ------ */
/* Get N numeric operands from the stack. */
/* Return a bit-mask indicating which ones are integers, */
/* or a (negative) error indication. */
/* The 1-bit in the bit-mask refers to the bottommost stack entry. */
/* If pval is non-zero, also store float versions of the operands there. */
int
num_params(ref *op, int count, float *pval)
{ int mask = 0;
while ( --count >= 0 )
{ mask <<= 1;
switch ( r_type(op) )
{
case t_real:
if ( pval ) pval[count] = op->value.realval;
break;
case t_integer:
if ( pval ) pval[count] = op->value.intval;
mask++;
break;
default:
return e_typecheck;
}
op--;
}
return mask;
}
/* Get a real parameter. */
/* If unit is true, the parameter must lie in [0..1],
/* to within a reasonable rounding error. */
/* If an error is returned, the return value is not updated. */
int
real_param(ref *op, float *pparam, int unit)
{ float fval;
switch ( r_type(op) )
{
case t_integer: fval = op->value.intval; break;
case t_real: fval = op->value.realval; break;
default: return e_typecheck;
}
if ( unit )
{ if ( fval < 0.0 )
{ if ( fval < -0.00001 ) return e_rangecheck;
fval = 0.0;
}
else if ( fval > 1.0 )
{ if ( fval > 1.00001 ) return e_rangecheck;
fval = 1.0;
}
}
*pparam = fval;
return 0;
}
/* Check for a matrix operand with read access. */
/* Return 0 if OK, error code if not. */
/* Store an all-float version of the matrix in *pmat. */
int
read_matrix(ref *op, gs_matrix *pmat)
{ check_array(*op);
if ( op->size != 6 ) return e_rangecheck;
if ( !(r_attrs(op) & a_read) ) return e_invalidaccess;
*pmat = *(gs_matrix *)op->value.refs;
{ ref *pel = (ref *)pmat;
int i;
for ( i = 0; i < 6; i++ )
{ switch ( r_type(pel) )
{
default: return e_typecheck;
case t_integer:
make_real(pel, pel->value.intval);
case t_real: ;
}
pel++;
}
}
return 0;
}
/* Check for a matrix operand with write access. */
/* Return 0 if OK, error code if not. */
/* Any element that isn't a number gets set to 0. */
int
write_matrix(register ref *op)
{ ref *aptr;
int i;
if ( r_type(op) != t_array ) return e_typecheck;
if ( op->size != 6 ) return e_rangecheck;
if ( !(r_attrs(op) & a_write) ) return e_invalidaccess;
aptr = op->value.refs;
for ( i = 5; i >= 0; i--, aptr++ )
{ switch ( r_type(aptr) )
{
default: store_int(aptr, 0);
case t_real: case t_integer: ;
}
}
return 0;
}