gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_param_list * plist)
{
    int ecode, code;
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
    float cl = (float)pdev->CompatibilityLevel;
    bool locked = pdev->params.LockDistillerParams, ForOPDFRead;
    gs_param_name param_name;

    pdev->pdf_memory = gs_memory_stable(pdev->memory);
    /*
     * If this is a pseudo-parameter (pdfmark or DSC),
     * don't bother checking for any real ones.
     */

    {
        gs_param_string_array ppa;
        gs_param_string pps;

        code = param_read_string_array(plist, (param_name = "pdfmark"), &ppa);
        switch (code) {
            case 0:
                code = pdfwrite_pdf_open_document(pdev);
                if (code < 0)
                    return code;
                code = pdfmark_process(pdev, &ppa);
                if (code >= 0)
                    return code;
                /* falls through for errors */
            default:
                param_signal_error(plist, param_name, code);
                return code;
            case 1:
                break;
        }

        code = param_read_string_array(plist, (param_name = "DSC"), &ppa);
        switch (code) {
            case 0:
                code = pdfwrite_pdf_open_document(pdev);
                if (code < 0)
                    return code;
                code = pdf_dsc_process(pdev, &ppa);
                if (code >= 0)
                    return code;
                /* falls through for errors */
            default:
                param_signal_error(plist, param_name, code);
                return code;
            case 1:
                break;
        }

        code = param_read_string(plist, (param_name = "pdfpagelabels"), &pps);
        switch (code) {
            case 0:
                {
                    if (!pdev->ForOPDFRead) {
                        cos_dict_t *const pcd = pdev->Catalog;
                        code = pdfwrite_pdf_open_document(pdev);
                        if (code < 0)
                            return code;
                        code = cos_dict_put_string(pcd, (const byte *)"/PageLabels", 11,
                                   pps.data, pps.size);
                        if (code >= 0)
                            return code;
                    } else
                        return 0;
                 }
                /* falls through for errors */
            default:
                param_signal_error(plist, param_name, code);
                return code;
            case 1:
                break;
        }
    }

    /*
     * Check for LockDistillerParams before doing anything else.
     * If LockDistillerParams is true and is not being set to false,
     * ignore all resettings of PDF-specific parameters.  Note that
     * LockDistillerParams is read again, and reset if necessary, in
     * psdf_put_params.
     */
    ecode = param_read_bool(plist, "LockDistillerParams", &locked);
    if (ecode < 0)
        param_signal_error(plist, param_name, ecode);

    /* General parameters. */

    {
        int efo = 1;

        ecode = param_put_int(plist, (param_name = ".EmbedFontObjects"), &efo, ecode);
        if (ecode < 0)
            param_signal_error(plist, param_name, ecode);
        if (efo != 1)
            param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
    }
    {
        int cdv = CoreDistVersion;

        ecode = param_put_int(plist, (param_name = "CoreDistVersion"), &cdv, ecode);
        if (ecode < 0)
            return gs_note_error(ecode);
        if (cdv != CoreDistVersion)
            param_signal_error(plist, param_name, ecode = gs_error_rangecheck);
    }

    switch (code = param_read_float(plist, (param_name = "CompatibilityLevel"), &cl)) {
        default:
            ecode = code;
            param_signal_error(plist, param_name, ecode);
            break;
        case 0:
            if (!(locked && pdev->params.LockDistillerParams)) {
                /*
                 * Must be 1.2, 1.3, 1.4, or 1.5.  Per Adobe documentation, substitute
                 * the nearest achievable value.
                 */
                if (cl < (float)1.15)
                    cl = (float)1.1;
                else if (cl < (float)1.25)
                    cl = (float)1.2;
                else if (cl < (float)1.35)
                    cl = (float)1.3;
                else if (cl < (float)1.45)
                    cl = (float)1.4;
                else if (cl < (float)1.55)
                    cl = (float)1.5;
                else if (cl < (float)1.65)
                    cl = (float)1.6;
                else if (cl < (float)1.75)
                    cl = (float)1.7;
                else {
                    cl = (float)2.0;
                    if (pdev->params.TransferFunctionInfo == tfi_Preserve)
                        pdev->params.TransferFunctionInfo = tfi_Apply;
                }
            }
        case 1:
            break;
    }
    {   /* HACK : gs_param_list_s::memory is documented in gsparam.h as
           "for allocating coerced arrays". Not sure why zputdeviceparams
           sets it to the current memory space, while the device
           assumes to store them in the device's memory space.
           As a hackish workaround we temporary replace it here.
           Doing so because we don't want to change the global code now
           because we're unable to test it with all devices.
           Bug 688531 "Segmentation fault running pdfwrite from 219-01.ps".

           This solution to be reconsidered after fixing
           the bug 688533 "zputdeviceparams specifies a wrong memory space.".
        */
        gs_memory_t *mem = plist->memory;

        plist->memory = pdev->pdf_memory;
        code = gs_param_read_items(plist, pdev, pdf_param_items);
        if (code < 0 || (code = param_read_bool(plist, "ForOPDFRead", &ForOPDFRead)) < 0)
        {
        }
        if (code == 0 && !pdev->is_ps2write && !(locked && pdev->params.LockDistillerParams))
            pdev->ForOPDFRead = ForOPDFRead;
        plist->memory = mem;
    }
    if (code < 0)
        ecode = code;
    {
        /*
         * Setting FirstObjectNumber is only legal if the file
         * has just been opened and nothing has been written,
         * or if we are setting it to the same value.
         */
        long fon = pdev->FirstObjectNumber;

        if (fon != save_dev->FirstObjectNumber) {
            if (fon <= 0 || fon > 0x7fff0000 ||
                (pdev->next_id != 0 &&
                 pdev->next_id !=
                 save_dev->FirstObjectNumber + pdf_num_initial_ids)
                ) {
                ecode = gs_error_rangecheck;
                param_signal_error(plist, "FirstObjectNumber", ecode);
            }
        }
    }
    {
        /*
         * Set ProcessColorModel now, because gx_default_put_params checks
         * it.
         */
        static const char *const pcm_names[] = {
            "DeviceGray", "DeviceRGB", "DeviceCMYK", "DeviceN", 0
        };
        int pcm = -1;

        ecode = param_put_enum(plist, "ProcessColorModel", &pcm,
                               pcm_names, ecode);
        if (pcm >= 0) {
            pdf_set_process_color_model(pdev, pcm);
            rc_decrement(pdev->icc_struct, "gdev_pdf_put_params_impl, ProcessColorModel changed");
            pdev->icc_struct = 0;
        }
    }
    if (ecode < 0)
        goto fail;

    if (pdev->is_ps2write && (code = param_read_bool(plist, "ProduceDSC", &pdev->ProduceDSC)) < 0) {
        param_signal_error(plist, param_name, code);
    }

    /* PDFA and PDFX are stored in the page device dictionary and therefore
     * set on every setpagedevice. However, if we have encountered a file which
     * can't be made this way, and the PDFACompatibilityPolicy is 1, we want to
     * continue producing the file, but not as a PDF/A or PDF/X file. Its more
     * or less impossible to alter the setting in the (potentially saved) page
     * device dictionary, so we use this rather clunky method.
     */
    if (pdev->PDFA < 0 || pdev->PDFA > 3){
        ecode = gs_note_error(gs_error_rangecheck);
        param_signal_error(plist, "PDFA", ecode);
        goto fail;
    }
    if(pdev->PDFA != 0 && pdev->AbortPDFAX)
        pdev->PDFA = 0;
    if(pdev->PDFX && pdev->AbortPDFAX)
        pdev->PDFX = 0;
    if (pdev->PDFX && pdev->PDFA != 0) {
        ecode = gs_note_error(gs_error_rangecheck);
        param_signal_error(plist, "PDFA", ecode);
        goto fail;
    }
    if (pdev->PDFX && pdev->ForOPDFRead) {
        ecode = gs_note_error(gs_error_rangecheck);
        param_signal_error(plist, "PDFX", ecode);
        goto fail;
    }
    if (pdev->PDFA != 0 && pdev->ForOPDFRead) {
        ecode = gs_note_error(gs_error_rangecheck);
        param_signal_error(plist, "PDFA", ecode);
        goto fail;
    }
    if (pdev->PDFA == 1 || pdev->PDFX || pdev->CompatibilityLevel < 1.4) {
         pdev->HaveTransparency = false;
         pdev->PreserveSMask = false;
    }

    /*
     * We have to set version to the new value, because the set of
     * legal parameter values for psdf_put_params varies according to
     * the version.
     */
    if (pdev->PDFX)
        cl = (float)1.3; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
    if (pdev->PDFA != 0 && cl < 1.4)
        cl = (float)1.4;
    pdev->version = (cl < 1.2 ? psdf_version_level2 : psdf_version_ll3);
    if (pdev->ForOPDFRead) {
        pdev->ResourcesBeforeUsage = true;
        pdev->HaveCFF = false;
        pdev->HavePDFWidths = false;
        pdev->HaveStrokeColor = false;
        cl = (float)1.2; /* Instead pdev->CompatibilityLevel = 1.2; - see below. */
        pdev->MaxInlineImageSize = max_long; /* Save printer's RAM from saving temporary image data.
                                                Immediate images doen't need buffering. */
        pdev->version = psdf_version_level2;
    } else {
        pdev->ResourcesBeforeUsage = false;
        pdev->HaveCFF = true;
        pdev->HavePDFWidths = true;
        pdev->HaveStrokeColor = true;
    }
    pdev->ParamCompatibilityLevel = cl;
    if (cl < 1.2) {
        pdev->HaveCFF = false;
    }
    ecode = gdev_psdf_put_params(dev, plist);
    if (ecode < 0)
        goto fail;

    if (pdev->CompatibilityLevel > 1.7 && pdev->params.TransferFunctionInfo == tfi_Preserve) {
        pdev->params.TransferFunctionInfo = tfi_Apply;
        emprintf(pdev->memory, "\nIt is not possible to preserve transfer functions in PDF 2.0\ntransfer functions will be applied instead\n");
    }

    if (pdev->params.ConvertCMYKImagesToRGB) {
        if (pdev->params.ColorConversionStrategy == ccs_CMYK) {
            emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of CMYK\n");
        } else {
            if (pdev->params.ColorConversionStrategy == ccs_Gray) {
                emprintf(pdev->memory, "ConvertCMYKImagesToRGB is not compatible with ColorConversionStrategy of Gray\n");
            } else {
                if (pdev->icc_struct)
                    rc_decrement(pdev->icc_struct,
                                 "reset default profile\n");
                pdf_set_process_color_model(pdev,1);
                ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
                if (ecode < 0)
                    goto fail;
            }
        }
    }
    switch (pdev->params.ColorConversionStrategy) {
        case ccs_ByObjectType:
        case ccs_LeaveColorUnchanged:
            break;
        case ccs_UseDeviceDependentColor:
        case ccs_UseDeviceIndependentColor:
        case ccs_UseDeviceIndependentColorForImages:
            pdev->params.TransferFunctionInfo = tfi_Apply;
            break;
        case ccs_CMYK:
            pdev->params.TransferFunctionInfo = tfi_Apply;
            if (pdev->icc_struct)
                rc_decrement(pdev->icc_struct,
                             "reset default profile\n");
            pdf_set_process_color_model(pdev, 2);
            ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
            if (ecode < 0)
                goto fail;
            break;
        case ccs_Gray:
            pdev->params.TransferFunctionInfo = tfi_Apply;
            if (pdev->icc_struct)
                rc_decrement(pdev->icc_struct,
                             "reset default profile\n");
            pdf_set_process_color_model(pdev,0);
            ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
            if (ecode < 0)
                goto fail;
            break;
        case ccs_sRGB:
        case ccs_RGB:
            pdev->params.TransferFunctionInfo = tfi_Apply;
            /* Only bother to do this if we didn't handle it above */
            if (!pdev->params.ConvertCMYKImagesToRGB) {
                if (pdev->icc_struct)
                    rc_decrement(pdev->icc_struct,
                                 "reset default profile\n");
                pdf_set_process_color_model(pdev,1);
                ecode = gsicc_init_device_profile_struct((gx_device *)pdev, NULL, 0);
                if (ecode < 0)
                    goto fail;
            }
            break;
        default:
            break;
    }
    if (cl < 1.5f && pdev->params.ColorImage.Filter != NULL &&
            !strcmp(pdev->params.ColorImage.Filter, "JPXEncode")) {
        emprintf(pdev->memory,
                 "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
        ecode = gs_note_error(gs_error_rangecheck);
    }
    if (cl < 1.5f && pdev->params.GrayImage.Filter != NULL &&
            !strcmp(pdev->params.GrayImage.Filter, "JPXEncode")) {
        emprintf(pdev->memory,
                 "JPXEncode requires CompatibilityLevel >= 1.5 .\n");
        ecode = gs_note_error(gs_error_rangecheck);
    }
    if (cl < 1.4f && pdev->params.MonoImage.Filter != NULL &&
            !strcmp(pdev->params.MonoImage.Filter, "JBIG2Encode")) {
        emprintf(pdev->memory,
                 "JBIG2Encode requires CompatibilityLevel >= 1.4 .\n");
        ecode = gs_note_error(gs_error_rangecheck);
    }
    if (pdev->HaveTrueTypes && pdev->version == psdf_version_level2) {
        pdev->version = psdf_version_level2_with_TT ;
    }
    if (ecode < 0)
        goto fail;

    if (pdev->FirstObjectNumber != save_dev->FirstObjectNumber) {
        if (pdev->xref.file != 0) {
            if (gp_fseek_64(pdev->xref.file, 0L, SEEK_SET) != 0) {
                ecode = gs_error_ioerror;
                goto fail;
            }
            pdf_initialize_ids(pdev);
        }
    }
    /* Handle the float/double mismatch. */
    pdev->CompatibilityLevel = (int)(cl * 10 + 0.5) / 10.0;
    if(pdev->OwnerPassword.size != save_dev->OwnerPassword.size ||
        (pdev->OwnerPassword.size != 0 &&
         memcmp(pdev->OwnerPassword.data, save_dev->OwnerPassword.data,
         pdev->OwnerPassword.size) != 0)) {
        if (pdev->is_open) {
            if (pdev->PageCount == 0) {
                gs_closedevice((gx_device *)save_dev);
                return 0;
            }
            else
                emprintf(pdev->memory, "Owner Password changed mid-job, ignoring.\n");
        }
    }

    if (pdev->Linearise && pdev->is_ps2write) {
        emprintf(pdev->memory, "Can't linearise PostScript output, ignoring\n");
        pdev->Linearise = false;
    }

    if (pdev->Linearise && pdev->OwnerPassword.size != 0) {
        emprintf(pdev->memory, "Can't linearise encrypted PDF, ignoring\n");
        pdev->Linearise = false;
    }

    if (pdev->FlattenFonts)
        pdev->PreserveTrMode = false;
    return 0;
 fail:
    /* Restore all the parameters to their original state. */
    pdev->version = save_dev->version;
    pdf_set_process_color_model(pdev, save_dev->pcm_color_info_index);
    pdev->saved_fill_color = save_dev->saved_fill_color;
    pdev->saved_stroke_color = save_dev->saved_fill_color;
    {
        const gs_param_item_t *ppi = pdf_param_items;

        for (; ppi->key; ++ppi)
            memcpy((char *)pdev + ppi->offset,
                   (char *)save_dev + ppi->offset,
                   gs_param_type_sizes[ppi->type]);
        pdev->ForOPDFRead = save_dev->ForOPDFRead;
    }
    return ecode;
}


ref_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
{
    iparam_list *const iplist = (iparam_list *) plist;
    iparam_loc loc;

    ref_param_read(iplist, pkey, &loc, -1);	/* can't fail */
    *loc.presult = code;
    switch (ref_param_read_get_policy(plist, pkey)) {
        case gs_param_policy_ignore:
            return 0;
        case gs_param_policy_consult_user:
            return_error(gs_error_configurationerror);
        default:
            return code;
    }
}


int get_random_value(unsigned char *data, int length)
{
  SECStatus rv = PK11_GenerateRandom(data,length);
  if (rv != SECSuccess) {
    DBG1("couldn't generate random number: %s", SECU_Strerror(PR_GetError()));
  }
  return (rv == SECSuccess) ? 0 : -1;
}


static StringInfo *ParseImageResourceBlocks(Image *image,
  const unsigned char *blocks,size_t length,
  MagickBooleanType *has_merged_image)
{
  const unsigned char
    *p;

  StringInfo
    *profile;

  unsigned char
    name_length;

  unsigned int
    count;

  unsigned short
    id,
    short_sans;

  if (length < 16)
    return((StringInfo *) NULL);
  profile=BlobToStringInfo((const void *) NULL,length);
  SetStringInfoDatum(profile,blocks);
  SetStringInfoName(profile,"8bim");
  for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
  {
    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
      break;
    p+=4;
    p=PushShortPixel(MSBEndian,p,&id);
    p=PushCharPixel(p,&name_length);
    if (name_length % 2 == 0)
      name_length++;
    p+=name_length;
    if (p > (blocks+length-4))
      break;
    p=PushLongPixel(MSBEndian,p,&count);
    if ((p+count) > (blocks+length))
      break;
    switch (id)
    {
      case 0x03ed:
      {
        char
          value[MaxTextExtent];

        unsigned short
          resolution;

        /*
          Resolution info.
        */
        if (count < 16)
          break;
        p=PushShortPixel(MSBEndian,p,&resolution);
        image->x_resolution=(double) resolution;
        (void) FormatLocaleString(value,MaxTextExtent,"%g",
          image->x_resolution);
        (void) SetImageProperty(image,"tiff:XResolution",value);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        p=PushShortPixel(MSBEndian,p,&resolution);
        image->y_resolution=(double) resolution;
        (void) FormatLocaleString(value,MaxTextExtent,"%g",
          image->y_resolution);
        (void) SetImageProperty(image,"tiff:YResolution",value);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        p=PushShortPixel(MSBEndian,p,&short_sans);
        image->units=PixelsPerInchResolution;
        break;
      }
      case 0x0421:
      {
        if ((count > 4) && (*(p+4) == 0))
          *has_merged_image=MagickFalse;
        p+=count;
        break;
      }
      default:
      {
        p+=count;
        break;
      }
    }
    if ((count & 0x01) != 0)
      p++;
  }
  return(profile);
}


void aes_crypt_ecb( aes_context *ctx,
                    int mode,
                    const unsigned char input[16],
                    unsigned char output[16] )
{
    int i;
    unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3;

#if defined(XYSSL_PADLOCK_C) && defined(XYSSL_HAVE_X86)
    if( padlock_supports( PADLOCK_ACE ) )
    {
        if( padlock_xcryptecb( ctx, mode, input, output ) == 0 )
            return;
    }
#endif

    RK = ctx->rk;

    GET_ULONG_LE( X0, input,  0 ); X0 ^= *RK++;
    GET_ULONG_LE( X1, input,  4 ); X1 ^= *RK++;
    GET_ULONG_LE( X2, input,  8 ); X2 ^= *RK++;
    GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++;

    if( mode == AES_DECRYPT )
    {
        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
        {
            AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
            AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
        }

        AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );

        X0 = *RK++ ^ ( RSb[ ( Y0       ) & 0xFF ]       ) ^
                     ( RSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)RSb[ ( Y1 >> 24 ) & 0xFF ]) << 24 );

        X1 = *RK++ ^ ( RSb[ ( Y1       ) & 0xFF ]       ) ^
                     ( RSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)RSb[ ( Y2 >> 24 ) & 0xFF ]) << 24 );

        X2 = *RK++ ^ ( RSb[ ( Y2       ) & 0xFF ]       ) ^
                     ( RSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)RSb[ ( Y3 >> 24 ) & 0xFF ]) << 24 );

        X3 = *RK++ ^ ( RSb[ ( Y3       ) & 0xFF ]       ) ^
                     ( RSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)RSb[ ( Y0 >> 24 ) & 0xFF ]) << 24 );
    }
    else /* AES_ENCRYPT */
    {
        for( i = (ctx->nr >> 1) - 1; i > 0; i-- )
        {
            AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );
            AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 );
        }

        AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 );

        X0 = *RK++ ^ ( FSb[ ( Y0       ) & 0xFF ]       ) ^
                     ( FSb[ ( Y1 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)FSb[ ( Y3 >> 24 ) & 0xFF ]) << 24 );

        X1 = *RK++ ^ ( FSb[ ( Y1       ) & 0xFF ]       ) ^
                     ( FSb[ ( Y2 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)FSb[ ( Y0 >> 24 ) & 0xFF ]) << 24 );

        X2 = *RK++ ^ ( FSb[ ( Y2       ) & 0xFF ]       ) ^
                     ( FSb[ ( Y3 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)FSb[ ( Y1 >> 24 ) & 0xFF ]) << 24 );

        X3 = *RK++ ^ ( FSb[ ( Y3       ) & 0xFF ]       ) ^
                     ( FSb[ ( Y0 >>  8 ) & 0xFF ] <<  8 ) ^
                     ( FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^
                     ( ((unsigned int)FSb[ ( Y2 >> 24 ) & 0xFF ]) << 24 );
    }

    PUT_ULONG_LE( X0, output,  0 );
    PUT_ULONG_LE( X1, output,  4 );
    PUT_ULONG_LE( X2, output,  8 );
    PUT_ULONG_LE( X3, output, 12 );
}


