static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
  const char *encoding,const PointInfo *offset,TypeMetric *metrics)
{
#if !defined(FT_OPEN_PATHNAME)
#define FT_OPEN_PATHNAME  ft_open_pathname
#endif

  typedef struct _GlyphInfo
  {
    FT_UInt
      id;

    FT_Vector
      origin;

    FT_Glyph
      image;
  } GlyphInfo;

  const char
    *value;

  DrawInfo
    *annotate_info;

  ExceptionInfo
    *exception;

  FT_BBox
    bounds;

  FT_BitmapGlyph
    bitmap;

  FT_Encoding
    encoding_type;

  FT_Error
    ft_status;

  FT_Face
    face;

  FT_Int32
    flags;

  FT_Library
    library;

  FT_Matrix
    affine;

  FT_Open_Args
    args;

  FT_Vector
    origin;

  GlyphInfo
    glyph,
    last_glyph;

  GraphemeInfo
    *grapheme;

  MagickBooleanType
    status;

  PointInfo
    point,
    resolution;

  register char
    *p;

  register ssize_t
    i;

  size_t
    length;

  ssize_t
    code,
    y;

  static FT_Outline_Funcs
    OutlineMethods =
    {
      (FT_Outline_MoveTo_Func) TraceMoveTo,
      (FT_Outline_LineTo_Func) TraceLineTo,
      (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
      (FT_Outline_CubicTo_Func) TraceCubicBezier,
      0, 0
    };

  unsigned char
    *utf8;

  /*
    Initialize Truetype library.
  */
  exception=(&image->exception);
  ft_status=FT_Init_FreeType(&library);
  if (ft_status != 0)
    ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
      image->filename);
  args.flags=FT_OPEN_PATHNAME;
  if (draw_info->font == (char *) NULL)
    args.pathname=ConstantString("helvetica");
  else
    if (*draw_info->font != '@')
      args.pathname=ConstantString(draw_info->font);
    else
      args.pathname=ConstantString(draw_info->font+1);
  face=(FT_Face) NULL;
  ft_status=FT_Open_Face(library,&args,(long) draw_info->face,&face);
  if (ft_status != 0)
    {
      (void) FT_Done_FreeType(library);
      (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
        "UnableToReadFont","`%s'",args.pathname);
      args.pathname=DestroyString(args.pathname);
      return(MagickFalse);
    }
  args.pathname=DestroyString(args.pathname);
  if ((draw_info->metrics != (char *) NULL) &&
      (IsPathAccessible(draw_info->metrics) != MagickFalse))
    (void) FT_Attach_File(face,draw_info->metrics);
  encoding_type=FT_ENCODING_UNICODE;
  ft_status=FT_Select_Charmap(face,encoding_type);
  if ((ft_status != 0) && (face->num_charmaps != 0))
    ft_status=FT_Set_Charmap(face,face->charmaps[0]);
  if (encoding != (const char *) NULL)
    {
      if (LocaleCompare(encoding,"AdobeCustom") == 0)
        encoding_type=FT_ENCODING_ADOBE_CUSTOM;
      if (LocaleCompare(encoding,"AdobeExpert") == 0)
        encoding_type=FT_ENCODING_ADOBE_EXPERT;
      if (LocaleCompare(encoding,"AdobeStandard") == 0)
        encoding_type=FT_ENCODING_ADOBE_STANDARD;
      if (LocaleCompare(encoding,"AppleRoman") == 0)
        encoding_type=FT_ENCODING_APPLE_ROMAN;
      if (LocaleCompare(encoding,"BIG5") == 0)
        encoding_type=FT_ENCODING_BIG5;
#if defined(FT_ENCODING_PRC)
      if (LocaleCompare(encoding,"GB2312") == 0)
        encoding_type=FT_ENCODING_PRC;
#endif
#if defined(FT_ENCODING_JOHAB)
      if (LocaleCompare(encoding,"Johab") == 0)
        encoding_type=FT_ENCODING_JOHAB;
#endif
#if defined(FT_ENCODING_ADOBE_LATIN_1)
      if (LocaleCompare(encoding,"Latin-1") == 0)
        encoding_type=FT_ENCODING_ADOBE_LATIN_1;
#endif
#if defined(FT_ENCODING_ADOBE_LATIN_2)
      if (LocaleCompare(encoding,"Latin-2") == 0)
        encoding_type=FT_ENCODING_OLD_LATIN_2;
#endif
      if (LocaleCompare(encoding,"None") == 0)
        encoding_type=FT_ENCODING_NONE;
      if (LocaleCompare(encoding,"SJIScode") == 0)
        encoding_type=FT_ENCODING_SJIS;
      if (LocaleCompare(encoding,"Symbol") == 0)
        encoding_type=FT_ENCODING_MS_SYMBOL;
      if (LocaleCompare(encoding,"Unicode") == 0)
        encoding_type=FT_ENCODING_UNICODE;
      if (LocaleCompare(encoding,"Wansung") == 0)
        encoding_type=FT_ENCODING_WANSUNG;
      ft_status=FT_Select_Charmap(face,encoding_type);
      if (ft_status != 0)
        {
          (void) FT_Done_Face(face);
          (void) FT_Done_FreeType(library);
          ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
        }
    }
  /*
    Set text size.
  */
  resolution.x=DefaultResolution;
  resolution.y=DefaultResolution;
  if (draw_info->density != (char *) NULL)
    {
      GeometryInfo
        geometry_info;

      MagickStatusType
        flags;

      flags=ParseGeometry(draw_info->density,&geometry_info);
      resolution.x=geometry_info.rho;
      resolution.y=geometry_info.sigma;
      if ((flags & SigmaValue) == 0)
        resolution.y=resolution.x;
    }
  ft_status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
    (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
    (FT_UInt) resolution.y);
  if (ft_status != 0)
    {
      (void) FT_Done_Face(face);
      (void) FT_Done_FreeType(library);
      ThrowBinaryException(TypeError,"UnableToReadFont",draw_info->font);
    }
  metrics->pixels_per_em.x=face->size->metrics.x_ppem;
  metrics->pixels_per_em.y=face->size->metrics.y_ppem;
  metrics->ascent=(double) face->size->metrics.ascender/64.0;
  metrics->descent=(double) face->size->metrics.descender/64.0;
  metrics->width=0;
  metrics->origin.x=0;
  metrics->origin.y=0;
  metrics->height=(double) face->size->metrics.height/64.0;
  metrics->max_advance=0.0;
  if (face->size->metrics.max_advance > MagickEpsilon)
    metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
  metrics->bounds.x1=0.0;
  metrics->bounds.y1=metrics->descent;
  metrics->bounds.x2=metrics->ascent+metrics->descent;
  metrics->bounds.y2=metrics->ascent+metrics->descent;
  metrics->underline_position=face->underline_position/64.0;
  metrics->underline_thickness=face->underline_thickness/64.0;
  if ((draw_info->text == (char *) NULL) || (*draw_info->text == '\0'))
    {
      (void) FT_Done_Face(face);
      (void) FT_Done_FreeType(library);
      return(MagickTrue);
    }
  /*
    Compute bounding box.
  */
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
      "font-encoding %s; text-encoding %s; pointsize %g",
      draw_info->font != (char *) NULL ? draw_info->font : "none",
      encoding != (char *) NULL ? encoding : "none",
      draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
      draw_info->pointsize);
  flags=FT_LOAD_DEFAULT;
  if (draw_info->render == MagickFalse)
    flags=FT_LOAD_NO_BITMAP;
  if (draw_info->text_antialias == MagickFalse)
    flags|=FT_LOAD_TARGET_MONO;
  else
    {
#if defined(FT_LOAD_TARGET_LIGHT)
      flags|=FT_LOAD_TARGET_LIGHT;
#elif defined(FT_LOAD_TARGET_LCD)
      flags|=FT_LOAD_TARGET_LCD;
#endif
    }
  value=GetImageProperty(image,"type:hinting");
  if ((value != (const char *) NULL) && (LocaleCompare(value,"off") == 0))
    flags|=FT_LOAD_NO_HINTING;
  glyph.id=0;
  glyph.image=NULL;
  last_glyph.id=0;
  last_glyph.image=NULL;
  origin.x=0;
  origin.y=0;
  affine.xx=65536L;
  affine.yx=0L;
  affine.xy=0L;
  affine.yy=65536L;
  if (draw_info->render != MagickFalse)
    {
      affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
      affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
      affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
      affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
    }
  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
  if (annotate_info->dash_pattern != (double *) NULL)
    annotate_info->dash_pattern[0]=0.0;
  (void) CloneString(&annotate_info->primitive,"path '");
  status=MagickTrue;
  if (draw_info->render != MagickFalse)
    {
      if (image->storage_class != DirectClass)
        (void) SetImageStorageClass(image,DirectClass);
      if (image->matte == MagickFalse)
        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
    }
  point.x=0.0;
  point.y=0.0;
  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
    if (GetUTFCode(p) < 0)
      break;
  utf8=(unsigned char *) NULL;
  if (GetUTFCode(p) == 0)
    p=draw_info->text;
  else
    {
      utf8=ConvertLatin1ToUTF8((unsigned char *) draw_info->text);
      if (utf8 != (unsigned char *) NULL)
        p=(char *) utf8;
    }
  grapheme=(GraphemeInfo *) NULL;
  length=ComplexTextLayout(image,draw_info,p,strlen(p),face,flags,&grapheme);
  code=0;
  for (i=0; i < (ssize_t) length; i++)
  {
    FT_Outline
      outline;

    /*
      Render UTF-8 sequence.
    */
    glyph.id=grapheme[i].index;
    if (glyph.id == 0)
      glyph.id=FT_Get_Char_Index(face,' ');
    if ((glyph.id != 0) && (last_glyph.id != 0))
      origin.x+=(FT_Pos) (64.0*draw_info->kerning);
    glyph.origin=origin;
    glyph.origin.x+=grapheme[i].x_offset;
    glyph.origin.y+=grapheme[i].y_offset;
    glyph.image=0;
    ft_status=FT_Load_Glyph(face,glyph.id,flags);
    if (ft_status != 0)
      continue;
    ft_status=FT_Get_Glyph(face->glyph,&glyph.image);
    if (ft_status != 0)
      continue;
    outline=((FT_OutlineGlyph) glyph.image)->outline;
    ft_status=FT_Outline_Get_BBox(&outline,&bounds);
    if (ft_status != 0)
      continue;
    if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
      if (bounds.xMin != 0)
        metrics->bounds.x1=(double) bounds.xMin;
    if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
      if (bounds.yMin != 0)
        metrics->bounds.y1=(double) bounds.yMin;
    if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
      if (bounds.xMax != 0)
        metrics->bounds.x2=(double) bounds.xMax;
    if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
      if (bounds.yMax != 0)
        metrics->bounds.y2=(double) bounds.yMax;
    if (((draw_info->stroke.opacity != TransparentOpacity) ||
         (draw_info->stroke_pattern != (Image *) NULL)) &&
        ((status != MagickFalse) && (draw_info->render != MagickFalse)))
      {
        /*
          Trace the glyph.
        */
        annotate_info->affine.tx=glyph.origin.x/64.0;
        annotate_info->affine.ty=(-glyph.origin.y/64.0);
        if ((outline.n_contours > 0) && (outline.n_points > 0))
          ft_status=FT_Outline_Decompose(&outline,&OutlineMethods,
            annotate_info);
      }
    FT_Vector_Transform(&glyph.origin,&affine);
    (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
    ft_status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
      (FT_Vector *) NULL,MagickTrue);
    if (ft_status != 0)
      continue;
    bitmap=(FT_BitmapGlyph) glyph.image;
    point.x=offset->x+bitmap->left;
    if (bitmap->bitmap.pixel_mode == ft_pixel_mode_mono)
      point.x=offset->x+(origin.x >> 6);
    point.y=offset->y-bitmap->top;
    if (draw_info->render != MagickFalse)
      {
        CacheView
          *image_view;

        register unsigned char
          *p;

        MagickBooleanType
          transparent_fill;

        /*
          Rasterize the glyph.
        */
        transparent_fill=((draw_info->fill.opacity == TransparentOpacity) &&
          (draw_info->fill_pattern == (Image *) NULL) &&
          (draw_info->stroke.opacity == TransparentOpacity) &&
          (draw_info->stroke_pattern == (Image *) NULL)) ? MagickTrue :
          MagickFalse;
        p=bitmap->bitmap.buffer;
        image_view=AcquireAuthenticCacheView(image,exception);
        for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++)
        {
          MagickBooleanType
            active,
            sync;

          MagickRealType
            fill_opacity;

          PixelPacket
            fill_color;

          register PixelPacket
            *magick_restrict q;

          register ssize_t
            x;

          ssize_t
            n,
            x_offset,
            y_offset;

          if (status == MagickFalse)
            continue;
          x_offset=(ssize_t) ceil(point.x-0.5);
          y_offset=(ssize_t) ceil(point.y+y-0.5);
          if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
            continue;
          q=(PixelPacket *) NULL;
          if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
            active=MagickFalse;
          else
            {
              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
                bitmap->bitmap.width,1,exception);
              active=q != (PixelPacket *) NULL ? MagickTrue : MagickFalse;
            }
          n=y*bitmap->bitmap.pitch-1;
          for (x=0; x < (ssize_t) bitmap->bitmap.width; x++)
          {
            n++;
            x_offset++;
            if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
              {
                if (q != (PixelPacket *) NULL)
                  q++;
                continue;
              }
            if (bitmap->bitmap.pixel_mode != ft_pixel_mode_mono)
              fill_opacity=(MagickRealType) (p[n])/(bitmap->bitmap.num_grays-1);
            else
              fill_opacity=((p[(x >> 3)+y*bitmap->bitmap.pitch] &
                (1 << (~x & 0x07)))) == 0 ? 0.0 : 1.0;
            if (draw_info->text_antialias == MagickFalse)
              fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
            if (active == MagickFalse)
              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
                exception);
            if (q == (PixelPacket *) NULL)
              continue;
            if (transparent_fill == MagickFalse)
              {
                (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color);
                fill_opacity=QuantumRange-fill_opacity*(QuantumRange-
                  fill_color.opacity);
                MagickCompositeOver(&fill_color,fill_opacity,q,q->opacity,q);
              }
            else
              {
                double
                  Sa,
                  Da;

                Da=1.0-(QuantumScale*(QuantumRange-q->opacity));
                Sa=fill_opacity;
                fill_opacity=(1.0-RoundToUnity(Sa+Da-Sa*Da))*QuantumRange;
                SetPixelAlpha(q,fill_opacity);
              }
            if (active == MagickFalse)
              {
                sync=SyncCacheViewAuthenticPixels(image_view,exception);
                if (sync == MagickFalse)
                  status=MagickFalse;
              }
            q++;
          }
          sync=SyncCacheViewAuthenticPixels(image_view,exception);
          if (sync == MagickFalse)
            status=MagickFalse;
        }
        image_view=DestroyCacheView(image_view);
        if (((draw_info->stroke.opacity != TransparentOpacity) ||
             (draw_info->stroke_pattern != (Image *) NULL)) &&
            (status != MagickFalse))
          {
            /*
              Draw text stroke.
            */
            annotate_info->linejoin=RoundJoin;
            annotate_info->affine.tx=offset->x;
            annotate_info->affine.ty=offset->y;
            (void) ConcatenateString(&annotate_info->primitive,"'");
            if (strlen(annotate_info->primitive) > 7)
              (void) DrawImage(image,annotate_info);
            (void) CloneString(&annotate_info->primitive,"path '");
          }
      }
    if ((fabs(draw_info->interword_spacing) >= MagickEpsilon) &&
        (IsUTFSpace(GetUTFCode(p+grapheme[i].cluster)) != MagickFalse) &&
        (IsUTFSpace(code) == MagickFalse))
      origin.x+=(FT_Pos) (64.0*draw_info->interword_spacing);
    else
      origin.x+=(FT_Pos) grapheme[i].x_advance;
    metrics->origin.x=(double) origin.x;
    metrics->origin.y=(double) origin.y;
    if (metrics->origin.x > metrics->width)
      metrics->width=metrics->origin.x;
    if (last_glyph.image != 0)
      {
        FT_Done_Glyph(last_glyph.image);
        last_glyph.image=0;
      }
    last_glyph=glyph;
    code=GetUTFCode(p+grapheme[i].cluster);
  }
  if (grapheme != (GraphemeInfo *) NULL)
    grapheme=(GraphemeInfo *) RelinquishMagickMemory(grapheme);
  if (utf8 != (unsigned char *) NULL)
    utf8=(unsigned char *) RelinquishMagickMemory(utf8);
  if (glyph.image != 0)
    {
      FT_Done_Glyph(glyph.image);
      glyph.image=0;
    }
  /*
    Determine font metrics.
  */
  metrics->bounds.x1/=64.0;
  metrics->bounds.y1/=64.0;
  metrics->bounds.x2/=64.0;
  metrics->bounds.y2/=64.0;
  metrics->origin.x/=64.0;
  metrics->origin.y/=64.0;
  metrics->width/=64.0;
  /*
    Relinquish resources.
  */
  annotate_info=DestroyDrawInfo(annotate_info);
  (void) FT_Done_Face(face);
  (void) FT_Done_FreeType(library);
  return(status);
}


