code:
/*
 * jidctint.c
 *
 * Copyright (C) 1991-1998, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains a slow-but-accurate integer implementation of the
 * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
 * must also perform dequantization of the input coefficients.
 *
 * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
 * on each row (or vice versa, but it's more convenient to emit a row at
 * a time).  Direct algorithms are also available, but they are much more
 * complex and seem not to be any faster when reduced to code.
 *
 * This implementation is based on an algorithm described in
 *   C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
 *   Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
 *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
 * The primary algorithm described there uses 11 multiplies and 29 adds.
 * We use their alternate method with 12 multiplies and 32 adds.
 * The advantage of this method is that no data path contains more than one
 * multiplication; this allows a very simple and accurate implementation in
 * scaled fixed-point arithmetic, with a minimal number of shifts.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdct.h"		/* Private declarations for DCT subsystem */

#ifdef DCT_ISLOW_SUPPORTED

/*
 * This module is specialized to the case DCTSIZE = 8.
 */

#if DCTSIZE != 8
  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
#endif

/*
 * The poop on this scaling stuff is as follows:
 *
 * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
 * larger than the true IDCT outputs.  The final outputs are therefore
 * a factor of N larger than desired; since N=8 this can be cured by
 * a simple right shift at the end of the algorithm.  The advantage of
 * this arrangement is that we save two multiplications per 1-D IDCT,
 * because the y0 and y4 inputs need not be divided by sqrt(N).
 *
 * We have to do addition and subtraction of the integer inputs, which
 * is no problem, and multiplication by fractional constants, which is
 * a problem to do in integer arithmetic.  We multiply all the constants
 * by CONST_SCALE and convert them to integer constants (thus retaining
 * CONST_BITS bits of precision in the constants).  After doing a
 * multiplication we have to divide the product by CONST_SCALE, with proper
 * rounding, to produce the correct output.  This division can be done
 * cheaply as a right shift of CONST_BITS bits.  We postpone shifting
 * as long as possible so that partial sums can be added together with
 * full fractional precision.
 *
 * The outputs of the first pass are scaled up by PASS1_BITS bits so that
 * they are represented to better-than-integral precision.  These outputs
 * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
 * with the recommended scaling.  (To scale up 12-bit sample data further, an
 * intermediate INT32 array would be needed.)
 *
 * To avoid overflow of the 32-bit intermediate results in pass 2, we must
 * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
 * shows that the values given below are the most effective.
 */

#if BITS_IN_JSAMPLE == 8
#define CONST_BITS  13
#define PASS1_BITS  2
#else
#define CONST_BITS  13
#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
#endif

/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
 * causing a lot of useless floating-point operations at run time.
 * To get around this we use the following pre-calculated constants.
 * If you change CONST_BITS you may want to add appropriate values.
 * (With a reasonable C compiler, you can just rely on the FIX() macro...)
 */

#if CONST_BITS == 13
#define FIX_0_298631336  ((INT32)  2446)	/* FIX(0.298631336) */
#define FIX_0_390180644  ((INT32)  3196)	/* FIX(0.390180644) */
#define FIX_0_541196100  ((INT32)  4433)	/* FIX(0.541196100) */
#define FIX_0_765366865  ((INT32)  6270)	/* FIX(0.765366865) */
#define FIX_0_899976223  ((INT32)  7373)	/* FIX(0.899976223) */
#define FIX_1_175875602  ((INT32)  9633)	/* FIX(1.175875602) */
#define FIX_1_501321110  ((INT32)  12299)	/* FIX(1.501321110) */
#define FIX_1_847759065  ((INT32)  15137)	/* FIX(1.847759065) */
#define FIX_1_961570560  ((INT32)  16069)	/* FIX(1.961570560) */
#define FIX_2_053119869  ((INT32)  16819)	/* FIX(2.053119869) */
#define FIX_2_562915447  ((INT32)  20995)	/* FIX(2.562915447) */
#define FIX_3_072711026  ((INT32)  25172)	/* FIX(3.072711026) */
#else
#define FIX_0_298631336  FIX(0.298631336)
#define FIX_0_390180644  FIX(0.390180644)
#define FIX_0_541196100  FIX(0.541196100)
#define FIX_0_765366865  FIX(0.765366865)
#define FIX_0_899976223  FIX(0.899976223)
#define FIX_1_175875602  FIX(1.175875602)
#define FIX_1_501321110  FIX(1.501321110)
#define FIX_1_847759065  FIX(1.847759065)
#define FIX_1_961570560  FIX(1.961570560)
#define FIX_2_053119869  FIX(2.053119869)
#define FIX_2_562915447  FIX(2.562915447)
#define FIX_3_072711026  FIX(3.072711026)
#endif

/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
 * For 8-bit samples with the recommended scaling, all the variable
 * and constant values involved are no more than 16 bits wide, so a
 * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
 * For 12-bit samples, a full 32-bit multiplication will be needed.
 */

#if BITS_IN_JSAMPLE == 8
#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)
#else
#define MULTIPLY(var,const)  ((var) * (const))
#endif

/* Dequantize a coefficient by multiplying it by the multiplier-table
 * entry; produce an int result.  In this module, both inputs and result
 * are 16 bits or less, so either int or short multiply will work.
 */

#define DEQUANTIZE(coef,quantval)  (((ISLOW_MULT_TYPE) (coef)) * (quantval))

/*
 * Perform dequantization and inverse DCT on one block of coefficients.
 */

