static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
                             struct bmp_progressive_state *State,
                             GError **error)
{
	gint clrUsed;

	/* First check for the two first bytes content. A sane
	   BMP file must start with bytes 0x42 0x4D.  */
	if (*BFH != 0x42 || *(BFH + 1) != 0x4D) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has bogus header data"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

        /* FIXME this is totally unrobust against bogus image data. */
	if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
		State->BufferSize = lsb_32 (&BIH[0]) + 14;
		if (!grow_buffer (State, error))
			return FALSE;
		return TRUE;
	}

#if DUMPBIH
	DumpBIH(BIH);
#endif

	State->Header.size = lsb_32 (&BIH[0]);
	if (State->Header.size == 124) {
                /* BMP v5 */
		State->Header.width = lsb_32 (&BIH[4]);
		State->Header.height = lsb_32 (&BIH[8]);
		State->Header.depth = lsb_16 (&BIH[14]);
		State->Compressed = lsb_32 (&BIH[16]);
	} else if (State->Header.size == 108) {
                /* BMP v4 */
		State->Header.width = lsb_32 (&BIH[4]);
		State->Header.height = lsb_32 (&BIH[8]);
		State->Header.depth = lsb_16 (&BIH[14]);
		State->Compressed = lsb_32 (&BIH[16]);
	} else if (State->Header.size == 64) {
                /* BMP OS/2 v2 */
		State->Header.width = lsb_32 (&BIH[4]);
		State->Header.height = lsb_32 (&BIH[8]);
		State->Header.depth = lsb_16 (&BIH[14]);
		State->Compressed = lsb_32 (&BIH[16]);
	} else if (State->Header.size == 40) {
                /* BMP v3 */
		State->Header.width = lsb_32 (&BIH[4]);
		State->Header.height = lsb_32 (&BIH[8]);
		State->Header.depth = lsb_16 (&BIH[14]);
		State->Compressed = lsb_32 (&BIH[16]);
	} else if (State->Header.size == 12) {
                /* BMP OS/2 */
		State->Header.width = lsb_16 (&BIH[4]);
		State->Header.height = lsb_16 (&BIH[6]);
		State->Header.depth = lsb_16 (&BIH[10]);
		State->Compressed = BI_RGB;
	} else {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has unsupported header size"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

        if (State->Header.depth > 32)
          {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has unsupported depth"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
          }

	if (State->Header.size == 12)
		clrUsed = 1 << State->Header.depth;
	else
		clrUsed = (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);

        if (clrUsed > (1 << State->Header.depth))
          {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has oversize palette"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
          }

	if (clrUsed != 0)
		State->Header.n_colors = clrUsed;
	else
            State->Header.n_colors = (1 << State->Header.depth);

	State->Type = State->Header.depth;	/* This may be less trivial someday */

	/* Negative heights indicates bottom-down pixelorder */
	if (State->Header.height < 0) {
		State->Header.height = -State->Header.height;
		State->Header.Negative = 1;
	}

	if (State->Header.Negative &&
	    (State->Compressed != BI_RGB && State->Compressed != BI_BITFIELDS))
	{
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Topdown BMP images cannot be compressed"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

	if (State->Header.width <= 0 || State->Header.height == 0 ||
	    (State->Compressed == BI_RLE4 && State->Type != 4)    ||
	    (State->Compressed == BI_RLE8 && State->Type != 8)	  ||
	    (State->Compressed == BI_BITFIELDS && !(State->Type == 16 || State->Type == 32)) ||
	    (State->Compressed > BI_BITFIELDS)) {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has bogus header data"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

	if (State->Type == 32)
		State->LineWidth = State->Header.width * 4;
	else if (State->Type == 24)
		State->LineWidth = State->Header.width * 3;
	else if (State->Type == 16)
		State->LineWidth = State->Header.width * 2;
	else if (State->Type == 8)
		State->LineWidth = State->Header.width * 1;
	else if (State->Type == 4)
		State->LineWidth = (State->Header.width + 1) / 2;
	else if (State->Type == 1) {
		State->LineWidth = State->Header.width / 8;
		if ((State->Header.width & 7) != 0)
			State->LineWidth++;
	} else {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has bogus header data"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

	/* Pad to a 32 bit boundary */
	if (((State->LineWidth % 4) > 0)
	    && (State->Compressed == BI_RGB || State->Compressed == BI_BITFIELDS))
		State->LineWidth = (State->LineWidth / 4) * 4 + 4;

	if (State->pixbuf == NULL) {
		if (State->size_func) {
			gint width = State->Header.width;
			gint height = State->Header.height;

			(*State->size_func) (&width, &height, State->user_data);
			if (width == 0 || height == 0) {
				State->read_state = READ_STATE_DONE;
				State->BufferSize = 0;
				return TRUE;
			}
		}

		if (State->Type == 32 ||
		    State->Compressed == BI_RLE4 ||
		    State->Compressed == BI_RLE8)
			State->pixbuf =
				gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
					       (gint) State->Header.width,
					       (gint) State->Header.height);
		else
			State->pixbuf =
				gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
					       (gint) State->Header.width,
					       (gint) State->Header.height);

		if (State->pixbuf == NULL) {
			g_set_error_literal (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                             _("Not enough memory to load bitmap image"));
			State->read_state = READ_STATE_ERROR;
			return FALSE;
			}

		if (State->prepared_func != NULL)
			/* Notify the client that we are ready to go */
			(*State->prepared_func) (State->pixbuf, NULL, State->user_data);

		/* make all pixels initially transparent */
		if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
			memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
			State->compr.p = State->pixbuf->pixels
				+ State->pixbuf->rowstride * (State->Header.height- 1);
		}
	}

	State->BufferDone = 0;
	if (State->Type <= 8) {
                gint samples;

		State->read_state = READ_STATE_PALETTE;

		/* Allocate enough to hold the palette */
	        samples = (State->Header.size == 12 ? 3 : 4);
		State->BufferSize = State->Header.n_colors * samples;

		/* Skip over everything between the palette and the data.
		   This protects us against a malicious BFH[10] value.
                */
		State->BufferPadding = (lsb_32 (&BFH[10]) - 14 - State->Header.size) - State->BufferSize;

	} else if (State->Compressed == BI_RGB) {
		if (State->BufferSize < lsb_32 (&BFH[10]))
		{
			/* skip over padding between headers and image data */
			State->read_state = READ_STATE_HEADERS;
			State->BufferDone = State->BufferSize;
			State->BufferSize = lsb_32 (&BFH[10]);
		}
		else
		{
			State->read_state = READ_STATE_DATA;
			State->BufferSize = State->LineWidth;
		}
	} else if (State->Compressed == BI_BITFIELDS) {
               if (State->Header.size == 108 || State->Header.size == 124)
               {
			/* v4 and v5 have the bitmasks in the header */
			if (!decode_bitmasks (&BIH[40], State, error)) {
			       State->read_state = READ_STATE_ERROR;
			       return FALSE;
                        }
               }
               else
               {
		       State->read_state = READ_STATE_BITMASKS;
		       State->BufferSize = 12;
               }
	} else {
		g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("BMP image has bogus header data"));
		State->read_state = READ_STATE_ERROR;
		return FALSE;
	}

	if (!grow_buffer (State, error))
		return FALSE;

        return TRUE;
}


local int decode(struct state *s, struct huffman *h)
{
    int len;            /* current number of bits in code */
    int code;           /* len bits being decoded */
    int first;          /* first code of length len */
    int count;          /* number of codes of length len */
    int index;          /* index of first code of length len in symbol table */

    code = first = index = 0;
    for (len = 1; len <= MAXBITS; len++) {
        code |= bits(s, 1);             /* get next bit */
        count = h->count[len];
        if (code < first + count)       /* if length len, return symbol */
            return h->symbol[index + (code - first)];
        index += count;                 /* else update for next length */
        first += count;
        first <<= 1;
        code <<= 1;
    }
    return -9;                          /* ran out of codes */
}