MagickExport MagickBooleanType GetTypeMetrics(Image *image,
  const DrawInfo *draw_info,TypeMetric *metrics)
{
  DrawInfo
    *annotate_info;

  MagickBooleanType
    status;

  PointInfo
    offset;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(draw_info != (DrawInfo *) NULL);
  assert(draw_info->text != (char *) NULL);
  assert(draw_info->signature == MagickCoreSignature);
  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
  annotate_info->render=MagickFalse;
  annotate_info->direction=UndefinedDirection;
  (void) memset(metrics,0,sizeof(*metrics));
  offset.x=0.0;
  offset.y=0.0;
  status=RenderType(image,annotate_info,&offset,metrics);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
      "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
      "bounds: %g,%g  %g,%g; origin: %g,%g; pixels per em: %g,%g; "
      "underline position: %g; underline thickness: %g",annotate_info->text,
      metrics->width,metrics->height,metrics->ascent,metrics->descent,
      metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
      metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
      metrics->pixels_per_em.x,metrics->pixels_per_em.y,
      metrics->underline_position,metrics->underline_thickness);
  annotate_info=DestroyDrawInfo(annotate_info);
  return(status);
}


MagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
  const MagickBooleanType split,TypeMetric *metrics,char **caption)
{
  MagickBooleanType
    status;

  register char
    *p,
    *q,
    *s;

  register ssize_t
    i;

  size_t
    width;

  ssize_t
    n;

  q=draw_info->text;
  s=(char *) NULL;
  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
  {
    if (IsUTFSpace(GetUTFCode(p)) != MagickFalse)
      s=p;
    if (GetUTFCode(p) == '\n')
      {
        q=draw_info->text;
        continue;
      }
    for (i=0; i < (ssize_t) GetUTFOctets(p); i++)
      *q++=(*(p+i));
    *q='\0';
    status=GetTypeMetrics(image,draw_info,metrics);
    if (status == MagickFalse)
      break;
    width=(size_t) floor(metrics->width+draw_info->stroke_width+0.5);
    if (width <= image->columns)
      continue;
    if (s != (char *) NULL)
      {
        *s='\n';
        p=s;
      }
    else
      if (split != MagickFalse)
        {
          /*
            No convenient line breaks-- insert newline.
          */
          n=p-(*caption);
          if ((n > 0) && ((*caption)[n-1] != '\n'))
            {
              char
                *target;

              target=AcquireString(*caption);
              CopyMagickString(target,*caption,n+1);
              ConcatenateMagickString(target,"\n",strlen(*caption)+1);
              ConcatenateMagickString(target,p,strlen(*caption)+2);
              (void) DestroyString(*caption);
              *caption=target;
              p=(*caption)+n;
            }
        }
    q=draw_info->text;
    s=(char *) NULL;
  }
  n=0;
  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
    if (GetUTFCode(p) == '\n')
      n++;
  return(n);
}


static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
  const Image *magnitude_image,const Image *phase_image,
  fftw_complex *fourier_pixels,ExceptionInfo *exception)
{
  CacheView
    *magnitude_view,
    *phase_view;

  double
    *inverse_pixels,
    *magnitude_pixels,
    *phase_pixels;

  MagickBooleanType
    status;

  MemoryInfo
    *inverse_info,
    *magnitude_info,
    *phase_info;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    i,
    x;

  ssize_t
    y;

  /*
    Inverse Fourier - read image and break down into a double array.
  */
  magnitude_info=AcquireVirtualMemory((size_t) fourier_info->width,
    fourier_info->height*sizeof(*magnitude_pixels));
  phase_info=AcquireVirtualMemory((size_t) fourier_info->width,
    fourier_info->height*sizeof(*phase_pixels));
  inverse_info=AcquireVirtualMemory((size_t) fourier_info->width,
    (fourier_info->height/2+1)*sizeof(*inverse_pixels));
  if ((magnitude_info == (MemoryInfo *) NULL) ||
      (phase_info == (MemoryInfo *) NULL) ||
      (inverse_info == (MemoryInfo *) NULL))
    {
      if (magnitude_info != (MemoryInfo *) NULL)
        magnitude_info=RelinquishVirtualMemory(magnitude_info);
      if (phase_info != (MemoryInfo *) NULL)
        phase_info=RelinquishVirtualMemory(phase_info);
      if (inverse_info != (MemoryInfo *) NULL)
        inverse_info=RelinquishVirtualMemory(inverse_info);
      (void) ThrowMagickException(exception,GetMagickModule(),
        ResourceLimitError,"MemoryAllocationFailed","`%s'",
        magnitude_image->filename);
      return(MagickFalse);
    }
  magnitude_pixels=(double *) GetVirtualMemoryBlob(magnitude_info);
  phase_pixels=(double *) GetVirtualMemoryBlob(phase_info);
  inverse_pixels=(double *) GetVirtualMemoryBlob(inverse_info);
  i=0L;
  magnitude_view=AcquireVirtualCacheView(magnitude_image,exception);
  for (y=0L; y < (ssize_t) fourier_info->height; y++)
  {
    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
      exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(magnitude_view);
    for (x=0L; x < (ssize_t) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelRed(p);
          break;
        }
        case GreenChannel:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelGreen(p);
          break;
        }
        case BlueChannel:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelBlue(p);
          break;
        }
        case OpacityChannel:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelOpacity(p);
          break;
        }
        case IndexChannel:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelIndex(indexes+x);
          break;
        }
        case GrayChannels:
        {
          magnitude_pixels[i]=QuantumScale*GetPixelGray(p);
          break;
        }
      }
      i++;
      p++;
    }
  }
  magnitude_view=DestroyCacheView(magnitude_view);
  status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
    magnitude_pixels,inverse_pixels);
  (void) memcpy(magnitude_pixels,inverse_pixels,fourier_info->height*
    fourier_info->center*sizeof(*magnitude_pixels));
  i=0L;
  phase_view=AcquireVirtualCacheView(phase_image,exception);
  for (y=0L; y < (ssize_t) fourier_info->height; y++)
  {
    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
      exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetCacheViewAuthenticIndexQueue(phase_view);
    for (x=0L; x < (ssize_t) fourier_info->width; x++)
    {
      switch (fourier_info->channel)
      {
        case RedChannel:
        default:
        {
          phase_pixels[i]=QuantumScale*GetPixelRed(p);
          break;
        }
        case GreenChannel:
        {
          phase_pixels[i]=QuantumScale*GetPixelGreen(p);
          break;
        }
        case BlueChannel:
        {
          phase_pixels[i]=QuantumScale*GetPixelBlue(p);
          break;
        }
        case OpacityChannel:
        {
          phase_pixels[i]=QuantumScale*GetPixelOpacity(p);
          break;
        }
        case IndexChannel:
        {
          phase_pixels[i]=QuantumScale*GetPixelIndex(indexes+x);
          break;
        }
        case GrayChannels:
        {
          phase_pixels[i]=QuantumScale*GetPixelGray(p);
          break;
        }
      }
      i++;
      p++;
    }
  }
  if (fourier_info->modulus != MagickFalse)
    {
      i=0L;
      for (y=0L; y < (ssize_t) fourier_info->height; y++)
        for (x=0L; x < (ssize_t) fourier_info->width; x++)
        {
          phase_pixels[i]-=0.5;
          phase_pixels[i]*=(2.0*MagickPI);
          i++;
        }
    }
  phase_view=DestroyCacheView(phase_view);
  CorrectPhaseLHS(fourier_info->width,fourier_info->height,phase_pixels);
  if (status != MagickFalse)
    status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
      phase_pixels,inverse_pixels);
  (void) memcpy(phase_pixels,inverse_pixels,fourier_info->height*
    fourier_info->center*sizeof(*phase_pixels));
  inverse_info=RelinquishVirtualMemory(inverse_info);
  /*
    Merge two sets.
  */
  i=0L;
  if (fourier_info->modulus != MagickFalse)
    for (y=0L; y < (ssize_t) fourier_info->height; y++)
       for (x=0L; x < (ssize_t) fourier_info->center; x++)
       {
#if defined(MAGICKCORE_HAVE_COMPLEX_H)
         fourier_pixels[i]=magnitude_pixels[i]*cos(phase_pixels[i])+I*
           magnitude_pixels[i]*sin(phase_pixels[i]);
#else
         fourier_pixels[i][0]=magnitude_pixels[i]*cos(phase_pixels[i]);
         fourier_pixels[i][1]=magnitude_pixels[i]*sin(phase_pixels[i]);
#endif
         i++;
      }
  else
    for (y=0L; y < (ssize_t) fourier_info->height; y++)
      for (x=0L; x < (ssize_t) fourier_info->center; x++)
      {
#if defined(MAGICKCORE_HAVE_COMPLEX_H)
        fourier_pixels[i]=magnitude_pixels[i]+I*phase_pixels[i];
#else
        fourier_pixels[i][0]=magnitude_pixels[i];
        fourier_pixels[i][1]=phase_pixels[i];
#endif
        i++;
      }
  magnitude_info=RelinquishVirtualMemory(magnitude_info);
  phase_info=RelinquishVirtualMemory(phase_info);
  return(status);
}