GLOBAL(void)
jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
		 JCOEFPTR coef_block,
		 JSAMPARRAY output_buf, JDIMENSION output_col)
{
  INT32 tmp0, tmp1, tmp2, tmp3;
  INT32 tmp10, tmp11, tmp12, tmp13;
  INT32 z1, z2, z3, z4, z5;
  JCOEFPTR inptr;
  ISLOW_MULT_TYPE * quantptr;
  int * wsptr;
  JSAMPROW outptr;
  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
  int ctr;
  int workspace[DCTSIZE2];	/* buffers data between passes */
  SHIFT_TEMPS

  /* Pass 1: process columns from input, store into work array. */
  /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
  /* furthermore, we scale the results by 2**PASS1_BITS. */

  inptr = coef_block;
  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
  wsptr = workspace;
  for (ctr = DCTSIZE; ctr > 0; ctr--) {
    /* Due to quantization, we will usually find that many of the input
     * coefficients are zero, especially the AC terms.  We can exploit this
     * by short-circuiting the IDCT calculation for any column in which all
     * the AC terms are zero.  In that case each output is equal to the
     * DC coefficient (with scale factor as needed).
     * With typical images and quantization tables, half or more of the
     * column DCT calculations can be simplified this way.
     */

    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
	inptr[DCTSIZE*7] == 0) {
      /* AC terms all zero */
      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;

      wsptr[DCTSIZE*0] = dcval;
      wsptr[DCTSIZE*1] = dcval;
      wsptr[DCTSIZE*2] = dcval;
      wsptr[DCTSIZE*3] = dcval;
      wsptr[DCTSIZE*4] = dcval;
      wsptr[DCTSIZE*5] = dcval;
      wsptr[DCTSIZE*6] = dcval;
      wsptr[DCTSIZE*7] = dcval;

      inptr++;			/* advance pointers to next column */
      quantptr++;
      wsptr++;
      continue;
    }

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */

    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);

    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
    tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
    tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);

    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);

    tmp0 = (z2 + z3) << CONST_BITS;
    tmp1 = (z2 - z3) << CONST_BITS;

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */

    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);

    z1 = tmp0 + tmp3;
    z2 = tmp1 + tmp2;
    z3 = tmp0 + tmp2;
    z4 = tmp1 + tmp3;
    z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */

    tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
    tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
    tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
    tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
    z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
    z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
    z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
    z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */

    z3 += z5;
    z4 += z5;

    tmp0 += z1 + z3;
    tmp1 += z2 + z4;
    tmp2 += z2 + z3;
    tmp3 += z1 + z4;

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
    wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS);

    inptr++;			/* advance pointers to next column */
    quantptr++;
    wsptr++;
  }

  /* Pass 2: process rows from work array, store into output array. */
  /* Note that we must descale the results by a factor of 8 == 2**3, */
  /* and also undo the PASS1_BITS scaling. */

  wsptr = workspace;
  for (ctr = 0; ctr < DCTSIZE; ctr++) {
    outptr = output_buf[ctr] + output_col;
    /* Rows of zeroes can be exploited in the same way as we did with columns.
     * However, the column calculation has created many nonzero AC terms, so
     * the simplification applies less often (typically 5% to 10% of the time).
     * On machines with very fast multiplication, it's possible that the
     * test takes more time than it's worth.  In that case this section
     * may be commented out.
     */

#ifndef NO_ZERO_ROW_TEST
    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
	wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
      /* AC terms all zero */
      JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
				  & RANGE_MASK];

      outptr[0] = dcval;
      outptr[1] = dcval;
      outptr[2] = dcval;
      outptr[3] = dcval;
      outptr[4] = dcval;
      outptr[5] = dcval;
      outptr[6] = dcval;
      outptr[7] = dcval;

      wsptr += DCTSIZE;		/* advance pointer to next row */
      continue;
    }
#endif

    /* Even part: reverse the even part of the forward DCT. */
    /* The rotator is sqrt(2)*c(-6). */

    z2 = (INT32) wsptr[2];
    z3 = (INT32) wsptr[6];

    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
    tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
    tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);

    tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS;
    tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS;

    tmp10 = tmp0 + tmp3;
    tmp13 = tmp0 - tmp3;
    tmp11 = tmp1 + tmp2;
    tmp12 = tmp1 - tmp2;

    /* Odd part per figure 8; the matrix is unitary and hence its
     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.
     */

    tmp0 = (INT32) wsptr[7];
    tmp1 = (INT32) wsptr[5];
    tmp2 = (INT32) wsptr[3];
    tmp3 = (INT32) wsptr[1];

    z1 = tmp0 + tmp3;
    z2 = tmp1 + tmp2;
    z3 = tmp0 + tmp2;
    z4 = tmp1 + tmp3;
    z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */

    tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
    tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
    tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
    tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
    z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
    z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
    z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
    z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */

    z3 += z5;
    z4 += z5;

    tmp0 += z1 + z3;
    tmp1 += z2 + z4;
    tmp2 += z2 + z3;
    tmp3 += z1 + z4;

    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */

    outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];
    outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0,
					  CONST_BITS+PASS1_BITS+3)
			    & RANGE_MASK];

    wsptr += DCTSIZE;		/* advance pointer to next row */
  }
}

#endif /* DCT_ISLOW_SUPPORTED */


code:
/*
 * jidctred.c
 *
 * Copyright (C) 1994-1998, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains inverse-DCT routines that produce reduced-size output:
 * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block.
 *
 * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M)
 * algorithm used in jidctint.c.  We simply replace each 8-to-8 1-D IDCT step
 * with an 8-to-4 step that produces the four averages of two adjacent outputs
 * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output).
 * These steps were derived by computing the corresponding values at the end
 * of the normal LL&M code, then simplifying as much as possible.
 *
 * 1x1 is trivial: just take the DC coefficient divided by 8.
 *
 * See jidctint.c for additional comments.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdct.h"		/* Private declarations for DCT subsystem */

#ifdef IDCT_SCALING_SUPPORTED

/*
 * This module is specialized to the case DCTSIZE = 8.
 */

#if DCTSIZE != 8
  Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
#endif

/* Scaling is the same as in jidctint.c. */

#if BITS_IN_JSAMPLE == 8
#define CONST_BITS  13
#define PASS1_BITS  2
#else
#define CONST_BITS  13
#define PASS1_BITS  1		/* lose a little precision to avoid overflow */
#endif

/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
 * causing a lot of useless floating-point operations at run time.
 * To get around this we use the following pre-calculated constants.
 * If you change CONST_BITS you may want to add appropriate values.
 * (With a reasonable C compiler, you can just rely on the FIX() macro...)
 */

#if CONST_BITS == 13
#define FIX_0_211164243  ((INT32)  1730)	/* FIX(0.211164243) */
#define FIX_0_509795579  ((INT32)  4176)	/* FIX(0.509795579) */
#define FIX_0_601344887  ((INT32)  4926)	/* FIX(0.601344887) */
#define FIX_0_720959822  ((INT32)  5906)	/* FIX(0.720959822) */
#define FIX_0_765366865  ((INT32)  6270)	/* FIX(0.765366865) */
#define FIX_0_850430095  ((INT32)  6967)	/* FIX(0.850430095) */
#define FIX_0_899976223  ((INT32)  7373)	/* FIX(0.899976223) */
#define FIX_1_061594337  ((INT32)  8697)	/* FIX(1.061594337) */
#define FIX_1_272758580  ((INT32)  10426)	/* FIX(1.272758580) */
#define FIX_1_451774981  ((INT32)  11893)	/* FIX(1.451774981) */
#define FIX_1_847759065  ((INT32)  15137)	/* FIX(1.847759065) */
#define FIX_2_172734803  ((INT32)  17799)	/* FIX(2.172734803) */
#define FIX_2_562915447  ((INT32)  20995)	/* FIX(2.562915447) */
#define FIX_3_624509785  ((INT32)  29692)	/* FIX(3.624509785) */
#else
#define FIX_0_211164243  FIX(0.211164243)
#define FIX_0_509795579  FIX(0.509795579)
#define FIX_0_601344887  FIX(0.601344887)
#define FIX_0_720959822  FIX(0.720959822)
#define FIX_0_765366865  FIX(0.765366865)
#define FIX_0_850430095  FIX(0.850430095)
#define FIX_0_899976223  FIX(0.899976223)
#define FIX_1_061594337  FIX(1.061594337)
#define FIX_1_272758580  FIX(1.272758580)
#define FIX_1_451774981  FIX(1.451774981)
#define FIX_1_847759065  FIX(1.847759065)
#define FIX_2_172734803  FIX(2.172734803)
#define FIX_2_562915447  FIX(2.562915447)
#define FIX_3_624509785  FIX(3.624509785)
#endif

