Corrected a fairly long-standing error in which the MASKHINTS_ values

in the .mag file "properties" list are not handled as being in
database units during .mag file reading and writing (although they
do track internally), making them subject to being scaled incorrectly
and change between a read and a write.  Thanks to Sylvain Munaut for
identifying the problem.
This commit is contained in:
Tim Edwards 2024-05-10 13:05:06 -04:00
parent fd2b1eb9ee
commit 9dec47c9b2
2 changed files with 177 additions and 36 deletions

View File

@ -1 +1 @@
8.3.479
8.3.480

View File

@ -2267,7 +2267,8 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
if (!strcmp(propertyname, "GDS_FILE"))
cellDef->cd_flags |= CDVENDORGDS;
/* Also process FIXED_BBOX property, as units must match */
/* Also process FIXED_BBOX property, as units must match, */
/* and ditto for MASKHINTS_*. */
if (!strcmp(propertyname, "FIXED_BBOX"))
{
@ -2308,6 +2309,74 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
}
else if (!strncmp(propertyname, "MASKHINTS_", 10))
{
Rect locbbox;
char *pptr = pvalueptr;
int numvals, numrects = 0, slen, n;
while (*pptr != '\0')
{
numvals = sscanf(pptr, "%d %d %d %d",
&(locbbox.r_xbot),
&(locbbox.r_ybot),
&(locbbox.r_xtop),
&(locbbox.r_ytop));
if (numvals <= 0)
break;
else if (numvals != 4)
{
TxError("Cannot read bounding box values in %s property",
propertyname);
break;
}
else
{
if (numrects == 0)
{
storedvalue = (char *)mallocMagic(40);
*storedvalue = '\0';
slen = -1;
}
else
{
char *newvalue;
slen = strlen(storedvalue);
newvalue = (char *)mallocMagic(40 + slen);
sprintf(newvalue, "%s ", storedvalue);
freeMagic(storedvalue);
storedvalue = newvalue;
}
numrects++;
if (scalen > 1)
{
locbbox.r_xbot *= scalen;
locbbox.r_ybot *= scalen;
locbbox.r_xtop *= scalen;
locbbox.r_ytop *= scalen;
}
if (scaled > 1)
{
locbbox.r_xbot /= scaled;
locbbox.r_ybot /= scaled;
locbbox.r_xtop /= scaled;
locbbox.r_ytop /= scaled;
}
sprintf(storedvalue + slen + 1, "%d %d %d %d",
locbbox.r_xbot, locbbox.r_ybot,
locbbox.r_xtop, locbbox.r_ytop);
/* Skip forward four values in pvalueptr */
for (n = 0; n < 4; n++)
{
while (!isspace(*pptr)) pptr++;
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
}
}
}
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
else
{
storedvalue = StrDup((char **)NULL, pvalueptr);
@ -3177,6 +3246,16 @@ dbCountPropFunc(key, value, count)
return 0;
}
/* Structure used by dbPropWriteFunc. Holds the FILE stream pointer of
* the file being written to, and the scale reducer for dimensional
* values in the output (magscale).
*/
typedef struct _pwfrec {
FILE *pwf_file;
int pwf_reducer;
} pwfrec;
/*
* ----------------------------------------------------------------------------
*
@ -3228,6 +3307,7 @@ DBCellWriteFile(cellDef, f)
CellUse **useList;
int i, numUses = 0, numProps = 0;
struct cellUseList cul;
pwfrec pwf;
#define FPUTSF(f,s)\
{\
@ -3450,34 +3530,6 @@ DBCellWriteFile(cellDef, f)
/* And any properties */
/* NOTE: FIXED_BBOX is treated specially; values are database */
/* values and should be divided by reducer. Easiest to do it */
/* here and revert values after. */
propvalue = (char *)DBPropGet(cellDef, "FIXED_BBOX", &propfound);
if (propfound)
{
char *proporig, *propscaled;
Rect scalebox, bbox;
proporig = StrDup((char **)NULL, propvalue);
propscaled = mallocMagic(strlen(propvalue) + 5);
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
scalebox.r_xbot = bbox.r_xbot / reducer;
scalebox.r_xtop = bbox.r_xtop / reducer;
scalebox.r_ybot = bbox.r_ybot / reducer;
scalebox.r_ytop = bbox.r_ytop / reducer;
sprintf(propscaled, "%d %d %d %d",
bbox.r_xbot / reducer, bbox.r_ybot / reducer,
bbox.r_xtop / reducer, bbox.r_ytop / reducer);
DBPropPut(cellDef, "FIXED_BBOX", propscaled);
propvalue = proporig;
}
}
DBPropEnum(cellDef, dbCountPropFunc, (ClientData)&numProps);
if (numProps > 0)
{
@ -3492,19 +3544,18 @@ DBCellWriteFile(cellDef, f)
keycompare);
FPUTSF(f, "<< properties >>\n");
pwf.pwf_file = f;
pwf.pwf_reducer = reducer;
for (i = 0; i < numProps; i++)
{
dbWritePropFunc(propRec.keyValueList[i]->key,
propRec.keyValueList[i]->value,
(ClientData)f);
(ClientData)&pwf);
freeMagic ((char *)propRec.keyValueList[i]);
}
freeMagic((char *)propRec.keyValueList);
}
/* Restore the original values in FIXED_BBOX, if any */
if (propfound) DBPropPut(cellDef, "FIXED_BBOX", propvalue);
FPUTSF(f, "<< end >>\n");
if (fflush(f) == EOF || ferror(f))
@ -3539,6 +3590,11 @@ ioerror:
* expected property strings and output the value based on the
* known format of what it points to.
*
* Also, this function assumes that properties FIXED_BBOX and
* MASKHINTS_* are in internal units, and converts them by
* dividing by the reducer value passed in cdata. No other
* properties are altered.
*
* ----------------------------------------------------------------------------
*/
@ -3548,14 +3604,99 @@ dbWritePropFunc(key, value, cdata)
char *value;
ClientData cdata;
{
FILE *f = (FILE *)cdata;
pwfrec *pwf = (pwfrec *)cdata;
FILE *f = pwf->pwf_file;
int reducer = pwf->pwf_reducer;
char *newvalue = value;
/* NOTE: FIXED_BBOX is treated specially; values are database */
/* values and should be divided by reducer. Easiest to do it */
/* here and revert values after. Ditto for MASKHINTS_*. */
if (!strcmp(key, "FIXED_BBOX"))
{
Rect scalebox, bbox;
if (sscanf(value, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
scalebox.r_xbot = bbox.r_xbot / reducer;
scalebox.r_xtop = bbox.r_xtop / reducer;
scalebox.r_ybot = bbox.r_ybot / reducer;
scalebox.r_ytop = bbox.r_ytop / reducer;
newvalue = mallocMagic(strlen(value) + 5);
sprintf(newvalue, "%d %d %d %d",
scalebox.r_xbot, scalebox.r_ybot,
scalebox.r_xtop, scalebox.r_ytop);
}
else
TxError("Error: Cannot parse FIXED_BBOX property value!\n");
}
else if (!strncmp(key, "MASKHINTS_", 10))
{
Rect scalebox, bbox;
char *vptr = value, *sptr;
int numvals, numrects = 0, n;
while (TRUE)
{
numvals = sscanf(vptr, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numvals <= 0)
break;
else if (numvals != 4)
{
TxError("Error: Cannot parse %s property value!\n", key);
/* Revert property value to original string */
if (newvalue != value) freeMagic(newvalue);
newvalue = value;
break;
}
else
{
scalebox.r_xbot = bbox.r_xbot / reducer;
scalebox.r_xtop = bbox.r_xtop / reducer;
scalebox.r_ybot = bbox.r_ybot / reducer;
scalebox.r_ytop = bbox.r_ytop / reducer;
if (numrects == 0)
{
newvalue = mallocMagic(40);
sptr = newvalue;
}
else
{
char *tempvalue;
tempvalue = mallocMagic(strlen(newvalue) + 40);
sprintf(tempvalue, "%s ", newvalue);
sptr = tempvalue + strlen(newvalue) + 1;
freeMagic(newvalue);
newvalue = tempvalue;
}
sprintf(sptr, "%d %d %d %d",
scalebox.r_xbot, scalebox.r_ybot,
scalebox.r_xtop, scalebox.r_ytop);
numrects++;
}
/* Skip forward four values in value */
for (n = 0; n < 4; n++)
{
while (!isspace(*vptr)) vptr++;
while (isspace(*vptr) && (*vptr != '\0')) vptr++;
}
}
}
FPUTSR(f, "string ");
FPUTSR(f, key);
FPUTSR(f, " ");
FPUTSR(f, value);
FPUTSR(f, newvalue);
FPUTSR(f, "\n");
if (newvalue != value) freeMagic(newvalue);
return 0;
}