MagickExport MagickBooleanType AnnotateComponentGenesis(void)
{
  if (annotate_semaphore == (SemaphoreInfo *) NULL)
    annotate_semaphore=AllocateSemaphoreInfo();
  return(MagickTrue);
}


static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs)
{
	unsigned long linear_addr = -1L, seg_base, seg_limit;
	int ret, regoff;
	short eff_addr;
	long tmp;

	insn_get_modrm(insn);
	insn_get_displacement(insn);

	if (insn->addr_bytes != 2)
		goto out;

	if (X86_MODRM_MOD(insn->modrm.value) == 3) {
		ret = get_eff_addr_reg(insn, regs, &regoff, &tmp);
		if (ret)
			goto out;

		eff_addr = tmp;
	} else {
		ret = get_eff_addr_modrm_16(insn, regs, &regoff, &eff_addr);
		if (ret)
			goto out;
	}

	ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
	if (ret)
		goto out;

	/*
	 * Before computing the linear address, make sure the effective address
	 * is within the limits of the segment. In virtual-8086 mode, segment
	 * limits are not enforced. In such a case, the segment limit is -1L to
	 * reflect this fact.
	 */
	if ((unsigned long)(eff_addr & 0xffff) > seg_limit)
		goto out;

	linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base;

	/* Limit linear address to 20 bits */
	if (v8086_mode(regs))
		linear_addr &= 0xfffff;

out:
	return (void __user *)linear_addr;
}


int readbyte(__G)   /* refill inbuf and return a byte if available, else EOF */
    __GDEF
{
    if (G.mem_mode)
        return EOF;
    if (G.csize <= 0) {
        G.csize--;             /* for tests done after exploding */
        G.incnt = 0;
        return EOF;
    }
    if (G.incnt <= 0) {
        if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) {
            return EOF;
        } else if (G.incnt < 0) {  /* "fail" (abort, retry, ...) returns this */
            /* another hack, but no real harm copying same thing twice */
            (*G.message)((zvoid *)&G,
              (uch *)LoadFarString(ReadError),
              (ulg)strlen(LoadFarString(ReadError)), 0x401);
            echon();
#ifdef WINDLL
            longjmp(dll_error_return, 1);
#else
            DESTROYGLOBALS();
            EXIT(PK_BADERR);    /* totally bailing; better than lock-up */
#endif
        }
        G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on block bndry */
        G.inptr = G.inbuf;
        defer_leftover_input(__G);           /* decrements G.csize */
    }

#if CRYPT
    if (G.pInfo->encrypted) {
        uch *p;
        int n;

        /* This was previously set to decrypt one byte beyond G.csize, when
         * incnt reached that far.  GRR said, "but it's required:  why?"  This
         * was a bug in fillinbuf() -- was it also a bug here?
         */
        for (n = G.incnt, p = G.inptr;  n--;  p++)
            zdecode(*p);
    }
#endif /* CRYPT */

    --G.incnt;
    return *G.inptr++;

} /* end function readbyte() */


char *str2iso(dst, src)
    char *dst;                          /* destination buffer */
    register ZCONST char *src;          /* source string */
{
#ifdef INTERN_TO_ISO
    INTERN_TO_ISO(src, dst);
#else
    register uch c;
    register char *dstp = dst;

    do {
        c = (uch)foreign(*src++);
        *dstp++ = (char)ASCII2ISO(c);
    } while (c != '\0');
#endif

    return dst;
}


zusz_t makeint64(sig)
    ZCONST uch *sig;
{
#ifdef LARGE_FILE_SUPPORT
    /*
     * Convert intel style 'int64' variable to non-Intel non-16-bit
     * host format.  This routine also takes care of byte-ordering.
     */
    return (((zusz_t)sig[7]) << 56)
        + (((zusz_t)sig[6]) << 48)
        + (((zusz_t)sig[4]) << 32)
        + (zusz_t)((((ulg)sig[3]) << 24)
                 + (((ulg)sig[2]) << 16)
                 + (((unsigned)sig[1]) << 8)
                 + (sig[0]));

#else /* !LARGE_FILE_SUPPORT */

    if ((sig[7] | sig[6] | sig[5] | sig[4]) != 0)
        return (zusz_t)0xffffffffL;
    else
        return (zusz_t)((((ulg)sig[3]) << 24)
                      + (((ulg)sig[2]) << 16)
                      + (((unsigned)sig[1]) << 8)
                      + (sig[0]));

#endif /* ?LARGE_FILE_SUPPORT */
}


unsigned readbuf(__G__ buf, size)   /* return number of bytes read into buf */
    __GDEF
    char *buf;
    register unsigned size;
{
    register unsigned count;
    unsigned n;

    n = size;
    while (size) {
        if (G.incnt <= 0) {
            if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
                return (n-size);
            else if (G.incnt < 0) {
                /* another hack, but no real harm copying same thing twice */
                (*G.message)((zvoid *)&G,
                  (uch *)LoadFarString(ReadError),  /* CANNOT use slide */
                  (ulg)strlen(LoadFarString(ReadError)), 0x401);
                return 0;  /* discarding some data; better than lock-up */
            }
            /* buffer ALWAYS starts on a block boundary:  */
            G.cur_zipfile_bufstart += INBUFSIZ;
            G.inptr = G.inbuf;
        }
        count = MIN(size, (unsigned)G.incnt);
        memcpy(buf, G.inptr, count);
        buf += count;
        G.inptr += count;
        G.incnt -= count;
        size -= count;
    }
    return n;

} /* end function readbuf() */


unsigned find_compr_idx(compr_methodnum)
    unsigned compr_methodnum;
{
    unsigned i;

    for (i = 0; i < NUM_METHODS; i++) {
        if (ComprIDs[i] == compr_methodnum) break;
    }
    return i;
}


Uz_Globs *getGlobalPointer()
{
    int scan=0;
    ulg tid = GetThreadId();

    while (threadIdTable[scan] != tid && scan < THREADID_ENTRIES)
        scan++;

/*---------------------------------------------------------------------------
    There are two things we can do if we can't find the entry:  ignore it or
    scream.  The most likely reason for it not to be here is the user calling
    this routine twice.  Since this could cause BIG problems if any globals
    are accessed after the first call, we'd better scream.
  ---------------------------------------------------------------------------*/

    if (scan == THREADID_ENTRIES) {
        ZCONST char *noEntry = LoadFarString(EntryNotFound);
        fprintf(stderr, noEntry);  /* can't use Info w/o a global pointer */
        EXIT(PK_ERR);   /* programming error while still working */
    }

    return threadPtrTable[scan];
}


int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
{
	BT_DBG("hcon %p", conn);

	if (role == conn->role)
		return 1;

	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
		struct hci_cp_switch_role cp;
		bacpy(&cp.bdaddr, &conn->dst);
		cp.role = role;
		hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
	}

	return 0;
}


static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon,
						 __u16 handle)
{
	struct hci_chan *hchan;

	list_for_each_entry(hchan, &hcon->chan_list, list) {
		if (hchan->handle == handle)
			return hchan;
	}

	return NULL;
}


bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_setup_sync_conn cp;
	const struct sco_param *param;

	BT_DBG("hcon %p", conn);

	conn->state = BT_CONNECT;
	conn->out = true;

	conn->attempt++;

	cp.handle   = cpu_to_le16(handle);

	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
	cp.voice_setting  = cpu_to_le16(conn->setting);

	switch (conn->setting & SCO_AIRMODE_MASK) {
	case SCO_AIRMODE_TRANSP:
		if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
			return false;
		param = &esco_param_msbc[conn->attempt - 1];
		break;
	case SCO_AIRMODE_CVSD:
		if (lmp_esco_capable(conn->link)) {
			if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
				return false;
			param = &esco_param_cvsd[conn->attempt - 1];
		} else {
			if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
				return false;
			param = &sco_param_cvsd[conn->attempt - 1];
		}
		break;
	default:
		return false;
	}

	cp.retrans_effort = param->retrans_effort;
	cp.pkt_type = __cpu_to_le16(param->pkt_type);
	cp.max_latency = __cpu_to_le16(param->max_latency);

	if (hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
		return false;

	return true;
}


struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
				 u8 sec_level, u8 auth_type)
{
	struct hci_conn *acl;

	if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
		if (lmp_bredr_capable(hdev))
			return ERR_PTR(-ECONNREFUSED);

		return ERR_PTR(-EOPNOTSUPP);
	}

	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
	if (!acl) {
		acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
		if (!acl)
			return ERR_PTR(-ENOMEM);
	}

	hci_conn_hold(acl);

	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
		acl->sec_level = BT_SECURITY_LOW;
		acl->pending_sec_level = sec_level;
		acl->auth_type = auth_type;
		hci_acl_create_connection(acl);
	}

	return acl;
}


static void l2cap_conn_start(struct l2cap_conn *conn)
{
	struct l2cap_chan *chan, *tmp;

	BT_DBG("conn %p", conn);

	mutex_lock(&conn->chan_lock);

	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
		l2cap_chan_lock(chan);

		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
			l2cap_chan_ready(chan);
			l2cap_chan_unlock(chan);
			continue;
		}

		if (chan->state == BT_CONNECT) {
			if (!l2cap_chan_check_security(chan, true) ||
			    !__l2cap_no_conn_pending(chan)) {
				l2cap_chan_unlock(chan);
				continue;
			}

			if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
			    && test_bit(CONF_STATE2_DEVICE,
					&chan->conf_state)) {
				l2cap_chan_close(chan, ECONNRESET);
				l2cap_chan_unlock(chan);
				continue;
			}

			if (l2cap_check_enc_key_size(conn->hcon))
				l2cap_start_connection(chan);
			else
				l2cap_chan_close(chan, ECONNREFUSED);

		} else if (chan->state == BT_CONNECT2) {
			struct l2cap_conn_rsp rsp;
			char buf[128];
			rsp.scid = cpu_to_le16(chan->dcid);
			rsp.dcid = cpu_to_le16(chan->scid);

			if (l2cap_chan_check_security(chan, false)) {
				if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
					rsp.result = cpu_to_le16(L2CAP_CR_PEND);
					rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
					chan->ops->defer(chan);

				} else {
					l2cap_state_change(chan, BT_CONFIG);
					rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
					rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
				}
			} else {
				rsp.result = cpu_to_le16(L2CAP_CR_PEND);
				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
			}

			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
				       sizeof(rsp), &rsp);

			if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
			    rsp.result != L2CAP_CR_SUCCESS) {
				l2cap_chan_unlock(chan);
				continue;
			}

			set_bit(CONF_REQ_SENT, &chan->conf_state);
			l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
				       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
			chan->num_conf_req++;
		}

		l2cap_chan_unlock(chan);
	}

	mutex_unlock(&conn->chan_lock);
}