/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
 * For 8-bit samples with the recommended scaling, all the variable
 * and constant values involved are no more than 16 bits wide, so a
 * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
 * For 12-bit samples, a full 32-bit multiplication will be needed.
 */

#if BITS_IN_JSAMPLE == 8
#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)
#else
#define MULTIPLY(var,const)  ((var) * (const))
#endif

/* Dequantize a coefficient by multiplying it by the multiplier-table
 * entry; produce an int result.  In this module, both inputs and result
 * are 16 bits or less, so either int or short multiply will work.
 */

#define DEQUANTIZE(coef,quantval)  (((ISLOW_MULT_TYPE) (coef)) * (quantval))

/*
 * Perform dequantization and inverse DCT on one block of coefficients,
 * producing a reduced-size 4x4 output block.
 */

GLOBAL(void)
jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
	       JCOEFPTR coef_block,
	       JSAMPARRAY output_buf, JDIMENSION output_col)
{
  INT32 tmp0, tmp2, tmp10, tmp12;
  INT32 z1, z2, z3, z4;
  JCOEFPTR inptr;
  ISLOW_MULT_TYPE * quantptr;
  int * wsptr;
  JSAMPROW outptr;
  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
  int ctr;
  int workspace[DCTSIZE*4];	/* buffers data between passes */
  SHIFT_TEMPS

  /* Pass 1: process columns from input, store into work array. */

  inptr = coef_block;
  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
  wsptr = workspace;
  for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
    /* Don't bother to process column 4, because second pass won't use it */
    if (ctr == DCTSIZE-4)
      continue;
    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 &&
	inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) {
      /* AC terms all zero; we need not examine term 4 for 4x4 output */
      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;

      wsptr[DCTSIZE*0] = dcval;
      wsptr[DCTSIZE*1] = dcval;
      wsptr[DCTSIZE*2] = dcval;
      wsptr[DCTSIZE*3] = dcval;

      continue;
    }

    /* Even part */

    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
    tmp0 <<= (CONST_BITS+1);

    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);

    tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865);

    tmp10 = tmp0 + tmp2;
    tmp12 = tmp0 - tmp2;

    /* Odd part */

    z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
    z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
    z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);

    tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
	 + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
	 + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
	 + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */

    tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
	 + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
	 + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
	 + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */

    /* Final output stage */

    wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1);
    wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1);
    wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1);
    wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1);
  }

  /* Pass 2: process 4 rows from work array, store into output array. */

  wsptr = workspace;
  for (ctr = 0; ctr < 4; ctr++) {
    outptr = output_buf[ctr] + output_col;
    /* It's not clear whether a zero row test is worthwhile here ... */

#ifndef NO_ZERO_ROW_TEST
    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 &&
	wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
      /* AC terms all zero */
      JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
				  & RANGE_MASK];

      outptr[0] = dcval;
      outptr[1] = dcval;
      outptr[2] = dcval;
      outptr[3] = dcval;

      wsptr += DCTSIZE;		/* advance pointer to next row */
      continue;
    }
#endif

    /* Even part */

    tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1);

    tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065)
	 + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865);

    tmp10 = tmp0 + tmp2;
    tmp12 = tmp0 - tmp2;

    /* Odd part */

    z1 = (INT32) wsptr[7];
    z2 = (INT32) wsptr[5];
    z3 = (INT32) wsptr[3];
    z4 = (INT32) wsptr[1];

    tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */
	 + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */
	 + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */
	 + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */

    tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */
	 + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */
	 + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */
	 + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */

    /* Final output stage */

    outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2,
					  CONST_BITS+PASS1_BITS+3+1)
			    & RANGE_MASK];
    outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2,
					  CONST_BITS+PASS1_BITS+3+1)
			    & RANGE_MASK];
    outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0,
					  CONST_BITS+PASS1_BITS+3+1)
			    & RANGE_MASK];
    outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0,
					  CONST_BITS+PASS1_BITS+3+1)
			    & RANGE_MASK];

    wsptr += DCTSIZE;		/* advance pointer to next row */
  }
}

/*
 * Perform dequantization and inverse DCT on one block of coefficients,
 * producing a reduced-size 2x2 output block.
 */

GLOBAL(void)
jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
	       JCOEFPTR coef_block,
	       JSAMPARRAY output_buf, JDIMENSION output_col)
{
  INT32 tmp0, tmp10, z1;
  JCOEFPTR inptr;
  ISLOW_MULT_TYPE * quantptr;
  int * wsptr;
  JSAMPROW outptr;
  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
  int ctr;
  int workspace[DCTSIZE*2];	/* buffers data between passes */
  SHIFT_TEMPS

  /* Pass 1: process columns from input, store into work array. */

  inptr = coef_block;
  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
  wsptr = workspace;
  for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) {
    /* Don't bother to process columns 2,4,6 */
    if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6)
      continue;
    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 &&
	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) {
      /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */
      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;

      wsptr[DCTSIZE*0] = dcval;
      wsptr[DCTSIZE*1] = dcval;

      continue;
    }

    /* Even part */

    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
    tmp10 = z1 << (CONST_BITS+2);

    /* Odd part */

    z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
    tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */
    z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
    tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */
    z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
    tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */
    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
    tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */

    /* Final output stage */

    wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2);
    wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2);
  }

  /* Pass 2: process 2 rows from work array, store into output array. */

  wsptr = workspace;
  for (ctr = 0; ctr < 2; ctr++) {
    outptr = output_buf[ctr] + output_col;
    /* It's not clear whether a zero row test is worthwhile here ... */

#ifndef NO_ZERO_ROW_TEST
    if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) {
      /* AC terms all zero */
      JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
				  & RANGE_MASK];

      outptr[0] = dcval;
      outptr[1] = dcval;

      wsptr += DCTSIZE;		/* advance pointer to next row */
      continue;
    }
#endif

    /* Even part */

    tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2);

    /* Odd part */

    tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */
	 + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */
	 + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */
	 + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */

    /* Final output stage */

    outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0,
					  CONST_BITS+PASS1_BITS+3+2)
			    & RANGE_MASK];
    outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0,
					  CONST_BITS+PASS1_BITS+3+2)
			    & RANGE_MASK];

    wsptr += DCTSIZE;		/* advance pointer to next row */
  }
}

/*
 * Perform dequantization and inverse DCT on one block of coefficients,
 * producing a reduced-size 1x1 output block.
 */