static MagickBooleanType WritePICTImage(const ImageInfo *image_info,
  Image *image,ExceptionInfo *exception)
{
#define MaxCount  128
#define PictCropRegionOp  0x01
#define PictEndOfPictureOp  0xff
#define PictJPEGOp  0x8200
#define PictInfoOp  0x0C00
#define PictInfoSize  512
#define PictPixmapOp  0x9A
#define PictPICTOp  0x98
#define PictVersion  0x11

  const StringInfo
    *profile;

  double
    x_resolution,
    y_resolution;

  MagickBooleanType
    status;

  MagickOffsetType
    offset;

  PICTPixmap
    pixmap;

  PICTRectangle
    bounds,
    crop_rectangle,
    destination_rectangle,
    frame_rectangle,
    size_rectangle,
    source_rectangle;

  register const Quantum
    *p;

  register ssize_t
    i,
    x;

  size_t
    bytes_per_line,
    count,
    row_bytes,
    storage_class;

  ssize_t
    y;

  unsigned char
    *buffer,
    *packed_scanline,
    *scanline;

  unsigned short
    base_address,
    transfer_mode;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if ((image->columns > 65535L) || (image->rows > 65535L))
    ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  (void) TransformImageColorspace(image,sRGBColorspace,exception);
  /*
    Initialize image info.
  */
  size_rectangle.top=0;
  size_rectangle.left=0;
  size_rectangle.bottom=(short) image->rows;
  size_rectangle.right=(short) image->columns;
  frame_rectangle=size_rectangle;
  crop_rectangle=size_rectangle;
  source_rectangle=size_rectangle;
  destination_rectangle=size_rectangle;
  base_address=0xff;
  row_bytes=image->columns;
  bounds.top=0;
  bounds.left=0;
  bounds.bottom=(short) image->rows;
  bounds.right=(short) image->columns;
  pixmap.version=0;
  pixmap.pack_type=0;
  pixmap.pack_size=0;
  pixmap.pixel_type=0;
  pixmap.bits_per_pixel=8;
  pixmap.component_count=1;
  pixmap.component_size=8;
  pixmap.plane_bytes=0;
  pixmap.table=0;
  pixmap.reserved=0;
  transfer_mode=0;
  x_resolution=image->resolution.x != 0.0 ? image->resolution.x :
    DefaultResolution;
  y_resolution=image->resolution.y != 0.0 ? image->resolution.y :
    DefaultResolution;
  storage_class=image->storage_class;
  if (image_info->compression == JPEGCompression)
    storage_class=DirectClass;
  if (storage_class == DirectClass)
    {
      pixmap.component_count=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
      pixmap.pixel_type=16;
      pixmap.bits_per_pixel=32;
      pixmap.pack_type=0x04;
      transfer_mode=0x40;
      row_bytes=4*image->columns;
    }
  /*
    Allocate memory.
  */
  bytes_per_line=image->columns;
  if (storage_class == DirectClass)
    bytes_per_line*=image->alpha_trait != UndefinedPixelTrait ? 4 : 3;
  buffer=(unsigned char *) AcquireQuantumMemory(PictInfoSize,sizeof(*buffer));
  packed_scanline=(unsigned char *) AcquireQuantumMemory((size_t)
   (row_bytes+MaxCount),sizeof(*packed_scanline));
  scanline=(unsigned char *) AcquireQuantumMemory(row_bytes,sizeof(*scanline));
  if ((buffer == (unsigned char *) NULL) ||
      (packed_scanline == (unsigned char *) NULL) ||
      (scanline == (unsigned char *) NULL))
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(scanline,0,row_bytes);
  (void) ResetMagickMemory(packed_scanline,0,(size_t) (row_bytes+MaxCount));
  /*
    Write header, header size, size bounding box, version, and reserved.
  */
  (void) ResetMagickMemory(buffer,0,PictInfoSize);
  (void) WriteBlob(image,PictInfoSize,buffer);
  (void) WriteBlobMSBShort(image,0);
  (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.top);
  (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.left);
  (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) size_rectangle.right);
  (void) WriteBlobMSBShort(image,PictVersion);
  (void) WriteBlobMSBShort(image,0x02ff);  /* version #2 */
  (void) WriteBlobMSBShort(image,PictInfoOp);
  (void) WriteBlobMSBLong(image,0xFFFE0000UL);
  /*
    Write full size of the file, resolution, frame bounding box, and reserved.
  */
  (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
  (void) WriteBlobMSBShort(image,0x0000);
  (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
  (void) WriteBlobMSBShort(image,0x0000);
  (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.top);
  (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.left);
  (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) frame_rectangle.right);
  (void) WriteBlobMSBLong(image,0x00000000L);
  profile=GetImageProfile(image,"iptc");
  if (profile != (StringInfo *) NULL)
    {
      (void) WriteBlobMSBShort(image,0xa1);
      (void) WriteBlobMSBShort(image,0x1f2);
      (void) WriteBlobMSBShort(image,(unsigned short)
        (GetStringInfoLength(profile)+4));
      (void) WriteBlobString(image,"8BIM");
      (void) WriteBlob(image,GetStringInfoLength(profile),
        GetStringInfoDatum(profile));
    }
  profile=GetImageProfile(image,"icc");
  if (profile != (StringInfo *) NULL)
    {
      (void) WriteBlobMSBShort(image,0xa1);
      (void) WriteBlobMSBShort(image,0xe0);
      (void) WriteBlobMSBShort(image,(unsigned short)
        (GetStringInfoLength(profile)+4));
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlob(image,GetStringInfoLength(profile),
        GetStringInfoDatum(profile));
      (void) WriteBlobMSBShort(image,0xa1);
      (void) WriteBlobMSBShort(image,0xe0);
      (void) WriteBlobMSBShort(image,4);
      (void) WriteBlobMSBLong(image,0x00000002UL);
    }
  /*
    Write crop region opcode and crop bounding box.
  */
  (void) WriteBlobMSBShort(image,PictCropRegionOp);
  (void) WriteBlobMSBShort(image,0xa);
  (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.top);
  (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.left);
  (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) crop_rectangle.right);
  if (image_info->compression == JPEGCompression)
    {
      Image
        *jpeg_image;

      ImageInfo
        *jpeg_info;

      size_t
        length;

      unsigned char
        *blob;

      jpeg_image=CloneImage(image,0,0,MagickTrue,exception);
      if (jpeg_image == (Image *) NULL)
        {
          (void) CloseBlob(image);
          return(MagickFalse);
        }
      jpeg_info=CloneImageInfo(image_info);
      (void) CopyMagickString(jpeg_info->magick,"JPEG",MagickPathExtent);
      length=0;
      blob=(unsigned char *) ImageToBlob(jpeg_info,jpeg_image,&length,
        exception);
      jpeg_info=DestroyImageInfo(jpeg_info);
      if (blob == (unsigned char *) NULL)
        return(MagickFalse);
      jpeg_image=DestroyImage(jpeg_image);
      (void) WriteBlobMSBShort(image,PictJPEGOp);
      (void) WriteBlobMSBLong(image,(unsigned int) length+154);
      (void) WriteBlobMSBShort(image,0x0000);
      (void) WriteBlobMSBLong(image,0x00010000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00010000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x40000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00400000UL);
      (void) WriteBlobMSBShort(image,0x0000);
      (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
      (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
      (void) WriteBlobMSBShort(image,0x0000);
      (void) WriteBlobMSBShort(image,768);
      (void) WriteBlobMSBShort(image,0x0000);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00566A70UL);
      (void) WriteBlobMSBLong(image,0x65670000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000001UL);
      (void) WriteBlobMSBLong(image,0x00016170UL);
      (void) WriteBlobMSBLong(image,0x706C0000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBShort(image,768);
      (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
      (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
      (void) WriteBlobMSBShort(image,(unsigned short) x_resolution);
      (void) WriteBlobMSBShort(image,0x0000);
      (void) WriteBlobMSBShort(image,(unsigned short) y_resolution);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x87AC0001UL);
      (void) WriteBlobMSBLong(image,0x0B466F74UL);
      (void) WriteBlobMSBLong(image,0x6F202D20UL);
      (void) WriteBlobMSBLong(image,0x4A504547UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x00000000UL);
      (void) WriteBlobMSBLong(image,0x0018FFFFUL);
      (void) WriteBlob(image,length,blob);
      if ((length & 0x01) != 0)
        (void) WriteBlobByte(image,'\0');
      blob=(unsigned char *) RelinquishMagickMemory(blob);
    }
  /*
    Write picture opcode, row bytes, and picture bounding box, and version.
  */
  if (storage_class == PseudoClass)
    (void) WriteBlobMSBShort(image,PictPICTOp);
  else
    {
      (void) WriteBlobMSBShort(image,PictPixmapOp);
      (void) WriteBlobMSBLong(image,(size_t) base_address);
    }
  (void) WriteBlobMSBShort(image,(unsigned short) (row_bytes | 0x8000));
  (void) WriteBlobMSBShort(image,(unsigned short) bounds.top);
  (void) WriteBlobMSBShort(image,(unsigned short) bounds.left);
  (void) WriteBlobMSBShort(image,(unsigned short) bounds.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) bounds.right);
  /*
    Write pack type, pack size, resolution, pixel type, and pixel size.
  */
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.version);
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pack_type);
  (void) WriteBlobMSBLong(image,(unsigned int) pixmap.pack_size);
  (void) WriteBlobMSBShort(image,(unsigned short) (x_resolution+0.5));
  (void) WriteBlobMSBShort(image,0x0000);
  (void) WriteBlobMSBShort(image,(unsigned short) (y_resolution+0.5));
  (void) WriteBlobMSBShort(image,0x0000);
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.pixel_type);
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.bits_per_pixel);
  /*
    Write component count, size, plane bytes, table size, and reserved.
  */
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_count);
  (void) WriteBlobMSBShort(image,(unsigned short) pixmap.component_size);
  (void) WriteBlobMSBLong(image,(unsigned int) pixmap.plane_bytes);
  (void) WriteBlobMSBLong(image,(unsigned int) pixmap.table);
  (void) WriteBlobMSBLong(image,(unsigned int) pixmap.reserved);
  if (storage_class == PseudoClass)
    {
      /*
        Write image colormap.
      */
      (void) WriteBlobMSBLong(image,0x00000000L);  /* color seed */
      (void) WriteBlobMSBShort(image,0L);  /* color flags */
      (void) WriteBlobMSBShort(image,(unsigned short) (image->colors-1));
      for (i=0; i < (ssize_t) image->colors; i++)
      {
        (void) WriteBlobMSBShort(image,(unsigned short) i);
        (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
          image->colormap[i].red));
        (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
          image->colormap[i].green));
        (void) WriteBlobMSBShort(image,ScaleQuantumToShort(
          image->colormap[i].blue));
      }
    }
  /*
    Write source and destination rectangle.
  */
  (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.top);
  (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.left);
  (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) source_rectangle.right);
  (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.top);
  (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.left);
  (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.bottom);
  (void) WriteBlobMSBShort(image,(unsigned short) destination_rectangle.right);
  (void) WriteBlobMSBShort(image,(unsigned short) transfer_mode);
  /*
    Write picture data.
  */
  count=0;
  if (storage_class == PseudoClass)
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
      if (p == (const Quantum *) NULL)
        break;
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        scanline[x]=(unsigned char) GetPixelIndex(image,p);
        p+=GetPixelChannels(image);
      }
      count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
        packed_scanline);
      if (image->previous == (Image *) NULL)
        {
          status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
            image->rows);
          if (status == MagickFalse)
            break;
        }
    }
  else
    if (image_info->compression == JPEGCompression)
      {
        (void) ResetMagickMemory(scanline,0,row_bytes);
        for (y=0; y < (ssize_t) image->rows; y++)
          count+=EncodeImage(image,scanline,(size_t) (row_bytes & 0x7FFF),
            packed_scanline);
      }
    else
      {
        register unsigned char
          *blue,
          *green,
          *opacity,
          *red;

        red=scanline;
        green=scanline+image->columns;
        blue=scanline+2*image->columns;
        opacity=scanline+3*image->columns;
        for (y=0; y < (ssize_t) image->rows; y++)
        {
          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
          if (p == (const Quantum *) NULL)
            break;
          red=scanline;
          green=scanline+image->columns;
          blue=scanline+2*image->columns;
          if (image->alpha_trait != UndefinedPixelTrait)
            {
              opacity=scanline;
              red=scanline+image->columns;
              green=scanline+2*image->columns;
              blue=scanline+3*image->columns;
            }
          for (x=0; x < (ssize_t) image->columns; x++)
          {
            *red++=ScaleQuantumToChar(GetPixelRed(image,p));
            *green++=ScaleQuantumToChar(GetPixelGreen(image,p));
            *blue++=ScaleQuantumToChar(GetPixelBlue(image,p));
            if (image->alpha_trait != UndefinedPixelTrait)
              *opacity++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
            p+=GetPixelChannels(image);
          }
          count+=EncodeImage(image,scanline,bytes_per_line & 0x7FFF,
            packed_scanline);
          if (image->previous == (Image *) NULL)
            {
              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
                image->rows);
              if (status == MagickFalse)
                break;
            }
        }
      }
  if ((count & 0x01) != 0)
    (void) WriteBlobByte(image,'\0');
  (void) WriteBlobMSBShort(image,PictEndOfPictureOp);
  offset=TellBlob(image);
  offset=SeekBlob(image,512,SEEK_SET);
  (void) WriteBlobMSBShort(image,(unsigned short) offset);
  scanline=(unsigned char *) RelinquishMagickMemory(scanline);
  packed_scanline=(unsigned char *) RelinquishMagickMemory(packed_scanline);
  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
  (void) CloseBlob(image);
  return(MagickTrue);
}


MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
  const size_t quantum)
{
  MemoryInfo
    *memory_info;

  size_t
    length;

  length=count*quantum;
  if ((count == 0) || (quantum != (length/count)))
    {
      errno=ENOMEM;
      return((MemoryInfo *) NULL);
    }
  memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
    sizeof(*memory_info)));
  if (memory_info == (MemoryInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(memory_info,0,sizeof(*memory_info));
  memory_info->length=length;
  memory_info->signature=MagickCoreSignature;
  if (AcquireMagickResource(MemoryResource,length) != MagickFalse)
    {
      memory_info->blob=AcquireAlignedMemory(1,length);
      if (memory_info->blob != NULL)
        {
          memory_info->type=AlignedVirtualMemory;
          return(memory_info);
        }
    }
  RelinquishMagickResource(MemoryResource,length);
  if (AcquireMagickResource(MapResource,length) != MagickFalse)
    {
      /*
        Heap memory failed, try anonymous memory mapping.
      */
      memory_info->blob=MapBlob(-1,IOMode,0,length);
      if (memory_info->blob != NULL)
        {
          memory_info->type=MapVirtualMemory;
          return(memory_info);
        }
      if (AcquireMagickResource(DiskResource,length) != MagickFalse)
        {
          int
            file;

          /*
            Anonymous memory mapping failed, try file-backed memory mapping.
            If the MapResource request failed, there is no point in trying
            file-backed memory mapping.
          */
          file=AcquireUniqueFileResource(memory_info->filename);
          if (file != -1)
            {
              if ((lseek(file,length-1,SEEK_SET) == (length-1)) &&
                  (write(file,"",1) == 1))
                {
                  memory_info->blob=MapBlob(file,IOMode,0,length);
                  if (memory_info->blob != NULL)
                    {
                      (void) close(file);
                      memory_info->type=MapVirtualMemory;
                      return(memory_info);
                    }
                }
              /*
                File-backed memory mapping failed, delete the temporary file.
              */
              (void) close(file);
              (void) RelinquishUniqueFileResource(memory_info->filename);
              *memory_info->filename = '\0';
            }
        }
      RelinquishMagickResource(DiskResource,length);
    }
  RelinquishMagickResource(MapResource,length);
  if (memory_info->blob == NULL)
    {
      memory_info->blob=AcquireMagickMemory(length);
      if (memory_info->blob != NULL)
        memory_info->type=UnalignedVirtualMemory;
    }
  if (memory_info->blob == NULL)
    memory_info=RelinquishVirtualMemory(memory_info);
  return(memory_info);
}


xfs_iflush_int(
	struct xfs_inode	*ip,
	struct xfs_buf		*bp)
{
	struct xfs_inode_log_item *iip = ip->i_itemp;
	struct xfs_dinode	*dip;
	struct xfs_mount	*mp = ip->i_mount;

	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
	ASSERT(xfs_isiflocked(ip));
	ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
	       ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));
	ASSERT(iip != NULL && iip->ili_fields != 0);
	ASSERT(ip->i_d.di_version > 1);

	/* set *dip = inode's place in the buffer */
	dip = xfs_buf_offset(bp, ip->i_imap.im_boffset);

	if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),
			       mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
			"%s: Bad inode %Lu magic number 0x%x, ptr 0x%p",
			__func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip);
		goto corrupt_out;
	}
	if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC,
				mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) {
		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
			"%s: Bad inode %Lu, ptr 0x%p, magic number 0x%x",
			__func__, ip->i_ino, ip, ip->i_d.di_magic);
		goto corrupt_out;
	}
	if (S_ISREG(ip->i_d.di_mode)) {
		if (XFS_TEST_ERROR(
		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
		    mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) {
			xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
				"%s: Bad regular inode %Lu, ptr 0x%p",
				__func__, ip->i_ino, ip);
			goto corrupt_out;
		}
	} else if (S_ISDIR(ip->i_d.di_mode)) {
		if (XFS_TEST_ERROR(
		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
		    (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
		    mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) {
			xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
				"%s: Bad directory inode %Lu, ptr 0x%p",
				__func__, ip->i_ino, ip);
			goto corrupt_out;
		}
	}
	if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents >
				ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5,
				XFS_RANDOM_IFLUSH_5)) {
		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
			"%s: detected corrupt incore inode %Lu, "
			"total extents = %d, nblocks = %Ld, ptr 0x%p",
			__func__, ip->i_ino,
			ip->i_d.di_nextents + ip->i_d.di_anextents,
			ip->i_d.di_nblocks, ip);
		goto corrupt_out;
	}
	if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize,
				mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) {
		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
			"%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p",
			__func__, ip->i_ino, ip->i_d.di_forkoff, ip);
		goto corrupt_out;
	}

	/*
	 * Inode item log recovery for v2 inodes are dependent on the
	 * di_flushiter count for correct sequencing. We bump the flush
	 * iteration count so we can detect flushes which postdate a log record
	 * during recovery. This is redundant as we now log every change and
	 * hence this can't happen but we need to still do it to ensure
	 * backwards compatibility with old kernels that predate logging all
	 * inode changes.
	 */
	if (ip->i_d.di_version < 3)
		ip->i_d.di_flushiter++;

	/*
	 * Copy the dirty parts of the inode into the on-disk
	 * inode.  We always copy out the core of the inode,
	 * because if the inode is dirty at all the core must
	 * be.
	 */
	xfs_dinode_to_disk(dip, &ip->i_d);

	/* Wrap, we never let the log put out DI_MAX_FLUSH */
	if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
		ip->i_d.di_flushiter = 0;

	xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
	if (XFS_IFORK_Q(ip))
		xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
	xfs_inobp_check(mp, bp);

	/*
	 * We've recorded everything logged in the inode, so we'd like to clear
	 * the ili_fields bits so we don't log and flush things unnecessarily.
	 * However, we can't stop logging all this information until the data
	 * we've copied into the disk buffer is written to disk.  If we did we
	 * might overwrite the copy of the inode in the log with all the data
	 * after re-logging only part of it, and in the face of a crash we
	 * wouldn't have all the data we need to recover.
	 *
	 * What we do is move the bits to the ili_last_fields field.  When
	 * logging the inode, these bits are moved back to the ili_fields field.
	 * In the xfs_iflush_done() routine we clear ili_last_fields, since we
	 * know that the information those bits represent is permanently on
	 * disk.  As long as the flush completes before the inode is logged
	 * again, then both ili_fields and ili_last_fields will be cleared.
	 *
	 * We can play with the ili_fields bits here, because the inode lock
	 * must be held exclusively in order to set bits there and the flush
	 * lock protects the ili_last_fields bits.  Set ili_logged so the flush
	 * done routine can tell whether or not to look in the AIL.  Also, store
	 * the current LSN of the inode so that we can tell whether the item has
	 * moved in the AIL from xfs_iflush_done().  In order to read the lsn we
	 * need the AIL lock, because it is a 64 bit value that cannot be read
	 * atomically.
	 */
	iip->ili_last_fields = iip->ili_fields;
	iip->ili_fields = 0;
	iip->ili_logged = 1;

	xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
				&iip->ili_item.li_lsn);

	/*
	 * Attach the function xfs_iflush_done to the inode's
	 * buffer.  This will remove the inode from the AIL
	 * and unlock the inode's flush lock when the inode is
	 * completely written to disk.
	 */
	xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item);

	/* update the lsn in the on disk inode if required */
	if (ip->i_d.di_version == 3)
		dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn);

	/* generate the checksum. */
	xfs_dinode_calc_crc(mp, dip);

	ASSERT(bp->b_fspriv != NULL);
	ASSERT(bp->b_iodone != NULL);
	return 0;

corrupt_out:
	return -EFSCORRUPTED;
}