gdev_x_open(gx_device_X * xdev)
{
    XSizeHints sizehints;
    char *window_id;
    XEvent event;
    XVisualInfo xvinfo;
    int nitems;
    XtAppContext app_con;
    Widget toplevel;
    Display *dpy;
    XColor xc;
    int zero = 0;
    int xid_height = 0, xid_width = 0;
    int code;

#ifdef DEBUG
# ifdef have_Xdebug
    if (gs_debug['X']) {
        extern int _Xdebug;

        _Xdebug = 1;
    }
# endif
#endif
    if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
        char *dispname = getenv("DISPLAY");

        emprintf1(xdev->memory,
                  "Cannot open X display `%s'.\n",
                 (dispname == NULL ? "(null)" : dispname));
        return_error(gs_error_ioerror);
    }
    xdev->dest = 0;
    if ((window_id = getenv("GHOSTVIEW"))) {
        if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
                                       &(xdev->win), &(xdev->dest)))) {
            emprintf(xdev->memory, "Cannot get Window ID from ghostview.\n");
            return_error(gs_error_ioerror);
        }
    }
    if (xdev->pwin != (Window) None) {	/* pick up the destination window parameters if specified */
        XWindowAttributes attrib;

        xdev->win = xdev->pwin;
        if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
            xdev->scr = attrib.screen;
            xvinfo.visual = attrib.visual;
            xdev->cmap = attrib.colormap;
            xid_width = attrib.width;
            xid_height = attrib.height;
        } else {
            /* No idea why we can't get the attributes, but */
            /* we shouldn't let it lead to a failure below. */
            xid_width = xid_height = 0;
        }
    } else if (xdev->ghostview) {
        XWindowAttributes attrib;
        Atom type;
        int format;
        unsigned long nitems, bytes_after;
        char *buf;
        Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);

        if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
            xdev->scr = attrib.screen;
            xvinfo.visual = attrib.visual;
            xdev->cmap = attrib.colormap;
            xdev->width = attrib.width;
            xdev->height = attrib.height;
        }
        /* Delete property if explicit dest is given */
        if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
                               256, (xdev->dest != 0), XA_STRING,
                               &type, &format, &nitems, &bytes_after,
                               (unsigned char **)&buf) == 0 &&
            type == XA_STRING) {
            int llx, lly, urx, ury;
            int left_margin = 0, bottom_margin = 0;
            int right_margin = 0, top_margin = 0;

            /* We declare page_orientation as an int so that we can */
            /* use an int * to reference it for sscanf; compilers */
            /* might be tempted to use less space to hold it if */
            /* it were declared as an orientation. */
            int /*orientation */ page_orientation;
            float xppp, yppp;	/* pixels per point */

            nitems = sscanf(buf,
                            "%ld %d %d %d %d %d %f %f %d %d %d %d",
                            &(xdev->bpixmap), &page_orientation,
                            &llx, &lly, &urx, &ury,
                            &(xdev->x_pixels_per_inch),
                            &(xdev->y_pixels_per_inch),
                            &left_margin, &bottom_margin,
                            &right_margin, &top_margin);
            if (!(nitems == 8 || nitems == 12)) {
                emprintf(xdev->memory, "Cannot get ghostview property.\n");
                return_error(gs_error_ioerror);
            }
            if (xdev->dest && xdev->bpixmap) {
                emprintf(xdev->memory,
                         "Both destination and backing pixmap specified.\n");
                return_error(gs_error_rangecheck);
            }
            if (xdev->dest) {
                Window root;
                int x, y;
                unsigned int width, height;
                unsigned int border_width, depth;

                if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
                                 &width, &height, &border_width, &depth)) {
                    xdev->width = width;
                    xdev->height = height;
                }
            }
            xppp = xdev->x_pixels_per_inch / 72.0;
            yppp = xdev->y_pixels_per_inch / 72.0;
            switch (page_orientation) {
                case Portrait:
                    xdev->initial_matrix.xx = xppp;
                    xdev->initial_matrix.xy = 0.0;
                    xdev->initial_matrix.yx = 0.0;
                    xdev->initial_matrix.yy = -yppp;
                    xdev->initial_matrix.tx = -llx * xppp;
                    xdev->initial_matrix.ty = ury * yppp;
                    break;
                case Landscape:
                    xdev->initial_matrix.xx = 0.0;
                    xdev->initial_matrix.xy = yppp;
                    xdev->initial_matrix.yx = xppp;
                    xdev->initial_matrix.yy = 0.0;
                    xdev->initial_matrix.tx = -lly * xppp;
                    xdev->initial_matrix.ty = -llx * yppp;
                    break;
                case Upsidedown:
                    xdev->initial_matrix.xx = -xppp;
                    xdev->initial_matrix.xy = 0.0;
                    xdev->initial_matrix.yx = 0.0;
                    xdev->initial_matrix.yy = yppp;
                    xdev->initial_matrix.tx = urx * xppp;
                    xdev->initial_matrix.ty = -lly * yppp;
                    break;
                case Seascape:
                    xdev->initial_matrix.xx = 0.0;
                    xdev->initial_matrix.xy = -yppp;
                    xdev->initial_matrix.yx = -xppp;
                    xdev->initial_matrix.yy = 0.0;
                    xdev->initial_matrix.tx = ury * xppp;
                    xdev->initial_matrix.ty = urx * yppp;
                    break;
            }

            /* The following sets the imageable area according to the */
            /* bounding box and margins sent by ghostview.            */
            /* This code has been patched many times; its current state */
            /* is per a recommendation by Tim Theisen on 4/28/95. */

            xdev->ImagingBBox[0] = llx - left_margin;
            xdev->ImagingBBox[1] = lly - bottom_margin;
            xdev->ImagingBBox[2] = urx + right_margin;
            xdev->ImagingBBox[3] = ury + top_margin;
            xdev->ImagingBBox_set = true;

        } else if (xdev->pwin == (Window) None) {
            emprintf(xdev->memory, "Cannot get ghostview property.\n");
            return_error(gs_error_ioerror);
        }
    } else {
        Screen *scr = DefaultScreenOfDisplay(xdev->dpy);

        xdev->scr = scr;
        xvinfo.visual = DefaultVisualOfScreen(scr);
        xdev->cmap = DefaultColormapOfScreen(scr);
        if (xvinfo.visual->class != TrueColor) {
            int scrno = DefaultScreen(xdev->dpy);
            if ( XMatchVisualInfo(xdev->dpy, scrno, 24, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 32, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 16, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 15, TrueColor, &xvinfo)  ) {
                xdev->cmap = XCreateColormap (xdev->dpy,
                                              DefaultRootWindow(xdev->dpy),
                                              xvinfo.visual, AllocNone );
            }
        }
    }
    xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
    xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
    if (xdev->vinfo == NULL) {
        emprintf(xdev->memory, "Cannot get XVisualInfo.\n");
        return_error(gs_error_ioerror);
    }
    /* Buggy X servers may cause a Bad Access on XFreeColors. */
    x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);

    /* Get X Resources.  Use the toolkit for this. */
    XtToolkitInitialize();
    app_con = XtCreateApplicationContext();
    XtAppSetFallbackResources(app_con, gdev_x_fallback_resources);
    dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
                        NULL, 0, &zero, NULL);
    toplevel = XtAppCreateShell(NULL, "Ghostscript",
                                applicationShellWidgetClass, dpy, NULL, 0);
    XtGetApplicationResources(toplevel, (XtPointer) xdev,
                              gdev_x_resources, gdev_x_resource_count,
                              NULL, 0);

    /* Reserve foreground and background colors under the regular connection. */
    xc.pixel = xdev->foreground;
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
    xdev->foreground = xc.pixel;
    xc.pixel = xdev->background;
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
    xdev->background = xc.pixel;

    code = gdev_x_setup_colors(xdev);
    if (code < 0) {
        XCloseDisplay(xdev->dpy);
        return code;
    }
    /* Now that the color map is setup check if the device is separable. */
    check_device_separable((gx_device *)xdev);

    if (!xdev->ghostview) {
        XWMHints wm_hints;
        XClassHint class_hint;
        XSetWindowAttributes xswa;
        gx_device *dev = (gx_device *) xdev;

        /* Take care of resolution and paper size. */
        if (xdev->x_pixels_per_inch == FAKE_RES ||
            xdev->y_pixels_per_inch == FAKE_RES) {
            float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
            float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
            int workarea_width = WidthOfScreen(xdev->scr), workarea_height = HeightOfScreen(xdev->scr);

            /* Get area available for windows placement */
            x_get_work_area(xdev, &workarea_width, &workarea_height);

            if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
                float dpi, xdpi, ydpi;

                xdpi = 25.4 * WidthOfScreen(xdev->scr) /
                    WidthMMOfScreen(xdev->scr);
                ydpi = 25.4 * HeightOfScreen(xdev->scr) /
                    HeightMMOfScreen(xdev->scr);
                dpi = min(xdpi, ydpi);
                /*
                 * Some X servers provide very large "virtual screens", and
                 * return the virtual screen size for Width/HeightMM but the
                 * physical size for Width/Height.  Attempt to detect and
                 * correct for this now.  This is a KLUDGE required because
                 * the X server provides no way to read the screen
                 * resolution directly.
                 */
                if (dpi < 30)
                    dpi = 75;	/* arbitrary */
                else {
                    while (xsize * dpi > WidthOfScreen(xdev->scr) - 32 ||
                           ysize * dpi > HeightOfScreen(xdev->scr) - 32)
                        dpi *= 0.95;
                }
                xdev->x_pixels_per_inch = dpi;
                xdev->y_pixels_per_inch = dpi;
            } else {
                xdev->x_pixels_per_inch = xdev->xResolution;
                xdev->y_pixels_per_inch = xdev->yResolution;
            }
            /* Restrict maximum window size to available work area */
            if (xdev->width > workarea_width) {
                xdev->width = min(xsize * xdev->x_pixels_per_inch, workarea_width);
            }
            if (xdev->height > workarea_height) {
                xdev->height = min(ysize * xdev->y_pixels_per_inch, workarea_height);
            }
            xdev->MediaSize[0] =
                (float)xdev->width / xdev->x_pixels_per_inch * 72;
            xdev->MediaSize[1] =
                (float)xdev->height / xdev->y_pixels_per_inch * 72;
        }

        sizehints.x = 0;
        sizehints.y = 0;
        sizehints.width = xdev->width;
        sizehints.height = xdev->height;
        sizehints.flags = 0;

        if (xdev->geometry != NULL) {
            /*
             * Note that border_width must be set first.  We can't use
             * scr, because that is a Screen*, and XWMGeometry wants
             * the screen number.
             */
            char gstr[40];
            int bitmask;

            gs_sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
                    sizehints.height, sizehints.x, sizehints.y);
            bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
                                  xdev->geometry, gstr, xdev->borderWidth,
                                  &sizehints,
                                  &sizehints.x, &sizehints.y,
                                  &sizehints.width, &sizehints.height,
                                  &sizehints.win_gravity);

            if (bitmask & (XValue | YValue))
                sizehints.flags |= USPosition;
        }
        gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));

        if (xdev->pwin != (Window) None && xid_width != 0 && xid_height != 0) {
#if 0				/*************** */

            /*
             * The user who originally implemented the WindowID feature
             * provided the following code to scale the displayed output
             * to fit in the window.  We think this is a bad idea,
             * since it doesn't track window resizing and is generally
             * completely at odds with the way Ghostscript treats
             * window or paper size in all other contexts.  We are
             * leaving the code here in case someone decides that
             * this really is the behavior they want.
             */

            /* Scale to fit in the window. */
            xdev->initial_matrix.xx
                = xdev->initial_matrix.xx *
                (float)xid_width / (float)xdev->width;
            xdev->initial_matrix.yy
                = xdev->initial_matrix.yy *
                (float)xid_height / (float)xdev->height;

#endif /*************** */
            xdev->width = xid_width;
            xdev->height = xid_height;
            xdev->initial_matrix.ty = xdev->height;
        } else {		/* !xdev->pwin */
            xswa.event_mask = ExposureMask;
            xswa.background_pixel = xdev->background;
            xswa.border_pixel = xdev->borderColor;
            xswa.colormap = xdev->cmap;
            xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
                                      sizehints.x, sizehints.y,		/* upper left */
                                      xdev->width, xdev->height,
                                      xdev->borderWidth,
                                      xdev->vinfo->depth,
                                      InputOutput,	/* class        */
                                      xdev->vinfo->visual,	/* visual */
                                      CWEventMask | CWBackPixel |
                                      CWBorderPixel | CWColormap,
                                      &xswa);
            XStoreName(xdev->dpy, xdev->win, "ghostscript");
            XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
            wm_hints.flags = InputHint;
            wm_hints.input = False;
            XSetWMHints(xdev->dpy, xdev->win, &wm_hints);	/* avoid input focus */
            class_hint.res_name = (char *)"ghostscript";
            class_hint.res_class = (char *)"Ghostscript";
            XSetClassHint(xdev->dpy, xdev->win, &class_hint);
        }
    }
    /***
     *** According to Ricard Torres (torres@upf.es), we have to wait until here
     *** to close the toolkit connection, which we formerly did
     *** just after the calls on XAllocColor above.  I suspect that
     *** this will cause things to be left dangling if an error occurs
     *** anywhere in the above code, but I'm willing to let users
     *** fight over fixing it, since I have no idea what's right.
     ***/

    /* And close the toolkit connection. */
    XtDestroyWidget(toplevel);
    XtCloseDisplay(dpy);
    XtDestroyApplicationContext(app_con);

    xdev->ht.pixmap = (Pixmap) 0;
    xdev->ht.id = gx_no_bitmap_id;;
    xdev->fill_style = FillSolid;
    xdev->function = GXcopy;
    xdev->fid = (Font) 0;

    /* Set up a graphics context */
    xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
    XSetFunction(xdev->dpy, xdev->gc, GXcopy);
    XSetLineAttributes(xdev->dpy, xdev->gc, 0,
                       LineSolid, CapButt, JoinMiter);

    gdev_x_clear_window(xdev);

    if (!xdev->ghostview) {	/* Make the window appear. */
        XMapWindow(xdev->dpy, xdev->win);

        /* Before anything else, do a flush and wait for */
        /* an exposure event. */
        XSync(xdev->dpy, False);
        if (xdev->pwin == (Window) None) {	/* there isn't a next event for existing windows */
            XNextEvent(xdev->dpy, &event);
        }
        /* Now turn off graphics exposure events so they don't queue up */
        /* indefinitely.  Also, since we can't do anything about real */
        /* Expose events, mask them out. */
        XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
        XSelectInput(xdev->dpy, xdev->win, NoEventMask);
    } else {
        /* Create an unmapped window, that the window manager will ignore.
         * This invisible window will be used to receive "next page"
         * events from ghostview */
        XSetWindowAttributes attributes;

        attributes.override_redirect = True;
        xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
                                   0, 0, 1, 1, 0, CopyFromParent,
                                   CopyFromParent, CopyFromParent,
                                   CWOverrideRedirect, &attributes);
        xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
        xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
        xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
    }

    xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
                                       xdev->vinfo->depth);

    return 0;
}