static inline int l2cap_config_rsp(struct l2cap_conn *conn,
				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
				   u8 *data)
{
	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
	u16 scid, flags, result;
	struct l2cap_chan *chan;
	int len = cmd_len - sizeof(*rsp);
	int err = 0;

	if (cmd_len < sizeof(*rsp))
		return -EPROTO;

	scid   = __le16_to_cpu(rsp->scid);
	flags  = __le16_to_cpu(rsp->flags);
	result = __le16_to_cpu(rsp->result);

	BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
	       result, len);

	chan = l2cap_get_chan_by_scid(conn, scid);
	if (!chan)
		return 0;

	switch (result) {
	case L2CAP_CONF_SUCCESS:
		l2cap_conf_rfc_get(chan, rsp->data, len);
		clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
		break;

	case L2CAP_CONF_PENDING:
		set_bit(CONF_REM_CONF_PEND, &chan->conf_state);

		if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
			char buf[64];

			len = l2cap_parse_conf_rsp(chan, rsp->data, len,
						   buf, sizeof(buf), &result);
			if (len < 0) {
				l2cap_send_disconn_req(chan, ECONNRESET);
				goto done;
			}

			if (!chan->hs_hcon) {
				l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
							0);
			} else {
				if (l2cap_check_efs(chan)) {
					amp_create_logical_link(chan);
					chan->ident = cmd->ident;
				}
			}
		}
		goto done;

	case L2CAP_CONF_UNACCEPT:
		if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
			char req[64];

			if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
				l2cap_send_disconn_req(chan, ECONNRESET);
				goto done;
			}

			/* throw out any old stored conf requests */
			result = L2CAP_CONF_SUCCESS;
			len = l2cap_parse_conf_rsp(chan, rsp->data, len,
						   req, sizeof(req), &result);
			if (len < 0) {
				l2cap_send_disconn_req(chan, ECONNRESET);
				goto done;
			}

			l2cap_send_cmd(conn, l2cap_get_ident(conn),
				       L2CAP_CONF_REQ, len, req);
			chan->num_conf_req++;
			if (result != L2CAP_CONF_SUCCESS)
				goto done;
			break;
		}
		/* fall through */

	default:
		l2cap_chan_set_err(chan, ECONNRESET);

		__set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
		l2cap_send_disconn_req(chan, ECONNRESET);
		goto done;
	}

	if (flags & L2CAP_CONF_FLAG_CONTINUATION)
		goto done;

	set_bit(CONF_INPUT_DONE, &chan->conf_state);

	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
		set_default_fcs(chan);

		if (chan->mode == L2CAP_MODE_ERTM ||
		    chan->mode == L2CAP_MODE_STREAMING)
			err = l2cap_ertm_init(chan);

		if (err < 0)
			l2cap_send_disconn_req(chan, -err);
		else
			l2cap_chan_ready(chan);
	}

done:
	l2cap_chan_unlock(chan);
	return err;
}


static inline void CompositeCanvas(Image *destination,
  const CompositeOperator compose,Image *source,ssize_t x_offset,
  ssize_t y_offset,ExceptionInfo *exception)
{
  const char
    *value;

  x_offset+=source->page.x-destination->page.x;
  y_offset+=source->page.y-destination->page.y;
  value=GetImageArtifact(source,"compose:outside-overlay");
  (void) CompositeImage(destination,source,compose,
    (value != (const char *) NULL) && (IsStringTrue(value) != MagickFalse) ?
    MagickFalse : MagickTrue,x_offset,y_offset,exception);
}


MagickExport void OptimizeImageTransparency(const Image *image,
     ExceptionInfo *exception)
{
  Image
    *dispose_image;

  register Image
    *next;

  /*
    Run the image through the animation sequence
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  next=GetFirstImageInList(image);
  dispose_image=CloneImage(next,next->page.width,next->page.height,
    MagickTrue,exception);
  if (dispose_image == (Image *) NULL)
    return;
  dispose_image->page=next->page;
  dispose_image->page.x=0;
  dispose_image->page.y=0;
  dispose_image->dispose=NoneDispose;
  dispose_image->background_color.alpha_trait=BlendPixelTrait;
  dispose_image->background_color.alpha=(MagickRealType) TransparentAlpha;
  (void) SetImageBackgroundColor(dispose_image,exception);

  while ( next != (Image *) NULL )
  {
    Image
      *current_image;

    /*
      Overlay this frame's image over the previous disposal image
    */
    current_image=CloneImage(dispose_image,0,0,MagickTrue,exception);
    if (current_image == (Image *) NULL)
      {
        dispose_image=DestroyImage(dispose_image);
        return;
      }
    (void) CompositeImage(current_image,next,next->alpha_trait != UndefinedPixelTrait ?
      OverCompositeOp : CopyCompositeOp,MagickTrue,next->page.x,next->page.y,
      exception);
    /*
      At this point the image would be displayed, for the delay period
    **
      Work out the disposal of the previous image
    */
    if (next->dispose == BackgroundDispose)
      {
        RectangleInfo
          bounds=next->page;

        bounds.width=next->columns;
        bounds.height=next->rows;
        if (bounds.x < 0)
          {
            bounds.width+=bounds.x;
            bounds.x=0;
          }
        if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) current_image->columns)
          bounds.width=current_image->columns-bounds.x;
        if (bounds.y < 0)
          {
            bounds.height+=bounds.y;
            bounds.y=0;
          }
        if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) current_image->rows)
          bounds.height=current_image->rows-bounds.y;
        ClearBounds(current_image,&bounds,exception);
      }
    if (next->dispose != PreviousDispose)
      {
        dispose_image=DestroyImage(dispose_image);
        dispose_image=current_image;
      }
    else
      current_image=DestroyImage(current_image);

    /*
      Optimize Transparency of the next frame (if present)
    */
    next=GetNextImageInList(next);
    if (next != (Image *) NULL) {
      (void) CompositeImage(next,dispose_image,ChangeMaskCompositeOp,
        MagickTrue,-(next->page.x),-(next->page.y),exception);
    }
  }
  dispose_image=DestroyImage(dispose_image);
  return;
}


static inline void CompositeCanvas(Image *destination,
  const CompositeOperator compose, Image *source,ssize_t x_offset,
  ssize_t y_offset )
{
  x_offset+=source->page.x-destination->page.x;
  y_offset+=source->page.y-destination->page.y;
  (void) CompositeImage(destination,compose,source,x_offset,y_offset);
}


MagickExport Image *MergeImageLayers(Image *image,
  const ImageLayerMethod method,ExceptionInfo *exception)
{
#define MergeLayersTag  "Merge/Layers"

  Image
    *canvas;

  MagickBooleanType
    proceed;

  RectangleInfo
    page;

  register const Image
    *next;

  size_t
    number_images,
    height,
    width;

  ssize_t
    scene;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  /*
    Determine canvas image size, and its virtual canvas size and offset.
  */
  page=image->page;
  width=image->columns;
  height=image->rows;
  switch (method)
  {
    case TrimBoundsLayer:
    case MergeLayer:
    default:
    {
      next=GetNextImageInList(image);
      for ( ; next != (Image *) NULL;  next=GetNextImageInList(next))
      {
        if (page.x > next->page.x)
          {
            width+=page.x-next->page.x;
            page.x=next->page.x;
          }
        if (page.y > next->page.y)
          {
            height+=page.y-next->page.y;
            page.y=next->page.y;
          }
        if ((ssize_t) width < (next->page.x+(ssize_t) next->columns-page.x))
          width=(size_t) next->page.x+(ssize_t) next->columns-page.x;
        if ((ssize_t) height < (next->page.y+(ssize_t) next->rows-page.y))
          height=(size_t) next->page.y+(ssize_t) next->rows-page.y;
      }
      break;
    }
    case FlattenLayer:
    {
      if (page.width > 0)
        width=page.width;
      if (page.height > 0)
        height=page.height;
      page.x=0;
      page.y=0;
      break;
    }
    case MosaicLayer:
    {
      if (page.width > 0)
        width=page.width;
      if (page.height > 0)
        height=page.height;
      for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
      {
        if ((ssize_t) width < (next->page.x+(ssize_t) next->columns))
          width=(size_t) next->page.x+next->columns;
        if ((ssize_t) height < (next->page.y+(ssize_t) next->rows))
          height=(size_t) next->page.y+next->rows;
      }
      page.width=width;
      page.height=height;
      page.x=0;
      page.y=0;
      break;
    }
  }
  /*
    Set virtual canvas size if not defined.
  */
  if (page.width == 0)
    page.width=page.x < 0 ? width : width+page.x;
  if (page.height == 0)
    page.height=page.y < 0 ? height : height+page.y;
  /*
    Handle "TrimBoundsLayer" method separately to normal 'layer merge'.
  */
  if (method == TrimBoundsLayer)
    {
      number_images=GetImageListLength(image);
      for (scene=0; scene < (ssize_t) number_images; scene++)
      {
        image->page.x-=page.x;
        image->page.y-=page.y;
        image->page.width=width;
        image->page.height=height;
        proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
          number_images);
        if (proceed == MagickFalse)
          break;
        image=GetNextImageInList(image);
        if (image == (Image *) NULL)
          break;
      }
      return((Image *) NULL);
    }
  /*
    Create canvas size of width and height, and background color.
  */
  canvas=CloneImage(image,width,height,MagickTrue,exception);
  if (canvas == (Image *) NULL)
    return((Image *) NULL);
  (void) SetImageBackgroundColor(canvas);
  canvas->page=page;
  canvas->dispose=UndefinedDispose;
  /*
    Compose images onto canvas, with progress monitor
  */
  number_images=GetImageListLength(image);
  for (scene=0; scene < (ssize_t) number_images; scene++)
  {
    (void) CompositeImage(canvas,image->compose,image,image->page.x-
      canvas->page.x,image->page.y-canvas->page.y);
    proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
      number_images);
    if (proceed == MagickFalse)
      break;
    image=GetNextImageInList(image);
    if (image == (Image *) NULL)
      break;
  }
  return(canvas);
}


MagickExport void RemoveDuplicateLayers(Image **images,ExceptionInfo *exception)
{
  RectangleInfo
    bounds;

  register Image
    *image,
    *next;

  assert((*images) != (const Image *) NULL);
  assert((*images)->signature == MagickCoreSignature);
  if ((*images)->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      (*images)->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  image=GetFirstImageInList(*images);
  for ( ; (next=GetNextImageInList(image)) != (Image *) NULL; image=next)
  {
    if ((image->columns != next->columns) || (image->rows != next->rows) ||
        (image->page.x != next->page.x) || (image->page.y != next->page.y))
      continue;
    bounds=CompareImageBounds(image,next,CompareAnyLayer,exception);
    if (bounds.x < 0)
      {
        /*
          Two images are the same, merge time delays and delete one.
        */
        size_t
          time;

        time=1000*image->delay*PerceptibleReciprocal(image->ticks_per_second);
        time+=1000*next->delay*PerceptibleReciprocal(next->ticks_per_second);
        next->ticks_per_second=100L;
        next->delay=time*image->ticks_per_second/1000;
        next->iterations=image->iterations;
        *images=image;
        (void) DeleteImageFromList(images);
      }
  }
  *images=GetFirstImageInList(*images);
}


    PngImage::PngImage(BasicIo::UniquePtr io, bool create)
        : Image(ImageType::png, mdExif | mdIptc | mdXmp | mdComment, std::move(io))
    {
        if (create) {
            if (io_->open() == 0) {
#ifdef DEBUG
                std::cerr << "Exiv2::PngImage:: Creating PNG image to memory\n";
#endif
                IoCloser closer(*io_);
                if (io_->write(pngBlank, sizeof(pngBlank)) != sizeof(pngBlank)) {
#ifdef DEBUG
                    std::cerr << "Exiv2::PngImage:: Failed to create PNG image on memory\n";
#endif
                }
            }
        }
    }  // PngImage::PngImage


    void CiffDirectory::doAddComponent(UniquePtr component)
    {
        components_.push_back(component.release());
    }


    int FileIo::Impl::switchMode(OpMode opMode)
    {
        if (fp_ == nullptr)
            return 1;
        if (opMode_ == opMode)
            return 0;
        OpMode oldOpMode = opMode_;
        opMode_ = opMode;

        bool reopen = true;
        switch (opMode) {
            case opRead:
                // Flush if current mode allows reading, else reopen (in mode "r+b"
                // as in this case we know that we can write to the file)
                if (openMode_[0] == 'r' || openMode_[1] == '+')
                    reopen = false;
                break;
            case opWrite:
                // Flush if current mode allows writing, else reopen
                if (openMode_[0] != 'r' || openMode_[1] == '+')
                    reopen = false;
                break;
            case opSeek:
                reopen = false;
                break;
        }

        if (!reopen) {
            // Do not do anything when switching _from_ opSeek mode; we
            // flush when switching _to_ opSeek.
            if (oldOpMode == opSeek)
                return 0;

            // Flush. On msvcrt fflush does not do the job
            std::fseek(fp_, 0, SEEK_CUR);
            return 0;
        }

        // Reopen the file
        long offset = std::ftell(fp_);
        if (offset == -1)
            return -1;
        // 'Manual' open("r+b") to avoid munmap()
        std::fclose(fp_);
        openMode_ = "r+b";
        opMode_ = opSeek;
#ifdef EXV_UNICODE_PATH
        if (wpMode_ == wpUnicode) {
            fp_ = ::_wfopen(wpath_.c_str(), s2ws(openMode_).c_str());
        } else
#endif
        {
            fp_ = std::fopen(path_.c_str(), openMode_.c_str());
        }
        if (fp_ == nullptr)
            return 1;
        return std::fseek(fp_, offset, SEEK_SET);
    }  // FileIo::Impl::switchMode


        bool    isInMem () const
        {
            return type_ == bMemory;
        }


    long SshIo::SshImpl::getFileLength()
    {
        long length = 0;
        if (protocol_ == pSftp) { // sftp
            sftp_attributes attributes = sftp_fstat(fileHandler_);
            length = (long)attributes->size;
        } else { // ssh
            std::string response;
            //std::string cmd = "stat -c %s " + hostInfo_.Path;
            std::string cmd = "declare -a x=($(ls -alt " + hostInfo_.Path + ")); echo ${x[4]}";
            if (ssh_->runCommand(cmd, &response) != 0) {
                throw Error(kerErrorMessage, "Unable to get file length.");
            } else {
                length = atol(response.c_str());
                if (length == 0) {
                    throw Error(kerErrorMessage, "File is empty or not found.");
                }
            }
        }
        return length;
    }


    void CurlIo::CurlImpl::getDataByRange(long lowBlock, long highBlock, std::string& response)
    {
        curl_easy_reset(curl_); // reset all options
        curl_easy_setopt(curl_, CURLOPT_URL, path_.c_str());
        curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L); // no progress meter please
        curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curlWriter);
        curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response);
        curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT, timeout_);
        curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 0L);

        //curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1); // debugging mode

        if (lowBlock > -1 && highBlock> -1) {
            std::stringstream ss;
            ss << lowBlock * blockSize_  << "-" << ((highBlock + 1) * blockSize_ - 1);
            std::string range = ss.str();
            curl_easy_setopt(curl_, CURLOPT_RANGE, range.c_str());
        }

        /* Perform the request, res will get the return code */
        CURLcode res = curl_easy_perform(curl_);

        if(res != CURLE_OK) {
            throw Error(kerErrorMessage, curl_easy_strerror(res));
        } else {
            long serverCode;
            curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &serverCode); // get code
            if (serverCode >= 400 || serverCode < 0) {
                throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
            }
        }
    }


    static void readOrThrow(BasicIo& iIo, byte* buf, long rcount, ErrorCode err) {
      const long nread = iIo.read(buf, rcount);
      enforce(nread == rcount, err);
      enforce(!iIo.error(), err);
    }


    DataLocId CiffComponent::dataLocation(uint16_t tag)
    {
        switch (tag & 0xc000) {
        case 0x0000: return valueData;
        case 0x4000: return directoryData;
        default: throw Error(kerCorruptedMetadata);
        }
    } // CiffComponent::dataLocation


