Commit message: Bug 701793: check we are within buffer before comparing buffer contents.

Fixes:
    ./sanbin/gs -sOutputFile=tmp -sDEVICE=mj700v2c ../bug-701793.pdf
CVE: CVE-2020-16292
CWE: CWE-787
Vulnerability description: A buffer overflow vulnerability in mj_raster_cmd() in contrib/japanese/gdevmjc.c of Artifex Software GhostScript v9.50 allows a remote attacker to cause a denial of service via a crafted PDF file. This is fixed in v9.51.

Project: ghostpdl
File: gdevmjc.c

DifSubK( int d0 , short *a4 , short *a5 )
{
/*
                                +---+---+---+
                                |   | X |1/2|
                                +---+---+---+
                                |1/4|1/8|1/8|
                                +---+---+---+
*/
        *a4++   =  0;
        d0 >>= 1;
        *a4     += d0;
        d0 >>= 1;
        *(a5-1) += d0;
        d0 >>= 1;
        *a5++   += d0;
        *a5     += d0;
}

Project: ghostpdl
File: gdevmjc.c

bld_barrier( short **bar , int x )
{
        int i , j;

        short t;
        short *p;
        short *b;
        short *dat = barrier_dat + 1;

        p = *bar++ + x + 1;

        for ( i = 0 ; i < 11 ; i++ ) {
                t = *dat++;
                if (*p < t )
                        *p = t;
                p++;
        }

        for ( j = 0 ; j < 11 ; j++ ) {
                p = *bar++ + x;
                b = p;

                t = *dat++;
                if (*p < t )
                        *p = t;
                p++;
                for ( i = 0 ; i < 11 ; i++ ) {
                        t = *dat++;
                        if (*p < t )
                                *p = t;
                        p++;

                        if (*(--b) < t )
                                *b = t;
                }
        }
}

Project: ghostpdl
File: gdevmjc.c

xtal_plane( byte *dp , short *buf[] , byte *oP , short **bar , int plane_size , int xtalbuff_size )
{
        int i;
        int j;
        int x = 0;
        byte bitmask;
        byte out;
        short *p;
        short *b1 , *b2;

        b1 = buf[0];
        b2 = buf[1];
/*
        for ( i = 0 ; i < 100 ; i++ ) {
                dprintf1("[%04X]",bar[0][i]);
        }
        dprintf("\n");
*/
        for ( i = 0 ; i < plane_size ; i++ ) {
                bitmask = 0x80;
                out = 0;
                for ( j = 0 ; j < 8 ; j++ ) {
                        out |= Xtal( bitmask , (short)(*dp) << 6 , x++ , bar , b1++ , b2++ );
                        dp += 4;
                        bitmask >>= 1;
                }
                *oP++ = out;
        }
/*dprintf("\n");*/
        p = buf[0];
/*	dprintf("\n"); */
        buf[0] = buf[1];
        buf[1] = p;

        p = bar[0];
        for ( i = 0 ; i < plane_size*8 ; i++ )
                *p++ = 0;

        /*	memset( p, 0, (xtalbuff_size-16) * W);*/
        p = bar[0];
        for ( i = 0 ; i <= 14 ; i++ )
                bar[i] = bar[i+1];
        bar[15] = p;
}

Project: ghostpdl
File: gdevmjc.c

expand_line(word *line, int linesize, int bpp, int ebpp)
{
  int endline = linesize;
  byte *start = (byte *)line;
  register byte *in, *out;

  if (bpp == 16)              /* 16 to 24 (cmy) if required */
    { register byte b0, b1;
      endline = ((endline + 1) / 2);
      in = start + endline * 2;
      out = start + (endline *= 3);

      while (in > start)
        { b0 = *--in;
          b1 = *--in;
          *--out = (b0 << 3) + ((b0 >> 2) & 0x7);
          *--out = (b1 << 5) + ((b0 >> 3)  & 0x1c) + ((b1 >> 1) & 0x3);
          *--out = (b1 & 0xf8) + (b1 >> 5);
        }
    }

  if (ebpp == 32)             /* 24 (cmy) to 32 (cmyk) if required */
    { register byte c, m, y, k;
      endline = ((endline + 2) / 3);
      in = start + endline * 3;
      out = start + endline * 4;

      while (in > start)
        { y = *--in;
          m = *--in;
          c = *--in;
          k = c < m ? (c < y ? c : y) : (m < y ? m : y);
          *--out = y - k;
          *--out = m - k;
          *--out = c - k;
          *--out = k;
        }
    }
}

Project: ghostpdl
File: gdevmjc.c

mj500c_put_params(gx_device *pdev, gs_param_list *plist)
{
  return mj_put_params(pdev, plist, MJ500C);
}

Project: ghostpdl
File: gdevmjc.c