static int chap_gen_challenge(
	struct iscsi_conn *conn,
	int caller,
	char *c_str,
	unsigned int *c_len)
{
	int ret;
	unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
	struct iscsi_chap *chap = conn->auth_protocol;

	memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);

	ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH);
	if (unlikely(ret))
		return ret;
	chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
				CHAP_CHALLENGE_LENGTH);
	/*
	 * Set CHAP_C, and copy the generated challenge into c_str.
	 */
	*c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
	*c_len += 1;

	pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
			challenge_asciihex);
	return 0;
}


static Image *ReadPICTImage(const ImageInfo *image_info,
  ExceptionInfo *exception)
{
#define ThrowPICTException(exception,message) \
{ \
  if (tile_image != (Image *) NULL) \
    tile_image=DestroyImage(tile_image); \
  if (read_info != (ImageInfo *) NULL) \
    read_info=DestroyImageInfo(read_info); \
  ThrowReaderException((exception),(message)); \
}

  char
    geometry[MaxTextExtent],
    header_ole[4];

  Image
    *image,
    *tile_image;

  ImageInfo
    *read_info;

  IndexPacket
    index;

  int
    c,
    code;

  MagickBooleanType
    jpeg,
    status;

  PICTRectangle
    frame;

  PICTPixmap
    pixmap;

  register IndexPacket
    *indexes;

  register ssize_t
    x;

  register PixelPacket
    *q;

  register ssize_t
    i;

  size_t
    extent,
    length;

  ssize_t
    count,
    flags,
    j,
    version,
    y;

  StringInfo
    *profile;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=AcquireImage(image_info);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    {
      image=DestroyImageList(image);
      return((Image *) NULL);
    }
  /*
    Read PICT header.
  */
  read_info=(ImageInfo *) NULL;
  tile_image=(Image *) NULL;
  pixmap.bits_per_pixel=0;
  pixmap.component_count=0;
  /*
    Skip header : 512 for standard PICT and 4, ie "PICT" for OLE2
  */
  header_ole[0]=ReadBlobByte(image);
  header_ole[1]=ReadBlobByte(image);
  header_ole[2]=ReadBlobByte(image);
  header_ole[3]=ReadBlobByte(image);
  if (!((header_ole[0] == 0x50) && (header_ole[1] == 0x49) &&
      (header_ole[2] == 0x43) && (header_ole[3] == 0x54)))
    for (i=0; i < 508; i++)
      if (ReadBlobByte(image) == EOF)
        break;
  (void) ReadBlobMSBShort(image);  /* skip picture size */
  if (ReadRectangle(image,&frame) == MagickFalse)
    ThrowPICTException(CorruptImageError,"ImproperImageHeader");
  while ((c=ReadBlobByte(image)) == 0) ;
  if (c != 0x11)
    ThrowPICTException(CorruptImageError,"ImproperImageHeader");
  version=(ssize_t) ReadBlobByte(image);
  if (version == 2)
    {
      c=ReadBlobByte(image);
      if (c != 0xff)
        ThrowPICTException(CorruptImageError,"ImproperImageHeader");
    }
  else
    if (version != 1)
      ThrowPICTException(CorruptImageError,"ImproperImageHeader");
  if ((frame.left < 0) || (frame.right < 0) || (frame.top < 0) ||
      (frame.bottom < 0) || (frame.left >= frame.right) ||
      (frame.top >= frame.bottom))
    ThrowPICTException(CorruptImageError,"ImproperImageHeader");
  /*
    Create black canvas.
  */
  flags=0;
  image->depth=8;
  image->columns=(unsigned int) (frame.right-frame.left);
  image->rows=(unsigned int) (frame.bottom-frame.top);
  image->x_resolution=DefaultResolution;
  image->y_resolution=DefaultResolution;
  image->units=UndefinedResolution;
  if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
    if (image->scene >= (image_info->scene+image_info->number_scenes-1))
      {
        (void) CloseBlob(image);
        return(GetFirstImageInList(image));
      }
  status=SetImageExtent(image,image->columns,image->rows);
  if (status != MagickFalse)
    status=ResetImagePixels(image,exception);
  if (status == MagickFalse)
    {
      InheritException(exception,&image->exception);
      return(DestroyImageList(image));
    }
  /*
    Interpret PICT opcodes.
  */
  jpeg=MagickFalse;
  for (code=0; EOFBlob(image) == MagickFalse; )
  {
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
    if ((version == 1) || ((TellBlob(image) % 2) != 0))
      code=ReadBlobByte(image);
    if (version == 2)
      code=ReadBlobMSBSignedShort(image);
    if (code < 0)
      break;
    if (code == 0)
      continue;
    if (code > 0xa1)
      {
        if (image->debug != MagickFalse)
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%04X:",code);
      }
    else
      {
        if (image->debug != MagickFalse)
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
            "  %04X %s: %s",code,codes[code].name,codes[code].description);
        switch (code)
        {
          case 0x01:
          {
            /*
              Clipping rectangle.
            */
            length=ReadBlobMSBShort(image);
            if (length != 0x000a)
              {
                for (i=0; i < (ssize_t) (length-2); i++)
                  if (ReadBlobByte(image) == EOF)
                    break;
                break;
              }
            if (ReadRectangle(image,&frame) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            if (((frame.left & 0x8000) != 0) || ((frame.top & 0x8000) != 0))
              break;
            image->columns=(size_t) (frame.right-frame.left);
            image->rows=(size_t) (frame.bottom-frame.top);
            status=SetImageExtent(image,image->columns,image->rows);
            if (status != MagickFalse)
              status=ResetImagePixels(image,&image->exception);
            if (status == MagickFalse)
              {
                InheritException(exception,&image->exception);
                return(DestroyImageList(image));
              }
            break;
          }
          case 0x12:
          case 0x13:
          case 0x14:
          {
            ssize_t
              pattern;

            size_t
              height,
              width;

            /*
              Skip pattern definition.
            */
            pattern=(ssize_t) ReadBlobMSBShort(image);
            for (i=0; i < 8; i++)
              if (ReadBlobByte(image) == EOF)
                break;
            if (pattern == 2)
              {
                for (i=0; i < 5; i++)
                  if (ReadBlobByte(image) == EOF)
                    break;
                break;
              }
            if (pattern != 1)
              ThrowPICTException(CorruptImageError,"UnknownPatternType");
            length=ReadBlobMSBShort(image);
            if (ReadRectangle(image,&frame) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            if (ReadPixmap(image,&pixmap) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            image->depth=(size_t) pixmap.component_size;
            image->x_resolution=1.0*pixmap.horizontal_resolution;
            image->y_resolution=1.0*pixmap.vertical_resolution;
            image->units=PixelsPerInchResolution;
            (void) ReadBlobMSBLong(image);
            flags=(ssize_t) ReadBlobMSBShort(image);
            length=ReadBlobMSBShort(image);
            for (i=0; i <= (ssize_t) length; i++)
              (void) ReadBlobMSBLong(image);
            width=(size_t) (frame.bottom-frame.top);
            height=(size_t) (frame.right-frame.left);
            if (pixmap.bits_per_pixel <= 8)
              length&=0x7fff;
            if (pixmap.bits_per_pixel == 16)
              width<<=1;
            if (length == 0)
              length=width;
            if (length < 8)
              {
                for (i=0; i < (ssize_t) (length*height); i++)
                  if (ReadBlobByte(image) == EOF)
                    break;
              }
            else
              for (i=0; i < (ssize_t) height; i++)
              {
                if (EOFBlob(image) != MagickFalse)
                  break;
                if (length > 200)
                  {
                    for (j=0; j < (ssize_t) ReadBlobMSBShort(image); j++)
                      if (ReadBlobByte(image) == EOF)
                        break;
                  }
                else
                  for (j=0; j < (ssize_t) ReadBlobByte(image); j++)
                    if (ReadBlobByte(image) == EOF)
                      break;
              }
            break;
          }
          case 0x1b:
          {
            /*
              Initialize image background color.
            */
            image->background_color.red=(Quantum)
              ScaleShortToQuantum(ReadBlobMSBShort(image));
            image->background_color.green=(Quantum)
              ScaleShortToQuantum(ReadBlobMSBShort(image));
            image->background_color.blue=(Quantum)
              ScaleShortToQuantum(ReadBlobMSBShort(image));
            break;
          }
          case 0x70:
          case 0x71:
          case 0x72:
          case 0x73:
          case 0x74:
          case 0x75:
          case 0x76:
          case 0x77:
          {
            /*
              Skip polygon or region.
            */
            length=ReadBlobMSBShort(image);
            for (i=0; i < (ssize_t) (length-2); i++)
              if (ReadBlobByte(image) == EOF)
                break;
            break;
          }
          case 0x90:
          case 0x91:
          case 0x98:
          case 0x99:
          case 0x9a:
          case 0x9b:
          {
            ssize_t
              bytes_per_line;

            PICTRectangle
              source,
              destination;

            register unsigned char
              *p;

            size_t
              j;

            unsigned char
              *pixels;

            /*
              Pixmap clipped by a rectangle.
            */
            bytes_per_line=0;
            if ((code != 0x9a) && (code != 0x9b))
              bytes_per_line=(ssize_t) ReadBlobMSBShort(image);
            else
              {
                (void) ReadBlobMSBShort(image);
                (void) ReadBlobMSBShort(image);
                (void) ReadBlobMSBShort(image);
              }
            if (ReadRectangle(image,&frame) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            /*
              Initialize tile image.
            */
            tile_image=CloneImage(image,(size_t) (frame.right-frame.left),
              (size_t) (frame.bottom-frame.top),MagickTrue,exception);
            if (tile_image == (Image *) NULL)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            if ((code == 0x9a) || (code == 0x9b) ||
                ((bytes_per_line & 0x8000) != 0))
              {
                if (ReadPixmap(image,&pixmap) == MagickFalse)
                  ThrowPICTException(CorruptImageError,"ImproperImageHeader");
                tile_image->depth=(size_t) pixmap.component_size;
                tile_image->matte=pixmap.component_count == 4 ?
                  MagickTrue : MagickFalse;
                tile_image->x_resolution=(double) pixmap.horizontal_resolution;
                tile_image->y_resolution=(double) pixmap.vertical_resolution;
                tile_image->units=PixelsPerInchResolution;
                if (tile_image->matte != MagickFalse)
                  (void) SetImageAlphaChannel(tile_image,OpaqueAlphaChannel);
              }
            if ((code != 0x9a) && (code != 0x9b))
              {
                /*
                  Initialize colormap.
                */
                tile_image->colors=2;
                if ((bytes_per_line & 0x8000) != 0)
                  {
                    (void) ReadBlobMSBLong(image);
                    flags=(ssize_t) ReadBlobMSBShort(image);
                    tile_image->colors=1UL*ReadBlobMSBShort(image)+1;
                  }
                status=AcquireImageColormap(tile_image,tile_image->colors);
                if (status == MagickFalse)
                  ThrowPICTException(ResourceLimitError,
                    "MemoryAllocationFailed");
                if ((bytes_per_line & 0x8000) != 0)
                  {
                    for (i=0; i < (ssize_t) tile_image->colors; i++)
                    {
                      j=ReadBlobMSBShort(image) % tile_image->colors;
                      if ((flags & 0x8000) != 0)
                        j=(size_t) i;
                      tile_image->colormap[j].red=(Quantum)
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
                      tile_image->colormap[j].green=(Quantum)
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
                      tile_image->colormap[j].blue=(Quantum)
                        ScaleShortToQuantum(ReadBlobMSBShort(image));
                    }
                  }
                else
                  {
                    for (i=0; i < (ssize_t) tile_image->colors; i++)
                    {
                      tile_image->colormap[i].red=(Quantum) (QuantumRange-
                        tile_image->colormap[i].red);
                      tile_image->colormap[i].green=(Quantum) (QuantumRange-
                        tile_image->colormap[i].green);
                      tile_image->colormap[i].blue=(Quantum) (QuantumRange-
                        tile_image->colormap[i].blue);
                    }
                  }
              }
            if (EOFBlob(image) != MagickFalse)
              ThrowPICTException(CorruptImageError,
                "InsufficientImageDataInFile");
            if (ReadRectangle(image,&source) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            if (ReadRectangle(image,&destination) == MagickFalse)
              ThrowPICTException(CorruptImageError,"ImproperImageHeader");
            (void) ReadBlobMSBShort(image);
            if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
              {
                /*
                  Skip region.
                */
                length=ReadBlobMSBShort(image);
                for (i=0; i < (ssize_t) (length-2); i++)
                  if (ReadBlobByte(image) == EOF)
                    break;
              }
            if ((code != 0x9a) && (code != 0x9b) &&
                (bytes_per_line & 0x8000) == 0)
              pixels=DecodeImage(image,tile_image,(size_t) bytes_per_line,1,
                &extent);
            else
              pixels=DecodeImage(image,tile_image,(unsigned int) bytes_per_line,
                (unsigned int) pixmap.bits_per_pixel,&extent);
            if (pixels == (unsigned char *) NULL)
              ThrowPICTException(CorruptImageError,"UnableToUncompressImage");
            /*
              Convert PICT tile image to pixel packets.
            */
            p=pixels;
            for (y=0; y < (ssize_t) tile_image->rows; y++)
            {
              if (p > (pixels+extent+image->columns))
                {
                  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
                  ThrowPICTException(CorruptImageError,"NotEnoughPixelData");
                }
              q=QueueAuthenticPixels(tile_image,0,y,tile_image->columns,1,
                exception);
              if (q == (PixelPacket *) NULL)
                break;
              indexes=GetAuthenticIndexQueue(tile_image);
              for (x=0; x < (ssize_t) tile_image->columns; x++)
              {
                if (tile_image->storage_class == PseudoClass)
                  {
                    index=ConstrainColormapIndex(tile_image,*p);
                    SetPixelIndex(indexes+x,index);
                    SetPixelRed(q,
                      tile_image->colormap[(ssize_t) index].red);
                    SetPixelGreen(q,
                      tile_image->colormap[(ssize_t) index].green);
                    SetPixelBlue(q,
                      tile_image->colormap[(ssize_t) index].blue);
                  }
                else
                  {
                    if (pixmap.bits_per_pixel == 16)
                      {
                        i=(ssize_t) (*p++);
                        j=(*p);
                        SetPixelRed(q,ScaleCharToQuantum(
                          (unsigned char) ((i & 0x7c) << 1)));
                        SetPixelGreen(q,ScaleCharToQuantum(
                          (unsigned char) (((i & 0x03) << 6) |
                          ((j & 0xe0) >> 2))));
                        SetPixelBlue(q,ScaleCharToQuantum(
                          (unsigned char) ((j & 0x1f) << 3)));
                      }
                    else
                      if (tile_image->matte == MagickFalse)
                        {
                          if (p > (pixels+extent+2*image->columns))
                            ThrowPICTException(CorruptImageError,
                              "NotEnoughPixelData");
                          SetPixelRed(q,ScaleCharToQuantum(*p));
                          SetPixelGreen(q,ScaleCharToQuantum(
                            *(p+tile_image->columns)));
                          SetPixelBlue(q,ScaleCharToQuantum(
                            *(p+2*tile_image->columns)));
                        }
                      else
                        {
                          if (p > (pixels+extent+3*image->columns))
                            ThrowPICTException(CorruptImageError,
                              "NotEnoughPixelData");
                          SetPixelAlpha(q,ScaleCharToQuantum(*p));
                          SetPixelRed(q,ScaleCharToQuantum(
                            *(p+tile_image->columns)));
                          SetPixelGreen(q,ScaleCharToQuantum(
                            *(p+2*tile_image->columns)));
                          SetPixelBlue(q,ScaleCharToQuantum(
                            *(p+3*tile_image->columns)));
                        }
                  }
                p++;
                q++;
              }
              if (SyncAuthenticPixels(tile_image,exception) == MagickFalse)
                break;
              if ((tile_image->storage_class == DirectClass) &&
                  (pixmap.bits_per_pixel != 16))
                {
                  p+=(pixmap.component_count-1)*tile_image->columns;
                  if (p < pixels)
                    break;
                }
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
                tile_image->rows);
              if (status == MagickFalse)
                break;
            }
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
            if ((jpeg == MagickFalse) && (EOFBlob(image) == MagickFalse))
              if ((code == 0x9a) || (code == 0x9b) ||
                  ((bytes_per_line & 0x8000) != 0))
                (void) CompositeImage(image,CopyCompositeOp,tile_image,
                  (ssize_t) destination.left,(ssize_t) destination.top);
            tile_image=DestroyImage(tile_image);
            break;
          }
          case 0xa1:
          {
            unsigned char
              *info;

            size_t
              type;

            /*
              Comment.
            */
            type=ReadBlobMSBShort(image);
            length=ReadBlobMSBShort(image);
            if (length == 0)
              break;
            (void) ReadBlobMSBLong(image);
            length-=MagickMin(length,4);
            if (length == 0)
              break;
            info=(unsigned char *) AcquireQuantumMemory(length,sizeof(*info));
            if (info == (unsigned char *) NULL)
              break;
            count=ReadBlob(image,length,info);
            if (count != (ssize_t) length)
              {
                info=(unsigned char *) RelinquishMagickMemory(info);
                ThrowPICTException(ResourceLimitError,"UnableToReadImageData");
              }
            switch (type)
            {
              case 0xe0:
              {
                profile=BlobToStringInfo((const void *) NULL,length);
                SetStringInfoDatum(profile,info);
                status=SetImageProfile(image,"icc",profile);
                profile=DestroyStringInfo(profile);
                if (status == MagickFalse)
                  {
                    info=(unsigned char *) RelinquishMagickMemory(info);
                    ThrowPICTException(ResourceLimitError,
                      "MemoryAllocationFailed");
                  }
                break;
              }
              case 0x1f2:
              {
                profile=BlobToStringInfo((const void *) NULL,length);
                SetStringInfoDatum(profile,info);
                status=SetImageProfile(image,"iptc",profile);
                if (status == MagickFalse)
                  {
                    info=(unsigned char *) RelinquishMagickMemory(info);
                    ThrowPICTException(ResourceLimitError,
                      "MemoryAllocationFailed");
                  }
                profile=DestroyStringInfo(profile);
                break;
              }
              default:
                break;
            }
            info=(unsigned char *) RelinquishMagickMemory(info);
            break;
          }
          default:
          {
            /*
              Skip to next op code.
            */
            if (codes[code].length == -1)
              (void) ReadBlobMSBShort(image);
            else
              for (i=0; i < (ssize_t) codes[code].length; i++)
                if (ReadBlobByte(image) == EOF)
                  break;
          }
        }
      }
    if (code == 0xc00)
      {
        /*
          Skip header.
        */
        for (i=0; i < 24; i++)
          if (ReadBlobByte(image) == EOF)
            break;
        continue;
      }
    if (((code >= 0xb0) && (code <= 0xcf)) ||
        ((code >= 0x8000) && (code <= 0x80ff)))
      continue;
    if (code == 0x8200)
      {
        char
          filename[MaxTextExtent];

        FILE
          *file;

        int
          unique_file;

        /*
          Embedded JPEG.
        */
        jpeg=MagickTrue;
        read_info=CloneImageInfo(image_info);
        SetImageInfoBlob(read_info,(void *) NULL,0);
        file=(FILE *) NULL;
        unique_file=AcquireUniqueFileResource(filename);
        (void) FormatLocaleString(read_info->filename,MaxTextExtent,"jpeg:%s",
          filename);
        if (unique_file != -1)
          file=fdopen(unique_file,"wb");
        if ((unique_file == -1) || (file == (FILE *) NULL))
          {
            (void) RelinquishUniqueFileResource(read_info->filename);
            (void) CopyMagickString(image->filename,read_info->filename,
              MaxTextExtent);
            ThrowPICTException(FileOpenError,"UnableToCreateTemporaryFile");
          }
        length=ReadBlobMSBLong(image);
        if (length > 154)
          {
            for (i=0; i < 6; i++)
              (void) ReadBlobMSBLong(image);
            if (ReadRectangle(image,&frame) == MagickFalse)
              {
                (void) fclose(file);
                (void) RelinquishUniqueFileResource(read_info->filename);
                ThrowPICTException(CorruptImageError,"ImproperImageHeader");
              }
            for (i=0; i < 122; i++)
              if (ReadBlobByte(image) == EOF)
                break;
            for (i=0; i < (ssize_t) (length-154); i++)
            {
              c=ReadBlobByte(image);
              if (c == EOF)
                break;
              (void) fputc(c,file);
            }
          }
        (void) fclose(file);
        (void) close(unique_file);
        tile_image=ReadImage(read_info,exception);
        (void) RelinquishUniqueFileResource(filename);
        read_info=DestroyImageInfo(read_info);
        if (tile_image == (Image *) NULL)
          continue;
        (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g",
          (double) MagickMax(image->columns,tile_image->columns),
          (double) MagickMax(image->rows,tile_image->rows));
        (void) SetImageExtent(image,
          MagickMax(image->columns,tile_image->columns),
          MagickMax(image->rows,tile_image->rows));
        (void) TransformImageColorspace(image,tile_image->colorspace);
        (void) CompositeImage(image,CopyCompositeOp,tile_image,(ssize_t)
          frame.left,(ssize_t) frame.right);
        image->compression=tile_image->compression;
        tile_image=DestroyImage(tile_image);
        continue;
      }
    if ((code == 0xff) || (code == 0xffff))
      break;
    if (((code >= 0xd0) && (code <= 0xfe)) ||
        ((code >= 0x8100) && (code <= 0xffff)))
      {
        /*
          Skip reserved.
        */
        length=ReadBlobMSBShort(image);
        for (i=0; i < (ssize_t) length; i++)
          if (ReadBlobByte(image) == EOF)
            break;
        continue;
      }
    if ((code >= 0x100) && (code <= 0x7fff))
      {
        /*
          Skip reserved.
        */
        length=(size_t) ((code >> 7) & 0xff);
        for (i=0; i < (ssize_t) length; i++)
          if (ReadBlobByte(image) == EOF)
            break;
        continue;
      }
  }
  (void) CloseBlob(image);
  return(GetFirstImageInList(image));
}


z2setgstate(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;

    check_stype(*op, st_igstate_obj);
    if (!restore_page_device(igs, igstate_ptr(op)))
        return zsetgstate(i_ctx_p);
    return push_callout(i_ctx_p, "%setgstatepagedevice");
}


static struct net *get_target_net(struct sk_buff *skb, int netnsid)
{
	struct net *net;

	net = get_net_ns_by_id(sock_net(skb->sk), netnsid);
	if (!net)
		return ERR_PTR(-EINVAL);

	/* For now, the caller is required to have CAP_NET_ADMIN in
	 * the user namespace owning the target net ns.
	 */
	if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
		put_net(net);
		return ERR_PTR(-EACCES);
	}
	return net;
}


static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
			struct netlink_ext_ack *extack)
{
	struct net *net = sock_net(skb->sk);
	struct net *tgt_net = net;
	struct ifinfomsg *ifm;
	char ifname[IFNAMSIZ];
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct sk_buff *nskb;
	int netnsid = -1;
	int err;
	u32 ext_filter_mask = 0;

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
	if (err < 0)
		return err;

	if (tb[IFLA_IF_NETNSID]) {
		netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]);
		tgt_net = get_target_net(skb, netnsid);
		if (IS_ERR(tgt_net))
			return PTR_ERR(tgt_net);
	}

	if (tb[IFLA_IFNAME])
		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);

	if (tb[IFLA_EXT_MASK])
		ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);

	err = -EINVAL;
	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index > 0)
		dev = __dev_get_by_index(tgt_net, ifm->ifi_index);
	else if (tb[IFLA_IFNAME])
		dev = __dev_get_by_name(tgt_net, ifname);
	else
		goto out;

	err = -ENODEV;
	if (dev == NULL)
		goto out;

	err = -ENOBUFS;
	nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL);
	if (nskb == NULL)
		goto out;

	err = rtnl_fill_ifinfo(nskb, dev, net,
			       RTM_NEWLINK, NETLINK_CB(skb).portid,
			       nlh->nlmsg_seq, 0, 0, ext_filter_mask,
			       0, NULL, netnsid);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
	} else
		err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