static int error(std::string& errors, const char* msg, const char* x, const char* y, int z)
{
    static const size_t buffer_size = 512;
    char buffer[buffer_size];
    memset(buffer, 0, buffer_size);
    snprintf(buffer, buffer_size, msg, x, y, z);
    if (errno) {
        perror(buffer);
    } else {
        fprintf(stderr, "%s\n", buffer);
    }
    errors += std::string(msg) + '\n';
    return -1;
}


static void flushBuffer(const char* buffer,size_t start,int& end,std::string& file)
{
    file += std::string(buffer+start,end-start) ;
    end = 0 ;
}


void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno)
{
    int compno, pino;
    opj_tcp_t *tcp = &cp->tcps[tileno];
    if (pi) {
        for (pino = 0; pino < tcp->numpocs + 1; pino++) {
            if (pi[pino].comps) {
                for (compno = 0; compno < pi->numcomps; compno++) {
                    opj_pi_comp_t *comp = &pi[pino].comps[compno];
                    if (comp->resolutions) {
                        opj_free(comp->resolutions);
                    }
                }
                opj_free(pi[pino].comps);
            }
        }
        if (pi->include) {
            opj_free(pi->include);
        }
        opj_free(pi);
    }
}


OPJ_BOOL opj_tcd_t1_decode ( opj_tcd_t *p_tcd )
{
        OPJ_UINT32 compno;
        opj_t1_t * l_t1;
        opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
        opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps;
        opj_tccp_t * l_tccp = p_tcd->tcp->tccps;

        l_t1 = opj_t1_create(OPJ_FALSE);
        if (l_t1 == 00) {
                return OPJ_FALSE;
        }

        for (compno = 0; compno < l_tile->numcomps; ++compno) {
                /* The +3 is headroom required by the vectorized DWT */
                if (OPJ_FALSE == opj_t1_decode_cblks(l_t1, l_tile_comp, l_tccp)) {
                        opj_t1_destroy(l_t1);
                        return OPJ_FALSE;
                }
                ++l_tile_comp;
                ++l_tccp;
        }

        opj_t1_destroy(l_t1);

        return OPJ_TRUE;
}


OPJ_BOOL opj_tcd_decode_tile(   opj_tcd_t *p_tcd,
                                OPJ_BYTE *p_src,
                                OPJ_UINT32 p_max_length,
                                OPJ_UINT32 p_tile_no,
                                opj_codestream_index_t *p_cstr_index
                                )
{
        OPJ_UINT32 l_data_read;
        p_tcd->tcd_tileno = p_tile_no;
        p_tcd->tcp = &(p_tcd->cp->tcps[p_tile_no]);

#ifdef TODO_MSD /* FIXME */
        /* INDEX >>  */
        if(p_cstr_info) {
                OPJ_UINT32 resno, compno, numprec = 0;
                for (compno = 0; compno < (OPJ_UINT32) p_cstr_info->numcomps; compno++) {
                        opj_tcp_t *tcp = &p_tcd->cp->tcps[0];
                        opj_tccp_t *tccp = &tcp->tccps[compno];
                        opj_tcd_tilecomp_t *tilec_idx = &p_tcd->tcd_image->tiles->comps[compno];
                        for (resno = 0; resno < tilec_idx->numresolutions; resno++) {
                                opj_tcd_resolution_t *res_idx = &tilec_idx->resolutions[resno];
                                p_cstr_info->tile[p_tile_no].pw[resno] = res_idx->pw;
                                p_cstr_info->tile[p_tile_no].ph[resno] = res_idx->ph;
                                numprec += res_idx->pw * res_idx->ph;
                                p_cstr_info->tile[p_tile_no].pdx[resno] = tccp->prcw[resno];
                                p_cstr_info->tile[p_tile_no].pdy[resno] = tccp->prch[resno];
                        }
                }
                p_cstr_info->tile[p_tile_no].packet = (opj_packet_info_t *) opj_malloc(p_cstr_info->numlayers * numprec * sizeof(opj_packet_info_t));
                p_cstr_info->packno = 0;
        }
        /* << INDEX */
#endif

        /*--------------TIER2------------------*/
        /* FIXME _ProfStart(PGROUP_T2); */
        l_data_read = 0;
        if (! opj_tcd_t2_decode(p_tcd, p_src, &l_data_read, p_max_length, p_cstr_index))
        {
                return OPJ_FALSE;
        }
        /* FIXME _ProfStop(PGROUP_T2); */

        /*------------------TIER1-----------------*/

        /* FIXME _ProfStart(PGROUP_T1); */
        if
                (! opj_tcd_t1_decode(p_tcd))
        {
                return OPJ_FALSE;
        }
        /* FIXME _ProfStop(PGROUP_T1); */

        /*----------------DWT---------------------*/

        /* FIXME _ProfStart(PGROUP_DWT); */
        if
                (! opj_tcd_dwt_decode(p_tcd))
        {
                return OPJ_FALSE;
        }
        /* FIXME _ProfStop(PGROUP_DWT); */

        /*----------------MCT-------------------*/
        /* FIXME _ProfStart(PGROUP_MCT); */
        if
                (! opj_tcd_mct_decode(p_tcd))
        {
                return OPJ_FALSE;
        }
        /* FIXME _ProfStop(PGROUP_MCT); */

        /* FIXME _ProfStart(PGROUP_DC_SHIFT); */
        if
                (! opj_tcd_dc_level_shift_decode(p_tcd))
        {
                return OPJ_FALSE;
        }
        /* FIXME _ProfStop(PGROUP_DC_SHIFT); */

        /*---------------TILE-------------------*/
        return OPJ_TRUE;
}


OPJ_BOOL opj_pi_check_next_level(	OPJ_INT32 pos,
								opj_cp_t *cp,
								OPJ_UINT32 tileno,
								OPJ_UINT32 pino,
								const OPJ_CHAR *prog)
{
	OPJ_INT32 i;
	opj_tcp_t *tcps =&cp->tcps[tileno];
	opj_poc_t *tcp = &tcps->pocs[pino];

	if(pos>=0){
		for(i=pos;pos>=0;i--){
			switch(prog[i]){
		    case 'R':
			    if(tcp->res_t==tcp->resE){
				    if(opj_pi_check_next_level(pos-1,cp,tileno,pino,prog)){
					    return OPJ_TRUE;
				    }else{
					    return OPJ_FALSE;
				    }
			    }else{
				    return OPJ_TRUE;
			    }
			    break;
		    case 'C':
			    if(tcp->comp_t==tcp->compE){
				    if(opj_pi_check_next_level(pos-1,cp,tileno,pino,prog)){
					    return OPJ_TRUE;
				    }else{
					    return OPJ_FALSE;
				    }
			    }else{
				    return OPJ_TRUE;
			    }
			    break;
		    case 'L':
			    if(tcp->lay_t==tcp->layE){
				    if(opj_pi_check_next_level(pos-1,cp,tileno,pino,prog)){
					    return OPJ_TRUE;
				    }else{
					    return OPJ_FALSE;
				    }
			    }else{
				    return OPJ_TRUE;
			    }
			    break;
		    case 'P':
			    switch(tcp->prg){
                    case OPJ_LRCP: /* fall through */
                    case OPJ_RLCP:
					    if(tcp->prc_t == tcp->prcE){
						    if(opj_pi_check_next_level(i-1,cp,tileno,pino,prog)){
							    return OPJ_TRUE;
						    }else{
							    return OPJ_FALSE;
						    }
					    }else{
						    return OPJ_TRUE;
					    }
					    break;
			    default:
				    if(tcp->tx0_t == tcp->txE){
					    /*TY*/
					    if(tcp->ty0_t == tcp->tyE){
						    if(opj_pi_check_next_level(i-1,cp,tileno,pino,prog)){
							    return OPJ_TRUE;
						    }else{
							    return OPJ_FALSE;
						    }
					    }else{
						    return OPJ_TRUE;
					    }/*TY*/
				    }else{
					    return OPJ_TRUE;
				    }
				    break;
			    }/*end case P*/
		    }/*end switch*/
		}/*end for*/
	}/*end if*/
	return OPJ_FALSE;
}