GLOBAL(void)
jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
	       JCOEFPTR coef_block,
	       JSAMPARRAY output_buf, JDIMENSION output_col)
{
  int dcval;
  ISLOW_MULT_TYPE * quantptr;
  JSAMPLE *range_limit = IDCT_range_limit(cinfo);
  SHIFT_TEMPS

  /* We hardly need an inverse DCT routine for this: just take the
   * average pixel value, which is one-eighth of the DC coefficient.
   */
  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
  dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
  dcval = (int) DESCALE((INT32) dcval, 3);

  output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
}

#endif /* IDCT_SCALING_SUPPORTED */

license: mit


code:
/*
 * jinclude.h
 *
 * Copyright (C) 1991-1994, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file exists to provide a single place to fix any problems with
 * including the wrong system include files.  (Common problems are taken
 * care of by the standard jconfig symbols, but on really weird systems
 * you may have to edit this file.)
 *
 * NOTE: this file is NOT intended to be included by applications using the
 * JPEG library.  Most applications need only include jpeglib.h.
 */

/* Include auto-config file to find out which system include files we need. */

#include "jconfig.h"		/* auto configuration options */
#define JCONFIG_INCLUDED	/* so that jpeglib.h doesn't do it again */

/*
 * We need the NULL macro and size_t typedef.
 * On an ANSI-conforming system it is sufficient to include <stddef.h>.
 * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
 * pull in <sys/types.h> as well.
 * Note that the core JPEG library does not require <stdio.h>;
 * only the default error handler and data source/destination modules do.
 * But we must pull it in because of the references to FILE in jpeglib.h.
 * You can remove those references if you want to compile without <stdio.h>.
 */

#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef NEED_SYS_TYPES_H
#include <sys/types.h>
#endif

#include <stdio.h>

/*
 * We need memory copying and zeroing functions, plus strncpy().
 * ANSI and System V implementations declare these in <string.h>.
 * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
 * Some systems may declare memset and memcpy in <memory.h>.
 *
 * NOTE: we assume the size parameters to these functions are of type size_t.
 * Change the casts in these macros if not!
 */

#ifdef NEED_BSD_STRINGS

#include <strings.h>
#define MEMZERO(target,size)	bzero((void *)(target), (size_t)(size))
#define MEMCOPY(dest,src,size)	bcopy((const void *)(src), (void *)(dest), (size_t)(size))

#else /* not BSD, assume ANSI/SysV string lib */

#include <string.h>
#define MEMZERO(target,size)	memset((void *)(target), 0, (size_t)(size))
#define MEMCOPY(dest,src,size)	memcpy((void *)(dest), (const void *)(src), (size_t)(size))

#endif

/*
 * In ANSI C, and indeed any rational implementation, size_t is also the
 * type returned by sizeof().  However, it seems there are some irrational
 * implementations out there, in which sizeof() returns an int even though
 * size_t is defined as long or unsigned long.  To ensure consistent results
 * we always use this SIZEOF() macro in place of using sizeof() directly.
 */

#define SIZEOF(object)	((size_t) sizeof(object))

/*
 * The modules that use fread() and fwrite() always invoke them through
 * these macros.  On some systems you may need to twiddle the argument casts.
 * CAUTION: argument order is different from underlying functions!
 */

#define JFREAD(file,buf,sizeofbuf)  \
  ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
#define JFWRITE(file,buf,sizeofbuf)  \
  ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))


code:
/*
 * jmemansi.c
 *
 * Copyright (C) 1992-1996, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file provides a simple generic implementation of the system-
 * dependent portion of the JPEG memory manager.  This implementation
 * assumes that you have the ANSI-standard library routine tmpfile().
 * Also, the problem of determining the amount of memory available
 * is shoved onto the user.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h"		/* import the system-dependent declarations */

#ifndef HAVE_STDLIB_H		/* <stdlib.h> should declare malloc(),free() */
extern void * malloc JPP((size_t size));
extern void free JPP((void *ptr));
#endif

#ifndef SEEK_SET		/* pre-ANSI systems may not define this; */
#define SEEK_SET  0		/* if not, assume 0 is correct */
#endif

/*
 * Memory allocation and freeing are controlled by the regular library
 * routines malloc() and free().
 */

GLOBAL(void *)
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void *) malloc(sizeofobject);
}

GLOBAL(void)
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
  free(object);
}

/*
 * "Large" objects are treated the same as "small" ones.
 * NB: although we include FAR keywords in the routine declarations,
 * this file won't actually work in 80x86 small/medium model; at least,
 * you probably won't be able to process useful-size images in only 64KB.
 */

GLOBAL(void FAR *)
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void FAR *) malloc(sizeofobject);
}

GLOBAL(void)
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
  free(object);
}

/*
 * This routine computes the total memory space available for allocation.
 * It's impossible to do this in a portable way; our current solution is
 * to make the user tell us (with a default value set at compile time).
 * If you can actually get the available space, it's a good idea to subtract
 * a slop factor of 5% or so.
 */

#ifndef DEFAULT_MAX_MEM		/* so can override from makefile */
#define DEFAULT_MAX_MEM		1000000L /* default: one megabyte */
#endif

GLOBAL(long)
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
		    long max_bytes_needed, long already_allocated)
{
  return cinfo->mem->max_memory_to_use - already_allocated;
}

/*
 * Backing store (temporary file) management.
 * Backing store objects are only used when the value returned by
 * jpeg_mem_available is less than the total space needed.  You can dispense
 * with these routines if you have plenty of virtual memory; see jmemnobs.c.
 */

METHODDEF(void)
read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
		    void FAR * buffer_address,
		    long file_offset, long byte_count)
{
  if (fseek(info->temp_file, file_offset, SEEK_SET))
    ERREXIT(cinfo, JERR_TFILE_SEEK);
  if (JFREAD(info->temp_file, buffer_address, byte_count)
      != (size_t) byte_count)
    ERREXIT(cinfo, JERR_TFILE_READ);
}

METHODDEF(void)
write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
		     void FAR * buffer_address,
		     long file_offset, long byte_count)
{
  if (fseek(info->temp_file, file_offset, SEEK_SET))
    ERREXIT(cinfo, JERR_TFILE_SEEK);
  if (JFWRITE(info->temp_file, buffer_address, byte_count)
      != (size_t) byte_count)
    ERREXIT(cinfo, JERR_TFILE_WRITE);
}

METHODDEF(void)
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
{
  fclose(info->temp_file);
  /* Since this implementation uses tmpfile() to create the file,
   * no explicit file deletion is needed.
   */
}

/*
 * Initial opening of a backing-store object.
 *
 * This version uses tmpfile(), which constructs a suitable file name
 * behind the scenes.  We don't have to use info->temp_name[] at all;
 * indeed, we can't even find out the actual name of the temp file.
 */

