--- ray/src/util/cmatrix.c 2020/03/26 02:48:31 2.26 +++ ray/src/util/cmatrix.c 2023/11/21 01:30:20 2.38 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: cmatrix.c,v 2.26 2020/03/26 02:48:31 greg Exp $"; +static const char RCSid[] = "$Id: cmatrix.c,v 2.38 2023/11/21 01:30:20 greg Exp $"; #endif /* * Color matrix routines. @@ -15,13 +15,15 @@ static const char RCSid[] = "$Id: cmatrix.c,v 2.26 202 #include "paths.h" #include "resolu.h" +const char stdin_name[] = ""; + const char *cm_fmt_id[] = { - "unknown", COLRFMT, CIEFMT, + "unknown", COLRFMT, CIEFMT, SPECFMT, "float", "ascii", "double" }; const int cm_elem_size[] = { - 0, 4, 4, 3*sizeof(float), 0, 3*sizeof(double) + 0, 4, 4, 0, 3*sizeof(float), 0, 3*sizeof(double) }; /* Allocate a color coefficient matrix */ @@ -33,7 +35,7 @@ cm_alloc(int nrows, int ncols) if ((nrows <= 0) | (ncols <= 0)) error(USER, "attempt to create empty matrix"); cm = (CMATRIX *)malloc(sizeof(CMATRIX) + - sizeof(COLOR)*(nrows*ncols - 1)); + sizeof(COLOR)*((size_t)nrows*ncols - 1)); if (!cm) error(SYSTEM, "out of memory in cm_alloc()"); cm->nrows = nrows; @@ -65,9 +67,9 @@ cm_resize(CMATRIX *cm, int nrows) cm_free(cm); return(NULL); } - old_size = sizeof(CMATRIX) + sizeof(COLOR)*(cm->nrows*cm->ncols - 1); + old_size = sizeof(CMATRIX) + sizeof(COLOR)*((size_t)cm->nrows*cm->ncols - 1); adjacent_ra_sizes(ra_bounds, old_size); - new_size = sizeof(CMATRIX) + sizeof(COLOR)*(nrows*cm->ncols - 1); + new_size = sizeof(CMATRIX) + sizeof(COLOR)*((size_t)nrows*cm->ncols - 1); if (nrows < cm->nrows ? new_size <= ra_bounds[0] : new_size > ra_bounds[1]) { adjacent_ra_sizes(ra_bounds, new_size); @@ -175,22 +177,14 @@ cm_getheader(int *dt, int *nr, int *nc, int *swp, COLO /* Allocate and load image data into matrix */ static CMATRIX * -cm_load_rgbe(FILE *fp, int nrows, int ncols, COLOR scale) +cm_load_rgbe(FILE *fp, int nrows, int ncols) { - int doscale; CMATRIX *cm; COLORV *mp; /* header already loaded */ - if ((nrows <= 0) | (ncols <= 0) && !fscnresolu(&ncols, &nrows, fp)) { - error(USER, "bad picture resolution string"); - return(NULL); - } cm = cm_alloc(nrows, ncols); if (!cm) return(NULL); - doscale = (scale[0] < .99) | (scale[0] > 1.01) | - (scale[1] < .99) | (scale[1] > 1.01) | - (scale[2] < .99) | (scale[2] > 1.01) ; mp = cm->cmem; while (nrows--) { if (freadscan((COLOR *)mp, ncols, fp) < 0) { @@ -198,15 +192,7 @@ cm_load_rgbe(FILE *fp, int nrows, int ncols, COLOR sca cm_free(cm); return(NULL); } - if (doscale) { - int i = ncols; - while (i--) { - *mp++ *= scale[0]; - *mp++ *= scale[1]; - *mp++ *= scale[2]; - } - } else - mp += 3*ncols; + mp += 3*ncols; } /* caller closes stream */ return(cm); } @@ -216,14 +202,19 @@ CMATRIX * cm_load(const char *inspec, int nrows, int ncols, int dtype) { const int ROWINC = 2048; - FILE *fp = stdin; + int dimsOK = (dtype == DTascii) | (nrows > 0) && ncols; int swap = 0; + FILE *fp; COLOR scale; CMATRIX *cm; if (!inspec) - inspec = ""; - else if (inspec[0] == '!') { + inspec = stdin_name; + else if (!*inspec) + return(NULL); + if (inspec == stdin_name) { /* reading from stdin? */ + fp = stdin; + } else if (inspec[0] == '!') { fp = popen(inspec+1, "r"); if (!fp) { sprintf(errmsg, "cannot start command '%s'", inspec); @@ -238,13 +229,15 @@ cm_load(const char *inspec, int nrows, int ncols, int #endif if (dtype != DTascii) SET_FILE_BINARY(fp); /* doesn't really work */ - if (!dtype | !ncols) { /* expecting header? */ + if (!dtype | !dimsOK) { /* expecting header? */ char *err = cm_getheader(&dtype, &nrows, &ncols, &swap, scale, fp); if (err) error(USER, err); - if (ncols <= 0) - error(USER, "unspecified number of columns"); + dimsOK = ncols > 0 && ( nrows > 0 || + (dtype != DTrgbe) & (dtype != DTxyze) ); } + if (!dimsOK && !fscnresolu(&ncols, &nrows, fp)) + error(USER, "unspecified matrix size"); switch (dtype) { case DTascii: case DTfloat: @@ -252,27 +245,26 @@ cm_load(const char *inspec, int nrows, int ncols, int break; case DTrgbe: case DTxyze: - cm = cm_load_rgbe(fp, nrows, ncols, scale); + cm = cm_load_rgbe(fp, nrows, ncols); goto cleanup; default: error(USER, "unexpected data type in cm_load()"); } if (nrows <= 0) { /* don't know length? */ int guessrows = 147; /* usually big enough */ - if ((dtype != DTascii) & (fp != stdin) & (inspec[0] != '!')) { + if (cm_elem_size[dtype] && (fp != stdin) & (inspec[0] != '!')) { long startpos = ftell(fp); if (fseek(fp, 0L, SEEK_END) == 0) { + long rowsiz = (long)ncols*cm_elem_size[dtype]; long endpos = ftell(fp); - long elemsiz = 3*(dtype==DTfloat ? - sizeof(float) : sizeof(double)); - if ((endpos - startpos) % (ncols*elemsiz)) { + if ((endpos - startpos) % rowsiz) { sprintf(errmsg, "improper length for binary file '%s'", inspec); error(USER, errmsg); } - guessrows = (endpos - startpos)/(ncols*elemsiz); + guessrows = (endpos - startpos)/rowsiz; if (fseek(fp, startpos, SEEK_SET) < 0) { sprintf(errmsg, "fseek() error on file '%s'", @@ -314,14 +306,14 @@ cm_load(const char *inspec, int nrows, int ncols, int } } else { /* read binary file */ if (sizeof(COLOR) == cm_elem_size[dtype]) { - int nread = 0; + size_t nread = 0; do { /* read all we can */ nread += getbinary(cm->cmem + 3*nread, sizeof(COLOR), - cm->nrows*cm->ncols - nread, + (size_t)cm->nrows*cm->ncols - nread, fp); if (nrows <= 0) { /* unknown length */ - if (nread == cm->nrows*cm->ncols) + if (nread == (size_t)cm->nrows*cm->ncols) /* need more space? */ cm = cm_resize(cm, cm->nrows+ROWINC); else if (nread && !(nread % cm->ncols)) @@ -329,22 +321,22 @@ cm_load(const char *inspec, int nrows, int ncols, int cm = cm_resize(cm, nread/cm->ncols); else /* ended mid-row */ goto EOFerror; - } else if (nread < cm->nrows*cm->ncols) + } else if (nread < (size_t)cm->nrows*cm->ncols) goto EOFerror; - } while (nread < cm->nrows*cm->ncols); + } while (nread < (size_t)cm->nrows*cm->ncols); if (swap) { if (sizeof(COLORV) == 4) swap32((char *)cm->cmem, - 3*cm->nrows*cm->ncols); + 3*(size_t)cm->nrows*cm->ncols); else /* sizeof(COLORV) == 8 */ swap64((char *)cm->cmem, - 3*cm->nrows*cm->ncols); + 3*(size_t)cm->nrows*cm->ncols); } } else if (dtype == DTdouble) { double dc[3]; /* load from double */ COLORV *cvp = cm->cmem; - int n = nrows*ncols; + size_t n = (size_t)nrows*ncols; if (n <= 0) goto not_handled; @@ -358,7 +350,7 @@ cm_load(const char *inspec, int nrows, int ncols, int } else /* dtype == DTfloat */ { float fc[3]; /* load from float */ COLORV *cvp = cm->cmem; - int n = nrows*ncols; + size_t n = (size_t)nrows*ncols; if (n <= 0) goto not_handled; @@ -390,6 +382,17 @@ cleanup: else funlockfile(fp); #endif + if ((scale[0] < .99) | (scale[0] > 1.01) | + (scale[1] < .99) | (scale[1] > 1.01) | + (scale[2] < .99) | (scale[2] > 1.01)) { + size_t n = (size_t)ncols*nrows; + COLORV *mp = cm->cmem; + while (n--) { /* apply exposure scaling */ + *mp++ *= scale[0]; + *mp++ *= scale[1]; + *mp++ *= scale[2]; + } + } return(cm); EOFerror: sprintf(errmsg, "unexpected EOF reading %s", inspec); @@ -488,6 +491,7 @@ cm_write(const CMATRIX *cm, int dtype, FILE *fp) static const char tabEOL[2] = {'\t','\n'}; const COLORV *mp; int r, c; + size_t n, rv; if (!cm) return(0); @@ -503,18 +507,18 @@ cm_write(const CMATRIX *cm, int dtype, FILE *fp) case DTfloat: case DTdouble: if (sizeof(COLOR) == cm_elem_size[dtype]) { - r = cm->ncols*cm->nrows; - while (r > 0) { - c = putbinary(mp, sizeof(COLOR), r, fp); - if (c <= 0) + n = (size_t)cm->ncols*cm->nrows; + while (n > 0) { + rv = fwrite(mp, sizeof(COLOR), n, fp); + if (rv <= 0) return(0); - mp += 3*c; - r -= c; + mp += 3*rv; + n -= rv; } } else if (dtype == DTdouble) { double dc[3]; - r = cm->ncols*cm->nrows; - while (r--) { + n = (size_t)cm->ncols*cm->nrows; + while (n--) { copycolor(dc, mp); if (putbinary(dc, sizeof(double), 3, fp) != 3) return(0); @@ -522,8 +526,8 @@ cm_write(const CMATRIX *cm, int dtype, FILE *fp) } } else /* dtype == DTfloat */ { float fc[3]; - r = cm->ncols*cm->nrows; - while (r--) { + n = (size_t)cm->ncols*cm->nrows; + while (n--) { copycolor(fc, mp); if (putbinary(fc, sizeof(float), 3, fp) != 3) return(0);