xsltFormatNumberConversion(xsltDecimalFormatPtr self,
			   xmlChar *format,
			   double number,
			   xmlChar **result)
{
    xmlXPathError status = XPATH_EXPRESSION_OK;
    xmlBufferPtr buffer;
    xmlChar *the_format, *prefix = NULL, *suffix = NULL;
    xmlChar *nprefix, *nsuffix = NULL;
    xmlChar pchar;
    int	    prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
    double  scale;
    int	    j, len;
    int     self_grouping_len;
    xsltFormatNumberInfo format_info;
    /*
     * delayed_multiplier allows a 'trailing' percent or
     * permille to be treated as suffix
     */
    int		delayed_multiplier = 0;
    /* flag to show no -ve format present for -ve number */
    char	default_sign = 0;
    /* flag to show error found, should use default format */
    char	found_error = 0;

    if (xmlStrlen(format) <= 0) {
	xsltTransformError(NULL, NULL, NULL,
                "xsltFormatNumberConversion : "
		"Invalid format (0-length)\n");
    }
    *result = NULL;
    switch (xmlXPathIsInf(number)) {
	case -1:
	    if (self->minusSign == NULL)
		*result = xmlStrdup(BAD_CAST "-");
	    else
		*result = xmlStrdup(self->minusSign);
	    /* no-break on purpose */
	case 1:
	    if ((self == NULL) || (self->infinity == NULL))
		*result = xmlStrcat(*result, BAD_CAST "Infinity");
	    else
		*result = xmlStrcat(*result, self->infinity);
	    return(status);
	default:
	    if (xmlXPathIsNaN(number)) {
		if ((self == NULL) || (self->noNumber == NULL))
		    *result = xmlStrdup(BAD_CAST "NaN");
		else
		    *result = xmlStrdup(self->noNumber);
		return(status);
	    }
    }

    buffer = xmlBufferCreate();
    if (buffer == NULL) {
	return XPATH_MEMORY_ERROR;
    }

    format_info.integer_hash = 0;
    format_info.integer_digits = 0;
    format_info.frac_digits = 0;
    format_info.frac_hash = 0;
    format_info.group = -1;
    format_info.multiplier = 1;
    format_info.add_decimal = FALSE;
    format_info.is_multiplier_set = FALSE;
    format_info.is_negative_pattern = FALSE;

    the_format = format;

    /*
     * First we process the +ve pattern to get percent / permille,
     * as well as main format
     */
    prefix = the_format;
    prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
    if (prefix_length < 0) {
	found_error = 1;
	goto OUTPUT_NUMBER;
    }

    /*
     * Here we process the "number" part of the format.  It gets
     * a little messy because of the percent/per-mille - if that
     * appears at the end, it may be part of the suffix instead
     * of part of the number, so the variable delayed_multiplier
     * is used to handle it
     */
    self_grouping_len = xmlStrlen(self->grouping);
    while ((*the_format != 0) &&
	   (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) &&
	   (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) {

	if (delayed_multiplier != 0) {
	    format_info.multiplier = delayed_multiplier;
	    format_info.is_multiplier_set = TRUE;
	    delayed_multiplier = 0;
	}
	if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
	    if (format_info.integer_digits > 0) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    format_info.integer_hash++;
	    if (format_info.group >= 0)
		format_info.group++;
	} else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
	    format_info.integer_digits++;
	    if (format_info.group >= 0)
		format_info.group++;
	} else if ((self_grouping_len > 0) &&
	    (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) {
	    /* Reset group count */
	    format_info.group = 0;
	    the_format += self_grouping_len;
	    continue;
	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
	    if (format_info.is_multiplier_set) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    delayed_multiplier = 100;
	} else  if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
	    if (format_info.is_multiplier_set) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    delayed_multiplier = 1000;
	} else
	    break; /* while */

	if ((len=xmlUTF8Strsize(the_format, 1)) < 1) {
	    found_error = 1;
	    goto OUTPUT_NUMBER;
	}
	the_format += len;

    }

    /* We have finished the integer part, now work on fraction */
    if ( (*the_format != 0) &&
         (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) {
        format_info.add_decimal = TRUE;
        if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
            found_error = 1;
            goto OUTPUT_NUMBER;
        }
	the_format += len;	/* Skip over the decimal */
    }

    while (*the_format != 0) {

	if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
	    if (format_info.frac_hash != 0) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    format_info.frac_digits++;
	} else if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
	    format_info.frac_hash++;
	} else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
	    if (format_info.is_multiplier_set) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    delayed_multiplier = 100;
	    if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
	        found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    the_format += len;
	    continue; /* while */
	} else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
	    if (format_info.is_multiplier_set) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    delayed_multiplier = 1000;
	    if  ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
	        found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    the_format += len;
	    continue; /* while */
	} else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
	    break; /* while */
	}
	if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
	    found_error = 1;
	    goto OUTPUT_NUMBER;
	}
	the_format += len;
	if (delayed_multiplier != 0) {
	    format_info.multiplier = delayed_multiplier;
	    delayed_multiplier = 0;
	    format_info.is_multiplier_set = TRUE;
	}
    }

    /*
     * If delayed_multiplier is set after processing the
     * "number" part, should be in suffix
     */
    if (delayed_multiplier != 0) {
	the_format -= len;
	delayed_multiplier = 0;
    }

    suffix = the_format;
    suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
    if ( (suffix_length < 0) ||
	 ((*the_format != 0) &&
	  (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) {
	found_error = 1;
	goto OUTPUT_NUMBER;
    }

    /*
     * We have processed the +ve prefix, number part and +ve suffix.
     * If the number is -ve, we must substitute the -ve prefix / suffix
     */
    if (number < 0) {
        /*
	 * Note that j is the number of UTF8 chars before the separator,
	 * not the number of bytes! (bug 151975)
	 */
        j =  xmlUTF8Strloc(format, self->patternSeparator);
	if (j < 0) {
	/* No -ve pattern present, so use default signing */
	    default_sign = 1;
	}
	else {
	    /* Skip over pattern separator (accounting for UTF8) */
	    the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1);
	    /*
	     * Flag changes interpretation of percent/permille
	     * in -ve pattern
	     */
	    format_info.is_negative_pattern = TRUE;
	    format_info.is_multiplier_set = FALSE;

	    /* First do the -ve prefix */
	    nprefix = the_format;
	    nprefix_length = xsltFormatNumberPreSuffix(self,
					&the_format, &format_info);
	    if (nprefix_length<0) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }

	    while (*the_format != 0) {
		if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) ||
		     (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) {
		    if (format_info.is_multiplier_set) {
			found_error = 1;
			goto OUTPUT_NUMBER;
		    }
		    format_info.is_multiplier_set = TRUE;
		    delayed_multiplier = 1;
		}
		else if (IS_SPECIAL(self, the_format))
		    delayed_multiplier = 0;
		else
		    break; /* while */
		if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
		    found_error = 1;
		    goto OUTPUT_NUMBER;
		}
		the_format += len;
	    }
	    if (delayed_multiplier != 0) {
		format_info.is_multiplier_set = FALSE;
		the_format -= len;
	    }

	    /* Finally do the -ve suffix */
	    if (*the_format != 0) {
		nsuffix = the_format;
		nsuffix_length = xsltFormatNumberPreSuffix(self,
					&the_format, &format_info);
		if (nsuffix_length < 0) {
		    found_error = 1;
		    goto OUTPUT_NUMBER;
		}
	    }
	    else
		nsuffix_length = 0;
	    if (*the_format != 0) {
		found_error = 1;
		goto OUTPUT_NUMBER;
	    }
	    /*
	     * Here's another Java peculiarity:
	     * if -ve prefix/suffix == +ve ones, discard & use default
	     */
	    if ((nprefix_length != prefix_length) ||
		(nsuffix_length != suffix_length) ||
		((nprefix_length > 0) &&
		 (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
		((nsuffix_length > 0) &&
		 (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
		prefix = nprefix;
		prefix_length = nprefix_length;
		suffix = nsuffix;
		suffix_length = nsuffix_length;
	    } /* else {
		default_sign = 1;
	    }
	    */
	}
    }

OUTPUT_NUMBER:
    if (found_error != 0) {
	xsltTransformError(NULL, NULL, NULL,
                "xsltFormatNumberConversion : "
		"error in format string '%s', using default\n", format);
	default_sign = (number < 0.0) ? 1 : 0;
	prefix_length = suffix_length = 0;
	format_info.integer_hash = 0;
	format_info.integer_digits = 1;
	format_info.frac_digits = 1;
	format_info.frac_hash = 4;
	format_info.group = -1;
	format_info.multiplier = 1;
	format_info.add_decimal = TRUE;
    }

    /* Ready to output our number.  First see if "default sign" is required */
    if (default_sign != 0)
	xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1));

    /* Put the prefix into the buffer */
    for (j = 0; j < prefix_length; j++) {
	if ((pchar = *prefix++) == SYMBOL_QUOTE) {
	    len = xmlUTF8Strsize(prefix, 1);
	    xmlBufferAdd(buffer, prefix, len);
	    prefix += len;
	    j += len - 1;	/* length of symbol less length of quote */
	} else
	    xmlBufferAdd(buffer, &pchar, 1);
    }

    /* Next do the integer part of the number */
    number = fabs(number) * (double)format_info.multiplier;
    scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
    number = floor((scale * number + 0.5)) / scale;
    if ((self->grouping != NULL) &&
        (self->grouping[0] != 0)) {
        int gchar;

	len = xmlStrlen(self->grouping);
	gchar = xsltGetUTF8Char(self->grouping, &len);
	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
				format_info.integer_digits,
				format_info.group,
				gchar, len);
    } else
	xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
				format_info.integer_digits,
				format_info.group,
				',', 1);

    /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */
    if ((format_info.integer_digits + format_info.integer_hash +
	 format_info.frac_digits == 0) && (format_info.frac_hash > 0)) {
        ++format_info.frac_digits;
	--format_info.frac_hash;
    }

    /* Add leading zero, if required */
    if ((floor(number) == 0) &&
	(format_info.integer_digits + format_info.frac_digits == 0)) {
        xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1));
    }

    /* Next the fractional part, if required */
    if (format_info.frac_digits + format_info.frac_hash == 0) {
        if (format_info.add_decimal)
	    xmlBufferAdd(buffer, self->decimalPoint,
			 xmlUTF8Strsize(self->decimalPoint, 1));
    }
    else {
      number -= floor(number);
	if ((number != 0) || (format_info.frac_digits != 0)) {
	    xmlBufferAdd(buffer, self->decimalPoint,
			 xmlUTF8Strsize(self->decimalPoint, 1));
	    number = floor(scale * number + 0.5);
	    for (j = format_info.frac_hash; j > 0; j--) {
		if (fmod(number, 10.0) >= 1.0)
		    break; /* for */
		number /= 10.0;
	    }
	    xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
				format_info.frac_digits + j,
				0, 0, 0);
	}
    }
    /* Put the suffix into the buffer */
    for (j = 0; j < suffix_length; j++) {
	if ((pchar = *suffix++) == SYMBOL_QUOTE) {
            len = xmlUTF8Strsize(suffix, 1);
	    xmlBufferAdd(buffer, suffix, len);
	    suffix += len;
	    j += len - 1;	/* length of symbol less length of escape */
	} else
	    xmlBufferAdd(buffer, &pchar, 1);
    }

    *result = xmlStrdup(xmlBufferContent(buffer));
    xmlBufferFree(buffer);
    return status;
}


do_create (GVfsBackend *backend,
           GVfsJobOpenForWrite *open_write_job,
           const char *filename,
           GFileCreateFlags flags)
{
  GVfsBackendAdmin *self = G_VFS_BACKEND_ADMIN (backend);
  GVfsJob *job = G_VFS_JOB (open_write_job);
  GError *error = NULL;
  GFile *file;
  GFileOutputStream *stream;

  if (!check_permission (self, job))
    return;

  file = g_file_new_for_path (filename);
  stream = g_file_create (file, flags, job->cancellable, &error);
  g_object_unref (file);

  if (error != NULL)
    goto out;

  set_open_for_write_attributes (open_write_job, stream);

 out:
  complete_job (job, error);
}


check_permission (GVfsBackendAdmin *self,
                  GVfsJob *job)
{
  GVfsJobDBus *dbus_job = G_VFS_JOB_DBUS (job);
  GError *error = NULL;
  GDBusMethodInvocation *invocation;
  GDBusConnection *connection;
  GCredentials *credentials;
  pid_t pid;
  uid_t uid;
  PolkitSubject *subject;
  PolkitAuthorizationResult *result;
  gboolean is_authorized;

  invocation = dbus_job->invocation;
  connection = g_dbus_method_invocation_get_connection (invocation);
  credentials = g_dbus_connection_get_peer_credentials (connection);

  pid = g_credentials_get_unix_pid (credentials, &error);
  if (error != NULL)
    {
      g_vfs_job_failed_from_error (job, error);
      g_error_free (error);
      return FALSE;
    }

  uid = g_credentials_get_unix_user (credentials, &error);
  if (error != NULL)
    {
      g_vfs_job_failed_from_error (job, error);
      g_error_free (error);
      return FALSE;
    }

  /* Only one polkit dialog at a time */
  g_mutex_lock (&self->polkit_mutex);

  subject = polkit_unix_process_new_for_owner (pid, 0, uid);
  result = polkit_authority_check_authorization_sync (self->authority,
                                                      subject,
                                                      "org.gtk.vfs.file-operations",
                                                      NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
                                                      NULL, &error);
  g_object_unref (subject);

  g_mutex_unlock (&self->polkit_mutex);

  if (error != NULL)
    {
      g_vfs_job_failed_from_error (job, error);
      g_error_free (error);
      return FALSE;
    }

  is_authorized = polkit_authorization_result_get_is_authorized (result);

  g_object_unref (result);

  if (!is_authorized)
    g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
                              _("Permission denied"));

  return is_authorized;
}


g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kfsb)
{
  gchar *contents;
  gsize length;

  contents = g_key_file_to_data (kfsb->keyfile, &length, NULL);
  g_file_replace_contents (kfsb->file, contents, length, NULL, FALSE,
                           G_FILE_CREATE_REPLACE_DESTINATION |
                           G_FILE_CREATE_PRIVATE,
                           NULL, NULL, NULL);

  compute_checksum (kfsb->digest, contents, length);
  g_free (contents);
}


dir_changed (GFileMonitor       *monitor,
              GFile             *file,
              GFile             *other_file,
              GFileMonitorEvent  event_type,
              gpointer           user_data)
{
  GKeyfileSettingsBackend *kfsb = user_data;

  g_keyfile_settings_backend_keyfile_writable (kfsb);
}