out:
	if (netnsid >= 0)
		put_net(tgt_net);

	return err;
}


struct posix_acl *ovl_get_acl(struct inode *inode, int type)
{
	struct inode *realinode = ovl_inode_real(inode);

	if (!realinode)
		return ERR_PTR(-ENOENT);

	if (!IS_POSIXACL(realinode))
		return NULL;

	if (!realinode->i_op->get_acl)
		return NULL;

	return realinode->i_op->get_acl(realinode, type);
}


    void TiffImage::readMetadata()
    {
#ifdef DEBUG
        std::cerr << "Reading TIFF file " << io_->path() << "\n";
#endif
        if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError());
        IoCloser closer(*io_);
        // Ensure that this is the correct image type
        if (!isTiffType(*io_, false)) {
            if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
            throw Error(kerNotAnImage, "TIFF");
        }
        clearMetadata();

        ByteOrder bo = TiffParser::decode(exifData_,
                                          iptcData_,
                                          xmpData_,
                                          io_->mmap(),
                                          (uint32_t) io_->size());
        setByteOrder(bo);

        // read profile from the metadata
        Exiv2::ExifKey            key("Exif.Image.InterColorProfile");
        Exiv2::ExifData::iterator pos   = exifData_.findKey(key);
        if ( pos != exifData_.end()  ) {
            iccProfile_.alloc(pos->count()*pos->typeSize());
            pos->copy(iccProfile_.pData_,bo);
        }

    } // TiffImage::readMetadata