GLOBAL(void)
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
			 long total_bytes_needed)
{
  if ((info->temp_file = tmpfile()) == NULL)
    ERREXITS(cinfo, JERR_TFILE_CREATE, "");
  info->read_backing_store = read_backing_store;
  info->write_backing_store = write_backing_store;
  info->close_backing_store = close_backing_store;
}

/*
 * These routines take care of any system-dependent initialization and
 * cleanup required.
 */

GLOBAL(long)
jpeg_mem_init (j_common_ptr cinfo)
{
  return DEFAULT_MAX_MEM;	/* default for max_memory_to_use */
}

GLOBAL(void)
jpeg_mem_term (j_common_ptr cinfo)
{
  /* no work */
}


code:
/*
 * jmemdos.c
 *
 * Copyright (C) 1992-1997, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file provides an MS-DOS-compatible implementation of the system-
 * dependent portion of the JPEG memory manager.  Temporary data can be
 * stored in extended or expanded memory as well as in regular DOS files.
 *
 * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
 * if you compile in a small-data memory model; it should NOT be defined if
 * you use a large-data memory model.  This file is not recommended if you
 * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
 * Also, this code will NOT work if struct fields are aligned on greater than
 * 2-byte boundaries.
 *
 * Based on code contributed by Ge' Weijers.
 */

/*
 * If you have both extended and expanded memory, you may want to change the
 * order in which they are tried in jopen_backing_store.  On a 286 machine
 * expanded memory is usually faster, since extended memory access involves
 * an expensive protected-mode-and-back switch.  On 386 and better, extended
 * memory is usually faster.  As distributed, the code tries extended memory
 * first (what? not everyone has a 386? :-).
 *
 * You can disable use of extended/expanded memory entirely by altering these
 * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
 */

#ifndef XMS_SUPPORTED
#define XMS_SUPPORTED  1
#endif
#ifndef EMS_SUPPORTED
#define EMS_SUPPORTED  1
#endif

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h"		/* import the system-dependent declarations */

#ifndef HAVE_STDLIB_H		/* <stdlib.h> should declare these */
extern void * malloc JPP((size_t size));
extern void free JPP((void *ptr));
extern char * getenv JPP((const char * name));
#endif

#ifdef NEED_FAR_POINTERS

#ifdef __TURBOC__
/* These definitions work for Borland C (Turbo C) */
#include <alloc.h>		/* need farmalloc(), farfree() */
#define far_malloc(x)	farmalloc(x)
#define far_free(x)	farfree(x)
#else
/* These definitions work for Microsoft C and compatible compilers */
#include <malloc.h>		/* need _fmalloc(), _ffree() */
#define far_malloc(x)	_fmalloc(x)
#define far_free(x)	_ffree(x)
#endif

#else /* not NEED_FAR_POINTERS */

#define far_malloc(x)	malloc(x)
#define far_free(x)	free(x)

#endif /* NEED_FAR_POINTERS */

#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
#define READ_BINARY	"r"
#else
#define READ_BINARY	"rb"
#endif

#ifndef USE_MSDOS_MEMMGR	/* make sure user got configuration right */
  You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
#endif

#if MAX_ALLOC_CHUNK >= 65535L	/* make sure jconfig.h got this right */
  MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
#endif

/*
 * Declarations for assembly-language support routines (see jmemdosa.asm).
 *
 * The functions are declared "far" as are all their pointer arguments;
 * this ensures the assembly source code will work regardless of the
 * compiler memory model.  We assume "short" is 16 bits, "long" is 32.
 */

typedef void far * XMSDRIVER;	/* actually a pointer to code */
typedef struct {		/* registers for calling XMS driver */
	unsigned short ax, dx, bx;
	void far * ds_si;
      } XMScontext;
typedef struct {		/* registers for calling EMS driver */
	unsigned short ax, dx, bx;
	void far * ds_si;
      } EMScontext;

extern short far jdos_open JPP((short far * handle, char far * filename));
extern short far jdos_close JPP((short handle));
extern short far jdos_seek JPP((short handle, long offset));
extern short far jdos_read JPP((short handle, void far * buffer,
				unsigned short count));
extern short far jdos_write JPP((short handle, void far * buffer,
				 unsigned short count));
extern void far jxms_getdriver JPP((XMSDRIVER far *));
extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
extern short far jems_available JPP((void));
extern void far jems_calldriver JPP((EMScontext far *));

/*
 * Selection of a file name for a temporary file.
 * This is highly system-dependent, and you may want to customize it.
 */

static int next_file_num;	/* to distinguish among several temp files */

LOCAL(void)
select_file_name (char * fname)
{
  const char * env;
  char * ptr;
  FILE * tfile;

  /* Keep generating file names till we find one that's not in use */
  for (;;) {
    /* Get temp directory name from environment TMP or TEMP variable;
     * if none, use "."
     */
    if ((env = (const char *) getenv("TMP")) == NULL)
      if ((env = (const char *) getenv("TEMP")) == NULL)
	env = ".";
    if (*env == '\0')		/* null string means "." */
      env = ".";
    ptr = fname;		/* copy name to fname */
    while (*env != '\0')
      *ptr++ = *env++;
    if (ptr[-1] != '\\' && ptr[-1] != '/')
      *ptr++ = '\\';		/* append backslash if not in env variable */
    /* Append a suitable file name */
    next_file_num++;		/* advance counter */
    sprintf(ptr, "JPG%03d.TMP", next_file_num);
    /* Probe to see if file name is already in use */
    if ((tfile = fopen(fname, READ_BINARY)) == NULL)
      break;
    fclose(tfile);		/* oops, it's there; close tfile & try again */
  }
}

/*
 * Near-memory allocation and freeing are controlled by the regular library
 * routines malloc() and free().
 */

GLOBAL(void *)
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void *) malloc(sizeofobject);
}

GLOBAL(void)
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
  free(object);
}

/*
 * "Large" objects are allocated in far memory, if possible
 */

GLOBAL(void FAR *)
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void FAR *) far_malloc(sizeofobject);
}

GLOBAL(void)
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
  far_free(object);
}

/*
 * This routine computes the total memory space available for allocation.
 * It's impossible to do this in a portable way; our current solution is
 * to make the user tell us (with a default value set at compile time).
 * If you can actually get the available space, it's a good idea to subtract
 * a slop factor of 5% or so.
 */

#ifndef DEFAULT_MAX_MEM		/* so can override from makefile */
#define DEFAULT_MAX_MEM		300000L /* for total usage about 450K */
#endif

GLOBAL(long)
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
		    long max_bytes_needed, long already_allocated)
{
  return cinfo->mem->max_memory_to_use - already_allocated;
}

/*
 * Backing store (temporary file) management.
 * Backing store objects are only used when the value returned by
 * jpeg_mem_available is less than the total space needed.  You can dispense
 * with these routines if you have plenty of virtual memory; see jmemnobs.c.
 */