g_keyfile_settings_backend_set_property (GObject      *object,
                                         guint         prop_id,
                                         const GValue *value,
                                         GParamSpec   *pspec)
{
  GKeyfileSettingsBackend *kfsb = G_KEYFILE_SETTINGS_BACKEND (object);

  switch ((GKeyfileSettingsBackendProperty)prop_id)
    {
    case PROP_FILENAME:
      /* Construct only. */
      g_assert (kfsb->file == NULL);
      kfsb->file = g_file_new_for_path (g_value_get_string (value));
      break;

    case PROP_ROOT_PATH:
      /* Construct only. */
      g_assert (kfsb->prefix == NULL);
      kfsb->prefix = g_value_dup_string (value);
      if (kfsb->prefix)
        kfsb->prefix_len = strlen (kfsb->prefix);
      break;

    case PROP_ROOT_GROUP:
      /* Construct only. */
      g_assert (kfsb->root_group == NULL);
      kfsb->root_group = g_value_dup_string (value);
      if (kfsb->root_group)
        kfsb->root_group_len = strlen (kfsb->root_group);
      break;

    case PROP_DEFAULTS_DIR:
      /* Construct only. */
      g_assert (kfsb->defaults_dir == NULL);
      kfsb->defaults_dir = g_value_dup_string (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}


expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[], UChar *p,
                            int slen, UChar *end, regex_t* reg, Node **rnode)
{
  int r, i, j;
  int len;
  int varlen;
  Node *anode, *var_anode, *snode, *xnode, *an;
  UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];

  *rnode = var_anode = NULL_NODE;

  varlen = 0;
  for (i = 0; i < item_num; i++) {
    if (items[i].byte_len != slen) {
      varlen = 1;
      break;
    }
  }

  if (varlen != 0) {
    *rnode = var_anode = onig_node_new_alt(NULL_NODE, NULL_NODE);
    if (IS_NULL(var_anode)) return ONIGERR_MEMORY;

    xnode = onig_node_new_list(NULL, NULL);
    if (IS_NULL(xnode)) goto mem_err;
    NODE_CAR(var_anode) = xnode;

    anode = onig_node_new_alt(NULL_NODE, NULL_NODE);
    if (IS_NULL(anode)) goto mem_err;
    NODE_CAR(xnode) = anode;
  }
  else {
    *rnode = anode = onig_node_new_alt(NULL_NODE, NULL_NODE);
    if (IS_NULL(anode)) return ONIGERR_MEMORY;
  }

  snode = onig_node_new_str(p, p + slen);
  if (IS_NULL(snode)) goto mem_err;

  NODE_CAR(anode) = snode;

  for (i = 0; i < item_num; i++) {
    snode = onig_node_new_str(NULL, NULL);
    if (IS_NULL(snode)) goto mem_err;

    for (j = 0; j < items[i].code_len; j++) {
      len = ONIGENC_CODE_TO_MBC(reg->enc, items[i].code[j], buf);
      if (len < 0) {
        r = len;
        goto mem_err2;
      }

      r = onig_node_str_cat(snode, buf, buf + len);
      if (r != 0) goto mem_err2;
    }

    an = onig_node_new_alt(NULL_NODE, NULL_NODE);
    if (IS_NULL(an)) {
      goto mem_err2;
    }

    if (items[i].byte_len != slen && IS_NOT_NULL(var_anode)) {
      Node *rem;
      UChar *q = p + items[i].byte_len;

      if (q < end) {
        r = expand_case_fold_make_rem_string(&rem, q, end, reg);
        if (r != 0) {
          onig_node_free(an);
          goto mem_err2;
        }

        xnode = onig_node_list_add(NULL_NODE, snode);
        if (IS_NULL(xnode)) {
          onig_node_free(an);
          onig_node_free(rem);
          goto mem_err2;
        }
        if (IS_NULL(onig_node_list_add(xnode, rem))) {
          onig_node_free(an);
          onig_node_free(xnode);
          onig_node_free(rem);
          goto mem_err;
        }

        NODE_CAR(an) = xnode;
      }
      else {
        NODE_CAR(an) = snode;
      }

      NODE_CDR(var_anode) = an;
      var_anode = an;
    }
    else {
      NODE_CAR(an)     = snode;
      NODE_CDR(anode) = an;
      anode = an;
    }
  }

  return varlen;

 mem_err2:
  onig_node_free(snode);

 mem_err:
  onig_node_free(*rnode);

  return ONIGERR_MEMORY;
}


tree_min_len(Node* node, ScanEnv* env)
{
  OnigLen len;
  OnigLen tmin;

  len = 0;
  switch (NODE_TYPE(node)) {
  case NODE_BACKREF:
    if (! NODE_IS_CHECKER(node)) {
      int i;
      int* backs;
      MemEnv* mem_env = SCANENV_MEMENV(env);
      BackRefNode* br = BACKREF_(node);
      if (NODE_IS_RECURSION(node)) break;

      backs = BACKREFS_P(br);
      len = tree_min_len(mem_env[backs[0]].node, env);
      for (i = 1; i < br->back_num; i++) {
        tmin = tree_min_len(mem_env[backs[i]].node, env);
        if (len > tmin) len = tmin;
      }
    }
    break;

#ifdef USE_CALL
  case NODE_CALL:
    {
      Node* t = NODE_BODY(node);
      if (NODE_IS_RECURSION(node)) {
        if (NODE_IS_MIN_FIXED(t))
          len = BAG_(t)->min_len;
      }
      else
        len = tree_min_len(t, env);
    }
    break;
#endif

  case NODE_LIST:
    do {
      tmin = tree_min_len(NODE_CAR(node), env);
      len = distance_add(len, tmin);
    } while (IS_NOT_NULL(node = NODE_CDR(node)));
    break;

  case NODE_ALT:
    {
      Node *x, *y;
      y = node;
      do {
        x = NODE_CAR(y);
        tmin = tree_min_len(x, env);
        if (y == node) len = tmin;
        else if (len > tmin) len = tmin;
      } while (IS_NOT_NULL(y = NODE_CDR(y)));
    }
    break;

  case NODE_STRING:
    {
      StrNode* sn = STR_(node);
      len = (int )(sn->end - sn->s);
    }
    break;

  case NODE_CTYPE:
  case NODE_CCLASS:
    len = ONIGENC_MBC_MINLEN(env->enc);
    break;

  case NODE_QUANT:
    {
      QuantNode* qn = QUANT_(node);

      if (qn->lower > 0) {
        len = tree_min_len(NODE_BODY(node), env);
        len = distance_multiply(len, qn->lower);
      }
    }
    break;

  case NODE_BAG:
    {
      BagNode* en = BAG_(node);
      switch (en->type) {
      case BAG_MEMORY:
        if (NODE_IS_MIN_FIXED(node))
          len = en->min_len;
        else {
          if (NODE_IS_MARK1(node))
            len = 0;  /* recursive */
          else {
            NODE_STATUS_ADD(node, MARK1);
            len = tree_min_len(NODE_BODY(node), env);
            NODE_STATUS_REMOVE(node, MARK1);

            en->min_len = len;
            NODE_STATUS_ADD(node, MIN_FIXED);
          }
        }
        break;

      case BAG_OPTION:
      case BAG_STOP_BACKTRACK:
        len = tree_min_len(NODE_BODY(node), env);
        break;
      case BAG_IF_ELSE:
        {
          OnigLen elen;

          len = tree_min_len(NODE_BODY(node), env);
          if (IS_NOT_NULL(en->te.Then))
            len += tree_min_len(en->te.Then, env);
          if (IS_NOT_NULL(en->te.Else))
            elen = tree_min_len(en->te.Else, env);
          else elen = 0;

          if (elen < len) len = elen;
        }
        break;
      }
    }
    break;

  case NODE_GIMMICK:
    {
      GimmickNode* g = GIMMICK_(node);
      if (g->type == GIMMICK_FAIL) {
        len = INFINITE_LEN;
        break;
      }
    }
    /* fall */
  case NODE_ANCHOR:
  default:
    break;
  }

  return len;
}


unset_addr_list_init(UnsetAddrList* list, int size)
{
  UnsetAddr* p = (UnsetAddr* )xmalloc(sizeof(UnsetAddr)* size);
  CHECK_NULL_RETURN_MEMERR(p);

  list->num   = 0;
  list->alloc = size;
  list->us    = p;
  return 0;
}


alt_merge_opt_exact(OptStr* to, OptStr* add, OptEnv* env)
{
  int i, j, len;

  if (add->len == 0 || to->len == 0) {
    clear_opt_exact(to);
    return ;
  }

  if (! is_equal_mml(&to->mmd, &add->mmd)) {
    clear_opt_exact(to);
    return ;
  }

  for (i = 0; i < to->len && i < add->len; ) {
    if (to->s[i] != add->s[i]) break;
    len = enclen(env->enc, to->s + i);

    for (j = 1; j < len; j++) {
      if (to->s[i+j] != add->s[i+j]) break;
    }
    if (j < len) break;
    i += len;
  }

  if (! add->reach_end || i < add->len || i < to->len) {
    to->reach_end = 0;
  }
  to->len = i;
  if (add->case_fold != 0)
    to->case_fold = 1;
  if (add->good_case_fold == 0)
    to->good_case_fold = 0;

  alt_merge_opt_anc_info(&to->anc, &add->anc);
  if (! to->reach_end) to->anc.right = 0;
}