void AES::encrypt(const byte* inBlock, const byte* xorBlock,
                  byte* outBlock) const
{
    word32 s0, s1, s2, s3;
    word32 t0, t1, t2, t3;

    const word32 *rk = key_;
    /*
     * map byte array block to cipher state
     * and add initial round key:
     */
    gpBlock::Get(inBlock)(s0)(s1)(s2)(s3);
    s0 ^= rk[0];
    s1 ^= rk[1];
    s2 ^= rk[2];
    s3 ^= rk[3];

    /*
     * Nr - 1 full rounds:
     */

    unsigned int r = rounds_ >> 1;
    for (;;) {
        t0 =
            Te0[GETBYTE(s0, 3)] ^
            Te1[GETBYTE(s1, 2)]  ^
            Te2[GETBYTE(s2, 1)]  ^
            Te3[GETBYTE(s3, 0)]  ^
            rk[4];
        t1 =
            Te0[GETBYTE(s1, 3)] ^
            Te1[GETBYTE(s2, 2)]  ^
            Te2[GETBYTE(s3, 1)]  ^
            Te3[GETBYTE(s0, 0)]  ^
            rk[5];
        t2 =
            Te0[GETBYTE(s2, 3)] ^
            Te1[GETBYTE(s3, 2)]  ^
            Te2[GETBYTE(s0, 1)]  ^
            Te3[GETBYTE(s1, 0)]  ^
            rk[6];
        t3 =
            Te0[GETBYTE(s3, 3)] ^
            Te1[GETBYTE(s0, 2)]  ^
            Te2[GETBYTE(s1, 1)]  ^
            Te3[GETBYTE(s2, 0)]  ^
            rk[7];

        rk += 8;
        if (--r == 0) {
            break;
        }

        s0 =
            Te0[GETBYTE(t0, 3)] ^
            Te1[GETBYTE(t1, 2)] ^
            Te2[GETBYTE(t2, 1)] ^
            Te3[GETBYTE(t3, 0)] ^
            rk[0];
        s1 =
            Te0[GETBYTE(t1, 3)] ^
            Te1[GETBYTE(t2, 2)] ^
            Te2[GETBYTE(t3, 1)] ^
            Te3[GETBYTE(t0, 0)] ^
            rk[1];
        s2 =
            Te0[GETBYTE(t2, 3)] ^
            Te1[GETBYTE(t3, 2)] ^
            Te2[GETBYTE(t0, 1)] ^
            Te3[GETBYTE(t1, 0)] ^
            rk[2];
        s3 =
            Te0[GETBYTE(t3, 3)] ^
            Te1[GETBYTE(t0, 2)] ^
            Te2[GETBYTE(t1, 1)] ^
            Te3[GETBYTE(t2, 0)] ^
            rk[3];
    }

    /*
     * apply last round and
     * map cipher state to byte array block:
     */

    s0 =
        (Te4[GETBYTE(t0, 3)] & 0xff000000) ^
        (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^
        (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^
        (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^
        rk[0];
    s1 =
        (Te4[GETBYTE(t1, 3)] & 0xff000000) ^
        (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^
        (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^
        (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^
        rk[1];
    s2 =
        (Te4[GETBYTE(t2, 3)] & 0xff000000) ^
        (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^
        (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^
        (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^
        rk[2];
    s3 =
        (Te4[GETBYTE(t3, 3)] & 0xff000000) ^
        (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^
        (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^
        (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^
        rk[3];

    gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3);
}


void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/)
{
    if (keylen <= 16)
        keylen = 16;
    else if (keylen >= 32)
        keylen = 32;
    else if (keylen != 24)
        keylen = 24;

    rounds_ = keylen/4 + 6;

    word32 temp, *rk = key_;
    unsigned int i=0;

    GetUserKey(BigEndianOrder, rk, keylen/4, userKey, keylen);

    switch(keylen)
    {
    case 16:
        while (true)
        {
            temp  = rk[3];
            rk[4] = rk[0] ^
                (Te4[GETBYTE(temp, 2)] & 0xff000000) ^
                (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^
                (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^
                (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^
                rcon_[i];
            rk[5] = rk[1] ^ rk[4];
            rk[6] = rk[2] ^ rk[5];
            rk[7] = rk[3] ^ rk[6];
            if (++i == 10)
                break;
            rk += 4;
        }
        break;

    case 24:
        while (true)    // for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack
        {
            temp = rk[ 5];
            rk[ 6] = rk[ 0] ^
                (Te4[GETBYTE(temp, 2)] & 0xff000000) ^
                (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^
                (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^
                (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^
                rcon_[i];
            rk[ 7] = rk[ 1] ^ rk[ 6];
            rk[ 8] = rk[ 2] ^ rk[ 7];
            rk[ 9] = rk[ 3] ^ rk[ 8];
            if (++i == 8)
                break;
            rk[10] = rk[ 4] ^ rk[ 9];
            rk[11] = rk[ 5] ^ rk[10];
            rk += 6;
        }
        break;

    case 32:
        while (true)
        {
            temp = rk[ 7];
            rk[ 8] = rk[ 0] ^
                (Te4[GETBYTE(temp, 2)] & 0xff000000) ^
                (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^
                (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^
                (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^
                rcon_[i];
            rk[ 9] = rk[ 1] ^ rk[ 8];
            rk[10] = rk[ 2] ^ rk[ 9];
            rk[11] = rk[ 3] ^ rk[10];
            if (++i == 7)
                break;
            temp = rk[11];
            rk[12] = rk[ 4] ^
                (Te4[GETBYTE(temp, 3)] & 0xff000000) ^
                (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^
                (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^
                (Te4[GETBYTE(temp, 0)] & 0x000000ff);
            rk[13] = rk[ 5] ^ rk[12];
            rk[14] = rk[ 6] ^ rk[13];
            rk[15] = rk[ 7] ^ rk[14];

            rk += 8;
        }
        break;
    }

    if (dir_ == DECRYPTION)
    {
        unsigned int i, j;
        rk = key_;

        /* invert the order of the round keys: */
        for (i = 0, j = 4*rounds_; i < j; i += 4, j -= 4) {
            temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
            temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
            temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
            temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
        }
        // apply the inverse MixColumn transform to all round keys but the
        // first and the last:
        for (i = 1; i < rounds_; i++) {
            rk += 4;
            rk[0] =
                Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^
                Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^
                Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^
                Td3[Te4[GETBYTE(rk[0], 0)] & 0xff];
            rk[1] =
                Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^
                Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^
                Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^
                Td3[Te4[GETBYTE(rk[1], 0)] & 0xff];
            rk[2] =
                Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^
                Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^
                Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^
                Td3[Te4[GETBYTE(rk[2], 0)] & 0xff];
            rk[3] =
                Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^
                Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^
                Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^
                Td3[Te4[GETBYTE(rk[3], 0)] & 0xff];
        }
    }
}


int read_file(SSL_CTX* ctx, const char* file, int format, CertType type)
{
    int ret = SSL_SUCCESS;

    if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM)
        return SSL_BAD_FILETYPE;

    if (file == NULL || !file[0])
      return SSL_BAD_FILE;

    FILE* input = fopen(file, "rb");
    if (!input)
        return SSL_BAD_FILE;

    if (type == CA) {
        // may have a bunch of CAs
        x509* ptr;
        while ( (ptr = PemToDer(input, Cert)) )
            ctx->AddCA(ptr);

        if (!feof(input)) {
            fclose(input);
            return SSL_BAD_FILE;
        }
    }
    else {
        x509*& x = (type == Cert) ? ctx->certificate_ : ctx->privateKey_;

        if (format == SSL_FILETYPE_ASN1) {
            fseek(input, 0, SEEK_END);
            long sz = ftell(input);
            rewind(input);
            x = NEW_YS x509(sz); // takes ownership
            size_t bytes = fread(x->use_buffer(), sz, 1, input);
            if (bytes != 1) {
                fclose(input);
                return SSL_BAD_FILE;
            }
        }
        else {
            EncryptedInfo info;
            x = PemToDer(input, type, &info);
            if (!x) {
                fclose(input);
                return SSL_BAD_FILE;
            }
            if (info.set) {
                // decrypt
                char password[80];
                pem_password_cb cb = ctx->GetPasswordCb();
                if (!cb) {
                    fclose(input);
                    return SSL_BAD_FILE;
                }
                int passwordSz = cb(password, sizeof(password), 0,
                                    ctx->GetUserData());
                byte key[AES_256_KEY_SZ];  // max sizes
                byte iv[AES_IV_SZ];

                // use file's salt for key derivation, but not real iv
                TaoCrypt::Source source(info.iv, info.ivSz);
                TaoCrypt::HexDecoder dec(source);
                memcpy(info.iv, source.get_buffer(), min((uint)sizeof(info.iv),
                                                         source.size()));
                EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password,
                               passwordSz, 1, key, iv);

                mySTL::auto_ptr<BulkCipher> cipher;
                if (strncmp(info.name, "DES-CBC", 7) == 0)
                    cipher.reset(NEW_YS DES);
                else if (strncmp(info.name, "DES-EDE3-CBC", 13) == 0)
                    cipher.reset(NEW_YS DES_EDE);
                else if (strncmp(info.name, "AES-128-CBC", 13) == 0)
                    cipher.reset(NEW_YS AES(AES_128_KEY_SZ));
                else if (strncmp(info.name, "AES-192-CBC", 13) == 0)
                    cipher.reset(NEW_YS AES(AES_192_KEY_SZ));
                else if (strncmp(info.name, "AES-256-CBC", 13) == 0)
                    cipher.reset(NEW_YS AES(AES_256_KEY_SZ));
                else {
                    fclose(input);
                    return SSL_BAD_FILE;
                }
                cipher->set_decryptKey(key, info.iv);
                mySTL::auto_ptr<x509> newx(NEW_YS x509(x->get_length()));
                cipher->decrypt(newx->use_buffer(), x->get_buffer(),
                                x->get_length());
                ysDelete(x);
                x = newx.release();
            }
        }
    }

    if (type == PrivateKey && ctx->privateKey_) {
        // see if key is valid early
        TaoCrypt::Source rsaSource(ctx->privateKey_->get_buffer(),
                                   ctx->privateKey_->get_length());
        TaoCrypt::RSA_PrivateKey rsaKey;
        rsaKey.Initialize(rsaSource);

        if (rsaSource.GetError().What()) {
            // rsa failed see if DSA works

            TaoCrypt::Source dsaSource(ctx->privateKey_->get_buffer(),
                                       ctx->privateKey_->get_length());
            TaoCrypt::DSA_PrivateKey dsaKey;
            dsaKey.Initialize(dsaSource);

            if (rsaSource.GetError().What()) {
                // neither worked
                ret = SSL_FAILURE;
            }
        }
    }

    fclose(input);
    return ret;
}


static int jpc_dec_decodepkt(jpc_dec_t *dec, jas_stream_t *pkthdrstream, jas_stream_t *in, int compno, int rlvlno,
  int prcno, int lyrno)
{
	jpc_bitstream_t *inb;
	jpc_dec_tcomp_t *tcomp;
	jpc_dec_rlvl_t *rlvl;
	jpc_dec_band_t *band;
	jpc_dec_cblk_t *cblk;
	int n;
	int m;
	int i;
	jpc_tagtreenode_t *leaf;
	int included;
	int ret;
	int numnewpasses;
	jpc_dec_seg_t *seg;
	int len;
	int present;
	int savenumnewpasses;
	int mycounter;
	jpc_ms_t *ms;
	jpc_dec_tile_t *tile;
	jpc_dec_ccp_t *ccp;
	jpc_dec_cp_t *cp;
	int bandno;
	jpc_dec_prc_t *prc;
	int usedcblkcnt;
	int cblkno;
	uint_fast32_t bodylen;
	bool discard;
	int passno;
	int maxpasses;
	int hdrlen;
	int hdroffstart;
	int hdroffend;

	/* Avoid compiler warning about possible use of uninitialized
	  variable. */
	bodylen = 0;

	discard = (lyrno >= dec->maxlyrs);

	tile = dec->curtile;
	cp = tile->cp;
	ccp = &cp->ccps[compno];

	/*
	 * Decode the packet header.
	 */

	/* Decode the SOP marker segment if present. */
	if (cp->csty & JPC_COD_SOP) {
		if (jpc_dec_lookahead(in) == JPC_MS_SOP) {
			if (!(ms = jpc_getms(in, dec->cstate))) {
				return -1;
			}
			if (jpc_ms_gettype(ms) != JPC_MS_SOP) {
				jpc_ms_destroy(ms);
				jas_eprintf("missing SOP marker segment\n");
				return -1;
			}
			jpc_ms_destroy(ms);
		}
	}

hdroffstart = jas_stream_getrwcount(pkthdrstream);

	if (!(inb = jpc_bitstream_sopen(pkthdrstream, "r"))) {
		return -1;
	}

	if ((present = jpc_bitstream_getbit(inb)) < 0) {
		jpc_bitstream_close(inb);
		return 1;
	}
	JAS_DBGLOG(10, ("\n", present));
	JAS_DBGLOG(10, ("present=%d ", present));

	/* Is the packet non-empty? */
	if (present) {
		/* The packet is non-empty. */
		tcomp = &tile->tcomps[compno];
		rlvl = &tcomp->rlvls[rlvlno];
		bodylen = 0;
		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
		  ++bandno, ++band) {
			if (!band->data) {
				continue;
			}
			prc = &band->prcs[prcno];
			if (!prc->cblks) {
				continue;
			}
			usedcblkcnt = 0;
			for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
			  ++cblkno, ++cblk) {
				++usedcblkcnt;
				if (!cblk->numpasses) {
					leaf = jpc_tagtree_getleaf(prc->incltagtree, usedcblkcnt - 1);
					if ((included = jpc_tagtree_decode(prc->incltagtree, leaf, lyrno + 1, inb)) < 0) {
						jpc_bitstream_close(inb);
						return -1;
					}
				} else {
					if ((included = jpc_bitstream_getbit(inb)) < 0) {
						jpc_bitstream_close(inb);
						return -1;
					}
				}
				JAS_DBGLOG(10, ("\n"));
				JAS_DBGLOG(10, ("included=%d ", included));
				if (!included) {
					continue;
				}
				if (!cblk->numpasses) {
					i = 1;
					leaf = jpc_tagtree_getleaf(prc->numimsbstagtree, usedcblkcnt - 1);
					for (;;) {
						if ((ret = jpc_tagtree_decode(prc->numimsbstagtree, leaf, i, inb)) < 0) {
							jpc_bitstream_close(inb);
							return -1;
						}
						if (ret) {
							break;
						}
						++i;
					}
					cblk->numimsbs = i - 1;
					cblk->firstpassno = cblk->numimsbs * 3;
				}
				if ((numnewpasses = jpc_getnumnewpasses(inb)) < 0) {
					jpc_bitstream_close(inb);
					return -1;
				}
				JAS_DBGLOG(10, ("numnewpasses=%d ", numnewpasses));
				seg = cblk->curseg;
				savenumnewpasses = numnewpasses;
				mycounter = 0;
				if (numnewpasses > 0) {
					if ((m = jpc_getcommacode(inb)) < 0) {
						jpc_bitstream_close(inb);
						return -1;
					}
					cblk->numlenbits += m;
					JAS_DBGLOG(10, ("increment=%d ", m));
					while (numnewpasses > 0) {
						passno = cblk->firstpassno + cblk->numpasses + mycounter;
	/* XXX - the maxpasses is not set precisely but this doesn't matter... */
						maxpasses = JPC_SEGPASSCNT(passno, cblk->firstpassno, 10000, (ccp->cblkctx & JPC_COX_LAZY) != 0, (ccp->cblkctx & JPC_COX_TERMALL) != 0);
						if (!discard && !seg) {
							if (!(seg = jpc_seg_alloc())) {
								jpc_bitstream_close(inb);
								return -1;
							}
							jpc_seglist_insert(&cblk->segs, cblk->segs.tail, seg);
							if (!cblk->curseg) {
								cblk->curseg = seg;
							}
							seg->passno = passno;
							seg->type = JPC_SEGTYPE(seg->passno, cblk->firstpassno, (ccp->cblkctx & JPC_COX_LAZY) != 0);
							seg->maxpasses = maxpasses;
						}
						n = JAS_MIN(numnewpasses, maxpasses);
						mycounter += n;
						numnewpasses -= n;
						if ((len = jpc_bitstream_getbits(inb, cblk->numlenbits + jpc_floorlog2(n))) < 0) {
							jpc_bitstream_close(inb);
							return -1;
						}
						JAS_DBGLOG(10, ("len=%d ", len));
						if (!discard) {
							seg->lyrno = lyrno;
							seg->numpasses += n;
							seg->cnt = len;
							seg = seg->next;
						}
						bodylen += len;
					}
				}
				cblk->numpasses += savenumnewpasses;
			}
		}

		jpc_bitstream_inalign(inb, 0, 0);

	} else {
		if (jpc_bitstream_inalign(inb, 0x7f, 0)) {
			jas_eprintf("alignment failed\n");
			jpc_bitstream_close(inb);
			return -1;
		}
	}
	jpc_bitstream_close(inb);

	hdroffend = jas_stream_getrwcount(pkthdrstream);
	hdrlen = hdroffend - hdroffstart;
	if (jas_getdbglevel() >= 5) {
		jas_eprintf("hdrlen=%lu bodylen=%lu \n", (unsigned long) hdrlen,
		  (unsigned long) bodylen);
	}

	if (cp->csty & JPC_COD_EPH) {
		if (jpc_dec_lookahead(pkthdrstream) == JPC_MS_EPH) {
			if (!(ms = jpc_getms(pkthdrstream, dec->cstate))) {
				jas_eprintf("cannot get (EPH) marker segment\n");
				return -1;
			}
			if (jpc_ms_gettype(ms) != JPC_MS_EPH) {
				jpc_ms_destroy(ms);
				jas_eprintf("missing EPH marker segment\n");
				return -1;
			}
			jpc_ms_destroy(ms);
		}
	}

	/* decode the packet body. */

	if (jas_getdbglevel() >= 1) {
		jas_eprintf("packet body offset=%06ld\n", (long) jas_stream_getrwcount(in));
	}

	if (!discard) {
		tcomp = &tile->tcomps[compno];
		rlvl = &tcomp->rlvls[rlvlno];
		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
		  ++bandno, ++band) {
			if (!band->data) {
				continue;
			}
			prc = &band->prcs[prcno];
			if (!prc->cblks) {
				continue;
			}
			for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
			  ++cblkno, ++cblk) {
				seg = cblk->curseg;
				while (seg) {
					if (!seg->stream) {
						if (!(seg->stream = jas_stream_memopen(0, 0))) {
							return -1;
						}
					}
#if 0
jas_eprintf("lyrno=%02d, compno=%02d, lvlno=%02d, prcno=%02d, bandno=%02d, cblkno=%02d, passno=%02d numpasses=%02d cnt=%d numbps=%d, numimsbs=%d\n", lyrno, compno, rlvlno, prcno, band - rlvl->bands, cblk - prc->cblks, seg->passno, seg->numpasses, seg->cnt, band->numbps, cblk->numimsbs);
#endif
					if (seg->cnt > 0) {
						if (jpc_getdata(in, seg->stream, seg->cnt) < 0) {
							return -1;
						}
						seg->cnt = 0;
					}
					if (seg->numpasses >= seg->maxpasses) {
						cblk->curseg = seg->next;
					}
					seg = seg->next;
				}
			}
		}
	} else {
		if (jas_stream_gobble(in, bodylen) != JAS_CAST(int, bodylen)) {
			return -1;
		}
	}
	return 0;
}


  GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_stubborn(size_t lb,
                                                        GC_EXTRA_PARAMS)
  {
    return GC_debug_malloc(lb, OPT_RA s, i);
  }


    GC_generic_malloc_ignore_off_page(size_t lb, int k)
{
    void *result;
    size_t lg;
    size_t lb_rounded;
    word n_blocks;
    GC_bool init;
    DCL_LOCK_STATE;

    if (SMALL_OBJ(lb))
        return GC_generic_malloc(lb, k);
    GC_ASSERT(k < MAXOBJKINDS);
    lg = ROUNDED_UP_GRANULES(lb);
    lb_rounded = GRANULES_TO_BYTES(lg);
    if (lb_rounded < lb)
        return((*GC_get_oom_fn())(lb));
    n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
    init = GC_obj_kinds[k].ok_init;
    if (EXPECT(GC_have_errors, FALSE))
      GC_print_all_errors();
    GC_INVOKE_FINALIZERS();
    GC_DBG_COLLECT_AT_MALLOC(lb);
    LOCK();
    result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE);
    if (0 != result) {
        if (GC_debugging_started) {
            BZERO(result, n_blocks * HBLKSIZE);
        } else {
#           ifdef THREADS
              /* Clear any memory that might be used for GC descriptors */
              /* before we release the lock.                          */
                ((word *)result)[0] = 0;
                ((word *)result)[1] = 0;
                ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
                ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
#           endif
        }
    }
    GC_bytes_allocd += lb_rounded;
    if (0 == result) {
        GC_oom_func oom_fn = GC_oom_fn;
        UNLOCK();
        return((*oom_fn)(lb));
    } else {
        UNLOCK();
        if (init && !GC_debugging_started) {
            BZERO(result, n_blocks * HBLKSIZE);
        }
        return(result);
    }
}


GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb,
                                                                GC_descr d)
{
    word *op;
    size_t lg;

    GC_ASSERT(GC_explicit_typing_initialized);
    lb += TYPD_EXTRA_BYTES;
    op = GC_malloc_kind(lb, GC_explicit_kind);
    if (EXPECT(NULL == op, FALSE))
        return NULL;
    lg = SMALL_OBJ(lb) ? GC_size_map[lb] : BYTES_TO_GRANULES(GC_size(op));
    op[GRANULES_TO_WORDS(lg) - 1] = d;
    return op;
}


  ptr_t GC_win32_get_mem(word bytes)
  {
    ptr_t result;

# ifndef USE_WINALLOC
    result = GC_unix_get_mem(bytes);
# else
#   ifdef MSWIN32
      if (GLOBAL_ALLOC_TEST) {
        /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */
        /* There are also unconfirmed rumors of other           */
        /* problems, so we dodge the issue.                     */
        result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
        result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
      } else
#   endif
    /* else */ {
        /* VirtualProtect only works on regions returned by a   */
        /* single VirtualAlloc call.  Thus we allocate one      */
        /* extra page, which will prevent merging of blocks     */
        /* in separate regions, and eliminate any temptation    */
        /* to call VirtualProtect on a range spanning regions.  */
        /* This wastes a small amount of memory, and risks      */
        /* increased fragmentation.  But better alternatives    */
        /* would require effort.                                */
#       ifdef MPROTECT_VDB
          /* We can't check for GC_incremental here (because    */
          /* GC_enable_incremental() might be called some time  */
          /* later after the GC initialization).                */
#         ifdef GWW_VDB
#           define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE() ? 0 : 1)
#         else
#           define VIRTUAL_ALLOC_PAD 1
#         endif
#       else
#         define VIRTUAL_ALLOC_PAD 0
#       endif
        /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
        /* VDBs are enabled and the GetWriteWatch function is   */
        /* available.  Otherwise we waste resources or possibly */
        /* cause VirtualAlloc to fail (observed in Windows 2000 */
        /* SP2).                                                */
        result = (ptr_t) VirtualAlloc(NULL, bytes + VIRTUAL_ALLOC_PAD,
                                GetWriteWatch_alloc_flag
                                | (MEM_COMMIT | MEM_RESERVE)
                                | GC_mem_top_down,
                                GC_pages_executable ? PAGE_EXECUTE_READWRITE :
                                                      PAGE_READWRITE);
#       undef IGNORE_PAGES_EXECUTABLE
    }
# endif /* USE_WINALLOC */
    if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
        /* If I read the documentation correctly, this can      */
        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
    if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
    if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
    return(result);
  }


  GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
                                                                int k)
  {
    void * result = GC_generic_malloc_inner_ignore_off_page(
                                                lb + DEBUG_BYTES, k);

    if (result == 0) {
        GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
                       (unsigned long) lb);
        return(0);
    }
    if (!GC_debugging_started) {
        GC_start_debugging_inner();
    }
    ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
    return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
  }


wc_push_to_iso2022(Str os, wc_wchar_t cc, wc_status *st)
{
    wc_uchar g = 0;
    wc_bool is_wide = WC_FALSE, retry = WC_FALSE;
    wc_wchar_t cc2;

  while (1) {
    switch (WC_CCS_TYPE(cc.ccs)) {
    case WC_CCS_A_CS94:
	if (cc.ccs == WC_CCS_US_ASCII)
	    cc.ccs = st->g0_ccs;
	g = cs94_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	break;
    case WC_CCS_A_CS94W:
	is_wide = 1;
	switch (cc.ccs) {
#ifdef USE_UNICODE
	case WC_CCS_JIS_X_0212:
	    if (!WcOption.use_jisx0212 && WcOption.use_jisx0213 &&
		WcOption.ucs_conv) {
		cc2 = wc_jisx0212_to_jisx0213(cc);
		if (cc2.ccs == WC_CCS_JIS_X_0213_1 ||
		    cc2.ccs == WC_CCS_JIS_X_0213_2) {
		    cc = cc2;
		    continue;
		}
	    }
	    break;
	case WC_CCS_JIS_X_0213_1:
	case WC_CCS_JIS_X_0213_2:
	    if (!WcOption.use_jisx0213 && WcOption.use_jisx0212 &&
		WcOption.ucs_conv) {
		cc2 = wc_jisx0213_to_jisx0212(cc);
		if (cc2.ccs == WC_CCS_JIS_X_0212) {
		    cc = cc2;
		    continue;
		}
	    }
	    break;
#endif
	}
	g = cs94w_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	break;
    case WC_CCS_A_CS96:
	g = cs96_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	break;
    case WC_CCS_A_CS96W:
	is_wide = 1;
	g = cs96w_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	break;
    case WC_CCS_A_CS942:
	g = cs942_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	break;
    case WC_CCS_A_UNKNOWN_W:
	if (WcOption.no_replace)
	    return;
	is_wide = 1;
	cc.ccs = WC_CCS_US_ASCII;
	g = cs94_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	cc.code = ((wc_uint32)WC_REPLACE_W[0] << 8) | WC_REPLACE_W[1];
	break;
    case WC_CCS_A_UNKNOWN:
	if (WcOption.no_replace)
	    return;
	cc.ccs = WC_CCS_US_ASCII;
	g = cs94_gmap[WC_CCS_INDEX(cc.ccs) - WC_F_ISO_BASE];
	cc.code = (wc_uint32)WC_REPLACE[0];
	break;
    default:
	if ((cc.ccs == WC_CCS_JOHAB || cc.ccs == WC_CCS_JOHAB_1 ||
		cc.ccs == WC_CCS_JOHAB_2 || cc.ccs == WC_CCS_JOHAB_3) &&
		cs94w_gmap[WC_F_KS_X_1001 - WC_F_ISO_BASE]) {
	    wc_wchar_t cc2 = wc_johab_to_ksx1001(cc);
	    if (cc2.ccs == WC_CCS_KS_X_1001) {
		cc = cc2;
		continue;
	    }
	}
#ifdef USE_UNICODE
	if (WcOption.ucs_conv)
	    cc = wc_any_to_iso2022(cc, st);
	else
#endif
	    cc.ccs = WC_CCS_IS_WIDE(cc.ccs) ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
	continue;
    }
    if (! g) {
#ifdef USE_UNICODE
	if (WcOption.ucs_conv && ! retry)
	    cc = wc_any_to_any_ces(cc, st);
	else
#endif
	    cc.ccs = WC_CCS_IS_WIDE(cc.ccs) ? WC_CCS_UNKNOWN_W : WC_CCS_UNKNOWN;
	retry = WC_TRUE;
	continue;
    }

    wc_push_iso2022_esc(os, cc.ccs, g, 1, st);
    if (is_wide)
	Strcat_char(os, (char)((cc.code >> 8) & 0x7f));
    Strcat_char(os, (char)(cc.code & 0x7f));
    return;
  }
}


static void fd_chr_update_read_handler(CharDriverState *chr,
                                       GMainContext *context,
                                       int tag)
{
    FDCharDriver *s = chr->opaque;

    remove_fd_in_watch(chr);
    if (s->ioc_in) {
        chr->fd_in_tag = io_add_watch_poll(s->ioc_in,
                                           fd_chr_read_poll,
                                           fd_chr_read, chr,
                                           context);
    }
}


static int mux_chr_new_handler_tag(CharDriverState *chr, Error **errp)
{
    MuxDriver *d = chr->opaque;

    if (d->mux_cnt >= MAX_MUX) {
        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
        return -1;
    }

    return d->mux_cnt++;
}


static CharDriverState *qemu_chr_open_mux(const char *id,
                                          ChardevBackend *backend,
                                          ChardevReturn *ret, Error **errp)
{
    ChardevMux *mux = backend->u.mux.data;
    CharDriverState *chr, *drv;
    MuxDriver *d;
    ChardevCommon *common = qapi_ChardevMux_base(mux);

    drv = qemu_chr_find(mux->chardev);
    if (drv == NULL) {
        error_setg(errp, "mux: base chardev %s not found", mux->chardev);
        return NULL;
    }

    chr = qemu_chr_alloc(common, errp);
    if (!chr) {
        return NULL;
    }
    d = g_new0(MuxDriver, 1);

    chr->opaque = d;
    d->focus = -1;
    chr->chr_close = mux_chr_close;
    chr->chr_write = mux_chr_write;
    chr->chr_update_read_handler = mux_chr_update_read_handler;
    chr->chr_accept_input = mux_chr_accept_input;
    /* Frontend guest-open / -close notification is not support with muxes */
    chr->chr_set_fe_open = NULL;
    if (drv->chr_add_watch) {
        chr->chr_add_watch = mux_chr_add_watch;
    }
    /* only default to opened state if we've realized the initial
     * set of muxes
     */
    chr->explicit_be_open = muxes_realized ? 0 : 1;
    chr->is_mux = 1;
    if (!qemu_chr_fe_init(&d->chr, drv, errp)) {
        qemu_chr_free(chr);
        return NULL;
    }

    return chr;
}


static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
    VirtIOGPU *g = VIRTIO_GPU(qdev);
    bool have_virgl;
    int i;

    if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUT) {
        error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUT);
        return;
    }

    g->config_size = sizeof(struct virtio_gpu_config);
    g->virtio_config.num_scanouts = g->conf.max_outputs;
    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
                g->config_size);

    g->req_state[0].width = 1024;
    g->req_state[0].height = 768;

    g->use_virgl_renderer = false;
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
    have_virgl = false;
#else
    have_virgl = display_opengl;
#endif
    if (!have_virgl) {
        g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
    }

    if (virtio_gpu_virgl_enabled(g->conf)) {
        /* use larger control queue in 3d mode */
        g->ctrl_vq   = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
        g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
        g->virtio_config.num_capsets = 1;
    } else {
        g->ctrl_vq   = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
        g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
    }

    g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
    g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
    QTAILQ_INIT(&g->reslist);
    QTAILQ_INIT(&g->cmdq);
    QTAILQ_INIT(&g->fenceq);

    g->enabled_output_bitmask = 1;
    g->qdev = qdev;

    for (i = 0; i < g->conf.max_outputs; i++) {
        g->scanout[i].con =
            graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
        if (i > 0) {
            dpy_gfx_replace_surface(g->scanout[i].con, NULL);
        }
    }

    vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g);
}


static void virtio_gpu_set_scanout(VirtIOGPU *g,
                                   struct virtio_gpu_ctrl_command *cmd)
{
    struct virtio_gpu_simple_resource *res;
    struct virtio_gpu_scanout *scanout;
    pixman_format_code_t format;
    uint32_t offset;
    int bpp;
    struct virtio_gpu_set_scanout ss;

    VIRTIO_GPU_FILL_CMD(ss);
    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);

    if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
        ss.scanout_id >= g->conf.max_outputs) {
        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
                      __func__, ss.scanout_id);
        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
        return;
    }

    g->enable = 1;
    if (ss.resource_id == 0) {
        scanout = &g->scanout[ss.scanout_id];
        if (scanout->resource_id) {
            res = virtio_gpu_find_resource(g, scanout->resource_id);
            if (res) {
                res->scanout_bitmask &= ~(1 << ss.scanout_id);
            }
        }
        if (ss.scanout_id == 0) {
            qemu_log_mask(LOG_GUEST_ERROR,
                          "%s: illegal scanout id specified %d",
                          __func__, ss.scanout_id);
            cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
            return;
        }
        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
        scanout->ds = NULL;
        scanout->width = 0;
        scanout->height = 0;
        return;
    }

    /* create a surface for this scanout */
    res = virtio_gpu_find_resource(g, ss.resource_id);
    if (!res) {
        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
                      __func__, ss.resource_id);
        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
        return;
    }

    if (ss.r.x > res->width ||
        ss.r.y > res->height ||
        ss.r.width > res->width ||
        ss.r.height > res->height ||
        ss.r.x + ss.r.width > res->width ||
        ss.r.y + ss.r.height > res->height) {
        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
                      " resource %d, (%d,%d)+%d,%d vs %d %d\n",
                      __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
                      ss.r.width, ss.r.height, res->width, res->height);
        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
        return;
    }

    scanout = &g->scanout[ss.scanout_id];

    format = pixman_image_get_format(res->image);
    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
    offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
    if (!scanout->ds || surface_data(scanout->ds)
        != ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
        scanout->width != ss.r.width ||
        scanout->height != ss.r.height) {
        /* realloc the surface ptr */
        scanout->ds = qemu_create_displaysurface_pixman(res->image);
        if (!scanout->ds) {
            cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
            return;
        }
        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
    }

    res->scanout_bitmask |= (1 << ss.scanout_id);
    scanout->resource_id = ss.resource_id;
    scanout->x = ss.r.x;
    scanout->y = ss.r.y;
    scanout->width = ss.r.width;
    scanout->height = ss.r.height;
}


QUERY_REC *irc_query_find(IRC_SERVER_REC *server, const char *nick)
{
	GSList *tmp;

	for (tmp = server->queries; tmp != NULL; tmp = tmp->next) {
		QUERY_REC *rec = tmp->data;

		if (server->nick_comp_func(rec->name, nick) == 0)
			return rec;
	}

	return NULL;
}


check_offset(char *memory, int total_size, char *name, void *offset, int size)
{
	ptrdiff_t need_size = (char *) offset - memory + size;

	/*debug("check_offset: size=%x vs %x offset=%x size=%x\n",
		need_size, total_size, (char *) offset - memory, size);*/

	if (need_size < 0 || need_size > total_size) {
		warn(_("%s: premature end"), name);
		return false;
	}

	return true;
}


function_call(int argc, VALUE argv[], VALUE self)
{
    struct nogvl_ffi_call_args args = { 0 };
    fiddle_generic *generic_args;
    VALUE cfunc, types, cPointer;
    int i;
    VALUE alloc_buffer = 0;

    cfunc    = rb_iv_get(self, "@ptr");
    types    = rb_iv_get(self, "@args");
    cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));

    Check_Max_Args("number of arguments", argc);
    if (argc != (i = RARRAY_LENINT(types))) {
	rb_error_arity(argc, i, i);
    }

    TypedData_Get_Struct(self, ffi_cif, &function_data_type, args.cif);

    if (rb_safe_level() >= 1) {
	for (i = 0; i < argc; i++) {
	    VALUE src = argv[i];
	    if (OBJ_TAINTED(src)) {
		rb_raise(rb_eSecurityError, "tainted parameter not allowed");
	    }
	}
    }

    generic_args = ALLOCV(alloc_buffer,
	(size_t)(argc + 1) * sizeof(void *) + (size_t)argc * sizeof(fiddle_generic));
    args.values = (void **)((char *)generic_args +
			    (size_t)argc * sizeof(fiddle_generic));

    for (i = 0; i < argc; i++) {
	VALUE type = RARRAY_AREF(types, i);
	VALUE src = argv[i];

	if(NUM2INT(type) == TYPE_VOIDP) {
	    if(NIL_P(src)) {
		src = INT2FIX(0);
	    } else if(cPointer != CLASS_OF(src)) {
		src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
	    }
	    src = rb_Integer(src);
	}

	VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
	args.values[i] = (void *)&generic_args[i];
    }
    args.values[argc] = NULL;
    args.fn = NUM2PTR(rb_Integer(cfunc));

    (void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);

    rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