mj500c_open(gx_device * pdev)
{
  return mj_open(pdev, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

mj6000c_print_page(gx_device_printer * pdev, gp_file * prn_stream)
{
  return mj_print_page(pdev, prn_stream, MJ6000C);
}

Project: ghostpdl
File: gdevmjc.c

put_param_int(gs_param_list *plist, gs_param_name pname, int *pvalue, int minval, int maxval, int ecode)
{       int code, value;
        switch ( code = param_read_int(plist, pname, &value) )
        {
        default:
                return code;
        case 1:
                return ecode;
        case 0:
                if ( value < minval || value > maxval )
                   param_signal_error(plist, pname, gs_error_rangecheck);
                *pvalue = value;
                return (ecode < 0 ? ecode : 1);
        }
}

Project: ghostpdl
File: gdevmjc.c

mj_raster_cmd(int c_id, int in_size, byte* in, byte* buf2,
              gx_device_printer* pdev, gp_file* prn_stream)
{
  int band_size = 1;	/* 1, 8, or 24 */

  byte *out = buf2;

  int width = in_size;
  int count;

  byte* in_end = in + in_size;

  static char colour_number[] = "\004\001\002\000"; /* color ID for MJ700V2C */

  byte *inp = in;
  byte *outp = out;
  register byte *p, *q;

  /* specifying a colour */

  gp_fputs("\033r",prn_stream); /* secape sequence to specify a color */
  gp_fputc(colour_number[c_id], prn_stream);

  /* end of specifying a colour */

        /* Following codes for compression are borrowed from gdevescp.c */

  for( p = inp, q = inp + 1 ; q < in_end ; ) {

    if( *p != *q ) {
      p += 2;
      q += 2;
    } else {

      /*
       ** Check behind us, just in case:
       */

      if( p > inp && *p == *(p-1) )
           p--;

      /*
       ** walk forward, looking for matches:
       */

      for( q++ ; q < in_end && *q == *p ; q++ ) {
        if( (q-p) >= 128 ) {
          if( p > inp ) {
            count = p - inp;
            while( count > 128 ) {
              *outp++ = '\177';
              memcpy(outp, inp, 128);	/* data */
              inp += 128;
              outp += 128;
              count -= 128;
            }
            *outp++ = (char) (count - 1); /* count */
            memcpy(outp, inp, count);	/* data */
            outp += count;
          }
          *outp++ = '\201';	/* Repeat 128 times */
          *outp++ = *p;
          p += 128;
          inp = p;
        }
      }

      if( (q - p) > 2 ) {	/* output this sequence */
        if( p > inp ) {
          count = p - inp;
          while( count > 128 ) {
            *outp++ = '\177';
            memcpy(outp, inp, 128);	/* data */
            inp += 128;
            outp += 128;
            count -= 128;
          }
          *outp++ = (char) (count - 1);	/* byte count */
          memcpy(outp, inp, count);	/* data */
          outp += count;
        }
        count = q - p;
        *outp++ = (char) (256 - count + 1);
        *outp++ = *p;
        p += count;
        inp = p;
      } else	/* add to non-repeating data list */
           p = q;
      if( q < in_end )
           q++;
    }
  }

  /*
   ** copy remaining part of line:
   */

  if( inp < in_end ) {

    count = in_end - inp;

    /*
     ** If we've had a long run of varying data followed by a
     ** sequence of repeated data and then hit the end of line,
     ** it's possible to get data counts > 128.
     */

    while( count > 128 ) {
      *outp++ = '\177';
      memcpy(outp, inp, 128);	/* data */
      inp += 128;
      outp += 128;
      count -= 128;
    }

    *outp++ = (char) (count - 1);	/* byte count */
    memcpy(outp, inp, count);	/* data */
    outp += count;
  }
  /*
   ** Output data:
   */

  gp_fwrite("\033.\001", 1, 3, prn_stream);

  if(pdev->y_pixels_per_inch == 720)
       gp_fputc('\005', prn_stream);
  else if(pdev->y_pixels_per_inch == 180)
       gp_fputc('\024', prn_stream);
  else /* pdev->y_pixels_per_inch == 360 */
       gp_fputc('\012', prn_stream);

  if(pdev->x_pixels_per_inch == 720)
       gp_fputc('\005', prn_stream);
  else if(pdev->x_pixels_per_inch == 180)
       gp_fputc('\024', prn_stream);
  else /* pdev->x_pixels_per_inch == 360 */
       gp_fputc('\012', prn_stream);

  gp_fputc(band_size, prn_stream);

  gp_fputc((width << 3) & 0xff, prn_stream);
  gp_fputc( width >> 5,	   prn_stream);

  gp_fwrite(out, 1, (outp - out), prn_stream);

  gp_fputc('\r', prn_stream);

  return 0;
}

Project: ghostpdl
File: gdevmjc.c

Xtal( byte bitmask , short d0 , int x , short **bar , short *b1 , short *b2 )
{
        short *a2;

        if (d0 != 0)
                d0 += *b1;

        a2 = *bar + x;

/*dprintf1("[%02X]",*a2);*/
        if (*a2 < d0) {
                d0 -= 16400;
                if (-4096 >= d0) {
                        DifSubK( d0 , b1 , b2 );
                        bld_barrier( bar , x );
                } else {
                        DifSubK( d0 , b1 , b2 );
                }
                return( bitmask );
        } else {
                if (d0 > 56)
                        d0 -= 56;
                DifSubK( d0 , b1 , b2 );
                return( 0 );
        }
}

Project: ghostpdl
File: gdevmjc.c

mj700v2c_open(gx_device * pdev)
{
  return mj_open(pdev, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

mj8000c_open(gx_device * pdev)
{
  return mj_open(pdev, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

mjc_correct_color(gx_device_printer *pdev, gx_color_index ci)
{
  gx_color_index c, m, y, k, co;
  gx_color_index k2, k3, k4;
#if __WORDSIZE == 64
  gx_color_index c2, m2, y2, k5, k6, k7, k8;
#endif
  const uint cmask = 0xff;
  uint dn = mj->density;
  uint mjy = mj->yellow;
  uint mjc = mj->cyan;
  uint mjm = mj->magenta;
  uint mjb = mj->black;
  switch (pdev->color_info.depth) {
 case 8:
    k = ((ci & cmask) * (mjb)) >> 10;
    k = (k < cmask) ? k : cmask;
    k2 = (((ci >> 8) & cmask) * (mjb)) >> 10;
    k2 = (k2 < cmask) ? k2 : cmask;
    k3 = (((ci >> 16) & cmask) * (mjb)) >> 10;
    k3 = (k3 < cmask) ? k3 : cmask;
    k4 = (((ci >> 24) & cmask) * (mjb)) >> 10;
    k4 = (k4 < cmask) ? k4 : cmask;
#if __WORDSIZE == 64
    /* This code is ugly... (for 64 bit OS) */
    if (sizeof(word) == 8)
      {
        k5 = (((ci >> 32) & cmask) * (mjb)) >> 10;
        k5 = (k5 < cmask) ? k5 : cmask;
        k6 = (((ci >> 40) & cmask) * (mjb)) >> 10;
        k6 = (k6 < cmask) ? k6 : cmask;
        k7 = (((ci >> 48) & cmask) * (mjb)) >> 10;
        k7 = (k7 < cmask) ? k7 : cmask;
        k8 = (((ci >> 56) & cmask) * (mjb)) >> 10;
        k8 = (k8 < cmask) ? k8 : cmask;
        co = k + (k2 << 8) + (k3 << 16) + (k4 << 24)
          + (k5 << 32) + (k6 << 40) + (k7 << 48) + (k8 << 56);
        if (ci != co)
          dprintf1("%s\n", "error");
        return co;
      }
#endif
    return k + (k2 << 8) + (k3 << 16) + (k << 24);
    break;
 case 32:
    y = ((ci & cmask) * mjy * dn) >> 20;
    y = (y < cmask) ? y : cmask;
    m = (((ci >> 8) & cmask) * mjm * dn) >> 20;
    m = (m < cmask) ? m : cmask;
    c = (((ci >> 16) & cmask) * mjc * dn) >> 20;
    c = (c < cmask) ? c : cmask;
    k = (((ci >> 24) & cmask) * mjb * dn) >> 20;
    k = (k < cmask) ? k : cmask;
#if __WORDSIZE == 64
    /* This code is ugly... (for 64 bit OS) */
    if (sizeof(word) == 8)
      {
        y2 = (((ci >> 32) & cmask) * mjy * dn) >> 20;
        y2 = (y2 < cmask) ? y2 : cmask;
        m2 = (((ci >> 40) & cmask) * mjm * dn) >> 20;
        m2 = (m2 < cmask) ? m2 : cmask;
        c2 = (((ci >> 48) & cmask) * mjc * dn) >> 20;
        c2 = (c2 < cmask) ? c2 : cmask;
        k2 = (((ci >> 56) & cmask) * mjb * dn) >> 20;
        k2 = (k2 < cmask) ? k2 : cmask;

        co = y + (m << 8) + (c << 16) + (k << 24)
          + (y2 << 32) + (m2 << 40) + (c2 << 48) + (k2 << 56);

        return co;
      }
#endif
    co =    (y + (m << 8) + (c << 16) + (k << 24));
/*     dprintf6("%d,%d:%d,%d,%d,%d\n", ci,co, y, m, c, k); */
    return co;
/*    return (gx_color_value_to_byte(y) +
            (gx_color_value_to_byte(m) << 8) +
            ((word)gx_color_value_to_byte(c) << 16) +
            ((word)gx_color_value_to_byte(k) << 24)); */
    break;
  }
  return ci;
}

Project: ghostpdl
File: gdevmjc.c

mj700v2c_print_page(gx_device_printer * pdev, gp_file * prn_stream)
{
  return mj_print_page(pdev, prn_stream, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

mj_print_page(gx_device_printer * pdev, gp_file * prn_stream, int ptype)
{
/*  int line_size = gdev_prn_rasterwidth(pdev, 0); */
  int line_size = gdev_prn_raster(pdev);
  int line_size_words = (line_size + W - 1) / W;
  int num_comps = pdev->color_info.num_components;
  int bits_per_pixel = pdev->color_info.depth;
  int storage_bpp = bits_per_pixel;
  int expanded_bpp = bits_per_pixel;
  int plane_size, databuff_size;
  int errbuff_size = 0;
  int outbuff_size = 0;
  int scan = 0;
  int *errors[2];
  byte *data[4], *plane_data[4][4], *out_data;
  byte *out_row;
  word *storage;
  uint storage_size_words;
  uint mj_tmp_buf_size;
  byte* mj_tmp_buf;
  int xtalbuff_size;
  short *xtalbuff;
  short *Cbar[16];
  short *Mbar[16];
  short *Ybar[16];
  short *Kbar[16];
  short *Cbuf[2];
  short *Mbuf[2];
  short *Ybuf[2];
  short *Kbuf[2];

  /* Tricks and cheats ... */
  if (num_comps == 3) num_comps = 4;            /* print CMYK */

  if (storage_bpp == 8 && num_comps >= 3)
    bits_per_pixel = expanded_bpp = 3;  /* Only 3 bits of each byte used */

  plane_size = calc_buffsize(line_size, storage_bpp);

  if (bits_per_pixel == 1) {            /* Data printed direct from i/p */
    databuff_size = 0;                  /* so no data buffer required, */
    outbuff_size = plane_size * 4;      /* but need separate output buffers */
  }

  if (bits_per_pixel > 4) {             /* Error buffer for FS dithering */
    expanded_bpp = storage_bpp =        /* 8, 24 or 32 bits */
      num_comps * 8;
    errbuff_size =                      /* 4n extra values for line ends */
      calc_buffsize((plane_size * expanded_bpp + num_comps * 4) * I, 1);
  }

  databuff_size = plane_size * storage_bpp;

  storage_size_words = ((plane_size + plane_size) * num_comps +
                        databuff_size + errbuff_size + outbuff_size) / W;

/* NOZ */
  xtalbuff_size = plane_size*8 + 64;
  xtalbuff = (short *) gs_malloc(pdev->memory->non_gc_memory,  xtalbuff_size*(16*4+2*4) , W, "mj_colour_print_barrier");
  memset(xtalbuff, 0, xtalbuff_size*(16*4+2*4) * W);
  {
        int i;
        short *p = xtalbuff + 16;
        for ( i = 0 ; i < 16 ; i++ ) {
                Cbar[i] = p;
                p += xtalbuff_size;
        }
        for ( i = 0 ; i < 16 ; i++ ) {
                Mbar[i] = p;
                p += xtalbuff_size;
        }
        for ( i = 0 ; i < 16 ; i++ ) {
                Ybar[i] = p;
                p += xtalbuff_size;
        }
        for ( i = 0 ; i < 16 ; i++ ) {
                Kbar[i] = p;
                p += xtalbuff_size;
        }
        Cbuf[0] = p;
        p += xtalbuff_size;
        Cbuf[1] = p;
        p += xtalbuff_size;
        Mbuf[0] = p;
        p += xtalbuff_size;
        Mbuf[1] = p;
        p += xtalbuff_size;
        Ybuf[0] = p;
        p += xtalbuff_size;
        Ybuf[1] = p;
        p += xtalbuff_size;
        Kbuf[0] = p;
        p += xtalbuff_size;
        Kbuf[1] = p;
        p += xtalbuff_size;
  }

  storage = (word *) gs_malloc(pdev->memory->non_gc_memory, storage_size_words, W, "mj_colour_print_page");

/* prepare a temporary buffer for mj_raster_cmd */

  mj_tmp_buf_size = plane_size;
  mj_tmp_buf = (byte *) gs_malloc(pdev->memory->non_gc_memory, mj_tmp_buf_size, W ,"mj_raster_buffer");

#if 0
  dprintf1("storage_size_words :%d\n", storage_size_words);
  dprintf1("mj_tmp_buf_size :%d\n", mj_tmp_buf_size);
#endif
  /*
   * The principal data pointers are stored as pairs of values, with
   * the selection being made by the 'scan' variable. The function of the
   * scan variable is overloaded, as it controls both the alternating
   * raster scan direction used in the Floyd-Steinberg dithering and also
   * the buffer alternation required for line-difference compression.
   *
   * Thus, the number of pointers required is as follows:
   *
   *   errors:      2  (scan direction only)
   *   data:        4  (scan direction and alternating buffers)
   *   plane_data:  4  (scan direction and alternating buffers)
   */

  if (storage == NULL || mj_tmp_buf == NULL) /* can't allocate working area */
    return_error(gs_error_VMerror);
  else {
    int i;
    byte *p = out_data = out_row = (byte *)storage;
    data[0] = data[1] = data[2] = p;
    data[3] = p + databuff_size;
    if (bits_per_pixel > 1) {
      p += databuff_size;
    }
    if (bits_per_pixel > 4) {
      errors[0] = (int *)p + num_comps * 2;
      errors[1] = errors[0] + databuff_size;
      p += errbuff_size;
    }
    for (i = 0; i < num_comps; i++) {
      plane_data[0][i] = plane_data[2][i] = p;
      p += plane_size;
    }
    for (i = 0; i < num_comps; i++) {
      plane_data[1][i] = p;
      plane_data[3][i] = p + plane_size;
      p += plane_size;
    }
    if (bits_per_pixel == 1) {
      out_data = out_row = p;	  /* size is outbuff_size * 4 */
      data[1] += databuff_size;   /* coincides with plane_data pointers */
      data[3] += databuff_size;
    }
  }

  /* Clear temp storage */
  memset(storage, 0, storage_size_words * W);

  /* Initialize printer. */
  {
    /** Reset printer, enter graphics mode: */

    gp_fwrite("\033@\033(G\001\000\001", sizeof(byte), 8, prn_stream);

    /** Micro-weave-Mode */
    if (mj->microweave) {
      gp_fwrite("\033(i\001\000\001", sizeof(byte), 6, prn_stream);
    }
    /** Dot-Size define */
    if (mj->dotsize) {
      gp_fwrite("\033(e\002\000\000\001", sizeof(byte), 7, prn_stream);
    }

    if (ptype == MJ6000C || ptype == MJ8000C) {
      /* Select Monochrome/Color Printing Mode Command */
      if (pdev->color_info.depth == 8)
        gp_fwrite("\033(K\002\000\000\001", sizeof(byte), 7, prn_stream);
    }

    if (mj->direction) /* set the direction of the head */
      gp_fwrite("\033U\1", 1, 3, prn_stream); /* Unidirectional Printing */
    else
      gp_fwrite("\033U\0", 1, 3, prn_stream);

#if 0
#ifdef A4
        /*
        ** After reset, the Stylus is set up for US letter paper.
        ** We need to set the page size appropriately for A4 paper.
        ** For some bizarre reason the ESC/P2 language wants the bottom
        ** margin measured from the *top* of the page:
        */

        gp_fwrite("\033(U\001\0\n\033(C\002\0t\020\033(c\004\0\0\0t\020",
                                                        1, 22, prn_stream);
#endif
#endif

        /*
        ** Set the line spacing to match the band height:
        */

        if( pdev->y_pixels_per_inch >= 720 )
          gp_fwrite("\033(U\001\0\005\033+\001", sizeof(byte), 9, prn_stream);
        else if( pdev->y_pixels_per_inch >= 360 )
           gp_fwrite("\033(U\001\0\012\033+\001", sizeof(byte), 9, prn_stream);
        else /* 180 dpi */
           gp_fwrite("\033(U\001\0\024\033+\002", sizeof(byte), 9, prn_stream);

    /* set the length of the page */
        gp_fwrite("\033(C\2\0", sizeof(byte), 5, prn_stream);
        gp_fputc(((pdev->height) % 256), prn_stream);
        gp_fputc(((pdev->height) / 256), prn_stream);
  }

#define MOFFSET (pdev->t_margin - MJ700V2C_PRINT_LIMIT) /* Print position */

  {
    int MJ_MARGIN_MM = 55;
    uint top_skip = ( MJ_MARGIN_MM  * pdev->y_pixels_per_inch ) / 254;
    top_skip = (top_skip ^ (-1)) & 65536;
    gp_fwrite("\033(V\2\0\0\0",sizeof(byte), 7, prn_stream);
    gp_fwrite("\033(v\2\0\0\xff",sizeof(byte), 7, prn_stream);
  }

  /* Send each scan line in turn */
  {
    long int lend = pdev->height -
      (dev_t_margin_points(pdev) + dev_b_margin_points(pdev));
    int cErr, mErr, yErr, kErr;
    int this_pass, i;
    long int lnum;
    int num_blank_lines = 0;
    int start_rows = (num_comps == 1) ?
      HEAD_ROWS_MONO - 1 : HEAD_ROWS_COLOUR - 1;
    word rmask = ~(word) 0 << ((-pdev->width * storage_bpp) & (W * 8 - 1));

    cErr = mErr = yErr = kErr = 0;

    if (bits_per_pixel > 4) { /* Randomly seed initial error buffer */
      int *ep = errors[0];
      for (i = 0; i < databuff_size; i++) {
        *ep++ = (rand() % (MAXVALUE / 2))  - MAXVALUE / 4;
      }
    }

    this_pass = start_rows;

    lnum = 0;

    /* for Debug */

    for (; lnum < lend; lnum++) {
      word *data_words = (word *)data[scan];
      register word *end_data = data_words + line_size_words;
      gx_color_index *p_data;

      gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);

      /* Mask off 1-bits beyond the line width. */
      end_data[-1] &= rmask;

      /* Remove trailing 0s. */
      while (end_data > data_words && end_data[-1] == 0)
        end_data--;
      if (end_data == data_words) {	/* Blank line */
        num_blank_lines++;
        continue; /* skip to  for (lnum) loop */
      }
      /* Skip blank lines if any */
      if (num_blank_lines > 0 ) {
        mj_v_skip(num_blank_lines, pdev, prn_stream);
        memset(plane_data[1 - scan][0], 0, plane_size * num_comps);
        num_blank_lines = 0;
        this_pass = start_rows;
      }

      /* Correct color depth. */
          if (mj->density != 1024 || mj->yellow != 1024 || mj->cyan != 1024
                  || mj->magenta != 1024 || mj->black != 1024 ) {
              for (p_data = (gx_color_index*) data_words; p_data < (gx_color_index *)end_data; p_data++) {
                        *p_data = mjc_correct_color(pdev, *p_data);
              }
          }

      {			/* Printing non-blank lines */
        register byte *kP = plane_data[scan + 2][3];
        register byte *cP = plane_data[scan + 2][2];
        register byte *mP = plane_data[scan + 2][1];
        register byte *yP = plane_data[scan + 2][0];
        register byte *dp = data[scan + 2];
        int i, j;
        byte *odp;

        if (this_pass)
          this_pass--;
        else
          this_pass = start_rows;

        if (expanded_bpp > bits_per_pixel)   /* Expand line if required */
          expand_line(data_words, line_size, bits_per_pixel, expanded_bpp);

        /* In colour modes, we have some bit-shuffling to do before
         * we can print the data; in FS mode we also have the
         * dithering to take care of. */
        switch (expanded_bpp) {    /* Can be 1, 3, 8, 24 or 32 */
        case 3:
          /* Transpose the data to get pixel planes. */
          for (i = 0, odp = plane_data[scan][0]; i < databuff_size;
               i += 8, odp++) {	/* The following is for 16-bit
                                 * machines */
#define spread3(c)\
    { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L }
            static word spr40[8] = spread3(0x40);
            static word spr08[8] = spread3(8);
            static word spr02[8] = spread3(2);
            register byte *dp = data[scan] + i;
            register word pword =
            (spr40[dp[0]] << 1) +
            (spr40[dp[1]]) +
            (spr40[dp[2]] >> 1) +
            (spr08[dp[3]] << 1) +
            (spr08[dp[4]]) +
            (spr08[dp[5]] >> 1) +
            (spr02[dp[6]]) +
            (spr02[dp[7]] >> 1);
            odp[0] = (byte) (pword >> 16);
            odp[plane_size] = (byte) (pword >> 8);
            odp[plane_size * 2] = (byte) (pword);
          }
          break;

        case 8:
          FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
                  cP, mP, yP, kP, 1);
          break;
        case 24:
          FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
                  cP, mP, yP, kP, 3);
          break;
        case 32:
                if (scan == 1) {
                        dp -= plane_size*8*4;
                        cP -= plane_size;
                        mP -= plane_size;
                        yP -= plane_size;
                        kP -= plane_size;
                }
/*
{
        byte *p = dp;
        int i;
        for ( i = 0 ; i < plane_size ; i++ ) {
                dprintf4 ( "[%02X%02X%02X%02X]" , p[0] , p[1] , p[2] , p[3] );
                p += 4;
        }
        dprintf("\n");

}
*/
/*
          FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr,
                  cP, mP, yP, kP, 4);
*/
/* NOZ */
          xtal_plane( dp++ , Kbuf , kP , Kbar , plane_size , xtalbuff_size );
          xtal_plane( dp++ , Cbuf , cP , Cbar , plane_size , xtalbuff_size );
          xtal_plane( dp++ , Mbuf , mP , Mbar , plane_size , xtalbuff_size );
          xtal_plane( dp++ , Ybuf , yP , Ybar , plane_size , xtalbuff_size );

          break;

        } /* switch(expanded_bpp) */

        /* Make sure all black is in the k plane */
        if (num_comps == 4 ) {
          if (mj->colorcomp > 3 ) {
            register word *kp = (word *)plane_data[scan][3];
            register word *cp = (word *)plane_data[scan][2];
            register word *mp = (word *)plane_data[scan][1];
            register word *yp = (word *)plane_data[scan][0];
            if (bits_per_pixel > 4) {  /* This has been done as 4 planes */
#if 0
              for (i = 0; i < plane_size / W; i++) {
                word bits = ~*kp++;
                *cp++ &= bits;
                *mp++ &= bits;
                *yp++ &= bits;
              }
#endif
            } else {  /* This has really been done as 3 planes */
              for (i = 0; i < plane_size / W; i++) {
                word bits = *cp & *mp & *yp;
                *kp++ = bits;
                bits = ~bits;
                *cp++ &= bits;
                *mp++ &= bits;
                *yp++ &= bits;
              }
            }
          } else if (mj->colorcomp == 3 ) {
            register word *kp = (word *)plane_data[scan][3];
            register word *cp = (word *)plane_data[scan][2];
            register word *mp = (word *)plane_data[scan][1];
            register word *yp = (word *)plane_data[scan][0];
            if (bits_per_pixel > 4) {  /* This has been done as 4 planes */
              for (i = 0; i < plane_size / W; i++) {
                word bits = *kp++; /* kp will not be used when printing */
                *cp++ |= bits;
                *mp++ |= bits;
                *yp++ |= bits;
              }
            } else {  /* This has really been done as 3 planes */
            }
          }
        }

        /* Transfer raster graphics
         * in the order (K), C, M, Y. */
        switch (mj->colorcomp) {
        case 1:
          out_data = (byte*) plane_data[scan][0];
          /* 3 for balck */
          mj_raster_cmd(3, plane_size, out_data, mj_tmp_buf, pdev, prn_stream);
          break;
        case 3:
          for (i = 3 - 1; i >= 0; i--) {
            out_data = (byte*) plane_data[scan][i];
            mj_raster_cmd(i, plane_size, out_data, mj_tmp_buf, pdev, prn_stream);
          }
          break;
        default:
          for (i = num_comps - 1; i >= 0; i--) {
            out_data = (byte*) plane_data[scan][i];
            mj_raster_cmd(i, plane_size, out_data, mj_tmp_buf, pdev, prn_stream);
          }
          break;
        } /* Transfer Raster Graphics ... */

        {
          if ( pdev->y_pixels_per_inch > 360 ) {
             gp_fwrite("\033(v\2\0\1\0",sizeof(byte),7, prn_stream);
           } else {
             gp_fputc('\n', prn_stream);
           }
        }
        scan = 1 - scan;          /* toggle scan direction */
      }	  /* Printing non-blank lines */
    }     /* for lnum ... */
  }       /* send each scan line in turn */

  /* end raster graphics & reset printer */

  /* eject page */
  {
    gp_fputs("\f\033@", prn_stream);
    gp_fflush(prn_stream);
  }
  /* free temporary storage */
  gs_free(pdev->memory->non_gc_memory, (char *) storage, storage_size_words, W, "mj_colour_print_page");
  gs_free(pdev->memory->non_gc_memory, (char *) mj_tmp_buf, mj_tmp_buf_size, W, "mj_raster_buffer");
  gs_free(pdev->memory->non_gc_memory, (char *) xtalbuff , xtalbuff_size*(16*4+2*4) , W, "mj_colour_print_barrier");

  return 0;
}

Project: ghostpdl
File: gdevmjc.c

gdev_mjc_map_color_rgb(gx_device *pdev, gx_color_index color,
                            gx_color_value prgb[3])
{
  /* For the moment, we simply ignore any black correction */
  switch (pdev->color_info.depth) {
  case 1:
    prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1);
    break;
  case 8:
      if (pdev->color_info.num_components >= 3)
        { gx_color_value c = (gx_color_value)color ^ 7;
          prgb[0] = -(c & 1);
          prgb[1] = -((c >> 1) & 1);
          prgb[2] = -(c >> 2);
        }
      else
        { gx_color_value value = (gx_color_value)color ^ 0xff;
          prgb[0] = prgb[1] = prgb[2] = (value << 8) + value;
        }
    break;
  case 16:
    { gx_color_value c = (gx_color_value)color ^ 0xffff;
      ushort value = c >> 11;
      prgb[0] = ((value << 11) + (value << 6) + (value << 1) +
                 (value >> 4)) >> (16 - gx_color_value_bits);
      value = (c >> 6) & 0x3f;
      prgb[1] = ((value << 10) + (value << 4) + (value >> 2))
        >> (16 - gx_color_value_bits);
      value = c & 0x1f;
      prgb[2] = ((value << 11) + (value << 6) + (value << 1) +
                 (value >> 4)) >> (16 - gx_color_value_bits);
    }
    break;
  case 24:
    { gx_color_value c = (gx_color_value)color ^ 0xffffff;
      prgb[0] = gx_color_value_from_byte(c >> 16);
      prgb[1] = gx_color_value_from_byte((c >> 8) & 0xff);
      prgb[2] = gx_color_value_from_byte(c & 0xff);
    }
    break;
  case 32:
#define  gx_maxcol gx_color_value_from_byte(gx_color_value_to_byte(gx_max_color_value))
    { gx_color_value w = gx_maxcol - gx_color_value_from_byte(color >> 24);
      prgb[0] = w - gx_color_value_from_byte((color >> 16) & 0xff);
      prgb[1] = w - gx_color_value_from_byte((color >> 8) & 0xff);
      prgb[2] = w - gx_color_value_from_byte(color & 0xff);
    }
    break;
  }
  return 0;
}

Project: ghostpdl
File: gdevmjc.c

mj6000c_open(gx_device * pdev)
{
  return mj_open(pdev, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

gdev_mjc_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
{
    return gdev_mjc_map_color_rgb(dev, color, out);
}

Project: ghostpdl
File: gdevmjc.c

mj8000c_print_page(gx_device_printer * pdev, gp_file * prn_stream)
{
  return mj_print_page(pdev, prn_stream, MJ8000C);
}

Project: ghostpdl
File: gdevmjc.c

set_bpp(gx_device *pdev, int bits_per_pixel)
{ gx_device_color_info *ci = &pdev->color_info;
  /* Only valid bits-per-pixel are 1, 3, 8, 16, 24, 32 */
  int bpp = bits_per_pixel < 3 ? 1 : bits_per_pixel < 8 ? 3 :
    (bits_per_pixel >> 3) << 3;
  ci->num_components = ((bpp == 1) || (bpp == 8) ? 1 : 3);
  ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp);
  ci->max_gray = (bpp >= 8 ? 255 : 1);
  ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0);
  ci->dither_grays = (bpp >= 8 ? 5 : 2);
  ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
  mj->colorcomp = (bpp == 8 ? 1 : 4);
}

Project: ghostpdl
File: gdevmjc.c

mj_get_params(gx_device *pdev, gs_param_list *plist)
{
        int code = gdev_prn_get_params(pdev, plist);

        if ( code < 0 ||
            (code = param_write_int(plist, "Density", &mj->density)) < 0 ||
            (code = param_write_int(plist, "Cyan", &mj->cyan)) < 0 ||
            (code = param_write_int(plist, "Magenta", &mj->magenta)) < 0 ||
            (code = param_write_int(plist, "Yellow", &mj->yellow)) < 0 ||
            (code = param_write_int(plist, "Black", &mj->black)) < 0 ||
            (code = param_write_bool(plist, "Unidirectional", &mj->direction)) < 0 ||
            (code = param_write_bool(plist, "Microweave", &mj->microweave)) < 0 ||
            (code = param_write_int(plist, "DotSize", &mj->dotsize)) < 0
           )
          return code;

        return code;
}

Project: ghostpdl
File: gdevmjc.c

mj500c_set_bpp(gx_device *pdev, int bits_per_pixel)
{ gx_device_color_info *ci = &pdev->color_info;
  /* Only valid bits-per-pixel are 1, 3, 8, 16, 24, 32 */
  int bpp = bits_per_pixel < 3 ? 1 : bits_per_pixel < 8 ? 3 :
    (bits_per_pixel >> 3) << 3;
  ci->num_components = ((bpp == 1) || (bpp == 8) ? 1 : 3);
  ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp);
  ci->max_gray = (bpp >= 8 ? 255 : 1);
  ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0);
  ci->dither_grays = (bpp >= 8 ? 5 : 2);
  ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0);
  mj->colorcomp = (bpp == 8 ? 1 : 3);
}

Project: ghostpdl
File: gdevmjc.c

gdev_mjc_paper_size(gx_device *dev)
{
  int width = dev->MediaSize[0];
  int height = dev->MediaSize[1];

  if (width == 1190 && height == 1684)
    return PAPER_SIZE_A2;
  else
    return PAPER_SIZE_A4;
}

Project: ghostpdl
File: gdevmjc.c

mj_open(gx_device *pdev, int ptype)
{       /* Change the margins if necessary. */
  int xdpi = pdev->x_pixels_per_inch;
  int ydpi = pdev->y_pixels_per_inch;

  static const float mj_margin[4] = { MJ700V2C_MARGINS_A4 };
  static const float mj6000c_a2[4] = { MJ6000C_MARGINS_A2 };
  static const float mj8000c_a2[4] = { MJ8000C_MARGINS_A2 };

  const float *m;

  int paper_size;

#if 0
  /* Set up colour params if put_props has not already done so */
  if (pdev->color_info.num_components == 0)
    set_bpp(pdev, pdev->color_info.depth);
#endif

  paper_size = gdev_mjc_paper_size(pdev);
  if (paper_size == PAPER_SIZE_A2 ) {
    if (ptype == MJ6000C)
      m = mj6000c_a2;
    else if (ptype == MJ8000C)
      m = mj8000c_a2;
    else
      m = mj_margin;
  } else {
    m = mj_margin;
  }

  gx_device_set_margins(pdev, m, true);

  if (mj->colorcomp == 3)
    mj->density = mj->density * 720 / ydpi * 1.5;
  else
    mj->density = mj->density * 720 / ydpi;

  /* Print Resolution Check */
  if (!((xdpi == 180 && ydpi == 180) ||
      (xdpi == 360 && ydpi == 360) ||
      (xdpi == 720 && ydpi == 720) ||
      (xdpi == 360 && ydpi == 720) ||
      (xdpi == 720 && ydpi == 360)))
    return_error(gs_error_rangecheck);

  return gdev_prn_open(pdev);
}

Project: ghostpdl
File: gdevmjc.c

mj_v_skip(int n, gx_device_printer *pdev, gp_file *stream)
{
        /* This is a kind of magic number. */
  static const int max_y_step = (256 * 15 + 255);

  int l = n - max_y_step;
  for (; l > 0; l -= max_y_step) {    /* move 256 * 15 + 255 dots at once*/
    gp_fwrite("\033(v\2\0\xff\x0f", sizeof(byte), 7, stream);
  }
  l += max_y_step;
  /* move to the end. */
  {
    int n2 = l / 256;
    int n1 = l - n2 * 256;
    gp_fwrite("\033(v\2\0", sizeof(byte) ,5 ,stream);
    gp_fputc(n1, stream);
    gp_fputc(n2, stream);
    gp_fputc('\r', stream);
  }
  return 0;
}

Project: ghostpdl
File: gdevmjc.c

gdev_mjc_map_rgb_color(gx_device *pdev, const gx_color_value cv[])
{
  gx_color_value r, g, b;

  r = cv[0]; g = cv[1]; b = cv[2];
  if (gx_color_value_to_byte(r & g & b) == 0xff)
    return (gx_color_index)0;         /* white */
  else {
    gx_color_value c = gx_max_color_value - r;
    gx_color_value m = gx_max_color_value - g;
    gx_color_value y = gx_max_color_value - b;

    switch (pdev->color_info.depth) {
    case 1:
      return ((c | m | y) > gx_max_color_value / 2 ?
              (gx_color_index)1 : (gx_color_index)0);
    case 8:
      if (pdev->color_info.num_components >= 3)
#define gx_color_value_to_1bit(cv) ((cv) >> (gx_color_value_bits - 1))
        return (gx_color_value_to_1bit(c) +
                (gx_color_value_to_1bit(m) << 1) +
                (gx_color_value_to_1bit(y) << 2));
      else
#define red_weight 306
#define green_weight 601
#define blue_weight 117
        return ((((word)c * red_weight +
                  (word)m * green_weight +
                  (word)y * blue_weight)
                 >> (gx_color_value_bits + 2)));
    case 16:
#define gx_color_value_to_5bits(cv) ((cv) >> (gx_color_value_bits - 5))
#define gx_color_value_to_6bits(cv) ((cv) >> (gx_color_value_bits - 6))
      return (gx_color_value_to_5bits(y) +
              (gx_color_value_to_6bits(m) << 5) +
              (gx_color_value_to_5bits(c) << 11));
    case 24:
      return (gx_color_value_to_byte(y) +
              (gx_color_value_to_byte(m) << 8) +
              ((word)gx_color_value_to_byte(c) << 16));
    case 32:
        {
                gx_color_value k;
                c = gx_color_value_to_byte(r);
                m = gx_color_value_to_byte(g);
                y = gx_color_value_to_byte(b);

                mj_color_correct( &c , &m , &y );

                c = esp_dat_c[c];
                m = esp_dat_m[m];
                y = esp_dat_y[y];

                k = c <= m ? (c <= y ? c : y) : (m <= y ? m : y);
                k = black_sep[ k >> 4 ] >> 6;
                c >>= 6;
                m >>= 6;
                y >>= 6;

        return ( (y - k) + ((m - k) << 8) +
                ((word)(c - k) << 16) + ((word)(k) << 24) );
      }
    }
  }
  return (gx_color_index)0;   /* This never happens */
}

Project: ghostpdl
File: gdevmjc.c

mj_put_params(gx_device *pdev,  gs_param_list *plist, int ptype)
{
        int old_bpp = mj->color_info.depth;
        int bpp = 0;
        int code = 0;
        int density = mj->density;
        int cyan = mj->cyan;
        int magenta = mj->magenta;
        int yellow = mj->yellow;
        int black = mj->black;
        bool direction = mj->direction;
        bool microweave = mj->microweave;
        int dotsize = mj->dotsize;
        gs_param_name param_name;
        int ecode = 0;

        code = put_param_int(plist, "Density", &density, 0, INT_MAX, code);
        code = put_param_int(plist, "Cyan", &cyan, 0, INT_MAX, code);
        code = put_param_int(plist, "Magenta", &magenta, 0, INT_MAX, code);
        code = put_param_int(plist, "Yellow", &yellow, 0, INT_MAX, code);
        code = put_param_int(plist, "Black", &black, 0, INT_MAX, code);

        if ((code = param_read_bool(plist,
                                     (param_name = "Unidirectional"),
                                     &direction))< 0) {
          param_signal_error(plist, param_name, ecode = code);
        }

        if ((code = param_read_bool(plist,
                                     (param_name = "Microweave"),
                                     &microweave))< 0) {
          param_signal_error(plist, param_name, ecode = code);
        }
        if (ecode < 0)
          return code;

        if (microweave && pdev->x_pixels_per_inch == 180)
            return_error(gs_error_rangecheck);

        code = put_param_int(plist, "DotSize", &dotsize, 0, 1, code);
        code = put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code);

        if ( code < 0 )
          return code;

        mj->density = density;
        mj->cyan = cyan;
        mj->magenta = magenta;
        mj->yellow = yellow;
        mj->black = black;
        mj->direction = direction;
        mj->microweave = microweave;
        mj->dotsize = dotsize;

        if ( bpp != 0 ) {
          if (bpp != 8 && bpp != 32)
            return_error(gs_error_rangecheck);

          if (ptype == MJ500C)
            mj500c_set_bpp(pdev, bpp);
          else
            set_bpp(pdev, bpp);
          gdev_prn_put_params(pdev, plist);
          if ( bpp != old_bpp && pdev->is_open )
            return gs_closedevice(pdev);
          return 0;
        }
        else
          return gdev_prn_put_params(pdev, plist);
}

Project: ghostpdl
File: gdevmjc.c

mj700v2c_put_params(gx_device *pdev, gs_param_list *plist)
{
  return mj_put_params(pdev, plist, MJ700V2C);
}

Project: ghostpdl
File: gdevmjc.c

gdev_mjc_encode_color(gx_device *dev, const gx_color_value colors[])
{
    return gdev_mjc_map_rgb_color(dev, colors);
}

Project: ghostpdl
File: gdevmjc.c

mj500c_print_page(gx_device_printer * pdev, gp_file * prn_stream)
{
  return mj_print_page(pdev, prn_stream, MJ500C);
}