/*
 * For MS-DOS we support three types of backing storage:
 *   1. Conventional DOS files.  We access these by direct DOS calls rather
 *      than via the stdio package.  This provides a bit better performance,
 *      but the real reason is that the buffers to be read or written are FAR.
 *      The stdio library for small-data memory models can't cope with that.
 *   2. Extended memory, accessed per the XMS V2.0 specification.
 *   3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
 * You'll need copies of those specs to make sense of the related code.
 * The specs are available by Internet FTP from the SIMTEL archives
 * (oak.oakland.edu and its various mirror sites).  See files
 * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
 */

/*
 * Access methods for a DOS file.
 */

METHODDEF(void)
read_file_store (j_common_ptr cinfo, backing_store_ptr info,
		 void FAR * buffer_address,
		 long file_offset, long byte_count)
{
  if (jdos_seek(info->handle.file_handle, file_offset))
    ERREXIT(cinfo, JERR_TFILE_SEEK);
  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  if (byte_count > 65535L)	/* safety check */
    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
  if (jdos_read(info->handle.file_handle, buffer_address,
		(unsigned short) byte_count))
    ERREXIT(cinfo, JERR_TFILE_READ);
}

METHODDEF(void)
write_file_store (j_common_ptr cinfo, backing_store_ptr info,
		  void FAR * buffer_address,
		  long file_offset, long byte_count)
{
  if (jdos_seek(info->handle.file_handle, file_offset))
    ERREXIT(cinfo, JERR_TFILE_SEEK);
  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  if (byte_count > 65535L)	/* safety check */
    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
  if (jdos_write(info->handle.file_handle, buffer_address,
		 (unsigned short) byte_count))
    ERREXIT(cinfo, JERR_TFILE_WRITE);
}

METHODDEF(void)
close_file_store (j_common_ptr cinfo, backing_store_ptr info)
{
  jdos_close(info->handle.file_handle);	/* close the file */
  remove(info->temp_name);	/* delete the file */
/* If your system doesn't have remove(), try unlink() instead.
 * remove() is the ANSI-standard name for this function, but
 * unlink() was more common in pre-ANSI systems.
 */
  TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
}

LOCAL(boolean)
open_file_store (j_common_ptr cinfo, backing_store_ptr info,
		 long total_bytes_needed)
{
  short handle;

  select_file_name(info->temp_name);
  if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
    /* might as well exit since jpeg_open_backing_store will fail anyway */
    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
    return FALSE;
  }
  info->handle.file_handle = handle;
  info->read_backing_store = read_file_store;
  info->write_backing_store = write_file_store;
  info->close_backing_store = close_file_store;
  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
  return TRUE;			/* succeeded */
}

/*
 * Access methods for extended memory.
 */

#if XMS_SUPPORTED

static XMSDRIVER xms_driver;	/* saved address of XMS driver */

typedef union {			/* either long offset or real-mode pointer */
	long offset;
	void far * ptr;
      } XMSPTR;

typedef struct {		/* XMS move specification structure */
	long length;
	XMSH src_handle;
	XMSPTR src;
	XMSH dst_handle;
	XMSPTR dst;
      } XMSspec;

#define ODD(X)	(((X) & 1L) != 0)

METHODDEF(void)
read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
		void FAR * buffer_address,
		long file_offset, long byte_count)
{
  XMScontext ctx;
  XMSspec spec;
  char endbuffer[2];

  /* The XMS driver can't cope with an odd length, so handle the last byte
   * specially if byte_count is odd.  We don't expect this to be common.
   */

  spec.length = byte_count & (~ 1L);
  spec.src_handle = info->handle.xms_handle;
  spec.src.offset = file_offset;
  spec.dst_handle = 0;
  spec.dst.ptr = buffer_address;

  ctx.ds_si = (void far *) & spec;
  ctx.ax = 0x0b00;		/* EMB move */
  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  if (ctx.ax != 1)
    ERREXIT(cinfo, JERR_XMS_READ);

  if (ODD(byte_count)) {
    read_xms_store(cinfo, info, (void FAR *) endbuffer,
		   file_offset + byte_count - 1L, 2L);
    ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
  }
}

METHODDEF(void)
write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
		 void FAR * buffer_address,
		 long file_offset, long byte_count)
{
  XMScontext ctx;
  XMSspec spec;
  char endbuffer[2];

  /* The XMS driver can't cope with an odd length, so handle the last byte
   * specially if byte_count is odd.  We don't expect this to be common.
   */

  spec.length = byte_count & (~ 1L);
  spec.src_handle = 0;
  spec.src.ptr = buffer_address;
  spec.dst_handle = info->handle.xms_handle;
  spec.dst.offset = file_offset;

  ctx.ds_si = (void far *) & spec;
  ctx.ax = 0x0b00;		/* EMB move */
  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  if (ctx.ax != 1)
    ERREXIT(cinfo, JERR_XMS_WRITE);

  if (ODD(byte_count)) {
    read_xms_store(cinfo, info, (void FAR *) endbuffer,
		   file_offset + byte_count - 1L, 2L);
    endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
    write_xms_store(cinfo, info, (void FAR *) endbuffer,
		    file_offset + byte_count - 1L, 2L);
  }
}

METHODDEF(void)
close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
{
  XMScontext ctx;

  ctx.dx = info->handle.xms_handle;
  ctx.ax = 0x0a00;
  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
  /* we ignore any error return from the driver */
}

LOCAL(boolean)
open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
		long total_bytes_needed)
{
  XMScontext ctx;

  /* Get address of XMS driver */
  jxms_getdriver((XMSDRIVER far *) & xms_driver);
  if (xms_driver == NULL)
    return FALSE;		/* no driver to be had */

  /* Get version number, must be >= 2.00 */
  ctx.ax = 0x0000;
  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  if (ctx.ax < (unsigned short) 0x0200)
    return FALSE;

  /* Try to get space (expressed in kilobytes) */
  ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
  ctx.ax = 0x0900;
  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  if (ctx.ax != 1)
    return FALSE;

  /* Succeeded, save the handle and away we go */
  info->handle.xms_handle = ctx.dx;
  info->read_backing_store = read_xms_store;
  info->write_backing_store = write_xms_store;
  info->close_backing_store = close_xms_store;
  TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
  return TRUE;			/* succeeded */
}

#endif /* XMS_SUPPORTED */

/*
 * Access methods for expanded memory.
 */

#if EMS_SUPPORTED

/* The EMS move specification structure requires word and long fields aligned
 * at odd byte boundaries.  Some compilers will align struct fields at even
 * byte boundaries.  While it's usually possible to force byte alignment,
 * that causes an overall performance penalty and may pose problems in merging
 * JPEG into a larger application.  Instead we accept some rather dirty code
 * here.  Note this code would fail if the hardware did not allow odd-byte
 * word & long accesses, but all 80x86 CPUs do.
 */