#if defined(_WIN32)
    rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
#endif

    ALLOCV_END(alloc_buffer);

    return GENERIC2VALUE(rb_iv_get(self, "@return_type"), args.retval);
}


    if (!NIL_P(exc)) {
        volatile VALUE eclass = rb_obj_class(exc);
        volatile VALUE backtrace;

        DUMP1("(failed)");

        thr_crit_bup = rb_thread_critical;
        rb_thread_critical = Qtrue;

        DUMP1("set backtrace");
        if (!NIL_P(backtrace = rb_funcallv(exc, ID_backtrace, 0, 0))) {
            backtrace = rb_ary_join(backtrace, rb_str_new2("\n"));
            Tcl_AddErrorInfo(interp, StringValuePtr(backtrace));
        }

        rb_thread_critical = thr_crit_bup;

        ip_set_exc_message(interp, exc);

        if (eclass == eTkCallbackReturn)
            return TCL_RETURN;

        if (eclass == eTkCallbackBreak)
            return TCL_BREAK;

        if (eclass == eTkCallbackContinue)
            return TCL_CONTINUE;

        if (eclass == rb_eSystemExit || eclass == rb_eInterrupt) {
            rbtk_pending_exception = exc;
            return TCL_RETURN;
        }

        if (rb_obj_is_kind_of(exc, eTkLocalJumpError)) {
            rbtk_pending_exception = exc;
            return TCL_ERROR;
        }

        if (rb_obj_is_kind_of(exc, eLocalJumpError)) {
            VALUE reason = rb_ivar_get(exc, ID_at_reason);

            if (RB_TYPE_P(reason, T_SYMBOL)) {
                if (SYM2ID(reason) == ID_return)
                    return TCL_RETURN;

                if (SYM2ID(reason) == ID_break)
                    return TCL_BREAK;

                if (SYM2ID(reason) == ID_next)
                    return TCL_CONTINUE;
            }
        }

        return TCL_ERROR;
    }