compile_length_quantifier_node(QuantNode* qn, regex_t* reg)
{
  int len, mod_tlen;
  int infinite = IS_REPEAT_INFINITE(qn->upper);
  enum BodyEmpty empty_info = qn->empty_info;
  int tlen = compile_length_tree(NODE_QUANT_BODY(qn), reg);

  if (tlen < 0) return tlen;
  if (tlen == 0) return 0;

  /* anychar repeat */
  if (is_anychar_infinite_greedy(qn)) {
    if (qn->lower <= 1 ||
        int_multiply_cmp(tlen, qn->lower, QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0) {
      if (IS_NOT_NULL(qn->next_head_exact))
        return SIZE_OP_ANYCHAR_STAR_PEEK_NEXT + tlen * qn->lower;
      else
        return SIZE_OP_ANYCHAR_STAR + tlen * qn->lower;
    }
  }

  if (empty_info == BODY_IS_NOT_EMPTY)
    mod_tlen = tlen;
  else
    mod_tlen = tlen + (SIZE_OP_EMPTY_CHECK_START + SIZE_OP_EMPTY_CHECK_END);

  if (infinite &&
      (qn->lower <= 1 ||
       int_multiply_cmp(tlen, qn->lower, QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
    if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
      len = SIZE_OP_JUMP;
    }
    else {
      len = tlen * qn->lower;
    }

    if (qn->greedy) {
#ifdef USE_OP_PUSH_OR_JUMP_EXACT
      if (IS_NOT_NULL(qn->head_exact))
        len += SIZE_OP_PUSH_OR_JUMP_EXACT1 + mod_tlen + SIZE_OP_JUMP;
      else
#endif
      if (IS_NOT_NULL(qn->next_head_exact))
        len += SIZE_OP_PUSH_IF_PEEK_NEXT + mod_tlen + SIZE_OP_JUMP;
      else
        len += SIZE_OP_PUSH + mod_tlen + SIZE_OP_JUMP;
    }
    else
      len += SIZE_OP_JUMP + mod_tlen + SIZE_OP_PUSH;
  }
  else if (qn->upper == 0) {
    if (qn->is_refered != 0) { /* /(?<n>..){0}/ */
      len = SIZE_OP_JUMP + tlen;
    }
    else
      len = 0;
  }
  else if (!infinite && qn->greedy &&
           (qn->upper == 1 ||
            int_multiply_cmp(tlen + SIZE_OP_PUSH, qn->upper,
                             QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
    len = tlen * qn->lower;
    len += (SIZE_OP_PUSH + tlen) * (qn->upper - qn->lower);
  }
  else if (!qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
    len = SIZE_OP_PUSH + SIZE_OP_JUMP + tlen;
  }
  else {
    len = SIZE_OP_REPEAT_INC + mod_tlen + SIZE_OP_REPEAT;
  }

  return len;
}


onig_is_code_in_cc_len(int elen, OnigCodePoint code, /* CClassNode* */ void* cc_arg)
{
  int found;
  CClassNode* cc = (CClassNode* )cc_arg;

  if (elen > 1 || (code >= SINGLE_BYTE_SIZE)) {
    if (IS_NULL(cc->mbuf)) {
      found = 0;
    }
    else {
      found = onig_is_in_code_range(cc->mbuf->p, code) != 0;
    }
  }
  else {
    found = BITSET_AT(cc->bs, code) != 0;
  }

  if (IS_NCCLASS_NOT(cc))
    return !found;
  else
    return found;
}


concat_opt_exact_str(OptStr* to, UChar* s, UChar* end, OnigEncoding enc)
{
  int i, j, len;
  UChar *p;

  for (i = to->len, p = s; p < end && i < OPT_EXACT_MAXLEN; ) {
    len = enclen(enc, p);
    if (i + len > OPT_EXACT_MAXLEN) break;
    for (j = 0; j < len && p < end; j++)
      to->s[i++] = *p++;
  }

  to->len = i;

  if (p >= end && to->len == (int )(end - s))
    to->reach_end = 1;
}


update_string_node_case_fold(regex_t* reg, Node *node)
{
  UChar *p, *end, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
  UChar *sbuf, *ebuf, *sp;
  int r, i, len, sbuf_size;
  StrNode* sn = STR_(node);

  end = sn->end;
  sbuf_size = (int )(end - sn->s) * 2;
  sbuf = (UChar* )xmalloc(sbuf_size);
  CHECK_NULL_RETURN_MEMERR(sbuf);
  ebuf = sbuf + sbuf_size;

  sp = sbuf;
  p = sn->s;
  while (p < end) {
    len = ONIGENC_MBC_CASE_FOLD(reg->enc, reg->case_fold_flag, &p, end, buf);
    for (i = 0; i < len; i++) {
      if (sp >= ebuf) {
        sbuf = (UChar* )xrealloc(sbuf, sbuf_size * 2);
        CHECK_NULL_RETURN_MEMERR(sbuf);
        sp = sbuf + sbuf_size;
        sbuf_size *= 2;
        ebuf = sbuf + sbuf_size;
      }

      *sp++ = buf[i];
    }
  }

  r = onig_node_str_set(node, sbuf, sp);
  if (r != 0) {
    xfree(sbuf);
    return r;
  }

  xfree(sbuf);
  return 0;
}


add_char_amb_opt_map(OptMap* map, UChar* p, UChar* end,
                     OnigEncoding enc, OnigCaseFoldType fold_flag)
{
  OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
  UChar buf[ONIGENC_CODE_TO_MBC_MAXLEN];
  int i, n;

  add_char_opt_map(map, p[0], enc);

  fold_flag = DISABLE_CASE_FOLD_MULTI_CHAR(fold_flag);
  n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, fold_flag, p, end, items);
  if (n < 0) return n;

  for (i = 0; i < n; i++) {
    ONIGENC_CODE_TO_MBC(enc, items[i].code[0], buf);
    add_char_opt_map(map, buf[0], enc);
  }

  return 0;
}


setup_call(Node* node, ScanEnv* env, int state)
{
  int r;

  switch (NODE_TYPE(node)) {
  case NODE_LIST:
  case NODE_ALT:
    do {
      r = setup_call(NODE_CAR(node), env, state);
    } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
    break;

  case NODE_QUANT:
    if (QUANT_(node)->upper == 0)
      state |= IN_ZERO_REPEAT;

    r = setup_call(NODE_BODY(node), env, state);
    break;

  case NODE_ANCHOR:
    if (ANCHOR_HAS_BODY(ANCHOR_(node)))
      r = setup_call(NODE_BODY(node), env, state);
    else
      r = 0;
    break;

  case NODE_BAG:
    {
      BagNode* en = BAG_(node);

      if (en->type == BAG_MEMORY) {
        if ((state & IN_ZERO_REPEAT) != 0) {
          NODE_STATUS_ADD(node, IN_ZERO_REPEAT);
          BAG_(node)->m.entry_count--;
        }
        r = setup_call(NODE_BODY(node), env, state);
      }
      else if (en->type == BAG_IF_ELSE) {
        r = setup_call(NODE_BODY(node), env, state);
        if (r != 0) return r;
        if (IS_NOT_NULL(en->te.Then)) {
          r = setup_call(en->te.Then, env, state);
          if (r != 0) return r;
        }
        if (IS_NOT_NULL(en->te.Else))
          r = setup_call(en->te.Else, env, state);
      }
      else
        r = setup_call(NODE_BODY(node), env, state);
    }
    break;

  case NODE_CALL:
    if ((state & IN_ZERO_REPEAT) != 0) {
      NODE_STATUS_ADD(node, IN_ZERO_REPEAT);
      CALL_(node)->entry_count--;
    }

    r = setup_call_node_call(CALL_(node), env, state);
    break;

  default:
    r = 0;
    break;
  }

  return r;
}


onig_end(void)
{
  exec_end_call_list();

#ifdef USE_CALLOUT
  onig_global_callout_names_free();
#endif

  onigenc_end();

  onig_inited = 0;

  return 0;
}


setup_quant(Node* node, regex_t* reg, int state, ScanEnv* env)
{
  int r;
  OnigLen d;
  QuantNode* qn = QUANT_(node);
  Node* body = NODE_BODY(node);

  if ((state & IN_REAL_REPEAT) != 0) {
    NODE_STATUS_ADD(node, IN_REAL_REPEAT);
  }
  if ((state & IN_MULTI_ENTRY) != 0) {
    NODE_STATUS_ADD(node, IN_MULTI_ENTRY);
  }

  if (IS_REPEAT_INFINITE(qn->upper) || qn->upper >= 1) {
    d = tree_min_len(body, env);
    if (d == 0) {
#ifdef USE_INSISTENT_CHECK_CAPTURES_IN_EMPTY_REPEAT
      qn->empty_info = quantifiers_memory_node_info(body);
      if (qn->empty_info == BODY_IS_EMPTY_REC) {
        if (NODE_TYPE(body) == NODE_BAG &&
            BAG_(body)->type == BAG_MEMORY) {
          MEM_STATUS_ON(env->bt_mem_end, BAG_(body)->m.regnum);
        }
      }
#else
      qn->empty_info = BODY_IS_EMPTY;
#endif
    }
  }

  if (IS_REPEAT_INFINITE(qn->upper) || qn->upper >= 2)
    state |= IN_REAL_REPEAT;
  if (qn->lower != qn->upper)
    state |= IN_VAR_REPEAT;

  r = setup_tree(body, reg, state, env);
  if (r != 0) return r;

  /* expand string */
#define EXPAND_STRING_MAX_LENGTH  100
  if (NODE_TYPE(body) == NODE_STRING) {
    if (!IS_REPEAT_INFINITE(qn->lower) && qn->lower == qn->upper &&
        qn->lower > 1 && qn->lower <= EXPAND_STRING_MAX_LENGTH) {
      int len = NODE_STRING_LEN(body);
      StrNode* sn = STR_(body);

      if (len * qn->lower <= EXPAND_STRING_MAX_LENGTH) {
        int i, n = qn->lower;
        onig_node_conv_to_str_node(node, STR_(body)->flag);
        for (i = 0; i < n; i++) {
          r = onig_node_str_cat(node, sn->s, sn->end);
          if (r != 0) return r;
        }
        onig_node_free(body);
        return r;
      }
    }
  }

  if (qn->greedy && (qn->empty_info == BODY_IS_NOT_EMPTY)) {
    if (NODE_TYPE(body) == NODE_QUANT) {
      QuantNode* tqn = QUANT_(body);
      if (IS_NOT_NULL(tqn->head_exact)) {
        qn->head_exact  = tqn->head_exact;
        tqn->head_exact = NULL;
      }
    }
    else {
      qn->head_exact = get_head_value_node(NODE_BODY(node), 1, reg);
    }
  }

  return r;
}


setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env)
{
  int r = 0;

  switch (NODE_TYPE(node)) {
  case NODE_LIST:
    {
      Node* prev = NULL_NODE;
      do {
        r = setup_tree(NODE_CAR(node), reg, state, env);
        if (IS_NOT_NULL(prev) && r == 0) {
          r = next_setup(prev, NODE_CAR(node), reg);
        }
        prev = NODE_CAR(node);
      } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
    }
    break;

  case NODE_ALT:
    do {
      r = setup_tree(NODE_CAR(node), reg, (state | IN_ALT), env);
    } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
    break;

  case NODE_STRING:
    if (IS_IGNORECASE(reg->options) && !NODE_STRING_IS_RAW(node)) {
      r = expand_case_fold_string(node, reg, state);
    }
    break;

  case NODE_BACKREF:
    {
      int i;
      int* p;
      BackRefNode* br = BACKREF_(node);
      p = BACKREFS_P(br);
      for (i = 0; i < br->back_num; i++) {
        if (p[i] > env->num_mem)  return ONIGERR_INVALID_BACKREF;
        MEM_STATUS_ON(env->backrefed_mem, p[i]);
        MEM_STATUS_ON(env->bt_mem_start, p[i]);
#ifdef USE_BACKREF_WITH_LEVEL
        if (NODE_IS_NEST_LEVEL(node)) {
          MEM_STATUS_ON(env->bt_mem_end, p[i]);
        }
#endif
      }
    }
    break;

  case NODE_BAG:
    {
      BagNode* en = BAG_(node);

      switch (en->type) {
      case BAG_OPTION:
        {
          OnigOptionType options = reg->options;
          reg->options = BAG_(node)->o.options;
          r = setup_tree(NODE_BODY(node), reg, state, env);
          reg->options = options;
        }
        break;

      case BAG_MEMORY:
#ifdef USE_CALL
        state |= en->m.called_state;
#endif

        if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT | IN_MULTI_ENTRY)) != 0
            || NODE_IS_RECURSION(node)) {
          MEM_STATUS_ON(env->bt_mem_start, en->m.regnum);
        }
        r = setup_tree(NODE_BODY(node), reg, state, env);
        break;

      case BAG_STOP_BACKTRACK:
        {
          Node* target = NODE_BODY(node);
          r = setup_tree(target, reg, state, env);
          if (NODE_TYPE(target) == NODE_QUANT) {
            QuantNode* tqn = QUANT_(target);
            if (IS_REPEAT_INFINITE(tqn->upper) && tqn->lower <= 1 &&
                tqn->greedy != 0) {  /* (?>a*), a*+ etc... */
              if (NODE_IS_SIMPLE_TYPE(NODE_BODY(target)))
                NODE_STATUS_ADD(node, STOP_BT_SIMPLE_REPEAT);
            }
          }
        }
        break;

      case BAG_IF_ELSE:
        r = setup_tree(NODE_BODY(node), reg, (state | IN_ALT), env);
        if (r != 0) return r;
        if (IS_NOT_NULL(en->te.Then)) {
          r = setup_tree(en->te.Then, reg, (state | IN_ALT), env);
          if (r != 0) return r;
        }
        if (IS_NOT_NULL(en->te.Else))
          r = setup_tree(en->te.Else, reg, (state | IN_ALT), env);
        break;
      }
    }
    break;

  case NODE_QUANT:
    r = setup_quant(node, reg, state, env);
    break;

  case NODE_ANCHOR:
    r = setup_anchor(node, reg, state, env);
    break;

#ifdef USE_CALL
  case NODE_CALL:
#endif
  case NODE_CTYPE:
  case NODE_CCLASS:
  case NODE_GIMMICK:
  default:
    break;
  }

  return r;
}


compile_length_cclass_node(CClassNode* cc, regex_t* reg)
{
  return 1;
}


onig_positive_int_multiply(int x, int y)
{
  if (x == 0 || y == 0) return 0;

  if (x < INT_MAX / y)
    return x * y;
  else
    return -1;
}


conv_ext0be(const UChar* s, const UChar* end, UChar* conv)
{
  while (s < end) {
    *conv++ = '\0';
    *conv++ = *s++;
  }
}


conv_encoding(OnigEncoding from, OnigEncoding to, const UChar* s, const UChar* end,
              UChar** conv, UChar** conv_end)
{
  int len = (int )(end - s);

  if (to == ONIG_ENCODING_UTF16_BE) {
    if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
      *conv = (UChar* )xmalloc(len * 2);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + (len * 2);
      conv_ext0be(s, end, *conv);
      return 0;
    }
    else if (from == ONIG_ENCODING_UTF16_LE) {
    swap16:
      *conv = (UChar* )xmalloc(len);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + len;
      conv_swap2bytes(s, end, *conv);
      return 0;
    }
  }
  else if (to == ONIG_ENCODING_UTF16_LE) {
    if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
      *conv = (UChar* )xmalloc(len * 2);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + (len * 2);
      conv_ext0le(s, end, *conv);
      return 0;
    }
    else if (from == ONIG_ENCODING_UTF16_BE) {
      goto swap16;
    }
  }
  if (to == ONIG_ENCODING_UTF32_BE) {
    if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
      *conv = (UChar* )xmalloc(len * 4);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + (len * 4);
      conv_ext0be32(s, end, *conv);
      return 0;
    }
    else if (from == ONIG_ENCODING_UTF32_LE) {
    swap32:
      *conv = (UChar* )xmalloc(len);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + len;
      conv_swap4bytes(s, end, *conv);
      return 0;
    }
  }
  else if (to == ONIG_ENCODING_UTF32_LE) {
    if (from == ONIG_ENCODING_ASCII || from == ONIG_ENCODING_ISO_8859_1) {
      *conv = (UChar* )xmalloc(len * 4);
      CHECK_NULL_RETURN_MEMERR(*conv);
      *conv_end = *conv + (len * 4);
      conv_ext0le32(s, end, *conv);
      return 0;
    }
    else if (from == ONIG_ENCODING_UTF32_BE) {
      goto swap32;
    }
  }

  return ONIGERR_NOT_SUPPORTED_ENCODING_COMBINATION;
}