typedef void far * EMSPTR;

typedef union {			/* EMS move specification structure */
	long length;		/* It's easy to access first 4 bytes */
	char bytes[18];		/* Misaligned fields in here! */
      } EMSspec;

/* Macros for accessing misaligned fields */
#define FIELD_AT(spec,offset,type)  (*((type *) &(spec.bytes[offset])))
#define SRC_TYPE(spec)		FIELD_AT(spec,4,char)
#define SRC_HANDLE(spec)	FIELD_AT(spec,5,EMSH)
#define SRC_OFFSET(spec)	FIELD_AT(spec,7,unsigned short)
#define SRC_PAGE(spec)		FIELD_AT(spec,9,unsigned short)
#define SRC_PTR(spec)		FIELD_AT(spec,7,EMSPTR)
#define DST_TYPE(spec)		FIELD_AT(spec,11,char)
#define DST_HANDLE(spec)	FIELD_AT(spec,12,EMSH)
#define DST_OFFSET(spec)	FIELD_AT(spec,14,unsigned short)
#define DST_PAGE(spec)		FIELD_AT(spec,16,unsigned short)
#define DST_PTR(spec)		FIELD_AT(spec,14,EMSPTR)

#define EMSPAGESIZE	16384L	/* gospel, see the EMS specs */

#define HIBYTE(W)  (((W) >> 8) & 0xFF)
#define LOBYTE(W)  ((W) & 0xFF)

METHODDEF(void)
read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
		void FAR * buffer_address,
		long file_offset, long byte_count)
{
  EMScontext ctx;
  EMSspec spec;

  spec.length = byte_count;
  SRC_TYPE(spec) = 1;
  SRC_HANDLE(spec) = info->handle.ems_handle;
  SRC_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
  DST_TYPE(spec) = 0;
  DST_HANDLE(spec) = 0;
  DST_PTR(spec)    = buffer_address;

  ctx.ds_si = (void far *) & spec;
  ctx.ax = 0x5700;		/* move memory region */
  jems_calldriver((EMScontext far *) & ctx);
  if (HIBYTE(ctx.ax) != 0)
    ERREXIT(cinfo, JERR_EMS_READ);
}

METHODDEF(void)
write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
		 void FAR * buffer_address,
		 long file_offset, long byte_count)
{
  EMScontext ctx;
  EMSspec spec;

  spec.length = byte_count;
  SRC_TYPE(spec) = 0;
  SRC_HANDLE(spec) = 0;
  SRC_PTR(spec)    = buffer_address;
  DST_TYPE(spec) = 1;
  DST_HANDLE(spec) = info->handle.ems_handle;
  DST_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);

  ctx.ds_si = (void far *) & spec;
  ctx.ax = 0x5700;		/* move memory region */
  jems_calldriver((EMScontext far *) & ctx);
  if (HIBYTE(ctx.ax) != 0)
    ERREXIT(cinfo, JERR_EMS_WRITE);
}

METHODDEF(void)
close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
{
  EMScontext ctx;

  ctx.ax = 0x4500;
  ctx.dx = info->handle.ems_handle;
  jems_calldriver((EMScontext far *) & ctx);
  TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
  /* we ignore any error return from the driver */
}

LOCAL(boolean)
open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
		long total_bytes_needed)
{
  EMScontext ctx;

  /* Is EMS driver there? */
  if (! jems_available())
    return FALSE;

  /* Get status, make sure EMS is OK */
  ctx.ax = 0x4000;
  jems_calldriver((EMScontext far *) & ctx);
  if (HIBYTE(ctx.ax) != 0)
    return FALSE;

  /* Get version, must be >= 4.0 */
  ctx.ax = 0x4600;
  jems_calldriver((EMScontext far *) & ctx);
  if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
    return FALSE;

  /* Try to allocate requested space */
  ctx.ax = 0x4300;
  ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
  jems_calldriver((EMScontext far *) & ctx);
  if (HIBYTE(ctx.ax) != 0)
    return FALSE;

  /* Succeeded, save the handle and away we go */
  info->handle.ems_handle = ctx.dx;
  info->read_backing_store = read_ems_store;
  info->write_backing_store = write_ems_store;
  info->close_backing_store = close_ems_store;
  TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
  return TRUE;			/* succeeded */
}

#endif /* EMS_SUPPORTED */

/*
 * Initial opening of a backing-store object.
 */

GLOBAL(void)
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
			 long total_bytes_needed)
{
  /* Try extended memory, then expanded memory, then regular file. */
#if XMS_SUPPORTED
  if (open_xms_store(cinfo, info, total_bytes_needed))
    return;
#endif
#if EMS_SUPPORTED
  if (open_ems_store(cinfo, info, total_bytes_needed))
    return;
#endif
  if (open_file_store(cinfo, info, total_bytes_needed))
    return;
  ERREXITS(cinfo, JERR_TFILE_CREATE, "");
}

/*
 * These routines take care of any system-dependent initialization and
 * cleanup required.
 */

GLOBAL(long)
jpeg_mem_init (j_common_ptr cinfo)
{
  next_file_num = 0;		/* initialize temp file name generator */
  return DEFAULT_MAX_MEM;	/* default for max_memory_to_use */
}

GLOBAL(void)
jpeg_mem_term (j_common_ptr cinfo)
{
  /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
   * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
   */
#ifdef NEED_FHEAPMIN
  _fheapmin();
#endif
}


code:
/*
 * jmemmac.c
 *
 * Copyright (C) 1992-1997, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * jmemmac.c provides an Apple Macintosh implementation of the system-
 * dependent portion of the JPEG memory manager.
 *
 * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
 * JPEG_INTERNALS part of jconfig.h.
 *
 * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
 * instead of malloc and free.  It accurately determines the amount of
 * memory available by using CompactMem.  Notice that if left to its
 * own devices, this code can chew up all available space in the
 * application's zone, with the exception of the rather small "slop"
 * factor computed in jpeg_mem_available().  The application can ensure
 * that more space is left over by reducing max_memory_to_use.
 *
 * Large images are swapped to disk using temporary files and System 7.0+'s
 * temporary folder functionality.
 *
 * Note that jmemmac.c depends on two features of MacOS that were first
 * introduced in System 7: FindFolder and the FSSpec-based calls.
 * If your application uses jmemmac.c and is run under System 6 or earlier,
 * and the jpeg library decides it needs a temporary file, it will abort,
 * printing error messages about requiring System 7.  (If no temporary files
 * are created, it will run fine.)
 *
 * If you want to use jmemmac.c in an application that might be used with
 * System 6 or earlier, then you should remove dependencies on FindFolder
 * and the FSSpec calls.  You will need to replace FindFolder with some
 * other mechanism for finding a place to put temporary files, and you
 * should replace the FSSpec calls with their HFS equivalents:
 *
 *     FSpDelete     ->  HDelete
 *     FSpGetFInfo   ->  HGetFInfo
 *     FSpCreate     ->  HCreate
 *     FSpOpenDF     ->  HOpen      *** Note: not HOpenDF ***
 *     FSMakeFSSpec  ->  (fill in spec by hand.)
 *
 * (Use HOpen instead of HOpenDF.  HOpen is just a glue-interface to PBHOpen,
 * which is on all HFS macs.  HOpenDF is a System 7 addition which avoids the
 * ages-old problem of names starting with a period.)
 *
 * Contributed by Sam Bushell (jsam@iagu.on.net) and
 * Dan Gildor (gyld@in-touch.com).
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h"    /* import the system-dependent declarations */