ip_create_slave_core(interp, argc, argv)
    VALUE interp;
    int   argc;
    VALUE *argv;
{
    struct tcltkip *master = get_ip(interp);
    struct tcltkip *slave;
    /* struct tcltkip *slave = RbTk_ALLOC_N(struct tcltkip, 1); */
    VALUE safemode;
    VALUE name;
    VALUE new_ip;
    int safe;
    int thr_crit_bup;
    Tk_Window mainWin;

    /* ip is deleted? */
    if (deleted_ip(master)) {
        return rb_exc_new2(rb_eRuntimeError,
                           "deleted master cannot create a new slave");
    }

    name     = argv[0];
    safemode = argv[1];

    if (Tcl_IsSafe(master->ip) == 1) {
        safe = 1;
    } else if (safemode == Qfalse || NIL_P(safemode)) {
        safe = 0;
    } else {
        safe = 1;
    }

    thr_crit_bup = rb_thread_critical;
    rb_thread_critical = Qtrue;

#if 0
    /* init Tk */
    if (RTEST(with_tk)) {
        volatile VALUE exc;
        if (!tk_stubs_init_p()) {
            exc = tcltkip_init_tk(interp);
            if (!NIL_P(exc)) {
                rb_thread_critical = thr_crit_bup;
                return exc;
            }
        }
    }
#endif

    new_ip = TypedData_Make_Struct(CLASS_OF(interp), struct tcltkip,
				   &tcltkip_type, slave);
    /* create slave-ip */
#ifdef RUBY_USE_NATIVE_THREAD
    /* slave->tk_thread_id = 0; */
    slave->tk_thread_id = master->tk_thread_id; /* == current thread */
#endif
    slave->ref_count = 0;
    slave->allow_ruby_exit = 0;
    slave->return_value = 0;

    slave->ip = Tcl_CreateSlave(master->ip, StringValuePtr(name), safe);
    if (slave->ip == NULL) {
        rb_thread_critical = thr_crit_bup;
        return rb_exc_new2(rb_eRuntimeError,
                           "fail to create the new slave interpreter");
    }
#if TCL_MAJOR_VERSION >= 8
#if TCL_NAMESPACE_DEBUG
    slave->default_ns = Tcl_GetCurrentNamespace(slave->ip);
#endif
#endif
    rbtk_preserve_ip(slave);

    slave->has_orig_exit
        = Tcl_GetCommandInfo(slave->ip, "exit", &(slave->orig_exit_info));

    /* replace 'exit' command --> 'interp_exit' command */
    mainWin = (tk_stubs_init_p())? Tk_MainWindow(slave->ip): (Tk_Window)NULL;
#if TCL_MAJOR_VERSION >= 8
    DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\"");
    Tcl_CreateObjCommand(slave->ip, "exit", ip_InterpExitObjCmd,
                         (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL);
#else /* TCL_MAJOR_VERSION < 8 */
    DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\"");
    Tcl_CreateCommand(slave->ip, "exit", ip_InterpExitCommand,
                      (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL);
#endif

    /* replace vwait and tkwait */
    ip_replace_wait_commands(slave->ip, mainWin);

    /* wrap namespace command */
    ip_wrap_namespace_command(slave->ip);

    /* define command to replace cmds which depend on slave-slave's MainWin */
#if TCL_MAJOR_VERSION >= 8
    Tcl_CreateObjCommand(slave->ip, "__replace_slave_tk_commands__",
			 ip_rb_replaceSlaveTkCmdsObjCmd,
                         (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#else /* TCL_MAJOR_VERSION < 8 */
    Tcl_CreateCommand(slave->ip, "__replace_slave_tk_commands__",
		      ip_rb_replaceSlaveTkCmdsCommand,
                      (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#endif

    /* set finalizer */
    Tcl_CallWhenDeleted(slave->ip, ip_CallWhenDeleted, (ClientData)mainWin);

    rb_thread_critical = thr_crit_bup;

    return new_ip;
}


inbound_cap_ls (server *serv, char *nick, char *extensions_str,
					 const message_tags_data *tags_data)
{
	char buffer[256];	/* buffer for requesting capabilities and emitting the signal */
	guint32 want_cap; /* format the CAP REQ string based on previous capabilities being requested or not */
	guint32 want_sasl; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */
	char **extensions;
	int i;

	EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPLIST, serv->server_session, nick,
								  extensions_str, NULL, NULL, 0, tags_data->timestamp);
	want_cap = 0;
	want_sasl = 0;

	extensions = g_strsplit (extensions_str, " ", 0);

	strcpy (buffer, "CAP REQ :");

	for (i=0; extensions[i]; i++)
	{
		const char *extension = extensions[i];

		if (!strcmp (extension, "identify-msg"))
		{
			strcat (buffer, "identify-msg ");
			want_cap = 1;
		}
		if (!strcmp (extension, "multi-prefix"))
		{
			strcat (buffer, "multi-prefix ");
			want_cap = 1;
		}
		if (!strcmp (extension, "away-notify"))
		{
			strcat (buffer, "away-notify ");
			want_cap = 1;
		}
		if (!strcmp (extension, "account-notify"))
		{
			strcat (buffer, "account-notify ");
			want_cap = 1;
		}
		if (!strcmp (extension, "extended-join"))
		{
			strcat (buffer, "extended-join ");
			want_cap = 1;
		}
		if (!strcmp (extension, "userhost-in-names"))
		{
			strcat (buffer, "userhost-in-names ");
			want_cap = 1;
		}

		/* bouncers can prefix a name space to the extension so we should use.
		 * znc <= 1.0 uses "znc.in/server-time" and newer use "znc.in/server-time-iso".
		 */
		if (!strcmp (extension, "znc.in/server-time-iso"))
		{
			strcat (buffer, "znc.in/server-time-iso ");
			want_cap = 1;
		}
		if (!strcmp (extension, "znc.in/server-time"))
		{
			strcat (buffer, "znc.in/server-time ");
			want_cap = 1;
		}
		if (prefs.hex_irc_cap_server_time
			 && !strcmp (extension, "server-time"))
		{
			strcat (buffer, "server-time ");
			want_cap = 1;
		}

		/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
		if (!strcmp (extension, "sasl")
			&& ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
			|| (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert)))
		{
			strcat (buffer, "sasl ");
			want_cap = 1;
			want_sasl = 1;
		}
	}

	g_strfreev (extensions);

	if (want_cap)
	{
		/* buffer + 9 = emit buffer without "CAP REQ :" */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
									  buffer + 9, NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
	}
	if (!want_sasl)
	{
		/* if we use SASL, CAP END is dealt via raw numerics */
		serv->sent_capend = TRUE;
		tcp_send_len (serv, "CAP END\r\n", 9);
	}
}


static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
{
    dma_addr_t iov_pa, iov_size;

    cmd->flags = le16_to_cpu(cmd->frame->header.flags);
    if (!cmd->frame->header.sge_count) {
        trace_megasas_dcmd_zero_sge(cmd->index);
        cmd->iov_size = 0;
        return 0;
    } else if (cmd->frame->header.sge_count > 1) {
        trace_megasas_dcmd_invalid_sge(cmd->index,
                                       cmd->frame->header.sge_count);
        cmd->iov_size = 0;
        return -1;
    }
    iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
    iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
    pci_dma_sglist_init(&cmd->qsg, PCI_DEVICE(s), 1);
    qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
    cmd->iov_size = iov_size;
    return cmd->iov_size;
}


static struct entry *tstat_lookup(struct entry *entry, char *comm)
{
	struct entry **head, *curr, *prev;

	head = tstat_hashentry(entry);
	curr = *head;

	/*
	 * The fastpath is when the entry is already hashed,
	 * we do this with the lookup lock held, but with the
	 * table lock not held:
	 */
	while (curr) {
		if (match_entries(curr, entry))
			return curr;

		curr = curr->next;
	}
	/*
	 * Slowpath: allocate, set up and link a new hash entry:
	 */
	prev = NULL;
	curr = *head;

	raw_spin_lock(&table_lock);
	/*
	 * Make sure we have not raced with another CPU:
	 */
	while (curr) {
		if (match_entries(curr, entry))
			goto out_unlock;

		prev = curr;
		curr = curr->next;
	}

	curr = alloc_entry();
	if (curr) {
		*curr = *entry;
		curr->count = 0;
		curr->next = NULL;
		memcpy(curr->comm, comm, TASK_COMM_LEN);

		smp_mb(); /* Ensure that curr is initialized before insert */

		if (prev)
			prev->next = curr;
		else
			*head = curr;
	}
 out_unlock:
	raw_spin_unlock(&table_lock);

	return curr;
}


void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
			    u64 delta_ns, const enum hrtimer_mode mode)
{
	struct hrtimer_clock_base *base, *new_base;
	unsigned long flags;
	int leftmost;

	base = lock_hrtimer_base(timer, &flags);

	/* Remove an active timer from the queue: */
	remove_hrtimer(timer, base, true);

	if (mode & HRTIMER_MODE_REL)
		tim = ktime_add_safe(tim, base->get_time());

	tim = hrtimer_update_lowres(timer, tim, mode);

	hrtimer_set_expires_range_ns(timer, tim, delta_ns);

	/* Switch the timer base, if necessary: */
	new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);

	timer_stats_hrtimer_set_start_info(timer);

	leftmost = enqueue_hrtimer(timer, new_base);
	if (!leftmost)
		goto unlock;

	if (!hrtimer_is_hres_active(timer)) {
		/*
		 * Kick to reschedule the next tick to handle the new timer
		 * on dynticks target.
		 */
		if (new_base->cpu_base->nohz_active)
			wake_up_nohz_cpu(new_base->cpu_base->cpu);
	} else {
		hrtimer_reprogram(timer, new_base);
	}
unlock:
	unlock_hrtimer_base(timer, &flags);
}