apr_status_t h2_session_process(h2_session *session, int async)
{
    apr_status_t status = APR_SUCCESS;
    conn_rec *c = session->c;
    int rv, mpm_state, trace = APLOGctrace3(c);

    if (trace) {
        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                      H2_SSSN_MSG(session, "process start, async=%d"), async);
    }

    while (session->state != H2_SESSION_ST_DONE) {
        session->have_read = session->have_written = 0;

        if (session->local.accepting
            && !ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
            if (mpm_state == AP_MPMQ_STOPPING) {
                dispatch_event(session, H2_SESSION_EV_MPM_STOPPING, 0, NULL);
            }
        }

        session->status[0] = '\0';

        switch (session->state) {
            case H2_SESSION_ST_INIT:
                ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
                if (!h2_is_acceptable_connection(c, 1)) {
                    update_child_status(session, SERVER_BUSY_READ,
                                        "inadequate security");
                    h2_session_shutdown(session,
                                        NGHTTP2_INADEQUATE_SECURITY, NULL, 1);
                }
                else {
                    update_child_status(session, SERVER_BUSY_READ, "init");
                    status = h2_session_start(session, &rv);
                    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
                                  H2_SSSN_LOG(APLOGNO(03079), session,
                                  "started on %s:%d"),
                                  session->s->server_hostname,
                                  c->local_addr->port);
                    if (status != APR_SUCCESS) {
                        dispatch_event(session,
                                       H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                    dispatch_event(session, H2_SESSION_EV_INIT, 0, NULL);
                }
                break;

            case H2_SESSION_ST_IDLE:
                /* We trust our connection into the default timeout/keepalive
                 * handling of the core filters/mpm iff:
                 * - keep_sync_until is not set
                 * - we have an async mpm
                 * - we have no open streams to process
                 * - we are not sitting on a Upgrade: request
                 * - we already have seen at least one request
                 */
                if (!session->keep_sync_until && async && !session->open_streams
                    && !session->r && session->remote.emitted_count) {
                    if (trace) {
                        ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "nonblock read, %d streams open"),
                                      session->open_streams);
                    }
                    h2_conn_io_flush(&session->io);
                    status = h2_session_read(session, 0);

                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                        dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
                    }
                    else if (APR_STATUS_IS_EAGAIN(status)
                        || APR_STATUS_IS_TIMEUP(status)) {
                        if (apr_time_now() > session->idle_until) {
                            dispatch_event(session,
                                           H2_SESSION_EV_CONN_TIMEOUT, 0, NULL);
                        }
                        else {
                            status = APR_EAGAIN;
                            goto out;
                        }
                    }
                    else {
                        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c,
                                      H2_SSSN_LOG(APLOGNO(03403), session,
                                      "no data, error"));
                        dispatch_event(session,
                                       H2_SESSION_EV_CONN_ERROR, 0, "timeout");
                    }
                }
                else {
                    /* make certain, we send everything before we idle */
                    h2_conn_io_flush(&session->io);
                    if (trace) {
                        ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "sync, stutter 1-sec, %d streams open"),
                                      session->open_streams);
                    }
                    /* We wait in smaller increments, using a 1 second timeout.
                     * That gives us the chance to check for MPMQ_STOPPING often.
                     */
                    status = h2_mplx_idle(session->mplx);
                    if (status == APR_EAGAIN) {
                        dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
                        break;
                    }
                    else if (status != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                       H2_ERR_ENHANCE_YOUR_CALM, "less is more");
                    }
                    h2_filter_cin_timeout_set(session->cin, apr_time_from_sec(1));
                    status = h2_session_read(session, 1);
                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                        dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
                    }
                    else if (status == APR_EAGAIN) {
                        /* nothing to read */
                    }
                    else if (APR_STATUS_IS_TIMEUP(status)) {
                        apr_time_t now = apr_time_now();
                        if (now > session->keep_sync_until) {
                            /* if we are on an async mpm, now is the time that
                             * we may dare to pass control to it. */
                            session->keep_sync_until = 0;
                        }
                        if (now > session->idle_until) {
                            if (trace) {
                                ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                              H2_SSSN_MSG(session,
                                              "keepalive timeout"));
                            }
                            dispatch_event(session,
                                           H2_SESSION_EV_CONN_TIMEOUT, 0, "timeout");
                        }
                        else if (trace) {
                            ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,
                                          H2_SSSN_MSG(session,
                                          "keepalive, %f sec left"),
                                          (session->idle_until - now) / 1000000.0);
                        }
                        /* continue reading handling */
                    }
                    else if (APR_STATUS_IS_ECONNABORTED(status)
                             || APR_STATUS_IS_ECONNRESET(status)
                             || APR_STATUS_IS_EOF(status)
                             || APR_STATUS_IS_EBADF(status)) {
                        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session, "input gone"));
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                    else {
                        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                                      H2_SSSN_MSG(session,
                                      "(1 sec timeout) read failed"));
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, "error");
                    }
                }
                break;

            case H2_SESSION_ST_BUSY:
                if (nghttp2_session_want_read(session->ngh2)) {
                    ap_update_child_status(session->c->sbh, SERVER_BUSY_READ, NULL);
                    h2_filter_cin_timeout_set(session->cin, session->s->timeout);
                    status = h2_session_read(session, 0);
                    if (status == APR_SUCCESS) {
                        session->have_read = 1;
                        dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
                    }
                    else if (status == APR_EAGAIN) {
                        /* nothing to read */
                    }
                    else if (APR_STATUS_IS_TIMEUP(status)) {
                        dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, 0, NULL);
                        break;
                    }
                    else {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                    }
                }

                status = dispatch_master(session);
                if (status != APR_SUCCESS && status != APR_EAGAIN) {
                    break;
                }

                if (nghttp2_session_want_write(session->ngh2)) {
                    ap_update_child_status(session->c->sbh, SERVER_BUSY_WRITE, NULL);
                    status = h2_session_send(session);
                    if (status == APR_SUCCESS) {
                        status = h2_conn_io_flush(&session->io);
                    }
                    if (status != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR,
                                       H2_ERR_INTERNAL_ERROR, "writing");
                        break;
                    }
                }

                if (session->have_read || session->have_written) {
                    if (session->wait_us) {
                        session->wait_us = 0;
                    }
                }
                else if (!nghttp2_session_want_write(session->ngh2)) {
                    dispatch_event(session, H2_SESSION_EV_NO_IO, 0, NULL);
                }
                break;

            case H2_SESSION_ST_WAIT:
                if (session->wait_us <= 0) {
                    session->wait_us = 10;
                    if (h2_conn_io_flush(&session->io) != APR_SUCCESS) {
                        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                        break;
                    }
                }
                else {
                    /* repeating, increase timer for graceful backoff */
                    session->wait_us = H2MIN(session->wait_us*2, MAX_WAIT_MICROS);
                }

                if (trace) {
                    ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c,
                                  "h2_session: wait for data, %ld micros",
                                  (long)session->wait_us);
                }
                status = h2_mplx_out_trywait(session->mplx, session->wait_us,
                                             session->iowait);
                if (status == APR_SUCCESS) {
                    session->wait_us = 0;
                    dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
                }
                else if (APR_STATUS_IS_TIMEUP(status)) {
                    /* go back to checking all inputs again */
                    transit(session, "wait cycle", session->local.shutdown?
                            H2_SESSION_ST_DONE : H2_SESSION_ST_BUSY);
                }
                else if (APR_STATUS_IS_ECONNRESET(status)
                         || APR_STATUS_IS_ECONNABORTED(status)) {
                    dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
                }
                else {
                    ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, c,
                                  H2_SSSN_LOG(APLOGNO(03404), session,
                                  "waiting on conditional"));
                    h2_session_shutdown(session, H2_ERR_INTERNAL_ERROR,
                                        "cond wait error", 0);
                }
                break;

            default:
                ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, c,
                              H2_SSSN_LOG(APLOGNO(03080), session,
                              "unknown state"));
                dispatch_event(session, H2_SESSION_EV_PROTO_ERROR, 0, NULL);
                break;
        }

        if (!nghttp2_session_want_read(session->ngh2)
                 && !nghttp2_session_want_write(session->ngh2)) {
            dispatch_event(session, H2_SESSION_EV_NGH2_DONE, 0, NULL);
        }
        if (session->reprioritize) {
            h2_mplx_reprioritize(session->mplx, stream_pri_cmp, session);
            session->reprioritize = 0;
        }
    }