#ifndef USE_MAC_MEMMGR	/* make sure user got configuration right */
  You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
#endif

#include <Memory.h>     /* we use the MacOS memory manager */
#include <Files.h>      /* we use the MacOS File stuff */
#include <Folders.h>    /* we use the MacOS HFS stuff */
#include <Script.h>     /* for smSystemScript */
#include <Gestalt.h>    /* we use Gestalt to test for specific functionality */

#ifndef TEMP_FILE_NAME		/* can override from jconfig.h or Makefile */
#define TEMP_FILE_NAME  "JPG%03d.TMP"
#endif

static int next_file_num;	/* to distinguish among several temp files */

/*
 * Memory allocation and freeing are controlled by the MacOS library
 * routines NewPtr() and DisposePtr(), which allocate fixed-address
 * storage.  Unfortunately, the IJG library isn't smart enough to cope
 * with relocatable storage.
 */

GLOBAL(void *)
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void *) NewPtr(sizeofobject);
}

GLOBAL(void)
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
  DisposePtr((Ptr) object);
}

/*
 * "Large" objects are treated the same as "small" ones.
 * NB: we include FAR keywords in the routine declarations simply for
 * consistency with the rest of the IJG code; FAR should expand to empty
 * on rational architectures like the Mac.
 */

GLOBAL(void FAR *)
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
  return (void FAR *) NewPtr(sizeofobject);
}

GLOBAL(void)
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
  DisposePtr((Ptr) object);
}

/*
 * This routine computes the total memory space available for allocation.
 */

GLOBAL(long)
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
		    long max_bytes_needed, long already_allocated)
{
  long limit = cinfo->mem->max_memory_to_use - already_allocated;
  long slop, mem;

  /* Don't ask for more than what application has told us we may use */
  if (max_bytes_needed > limit && limit > 0)
    max_bytes_needed = limit;
  /* Find whether there's a big enough free block in the heap.
   * CompactMem tries to create a contiguous block of the requested size,
   * and then returns the size of the largest free block (which could be
   * much more or much less than we asked for).
   * We add some slop to ensure we don't use up all available memory.
   */
  slop = max_bytes_needed / 16 + 32768L;
  mem = CompactMem(max_bytes_needed + slop) - slop;
  if (mem < 0)
    mem = 0;			/* sigh, couldn't even get the slop */
  /* Don't take more than the application says we can have */
  if (mem > limit && limit > 0)
    mem = limit;
  return mem;
}

/*
 * Backing store (temporary file) management.
 * Backing store objects are only used when the value returned by
 * jpeg_mem_available is less than the total space needed.  You can dispense
 * with these routines if you have plenty of virtual memory; see jmemnobs.c.
 */

METHODDEF(void)
read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
		    void FAR * buffer_address,
		    long file_offset, long byte_count)
{
  long bytes = byte_count;
  long retVal;

  if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
    ERREXIT(cinfo, JERR_TFILE_SEEK);

  retVal = FSRead ( info->temp_file, &bytes,
		    (unsigned char *) buffer_address );
  if ( retVal != noErr || bytes != byte_count )
    ERREXIT(cinfo, JERR_TFILE_READ);
}

METHODDEF(void)
write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
		     void FAR * buffer_address,
		     long file_offset, long byte_count)
{
  long bytes = byte_count;
  long retVal;

  if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
    ERREXIT(cinfo, JERR_TFILE_SEEK);

  retVal = FSWrite ( info->temp_file, &bytes,
		     (unsigned char *) buffer_address );
  if ( retVal != noErr || bytes != byte_count )
    ERREXIT(cinfo, JERR_TFILE_WRITE);
}

METHODDEF(void)
close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
{
  FSClose ( info->temp_file );
  FSpDelete ( &(info->tempSpec) );
}

/*
 * Initial opening of a backing-store object.
 *
 * This version uses FindFolder to find the Temporary Items folder,
 * and puts the temporary file in there.
 */

GLOBAL(void)
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
			 long total_bytes_needed)
{
  short         tmpRef, vRefNum;
  long          dirID;
  FInfo         finderInfo;
  FSSpec        theSpec;
  Str255        fName;
  OSErr         osErr;
  long          gestaltResponse = 0;

  /* Check that FSSpec calls are available. */
  osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
  if ( ( osErr != noErr )
       || !( gestaltResponse & (1<<gestaltHasFSSpecCalls) ) )
    ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required");
  /* TO DO: add a proper error message to jerror.h. */

  /* Check that FindFolder is available. */
  osErr = Gestalt( gestaltFindFolderAttr, &gestaltResponse );
  if ( ( osErr != noErr )
       || !( gestaltResponse & (1<<gestaltFindFolderPresent) ) )
    ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required.");
  /* TO DO: add a proper error message to jerror.h. */

  osErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
                       &vRefNum, &dirID );
  if ( osErr != noErr )
    ERREXITS(cinfo, JERR_TFILE_CREATE, "- temporary items folder unavailable");
  /* TO DO: Try putting the temp files somewhere else. */

  /* Keep generating file names till we find one that's not in use */
  for (;;) {
    next_file_num++;		/* advance counter */

    sprintf(info->temp_name, TEMP_FILE_NAME, next_file_num);
    strcpy ( (Ptr)fName+1, info->temp_name );
    *fName = strlen (info->temp_name);
    osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );

    if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
      break;
  }

  osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
  if ( osErr != noErr )
    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);

  osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
  if ( osErr != noErr )
    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);

  info->tempSpec = theSpec;

  info->read_backing_store = read_backing_store;
  info->write_backing_store = write_backing_store;
  info->close_backing_store = close_backing_store;
  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
}

/*
 * These routines take care of any system-dependent initialization and
 * cleanup required.
 */

GLOBAL(long)
jpeg_mem_init (j_common_ptr cinfo)
{
  next_file_num = 0;

  /* max_memory_to_use will be initialized to FreeMem()'s result;
   * the calling application might later reduce it, for example
   * to leave room to invoke multiple JPEG objects.
   * Note that FreeMem returns the total number of free bytes;
   * it may not be possible to allocate a single block of this size.
   */
  return FreeMem();
}

GLOBAL(void)
jpeg_mem_term (j_common_ptr cinfo)
{
  /* no work */
}