static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
{
}


void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
{
	if (timer->start_site)
		return;

	timer->start_site = addr;
	memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
	timer->start_pid = current->pid;
}


int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
{
	struct sk_buff *skb;
	/*
	 * FIXME: what if rebuild_header fails?
	 * Should we be doing a rebuild_header here?
	 */
	int err = inet_sk_rebuild_header(sk);

	if (err != 0)
		return err;

	skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, GFP_ATOMIC);
	if (skb == NULL)
		return -ENOBUFS;

	/* Reserve space for headers and prepare control bits. */
	skb_reserve(skb, sk->sk_prot->max_header);
	DCCP_SKB_CB(skb)->dccpd_type	   = DCCP_PKT_RESET;
	DCCP_SKB_CB(skb)->dccpd_reset_code = code;

	return dccp_transmit_skb(sk, skb);
}


static int parse_line(char *str)
{
	uint8_t array[256];
	uint16_t value, pskey, length = 0;
	char *off, *end;

	pskey = strtol(str + 1, NULL, 16);
	off = strstr(str, "=");
	if (!off)
		return -EIO;

	off++;

	while (1) {
		value = strtol(off, &end, 16);
		if (value == 0 && off == end)
			break;

		array[length++] = value & 0xff;
		array[length++] = value >> 8;

		if (*end == '\0')
			break;

		off = end + 1;
	}

	return psr_put(pskey, array, length);
}


static int oidc_handle_existing_session(request_rec *r, oidc_cfg *cfg,
		oidc_session_t *session) {

	oidc_debug(r, "enter");

	/* get the header name in which the remote user name needs to be passed */
	char *authn_header = oidc_cfg_dir_authn_header(r);
	int pass_headers = oidc_cfg_dir_pass_info_in_headers(r);
	int pass_envvars = oidc_cfg_dir_pass_info_in_envvars(r);

	/* verify current cookie domain against issued cookie domain */
	if (oidc_check_cookie_domain(r, cfg, session) == FALSE)
		return HTTP_UNAUTHORIZED;

	/* check if the maximum session duration was exceeded */
	int rc = oidc_check_max_session_duration(r, cfg, session);
	if (rc != OK)
		return rc;

	/* if needed, refresh claims from the user info endpoint */
	apr_byte_t needs_save = oidc_refresh_claims_from_userinfo_endpoint(r, cfg,
			session);

	/*
	 * we're going to pass the information that we have to the application,
	 * but first we need to scrub the headers that we're going to use for security reasons
	 */
	if (cfg->scrub_request_headers != 0) {

		/* scrub all headers starting with OIDC_ first */
		oidc_scrub_request_headers(r, OIDC_DEFAULT_HEADER_PREFIX,
				oidc_cfg_dir_authn_header(r));

		/*
		 * then see if the claim headers need to be removed on top of that
		 * (i.e. the prefix does not start with the default OIDC_)
		 */
		if ((strstr(cfg->claim_prefix, OIDC_DEFAULT_HEADER_PREFIX)
				!= cfg->claim_prefix)) {
			oidc_scrub_request_headers(r, cfg->claim_prefix, NULL);
		}
	}

	/* set the user authentication HTTP header if set and required */
	if ((r->user != NULL) && (authn_header != NULL))
		oidc_util_set_header(r, authn_header, r->user);

	const char *s_claims = NULL;
	const char *s_id_token = NULL;

	/* copy id_token and claims from session to request state and obtain their values */
	oidc_copy_tokens_to_request_state(r, session, &s_id_token, &s_claims);

	/* set the claims in the app headers  */
	if (oidc_set_app_claims(r, cfg, session, s_claims) == FALSE)
		return HTTP_INTERNAL_SERVER_ERROR;

	if ((cfg->pass_idtoken_as & OIDC_PASS_IDTOKEN_AS_CLAIMS)) {
		/* set the id_token in the app headers */
		if (oidc_set_app_claims(r, cfg, session, s_id_token) == FALSE)
			return HTTP_INTERNAL_SERVER_ERROR;
	}

	if ((cfg->pass_idtoken_as & OIDC_PASS_IDTOKEN_AS_PAYLOAD)) {
		/* pass the id_token JSON object to the app in a header or environment variable */
		oidc_util_set_app_info(r, "id_token_payload", s_id_token,
				OIDC_DEFAULT_HEADER_PREFIX, pass_headers, pass_envvars);
	}

	if ((cfg->pass_idtoken_as & OIDC_PASS_IDTOKEN_AS_SERIALIZED)) {
		if (cfg->session_type != OIDC_SESSION_TYPE_CLIENT_COOKIE) {
			const char *s_id_token = NULL;
			/* get the compact serialized JWT from the session */
			oidc_session_get(r, session, OIDC_IDTOKEN_SESSION_KEY, &s_id_token);
			/* pass the compact serialized JWT to the app in a header or environment variable */
			oidc_util_set_app_info(r, "id_token", s_id_token,
					OIDC_DEFAULT_HEADER_PREFIX, pass_headers, pass_envvars);
		} else {
			oidc_error(r,
					"session type \"client-cookie\" does not allow storing/passing the id_token; use \"OIDCSessionType server-cache\" for that");
		}
	}

	/* set the refresh_token in the app headers/variables, if enabled for this location/directory */
	const char *refresh_token = NULL;
	oidc_session_get(r, session, OIDC_REFRESHTOKEN_SESSION_KEY, &refresh_token);
	if ((oidc_cfg_dir_pass_refresh_token(r) != 0) && (refresh_token != NULL)) {
		/* pass it to the app in a header or environment variable */
		oidc_util_set_app_info(r, "refresh_token", refresh_token,
				OIDC_DEFAULT_HEADER_PREFIX, pass_headers, pass_envvars);
	}

	/* set the access_token in the app headers/variables */
	const char *access_token = NULL;
	oidc_session_get(r, session, OIDC_ACCESSTOKEN_SESSION_KEY, &access_token);
	if (access_token != NULL) {
		/* pass it to the app in a header or environment variable */
		oidc_util_set_app_info(r, "access_token", access_token,
				OIDC_DEFAULT_HEADER_PREFIX, pass_headers, pass_envvars);
	}

	/* set the expiry timestamp in the app headers/variables */
	const char *access_token_expires = NULL;
	oidc_session_get(r, session, OIDC_ACCESSTOKEN_EXPIRES_SESSION_KEY,
			&access_token_expires);
	if (access_token_expires != NULL) {
		/* pass it to the app in a header or environment variable */
		oidc_util_set_app_info(r, "access_token_expires", access_token_expires,
				OIDC_DEFAULT_HEADER_PREFIX, pass_headers, pass_envvars);
	}

	/*
	 * reset the session inactivity timer
	 * but only do this once per 10% of the inactivity timeout interval (with a max to 60 seconds)
	 * for performance reasons
	 *
	 * now there's a small chance that the session ends 10% (or a minute) earlier than configured/expected
	 * cq. when there's a request after a recent save (so no update) and then no activity happens until
	 * a request comes in just before the session should expire
	 * ("recent" and "just before" refer to 10%-with-a-max-of-60-seconds of the inactivity interval after
	 * the start/last-update and before the expiry of the session respectively)
	 *
	 * this is be deemed acceptable here because of performance gain
	 */
	apr_time_t interval = apr_time_from_sec(cfg->session_inactivity_timeout);
	apr_time_t now = apr_time_now();
	apr_time_t slack = interval / 10;
	if (slack > apr_time_from_sec(60))
		slack = apr_time_from_sec(60);
	if (session->expiry - now < interval - slack) {
		session->expiry = now + interval;
		needs_save = TRUE;
	}

	/* check if something was updated in the session and we need to save it again */
	if (needs_save)
		if (oidc_session_save(r, session) == FALSE)
			return HTTP_INTERNAL_SERVER_ERROR;

	/* return "user authenticated" status */
	return OK;
}