out:
    if (trace) {
        ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c,
                      H2_SSSN_MSG(session, "process returns"));
    }

    if ((session->state != H2_SESSION_ST_DONE)
        && (APR_STATUS_IS_EOF(status)
            || APR_STATUS_IS_ECONNRESET(status)
            || APR_STATUS_IS_ECONNABORTED(status))) {
        dispatch_event(session, H2_SESSION_EV_CONN_ERROR, 0, NULL);
    }

    return (session->state == H2_SESSION_ST_DONE)? APR_EOF : APR_SUCCESS;
}


static void ev_stream_open(h2_session *session, h2_stream *stream)
{
    h2_iq_append(session->in_process, stream->id);
    switch (session->state) {
        case H2_SESSION_ST_IDLE:
            if (session->open_streams == 1) {
                /* enter timeout, since we have a stream again */
                session->idle_until = (session->s->timeout + apr_time_now());
            }
            break;
        default:
            break;
    }
}


static int on_frame_recv_cb(nghttp2_session *ng2s,
                            const nghttp2_frame *frame,
                            void *userp)
{
    h2_session *session = (h2_session *)userp;
    h2_stream *stream;
    apr_status_t rv = APR_SUCCESS;

    if (APLOGcdebug(session->c)) {
        char buffer[256];

        h2_util_frame_print(frame, buffer, sizeof(buffer)/sizeof(buffer[0]));
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                      H2_SSSN_LOG(APLOGNO(03066), session,
                      "recv FRAME[%s], frames=%ld/%ld (r/s)"),
                      buffer, (long)session->frames_received,
                     (long)session->frames_sent);
    }

    ++session->frames_received;
    switch (frame->hd.type) {
        case NGHTTP2_HEADERS:
            /* This can be HEADERS for a new stream, defining the request,
             * or HEADER may come after DATA at the end of a stream as in
             * trailers */
            stream = h2_session_stream_get(session, frame->hd.stream_id);
            if (stream) {
                rv = h2_stream_recv_frame(stream, NGHTTP2_HEADERS, frame->hd.flags,
                    frame->hd.length + H2_FRAME_HDR_LEN);
            }
            break;
        case NGHTTP2_DATA:
            stream = h2_session_stream_get(session, frame->hd.stream_id);
            if (stream) {
                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                              H2_STRM_LOG(APLOGNO(02923), stream,
                              "DATA, len=%ld, flags=%d"),
                              (long)frame->hd.length, frame->hd.flags);
                rv = h2_stream_recv_frame(stream, NGHTTP2_DATA, frame->hd.flags,
                    frame->hd.length + H2_FRAME_HDR_LEN);
            }
            break;
        case NGHTTP2_PRIORITY:
            session->reprioritize = 1;
            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                          "h2_stream(%ld-%d): PRIORITY frame "
                          " weight=%d, dependsOn=%d, exclusive=%d",
                          session->id, (int)frame->hd.stream_id,
                          frame->priority.pri_spec.weight,
                          frame->priority.pri_spec.stream_id,
                          frame->priority.pri_spec.exclusive);
            break;
        case NGHTTP2_WINDOW_UPDATE:
            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                          "h2_stream(%ld-%d): WINDOW_UPDATE incr=%d",
                          session->id, (int)frame->hd.stream_id,
                          frame->window_update.window_size_increment);
            break;
        case NGHTTP2_RST_STREAM:
            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03067)
                          "h2_stream(%ld-%d): RST_STREAM by client, errror=%d",
                          session->id, (int)frame->hd.stream_id,
                          (int)frame->rst_stream.error_code);
            stream = h2_session_stream_get(session, frame->hd.stream_id);
            if (stream && stream->initiated_on) {
                ++session->pushes_reset;
            }
            else {
                ++session->streams_reset;
            }
            break;
        case NGHTTP2_GOAWAY:
            if (frame->goaway.error_code == 0
                && frame->goaway.last_stream_id == ((1u << 31) - 1)) {
                /* shutdown notice. Should not come from a client... */
                session->remote.accepting = 0;
            }
            else {
                session->remote.accepted_max = frame->goaway.last_stream_id;
                dispatch_event(session, H2_SESSION_EV_REMOTE_GOAWAY,
                               frame->goaway.error_code, NULL);
            }
            break;
        default:
            if (APLOGctrace2(session->c)) {
                char buffer[256];

                h2_util_frame_print(frame, buffer,
                                    sizeof(buffer)/sizeof(buffer[0]));
                ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
                              H2_SSSN_MSG(session, "on_frame_rcv %s"), buffer);
            }
            break;
    }
    return (APR_SUCCESS == rv)? 0 : NGHTTP2_ERR_PROTO;
}