static int vnc_cursor_define(VncState *vs)
{
    QEMUCursor *c = vs->vd->cursor;
    PixelFormat pf = qemu_default_pixelformat(32);
    int isize;

    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
        vnc_lock_output(vs);
        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
        vnc_write_u8(vs,  0);  /*  padding     */
        vnc_write_u16(vs, 1);  /*  # of rects  */
        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
                               VNC_ENCODING_RICH_CURSOR);
        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
        vnc_write_pixels_generic(vs, &pf, c->data, isize);
        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
        vnc_unlock_output(vs);
        return 0;
    }
    return -1;
}


static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
                                  void *pixels, int size)
{
    vnc_write(vs, pixels, size);
}


static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
                                             int x, int y, int w, int h,
                                             void *last_bg_,
                                             void *last_fg_,
                                             int *has_bg, int *has_fg)
{
    VncDisplay *vd = vs->vd;
    uint8_t *row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
    pixel_t *irow = (pixel_t *)row;
    int j, i;
    pixel_t *last_bg = (pixel_t *)last_bg_;
    pixel_t *last_fg = (pixel_t *)last_fg_;
    pixel_t bg = 0;
    pixel_t fg = 0;
    int n_colors = 0;
    int bg_count = 0;
    int fg_count = 0;
    int flags = 0;
    uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
    int n_data = 0;
    int n_subtiles = 0;

    for (j = 0; j < h; j++) {
	for (i = 0; i < w; i++) {
	    switch (n_colors) {
	    case 0:
		bg = irow[i];
		n_colors = 1;
		break;
	    case 1:
		if (irow[i] != bg) {
		    fg = irow[i];
		    n_colors = 2;
		}
		break;
	    case 2:
		if (irow[i] != bg && irow[i] != fg) {
		    n_colors = 3;
		} else {
		    if (irow[i] == bg)
			bg_count++;
		    else if (irow[i] == fg)
			fg_count++;
		}
		break;
	    default:
		break;
	    }
	}
	if (n_colors > 2)
	    break;
	irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
    }

    if (n_colors > 1 && fg_count > bg_count) {
	pixel_t tmp = fg;
	fg = bg;
	bg = tmp;
    }

    if (!*has_bg || *last_bg != bg) {
	flags |= 0x02;
	*has_bg = 1;
	*last_bg = bg;
    }

    if (n_colors < 3 && (!*has_fg || *last_fg != fg)) {
	flags |= 0x04;
	*has_fg = 1;
	*last_fg = fg;
    }

    switch (n_colors) {
    case 1:
	n_data = 0;
	break;
    case 2:
	flags |= 0x08;

	irow = (pixel_t *)row;

	for (j = 0; j < h; j++) {
	    int min_x = -1;
	    for (i = 0; i < w; i++) {
		if (irow[i] == fg) {
		    if (min_x == -1)
			min_x = i;
		} else if (min_x != -1) {
		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
		    n_data += 2;
		    n_subtiles++;
		    min_x = -1;
		}
	    }
	    if (min_x != -1) {
		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
		n_data += 2;
		n_subtiles++;
	    }
	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
	}
	break;
    case 3:
	flags |= 0x18;

	irow = (pixel_t *)row;

	if (!*has_bg || *last_bg != bg)
	    flags |= 0x02;

	for (j = 0; j < h; j++) {
	    int has_color = 0;
	    int min_x = -1;
	    pixel_t color = 0; /* shut up gcc */

	    for (i = 0; i < w; i++) {
		if (!has_color) {
		    if (irow[i] == bg)
			continue;
		    color = irow[i];
		    min_x = i;
		    has_color = 1;
		} else if (irow[i] != color) {
		    has_color = 0;
#ifdef GENERIC
                    vnc_convert_pixel(vs, data + n_data, color);
                    n_data += vs->clientds.pf.bytes_per_pixel;
#else
		    memcpy(data + n_data, &color, sizeof(color));
                    n_data += sizeof(pixel_t);
#endif
		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
		    n_data += 2;
		    n_subtiles++;

		    min_x = -1;
		    if (irow[i] != bg) {
			color = irow[i];
			min_x = i;
			has_color = 1;
		    }
		}
	    }
	    if (has_color) {
#ifdef GENERIC
                vnc_convert_pixel(vs, data + n_data, color);
                n_data += vs->clientds.pf.bytes_per_pixel;
#else
                memcpy(data + n_data, &color, sizeof(color));
                n_data += sizeof(pixel_t);
#endif
		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
		n_data += 2;
		n_subtiles++;
	    }
	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
	}

	/* A SubrectsColoured subtile invalidates the foreground color */
	*has_fg = 0;
	if (n_data > (w * h * sizeof(pixel_t))) {
	    n_colors = 4;
	    flags = 0x01;
	    *has_bg = 0;

	    /* we really don't have to invalidate either the bg or fg
	       but we've lost the old values.  oh well. */
	}
        break;
    default:
	break;
    }

    if (n_colors > 3) {
	flags = 0x01;
	*has_fg = 0;
	*has_bg = 0;
	n_colors = 4;
    }

    vnc_write_u8(vs, flags);
    if (n_colors < 4) {
	if (flags & 0x02)
	    vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
	if (flags & 0x04)
	    vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
	if (n_subtiles) {
	    vnc_write_u8(vs, n_subtiles);
	    vnc_write(vs, data, n_data);
	}
    } else {
	for (j = 0; j < h; j++) {
	    vs->write_pixels(vs, &vd->server->pf, row,
                             w * ds_get_bytes_per_pixel(vs->ds));
	    row += ds_get_linesize(vs->ds);
	}
    }
}


compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
{
  int r;
  tor_assert(a);
  tor_assert(b);

  if ((r = fast_memcmp(a->status.identity_digest, b->status.identity_digest,
                  DIGEST_LEN)))
    return r;
  if ((r = fast_memcmp(a->status.descriptor_digest,
                       b->status.descriptor_digest,
                       DIGEST_LEN)))
    return r;
  if ((r = (int)(b->status.published_on - a->status.published_on)))
    return r;
  if ((r = strcmp(b->status.nickname, a->status.nickname)))
    return r;
  if ((r = (((int)b->status.addr) - ((int)a->status.addr))))
    return r;
  if ((r = (((int)b->status.or_port) - ((int)a->status.or_port))))
    return r;
  if ((r = (((int)b->status.dir_port) - ((int)a->status.dir_port))))
    return r;
  return 0;
}


int main(int argc, char **argv)
{
  MYSQL mysql;
  option_string *eptr;

  MY_INIT(argv[0]);

  my_getopt_use_args_separator= TRUE;
  if (load_defaults("my",load_default_groups,&argc,&argv))
  {
    my_end(0);
    exit(1);
  }
  my_getopt_use_args_separator= FALSE;
  defaults_argv=argv;
  if (get_options(&argc,&argv))
  {
    free_defaults(defaults_argv);
    my_end(0);
    exit(1);
  }

  /* Seed the random number generator if we will be using it. */
  if (auto_generate_sql)
    srandom((uint)time(NULL));

  /* globals? Yes, so we only have to run strlen once */
  delimiter_length= strlen(delimiter);

  if (argc > 2)
  {
    fprintf(stderr,"%s: Too many arguments\n",my_progname);
    free_defaults(defaults_argv);
    my_end(0);
    exit(1);
  }
  mysql_init(&mysql);
  if (opt_compress)
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
  {
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
                  opt_ssl_capath, opt_ssl_cipher);
    mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
    mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
  }
#endif
  if (opt_protocol)
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
  if (!opt_secure_auth && slap_connect(&mysql))
    mysql_options(&mysql, MYSQL_SECURE_AUTH,(char*)&opt_secure_auth);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
#endif
  mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);

  if (opt_plugin_dir && *opt_plugin_dir)
    mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);

  if (opt_default_auth && *opt_default_auth)
    mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);

  mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
  mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
                 "program_name", "mysqlslap");
  if (using_opt_enable_cleartext_plugin)
    mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
                  (char*) &opt_enable_cleartext_plugin);
  if (!opt_only_print)
  {
    if (!(mysql_connect_ssl_check(&mysql, host, user, opt_password,
                                  NULL, opt_mysql_port, opt_mysql_unix_port,
                                  connect_flags, opt_ssl_required)))
    {
      fprintf(stderr,"%s: Error when connecting to server: %s\n",
              my_progname,mysql_error(&mysql));
      free_defaults(defaults_argv);
      my_end(0);
      exit(1);
    }
  }

  pthread_mutex_init(&counter_mutex, NULL);
  pthread_cond_init(&count_threshhold, NULL);
  pthread_mutex_init(&sleeper_mutex, NULL);
  pthread_cond_init(&sleep_threshhold, NULL);

  /* Main iterations loop */
  eptr= engine_options;
  do
  {
    /* For the final stage we run whatever queries we were asked to run */
    uint *current;

    if (verbose >= 2)
      printf("Starting Concurrency Test\n");

    if (*concurrency)
    {
      for (current= concurrency; current && *current; current++)
        concurrency_loop(&mysql, *current, eptr);
    }
    else
    {
      uint infinite= 1;
      do {
        concurrency_loop(&mysql, infinite, eptr);
      }
      while (infinite++);
    }

    if (!opt_preserve)
      drop_schema(&mysql, create_schema_string);

  } while (eptr ? (eptr= eptr->next) : 0);

  pthread_mutex_destroy(&counter_mutex);
  pthread_cond_destroy(&count_threshhold);
  pthread_mutex_destroy(&sleeper_mutex);
  pthread_cond_destroy(&sleep_threshhold);

  if (!opt_only_print)
    mysql_close(&mysql); /* Close & free connection */

  /* now free all the strings we created */
  my_free(opt_password);
  my_free(concurrency);

  statement_cleanup(create_statements);
  statement_cleanup(query_statements);
  statement_cleanup(pre_statements);
  statement_cleanup(post_statements);
  option_cleanup(engine_options);

#ifdef HAVE_SMEM
  my_free(shared_memory_base_name);
#endif
  free_defaults(defaults_argv);
  my_end(my_end_arg);

  return 0;
}