Variant HHVM_FUNCTION(imageaffinematrixconcat,
                      const Array& m1,
                      const Array& m2) {
  int nelem1 = m1.size();
  int nelem2 = m2.size();
  int i;
  double dm1[6];
  double dm2[6];
  double dmr[6];
  Array ret = Array::CreateDArray();

  if (nelem1 != 6 || nelem2 != 6) {
    raise_warning("imageaffinematrixconcat(): Affine array must "
                  "have six elements");
    return false;
  }

  for (i = 0; i < 6; i++) {
    if (m1[i].isInteger()) {
      dm1[i] = m1[i].toInt64();
    } else if (m1[i].isDouble() || m1[i].isString()) {
      dm1[i] = m1[i].toDouble();
    } else {
      raise_warning("imageaffinematrixconcat(): Invalid type for "
                    "element %i", i);
      return false;
    }
    if (m2[i].isInteger()) {
      dm2[i] = m2[i].toInt64();
    } else if (m2[i].isDouble() || m2[i].isString()) {
      dm2[i] = m2[i].toDouble();
    } else {
      raise_warning("imageaffinematrixconcat():Invalid type for"
                    "element %i", i);
      return false;
    }
  }
  if (gdAffineConcat(dmr, dm1, dm2) != GD_TRUE) {
    return false;
  }

  for (i = 0; i < 6; i++) {
    ret.set(String(i, CopyString), dmr[i]);
  }
  return ret;
}


static void exif_thumbnail_build(image_info_type *ImageInfo) {
  size_t new_size, new_move, new_value;
  char *new_data;
  void *value_ptr;
  int i, byte_count;
  image_info_list *info_list;
  image_info_data *info_data;

  if (!ImageInfo->read_thumbnail || !ImageInfo->Thumbnail.offset ||
      !ImageInfo->Thumbnail.size) {
    return; /* ignore this call */
  }
  switch(ImageInfo->Thumbnail.filetype) {
  default:
  case IMAGE_FILETYPE_JPEG:
    /* done */
    break;
  case IMAGE_FILETYPE_TIFF_II:
  case IMAGE_FILETYPE_TIFF_MM:
    info_list = &ImageInfo->info_list[SECTION_THUMBNAIL];
    new_size  = 8 + 2 + info_list->count * 12 + 4;
    new_value= new_size; /* offset for ifd values outside ifd directory */
    for (i=0; i<info_list->count; i++) {
      info_data  = &info_list->list[i];
      byte_count =
        get_php_tiff_bytes_per_format(info_data->format) * info_data->length;
      if (byte_count > 4) {
        new_size += byte_count;
      }
    }
    new_move = new_size;
    new_data = (char *)IM_REALLOC(ImageInfo->Thumbnail.data,
                                  ImageInfo->Thumbnail.size + new_size);
    CHECK_ALLOC(new_data, ImageInfo->Thumbnail.size + new_size);
    ImageInfo->Thumbnail.data = new_data;
    memmove(ImageInfo->Thumbnail.data + new_move,
            ImageInfo->Thumbnail.data, ImageInfo->Thumbnail.size);
    ImageInfo->Thumbnail.size += new_size;
    /* fill in data */
    if (ImageInfo->motorola_intel) {
      memmove(new_data, "MM\x00\x2a\x00\x00\x00\x08", 8);
    } else {
      memmove(new_data, "II\x2a\x00\x08\x00\x00\x00", 8);
    }
    new_data += 8;
    php_ifd_set16u(new_data, info_list->count, ImageInfo->motorola_intel);
    new_data += 2;
    for (i=0; i<info_list->count; i++) {
      info_data  = &info_list->list[i];
      byte_count =
        get_php_tiff_bytes_per_format(info_data->format) * info_data->length;
      if (info_data->tag==TAG_STRIP_OFFSETS ||
          info_data->tag==TAG_JPEG_INTERCHANGE_FORMAT) {
        php_ifd_set16u(new_data + 0, info_data->tag,
                       ImageInfo->motorola_intel);
        php_ifd_set16u(new_data + 2, TAG_FMT_ULONG,
                       ImageInfo->motorola_intel);
        php_ifd_set32u(new_data + 4, 1, ImageInfo->motorola_intel);
        php_ifd_set32u(new_data + 8, new_move, ImageInfo->motorola_intel);
      } else {
        php_ifd_set16u(new_data + 0, info_data->tag,
                       ImageInfo->motorola_intel);
        php_ifd_set16u(new_data + 2, info_data->format,
                       ImageInfo->motorola_intel);
        php_ifd_set32u(new_data + 4, info_data->length,
                       ImageInfo->motorola_intel);
        value_ptr = exif_ifd_make_value(info_data, ImageInfo->motorola_intel);
        if (byte_count <= 4) {
          memmove(new_data+8, value_ptr, 4);
        } else {
          php_ifd_set32u(new_data+8, new_value, ImageInfo->motorola_intel);
          memmove(ImageInfo->Thumbnail.data+new_value, value_ptr, byte_count);
          new_value += byte_count;
        }
        if (value_ptr) IM_FREE(value_ptr);
      }
      new_data += 12;
    }
    memset(new_data, 0, 4); /* next ifd pointer */
    break;
  }
}

security fixes

https://hhvm.com/blog/2021/02/25/security-update.html

#define IMAGE_TYPE_GIF 1

#define IMAGE_TYPE_JPEG 2

#define IMAGE_TYPE_PNG 4

#define IMAGE_FILTER_NEGATE         0

#define IMAGE_FILTER_GRAYSCALE      1

#define IMAGE_FILTER_COLORIZE       4

#define IMAGE_FILTER_MAX            11

#define IMAGE_FILTER_MAX_ARGS       6

#define IMAGE_TYPE_WBMP 8

#define IMAGE_TYPE_XPM 16

#define IMAGE_FILTER_BRIGHTNESS     2

#define IMAGE_FILTER_CONTRAST       3

#define IMAGE_FILTER_EDGEDETECT     5

#define IMAGE_FILTER_EMBOSS         6

#define IMAGE_FILTER_SELECTIVE_BLUR 8

#define IMAGE_FILTER_SMOOTH         10

#define IMAGE_FILTER_PIXELATE       11

#define IMAGE_FILTER_MEAN_REMOVAL   9

#define IMAGE_FILTER_GAUSSIAN_BLUR  7


static bool set_sockaddr(sockaddr_storage &sa_storage, req::ptr<Socket> sock,
                         const String& addr, int port,
                         struct sockaddr *&sa_ptr, size_t &sa_size) {
  // Always zero it out:
  // - fields are added over time; zeroing it out is future-proofing; for
  //   example, sockaddr_in6 did not originally include sin6_scope_id or
  //   sin6_flowinfo.
  // - required for all on MacOS for correct behavior
  // - on Linux, required for sockaddr_un to deal with buggy sun_path readers
  //   (they should look at the length)
  memset(&sa_storage, 0, sizeof(struct sockaddr_storage));
  struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
  switch (sock->getType()) {
  case AF_UNIX:
    {
#ifdef _MSC_VER
      return false;
#else
      struct sockaddr_un *sa = (struct sockaddr_un *)sock_type;
      sa->sun_family = AF_UNIX;
      if (addr.length() > sizeof(sa->sun_path)) {
        raise_warning(
          "Unix socket path length (%ld) is larger than system limit (%lu)",
          addr.length(),
          sizeof(sa->sun_path)
        );
        return false;
      }
      memcpy(sa->sun_path, addr.data(), addr.length());
      sa_ptr = (struct sockaddr *)sa;
      sa_size = offsetof(struct sockaddr_un, sun_path) + addr.length();
#ifdef __linux__
      if (addr.length() == 0) {
        // Linux supports 3 kinds of unix sockets; behavior of this struct
        // is in `man 7 unix`; relevant parts:
        // - unnamed: 0-length path. As paths are not required to be
        //   null-terminated, this needs to be undicated by the size.
        //   These might be created by `socketpair()`, for eaxmple.
        // - pathname (common): nothing strange. struct size technically
        //   indicates length, but null terminators are usually set. This
        //   does matter if addr.length() == size of the char array though
        // - abstract: these have a meaningful name, but start with `\0`
        //
        // Setting sa_size to indicate a 0-length path is required to
        // distinguish between unnamed and abstract.
        sa_size = offsetof(struct sockaddr_un, sun_path);
      }
#endif

#endif // ifdef _MSC_VER
    }
    break;
  case AF_INET:
    {
      struct sockaddr_in *sa = (struct sockaddr_in *)sock_type;
      sa->sin_family = AF_INET;
      sa->sin_port = htons((unsigned short) port);
      if (!php_set_inet_addr(sa, addr.c_str(), sock)) {
        return false;
      }
      sa_ptr = (struct sockaddr *)sa;
      sa_size = sizeof(struct sockaddr_in);
    }
    break;
  case AF_INET6:
    {
      struct sockaddr_in6 *sa = (struct sockaddr_in6 *)sock_type;
      sa->sin6_family = AF_INET6;
      sa->sin6_port = htons((unsigned short) port);
      if (!php_set_inet6_addr(sa, addr.c_str(), sock)) {
        return false;
      }
      sa_ptr = (struct sockaddr *)sa;
      sa_size = sizeof(struct sockaddr_in6);
    }
    break;
  default:
    raise_warning("unsupported socket type '%d', must be "
                    "AF_UNIX, AF_INET, or AF_INET6", sock->getType());
    return false;
  }
#ifdef __APPLE__
  // This field is not in the relevant standards, not defined on Linux, but is
  // technically required on MacOS (and other BSDs) according to the man pages:
  // - `man 4 netintro` covers the base sa_len
  // - `man 4 unix` and `man 4 inet6` cover AF_UNIX sun_len and AF_INET6
  //    sin6_len
  // - ... At least MacOS Catalina includes the wrong `man 4 inet`. Look at the
  //   (Net|Free|Open)BSD `man 4 inet` instead.
  //   The MacOS man page says it starts with `sin_family`, which would conflict
  //   with the base sockaddr definition. `sin_len` is actually the first field
  //   in the header file, matching `sa_len`.
  sa_ptr->sa_len = sa_size;
#endif
  return true;
}

#define PHP_NORMAL_READ 0x0001

#define PHP_BINARY_READ 0x0002


static int xbuf_format_converter(char **outbuf, const char *fmt, va_list ap)
{
  register char *s = nullptr;
  char *q;
  int s_len;

  register int min_width = 0;
  int precision = 0;
  enum {
    LEFT, RIGHT
  } adjust;
  char pad_char;
  char prefix_char;

  double fp_num;
  wide_int i_num = (wide_int) 0;
  u_wide_int ui_num;

  char num_buf[NUM_BUF_SIZE];
  char char_buf[2];      /* for printing %% and %<unknown> */

#ifdef HAVE_LOCALE_H
  struct lconv *lconv = nullptr;
#endif

  /*
   * Flag variables
   */
  length_modifier_e modifier;
  boolean_e alternate_form;
  boolean_e print_sign;
  boolean_e print_blank;
  boolean_e adjust_precision;
  boolean_e adjust_width;
  int is_negative;

  int size = 240;
  char *result = (char *)malloc(size);
  int outpos = 0;

  while (*fmt) {
    if (*fmt != '%') {
      appendchar(&result, &outpos, &size, *fmt);
    } else {
      /*
       * Default variable settings
       */
      adjust = RIGHT;
      alternate_form = print_sign = print_blank = NO;
      pad_char = ' ';
      prefix_char = NUL;

      fmt++;

      /*
       * Try to avoid checking for flags, width or precision
       */
      if (isascii((int)*fmt) && !islower((int)*fmt)) {
        /*
         * Recognize flags: -, #, BLANK, +
         */
        for (;; fmt++) {
          if (*fmt == '-')
            adjust = LEFT;
          else if (*fmt == '+')
            print_sign = YES;
          else if (*fmt == '#')
            alternate_form = YES;
          else if (*fmt == ' ')
            print_blank = YES;
          else if (*fmt == '0')
            pad_char = '0';
          else
            break;
        }

        /*
         * Check if a width was specified
         */
        if (isdigit((int)*fmt)) {
          STR_TO_DEC(fmt, min_width);
          adjust_width = YES;
        } else if (*fmt == '*') {
          min_width = va_arg(ap, int);
          fmt++;
          adjust_width = YES;
          if (min_width < 0) {
            adjust = LEFT;
            min_width = -min_width;
          }
        } else
          adjust_width = NO;

        /*
         * Check if a precision was specified
         *
         * XXX: an unreasonable amount of precision may be specified
         * resulting in overflow of num_buf. Currently we
         * ignore this possibility.
         */
        if (*fmt == '.') {
          adjust_precision = YES;
          fmt++;
          if (isdigit((int)*fmt)) {
            STR_TO_DEC(fmt, precision);
          } else if (*fmt == '*') {
            precision = va_arg(ap, int);
            fmt++;
            if (precision < 0)
              precision = 0;
          } else
            precision = 0;
        } else
          adjust_precision = NO;
      } else
        adjust_precision = adjust_width = NO;

      /*
       * Modifier check
       */
      switch (*fmt) {
        case 'L':
          fmt++;
          modifier = LM_LONG_DOUBLE;
          break;
        case 'I':
          fmt++;
#if SIZEOF_LONG_LONG
          if (*fmt == '6' && *(fmt+1) == '4') {
            fmt += 2;
            modifier = LM_LONG_LONG;
          } else
#endif
            if (*fmt == '3' && *(fmt+1) == '2') {
              fmt += 2;
              modifier = LM_LONG;
            } else {
#ifdef _WIN64
              modifier = LM_LONG_LONG;
#else
              modifier = LM_LONG;
#endif
            }
          break;
        case 'l':
          fmt++;
#if SIZEOF_LONG_LONG
          if (*fmt == 'l') {
            fmt++;
            modifier = LM_LONG_LONG;
          } else
#endif
            modifier = LM_LONG;
          break;
        case 'z':
          fmt++;
          modifier = LM_SIZE_T;
          break;
        case 'j':
          fmt++;
#if SIZEOF_INTMAX_T
          modifier = LM_INTMAX_T;
#else
          modifier = LM_SIZE_T;
#endif
          break;
        case 't':
          fmt++;
#if SIZEOF_PTRDIFF_T
          modifier = LM_PTRDIFF_T;
#else
          modifier = LM_SIZE_T;
#endif
          break;
        case 'h':
          fmt++;
          if (*fmt == 'h') {
            fmt++;
          }
          /* these are promoted to int, so no break */
        default:
          modifier = LM_STD;
          break;
      }

      /*
       * Argument extraction and printing.
       * First we determine the argument type.
       * Then, we convert the argument to a string.
       * On exit from the switch, s points to the string that
       * must be printed, s_len has the length of the string
       * The precision requirements, if any, are reflected in s_len.
       *
       * NOTE: pad_char may be set to '0' because of the 0 flag.
       *   It is reset to ' ' by non-numeric formats
       */
      switch (*fmt) {
        case 'u':
          switch(modifier) {
            default:
              i_num = (wide_int) va_arg(ap, unsigned int);
              break;
            case LM_LONG_DOUBLE:
              goto fmt_error;
            case LM_LONG:
              i_num = (wide_int) va_arg(ap, unsigned long int);
              break;
            case LM_SIZE_T:
              i_num = (wide_int) va_arg(ap, size_t);
              break;
#if SIZEOF_LONG_LONG
            case LM_LONG_LONG:
              i_num = (wide_int) va_arg(ap, u_wide_int);
              break;
#endif
#if SIZEOF_INTMAX_T
            case LM_INTMAX_T:
              i_num = (wide_int) va_arg(ap, uintmax_t);
              break;
#endif
#if SIZEOF_PTRDIFF_T
            case LM_PTRDIFF_T:
              i_num = (wide_int) va_arg(ap, ptrdiff_t);
              break;
#endif
          }
          /*
           * The rest also applies to other integer formats, so fall
           * into that case.
           */
        case 'd':
        case 'i':
          /*
           * Get the arg if we haven't already.
           */
          if ((*fmt) != 'u') {
            switch(modifier) {
              default:
                i_num = (wide_int) va_arg(ap, int);
                break;
              case LM_LONG_DOUBLE:
                goto fmt_error;
              case LM_LONG:
                i_num = (wide_int) va_arg(ap, long int);
                break;
              case LM_SIZE_T:
#if SIZEOF_SSIZE_T
                i_num = (wide_int) va_arg(ap, ssize_t);
#else
                i_num = (wide_int) va_arg(ap, size_t);
#endif
                break;
#if SIZEOF_LONG_LONG
              case LM_LONG_LONG:
                i_num = (wide_int) va_arg(ap, wide_int);
                break;
#endif
#if SIZEOF_INTMAX_T
              case LM_INTMAX_T:
                i_num = (wide_int) va_arg(ap, intmax_t);
                break;
#endif
#if SIZEOF_PTRDIFF_T
              case LM_PTRDIFF_T:
                i_num = (wide_int) va_arg(ap, ptrdiff_t);
                break;
#endif
            }
          }
          s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
                &num_buf[NUM_BUF_SIZE], &s_len);
          FIX_PRECISION(adjust_precision, precision, s, s_len);

          if (*fmt != 'u') {
            if (is_negative)
              prefix_char = '-';
            else if (print_sign)
              prefix_char = '+';
            else if (print_blank)
              prefix_char = ' ';
          }
          break;

        case 'o':
          switch(modifier) {
            default:
              ui_num = (u_wide_int) va_arg(ap, unsigned int);
              break;
            case LM_LONG_DOUBLE:
              goto fmt_error;
            case LM_LONG:
              ui_num = (u_wide_int) va_arg(ap, unsigned long int);
              break;
            case LM_SIZE_T:
              ui_num = (u_wide_int) va_arg(ap, size_t);
              break;
#if SIZEOF_LONG_LONG
            case LM_LONG_LONG:
              ui_num = (u_wide_int) va_arg(ap, u_wide_int);
              break;
#endif
#if SIZEOF_INTMAX_T
            case LM_INTMAX_T:
              ui_num = (u_wide_int) va_arg(ap, uintmax_t);
              break;
#endif
#if SIZEOF_PTRDIFF_T
            case LM_PTRDIFF_T:
              ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
              break;
#endif
          }
          s = ap_php_conv_p2(ui_num, 3, *fmt,
                &num_buf[NUM_BUF_SIZE], &s_len);
          FIX_PRECISION(adjust_precision, precision, s, s_len);
          if (alternate_form && *s != '0') {
            *--s = '0';
            s_len++;
          }
          break;

        case 'x':
        case 'X':
          switch(modifier) {
            default:
              ui_num = (u_wide_int) va_arg(ap, unsigned int);
              break;
            case LM_LONG_DOUBLE:
              goto fmt_error;
            case LM_LONG:
              ui_num = (u_wide_int) va_arg(ap, unsigned long int);
              break;
            case LM_SIZE_T:
              ui_num = (u_wide_int) va_arg(ap, size_t);
              break;
#if SIZEOF_LONG_LONG
            case LM_LONG_LONG:
              ui_num = (u_wide_int) va_arg(ap, u_wide_int);
              break;
#endif
#if SIZEOF_INTMAX_T
            case LM_INTMAX_T:
              ui_num = (u_wide_int) va_arg(ap, uintmax_t);
              break;
#endif
#if SIZEOF_PTRDIFF_T
            case LM_PTRDIFF_T:
              ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
              break;
#endif
          }
          s = ap_php_conv_p2(ui_num, 4, *fmt,
                &num_buf[NUM_BUF_SIZE], &s_len);
          FIX_PRECISION(adjust_precision, precision, s, s_len);
          if (alternate_form && i_num != 0) {
            *--s = *fmt;  /* 'x' or 'X' */
            *--s = '0';
            s_len += 2;
          }
          break;

        case 's':
        case 'v':
          s = va_arg(ap, char *);
          if (s != nullptr) {
            s_len = strlen(s);
            if (adjust_precision && precision < s_len)
              s_len = precision;
          } else {
            s = const_cast<char*>(s_null);
            s_len = S_NULL_LEN;
          }
          pad_char = ' ';
          break;

        case 'f':
        case 'F':
        case 'e':
        case 'E':
          switch(modifier) {
            case LM_LONG_DOUBLE:
              fp_num = (double) va_arg(ap, long double);
              break;
            case LM_STD:
              fp_num = va_arg(ap, double);
              break;
            default:
              goto fmt_error;
          }

          if (std::isnan(fp_num)) {
            s = const_cast<char*>("nan");
            s_len = 3;
          } else if (std::isinf(fp_num)) {
            s = const_cast<char*>("inf");
            s_len = 3;
          } else {
#ifdef HAVE_LOCALE_H
            if (!lconv) {
              lconv = localeconv();
            }
#endif
            s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
             (adjust_precision == NO) ? FLOAT_DIGITS : precision,
             (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
                  &is_negative, &num_buf[1], &s_len);
            if (is_negative)
              prefix_char = '-';
            else if (print_sign)
              prefix_char = '+';
            else if (print_blank)
              prefix_char = ' ';
          }
          break;

        case 'g':
        case 'k':
        case 'G':
        case 'H':
          switch(modifier) {
            case LM_LONG_DOUBLE:
              fp_num = (double) va_arg(ap, long double);
              break;
            case LM_STD:
              fp_num = va_arg(ap, double);
              break;
            default:
              goto fmt_error;
          }

          if (std::isnan(fp_num)) {
             s = const_cast<char*>("NAN");
             s_len = 3;
             break;
           } else if (std::isinf(fp_num)) {
             if (fp_num > 0) {
               s = const_cast<char*>("INF");
               s_len = 3;
             } else {
               s = const_cast<char*>("-INF");
               s_len = 4;
             }
             break;
           }

          if (adjust_precision == NO)
            precision = FLOAT_DIGITS;
          else if (precision == 0)
            precision = 1;
          /*
           * * We use &num_buf[ 1 ], so that we have room for the sign
           */
#ifdef HAVE_LOCALE_H
          if (!lconv) {
            lconv = localeconv();
          }
#endif
          s = php_gcvt(fp_num, precision,
                       (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT,
                       (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
          if (*s == '-')
            prefix_char = *s++;
          else if (print_sign)
            prefix_char = '+';
          else if (print_blank)
            prefix_char = ' ';

          s_len = strlen(s);

          if (alternate_form && (q = strchr(s, '.')) == nullptr)
            s[s_len++] = '.';
          break;

        case 'c':
          char_buf[0] = (char) (va_arg(ap, int));
          s = &char_buf[0];
          s_len = 1;
          pad_char = ' ';
          break;

        case '%':
          char_buf[0] = '%';
          s = &char_buf[0];
          s_len = 1;
          pad_char = ' ';
          break;

        case 'n':
          *(va_arg(ap, int *)) = outpos;
          goto skip_output;

          /*
           * Always extract the argument as a "char *" pointer. We
           * should be using "void *" but there are still machines
           * that don't understand it.
           * If the pointer size is equal to the size of an unsigned
           * integer we convert the pointer to a hex number, otherwise
           * we print "%p" to indicate that we don't handle "%p".
           */
        case 'p':
          if (sizeof(char *) <= sizeof(u_wide_int)) {
            ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
            s = ap_php_conv_p2(ui_num, 4, 'x',
                &num_buf[NUM_BUF_SIZE], &s_len);
            if (ui_num != 0) {
              *--s = 'x';
              *--s = '0';
              s_len += 2;
            }
          } else {
            s = const_cast<char*>("%p");
            s_len = 2;
          }
          pad_char = ' ';
          break;

        case NUL:
          /*
           * The last character of the format string was %.
           * We ignore it.
           */
          continue;

fmt_error:
        throw Exception("Illegal length modifier specified '%c'", *fmt);

          /*
           * The default case is for unrecognized %'s.
           * We print %<char> to help the user identify what
           * option is not understood.
           * This is also useful in case the user wants to pass
           * the output of format_converter to another function
           * that understands some other %<char> (like syslog).
           * Note that we can't point s inside fmt because the
           * unknown <char> could be preceded by width etc.
           */
        default:
          char_buf[0] = '%';
          char_buf[1] = *fmt;
          s = char_buf;
          s_len = 2;
          pad_char = ' ';
          break;
      }

      if (prefix_char != NUL) {
        *--s = prefix_char;
        s_len++;
      }
      if (adjust_width && adjust == RIGHT && min_width > s_len) {
        if (pad_char == '0' && prefix_char != NUL) {
          appendchar(&result, &outpos, &size, *s);
          s++;
          s_len--;
          min_width--;
        }
        for (int i = 0; i < min_width - s_len; i++) {
          appendchar(&result, &outpos, &size, pad_char);
        }
      }
      /*
       * Print the (for now) non-null terminated string s.
       */
      appendsimplestring(&result, &outpos, &size, s, s_len);

      if (adjust_width && adjust == LEFT && min_width > s_len) {
        for (int i = 0; i < min_width - s_len; i++) {
          appendchar(&result, &outpos, &size, pad_char);
        }
      }
    }
skip_output:
    fmt++;
  }
  /*
   * Add the terminating null here since it wasn't added incrementally above
   * once the whole string has been composed.
   */
  appendchar(&result, &outpos, &size, NUL);
  *outbuf = result;
  return outpos - 1;
}

typedef enum {
  LM_STD = 0,
  LM_INTMAX_T,
  LM_PTRDIFF_T,
  LM_LONG_LONG,
  LM_SIZE_T,
  LM_LONG,
  LM_LONG_DOUBLE
} length_modifier_e;

typedef enum {
  NO = 0, YES = 1
} boolean_e;

#define STR_TO_DEC(str, num) do {  \
  num = NUM(*str++);               \
  while (isdigit((int)*str)) {     \
    num *= 10;                     \
    num += NUM(*str++);            \
    if (num >= INT_MAX / 10) {     \
      while (isdigit((int)*str++)) \
        continue;                  \
      break;                       \
    }                              \
  }                                \
} while (0)

#define FIX_PRECISION(adjust, precision, s, s_len) do { \
  if (adjust)                                           \
    while (s_len < precision) {                         \
      *--s = '0';                                       \
      s_len++;                                          \
    }                                                   \
} while (0)

typedef int64_t wide_int;

typedef uint64_t u_wide_int;

#define NUL             '\0'

#define INT_NULL        ((int *)0)

static const char* s_null = "(null)";

#define S_NULL_LEN      6

#define FLOAT_DIGITS    6

#define HAVE_LOCALE_H 1


static struct gfxinfo *php_handle_xbm(const req::ptr<File>& stream) {
  struct gfxinfo *result;
  php_get_xbm(stream, &result);
  return result;
}


  void moduleInit() override {
    HHVM_RC_INT_SAME(AF_UNIX);
    HHVM_RC_INT_SAME(AF_INET);
    HHVM_RC_INT_SAME(AF_INET6);
    HHVM_RC_INT_SAME(SOCK_STREAM);
    HHVM_RC_INT_SAME(SOCK_DGRAM);
    HHVM_RC_INT_SAME(SOCK_RAW);
    HHVM_RC_INT_SAME(SOCK_SEQPACKET);
    HHVM_RC_INT_SAME(SOCK_RDM);

    HHVM_RC_INT_SAME(MSG_OOB);
    HHVM_RC_INT_SAME(MSG_WAITALL);
    HHVM_RC_INT_SAME(MSG_CTRUNC);
    HHVM_RC_INT_SAME(MSG_TRUNC);
    HHVM_RC_INT_SAME(MSG_PEEK);
    HHVM_RC_INT_SAME(MSG_DONTROUTE);
#ifdef MSG_EOR
    HHVM_RC_INT_SAME(MSG_EOR);
#endif
#ifdef MSG_EOF
    HHVM_RC_INT_SAME(MSG_EOF);
#endif
#ifdef MSG_CONFIRM
    HHVM_RC_INT_SAME(MSG_CONFIRM);
#endif
#ifdef MSG_ERRQUEUE
    HHVM_RC_INT_SAME(MSG_ERRQUEUE);
#endif
#ifdef MSG_NOSIGNAL
    HHVM_RC_INT_SAME(MSG_NOSIGNAL);
#endif
#ifdef MSG_DONTWAIT
    HHVM_RC_INT_SAME(MSG_DONTWAIT);
#endif
#ifdef MSG_MORE
    HHVM_RC_INT_SAME(MSG_MORE);
#endif
#ifdef MSG_WAITFORONE
    HHVM_RC_INT_SAME(MSG_WAITFORONE);
#endif
#ifdef MSG_CMSG_CLOEXEC
    HHVM_RC_INT_SAME(MSG_CMSG_CLOEXEC);
#endif

    HHVM_RC_INT_SAME(SO_DEBUG);
    HHVM_RC_INT_SAME(SO_REUSEADDR);
#ifdef SO_REUSEPORT
    HHVM_RC_INT_SAME(SO_REUSEPORT);
#endif
    HHVM_RC_INT_SAME(SO_KEEPALIVE);
    HHVM_RC_INT_SAME(SO_DONTROUTE);
    HHVM_RC_INT_SAME(SO_LINGER);
    HHVM_RC_INT_SAME(SO_BROADCAST);
    HHVM_RC_INT_SAME(SO_OOBINLINE);
    HHVM_RC_INT_SAME(SO_SNDBUF);
    HHVM_RC_INT_SAME(SO_RCVBUF);
    HHVM_RC_INT_SAME(SO_SNDLOWAT);
    HHVM_RC_INT_SAME(SO_RCVLOWAT);
    HHVM_RC_INT_SAME(SO_SNDTIMEO);
    HHVM_RC_INT_SAME(SO_RCVTIMEO);
    HHVM_RC_INT_SAME(SO_TYPE);
#ifdef SO_FAMILY
    HHVM_RC_INT_SAME(SO_FAMILY);
#endif
    HHVM_RC_INT_SAME(SO_ERROR);
#ifdef SO_BINDTODEVICE
    HHVM_RC_INT_SAME(SO_BINDTODEVICE);
#endif
    HHVM_RC_INT_SAME(SOL_SOCKET);
    HHVM_RC_INT_SAME(SOMAXCONN);
#ifdef TCP_NODELAY
    HHVM_RC_INT_SAME(TCP_NODELAY);
#endif
    HHVM_RC_INT_SAME(PHP_NORMAL_READ);
    HHVM_RC_INT_SAME(PHP_BINARY_READ);

    /* TODO: MCAST_* constants and logic to handle them */

    HHVM_RC_INT_SAME(IP_MULTICAST_IF);
    HHVM_RC_INT_SAME(IP_MULTICAST_TTL);
    HHVM_RC_INT_SAME(IP_MULTICAST_LOOP);
    HHVM_RC_INT_SAME(IPV6_MULTICAST_IF);
    HHVM_RC_INT_SAME(IPV6_MULTICAST_HOPS);
    HHVM_RC_INT_SAME(IPV6_MULTICAST_LOOP);
    HHVM_RC_INT_SAME(IPPROTO_IP);
    HHVM_RC_INT_SAME(IPPROTO_IPV6);

    HHVM_RC_INT(SOL_TCP, IPPROTO_TCP);
    HHVM_RC_INT(SOL_UDP, IPPROTO_UDP);

    HHVM_RC_INT_SAME(IPV6_UNICAST_HOPS);

#define REGISTER_LONG_CONSTANT(name, val, flags) \
    Native::registerConstant<KindOfInt64>(makeStaticString(name), val)
#include "hphp/runtime/ext/sockets/unix_socket_constants.h"
#undef REGISTER_LONG_CONSTANT

    HHVM_FE(socket_create);
    HHVM_FE(socket_create_listen);
    HHVM_FE(socket_create_pair);
    HHVM_FE(socket_get_option);
    HHVM_FE(socket_getpeername);
    HHVM_FE(socket_getsockname);
    HHVM_FE(socket_set_block);
    HHVM_FE(socket_set_nonblock);
    HHVM_FE(socket_set_option);
    HHVM_FE(socket_connect);
    HHVM_FE(socket_bind);
    HHVM_FE(socket_listen);
    HHVM_FE(socket_select);
    HHVM_FE(socket_server);
    HHVM_FE(socket_accept);
    HHVM_FE(socket_read);
    HHVM_FE(socket_write);
    HHVM_FE(socket_send);
    HHVM_FE(socket_sendto);
    HHVM_FE(socket_recv);
    HHVM_FE(socket_recvfrom);
    HHVM_FE(socket_shutdown);
    HHVM_FE(socket_close);
    HHVM_FE(socket_strerror);
    HHVM_FE(socket_last_error);
    HHVM_FE(socket_clear_error);
    HHVM_FE(getaddrinfo);

    loadSystemlib();
  }


Variant strpbrk_char_list_has_nulls_slow(const String& haystack,
                                         const String& char_list) {

  auto const charListSz = char_list.size();
  auto const charListData = char_list.c_str();
  assertx(memchr(charListData, '\0', charListSz) != nullptr);

  // in order to use strcspn, remove all null byte(s) from char_list
  auto charListWithoutNull = (char*) req::malloc_noptrs(charListSz);
  SCOPE_EXIT { req::free(charListWithoutNull); };

  auto copy_ptr = charListWithoutNull;
  auto const charListStop = charListData + char_list.size();
  for (auto ptr = charListData; ptr != charListStop; ++ptr) {
    if (*ptr != '\0') { *copy_ptr++ = *ptr; }
  }
  assertx((copy_ptr - charListWithoutNull) < charListSz);
  // at least one of charListData chars was null, so there must be room:
  *copy_ptr = '\0';

  // Use strcspn instead of strpbrk because the latter doesn't report when
  // its terminated due to a null byte in haystack in any manageable way.
  auto haySize = haystack.size();
  auto hayData = haystack.c_str();

  size_t idx = strcspn(hayData, charListWithoutNull);
  if (idx < haySize) {
    // we know that char_list contains null bytes, being terminated because
    // haystack has null bytes is just dandy
    if (existence_only) { return true; }
    return String(hayData + idx, haySize - idx, CopyString);
  }
  return false;
}

/* No explicit global definitions found. */


Variant HHVM_FUNCTION(metaphone, const String& str, int /*phones*/ /* = 0 */) {
  return string_metaphone(str.data(), str.size(), 0, 1);
}


char operator[](int pos) const { return charAt(pos);}

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

static const int npos = -1;

int find(char ch, int pos = 0, bool caseSensitive = true) const;

int find(const char *s, int pos = 0, bool caseSensitive = true) const;

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(char ch, int pos = 0, bool caseSensitive = true) const;

int rfind(const char *s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator == (const char* v) const = delete;

bool operator != (const char* v) const = delete;

bool operator >= (const char* v) const = delete;

bool operator <= (const char* v) const = delete;

bool operator >  (const char* v) const = delete;

bool operator <  (const char* v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

bool operator == (const Variant& v) const = delete;

bool operator != (const Variant& v) const = delete;

bool operator >= (const Variant& v) const = delete;

bool operator <= (const Variant& v) const = delete;

bool operator >  (const Variant& v) const = delete;

bool operator <  (const Variant& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;


Variant HHVM_FUNCTION(imageaffinematrixget,
                      int64_t type,
                      const Variant& options /* = Array() */) {
  Array ret = Array::CreateDArray();
  double affine[6];
  int res = GD_FALSE, i;

  switch((gdAffineStandardMatrix)type) {
    case GD_AFFINE_TRANSLATE:
    case GD_AFFINE_SCALE: {
      double x, y;
      Array aoptions = options.toArray();
      if (aoptions.empty()) {
        raise_warning("imageaffinematrixget(): Array expected as options");
        return false;
      }
      if (aoptions.exists(s_x)) {
        x = aoptions[s_x].toDouble();
      } else {
        raise_warning("imageaffinematrixget(): Missing x position");
        return false;
      }
      if (aoptions.exists(s_y)) {
        y = aoptions[s_y].toDouble();
      } else {
        raise_warning("imageaffinematrixget(): Missing x position");
        return false;
      }

      if (type == GD_AFFINE_TRANSLATE) {
        res = gdAffineTranslate(affine, x, y);
      } else {
        res = gdAffineScale(affine, x, y);
      }
      break;
    }

    case GD_AFFINE_ROTATE:
    case GD_AFFINE_SHEAR_HORIZONTAL:
    case GD_AFFINE_SHEAR_VERTICAL: {
      double angle;
      double doptions = options.toDouble();
      if (!doptions) {
        raise_warning("imageaffinematrixget(): Number is expected as option");
        return false;
      }

      angle = doptions;

      if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
        res = gdAffineShearHorizontal(affine, angle);
      } else if (type == GD_AFFINE_SHEAR_VERTICAL) {
        res = gdAffineShearVertical(affine, angle);
      } else {
        res = gdAffineRotate(affine, angle);
      }
      break;
    }

    default:
      raise_warning("imageaffinematrixget():Invalid type for "
                    "element %" PRId64, type);
      return false;
  }

  if (res == GD_FALSE) {
    return false;
  } else {
    for (i = 0; i < 6; i++) {
      ret.set(String(i, CopyString), affine[i]);
    }
  }
  return ret;
}


Array HHVM_FUNCTION(HH_object_prop_array, const Object& obj) {
  return obj.toArray().toDArray();
}


inline StringData* StringData::Make(char* data, AttachStringMode) {
  SCOPE_EXIT { free(data); };
  return Make(data, CopyString);
}

inline folly::StringPiece

inline folly::MutableStringPiece

struct string_data_hash {
  size_t operator()(const StringData *s) const {
    return s->hash();
  }

struct string_data_same {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->same(s2);
  }

struct string_data_eq_same {
  bool operator()(const StringData* a, const StringData* b) const {
    return a == b || a->same(b);
  }

struct string_data_isame {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->isame(s2);
  }

struct string_data_lt {
  bool operator()(const StringData *s1, const StringData *s2) const {
    int len1 = s1->size();
    int len2 = s2->size();
    if (len1 < len2) {
      return (len1 == 0) || (memcmp(s1->data(), s2->data(), len1) <= 0);
    } else

struct string_data_lti {
  bool operator()(const StringData *s1, const StringData *s2) const {
    return bstrcasecmp(s1->data(), s1->size(), s2->data(), s2->size()) < 0;
  }


  ~StaticString() {
    // prevent ~req::ptr from destroying contents.
    detach();
  }

static std::vector<std::tuple<const char*, size_t, StaticString*>>*
    s_registered;

StaticString getDataTypeString(DataType t, bool isLegacy = false);

inline String& String::operator=(const StaticString& v)


void Profiler::endFrame(const TypedValue *retval,
                        const char *symbol,
                        bool endMain) {
  if (m_stack) {
    // special case for main() frame that's only ended by endAllFrames()
    if (!endMain && m_stack->m_parent == nullptr) {
      return;
    }
    endFrameEx(retval, symbol);
    m_func_hash_counters[m_stack->m_hash_code]--;
    releaseFrame();
  }
}

#define HP_STACK_DELIM        "==>"

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


struct string_data_hash {
  size_t operator()(const StringData *s) const {
    return s->hash();
  }

struct string_data_same {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->same(s2);
  }

struct string_data_eq_same {
  bool operator()(const StringData* a, const StringData* b) const {
    return a == b || a->same(b);
  }

struct string_data_isame {
  bool operator()(const StringData *s1, const StringData *s2) const {
    assertx(s1 && s2);
    return s1->isame(s2);
  }

struct string_data_lt {
  bool operator()(const StringData *s1, const StringData *s2) const {
    int len1 = s1->size();
    int len2 = s2->size();
    if (len1 < len2) {
      return (len1 == 0) || (memcmp(s1->data(), s2->data(), len1) <= 0);
    } else

struct string_data_lti {
  bool operator()(const StringData *s1, const StringData *s2) const {
    return bstrcasecmp(s1->data(), s1->size(), s2->data(), s2->size()) < 0;
  }


SocketsExtension() : Extension("sockets", NO_EXTENSION_VERSION_YET) {}


  bool isInteger() const {
    return m_str ? m_str->isInteger() : false;
  }

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

static const int npos = -1;

int find(char ch, int pos = 0, bool caseSensitive = true) const;

int find(const char *s, int pos = 0, bool caseSensitive = true) const;

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(char ch, int pos = 0, bool caseSensitive = true) const;

int rfind(const char *s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator == (const char* v) const = delete;

bool operator != (const char* v) const = delete;

bool operator >= (const char* v) const = delete;

bool operator <= (const char* v) const = delete;

bool operator >  (const char* v) const = delete;

bool operator <  (const char* v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

bool operator == (const Variant& v) const = delete;

bool operator != (const Variant& v) const = delete;

bool operator >= (const Variant& v) const = delete;

bool operator <= (const Variant& v) const = delete;

bool operator >  (const Variant& v) const = delete;

bool operator <  (const Variant& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;


String stringForEachFast(const String& str, Op action) {
  if (str.empty()) {
    return str;
  }

  return stringForEach<false>(str.size(), str, action);
}


  explicit TraceProfiler(int flags)
    : Profiler(true)
    , m_traceBuffer(nullptr)
    , m_traceBufferSize(0)
    , m_nextTraceEntry(0)
    , m_traceBufferFilled(false)
    , m_maxTraceBuffer(0)
    , m_overflowCalls(0)
    , m_flags(flags)
  {
    if (!(m_flags & IHaveInfiniteMemory) && pthread_mutex_trylock(&s_inUse)) {
      // This profiler uses a very large amount of memory. Only allow
      // one in the process at any time.
      m_successful = false;
    } else {
      m_maxTraceBuffer = RuntimeOption::ProfilerMaxTraceBuffer;
      Extension* ext = ExtensionRegistry::get(s_hotprofiler);
      assertx(ext);
      IniSetting::Bind(ext, IniSetting::PHP_INI_ALL,
                       "profiler.max_trace_buffer",
                       &m_maxTraceBuffer);
    }
  }


php_image_filter_colorize(gdImagePtr im, int arg1 /* = 0 */, int arg2 /* = 0 */,
                          int arg3 /* = 0 */, int /*arg4*/ /* = 0 */) {
  int r = arg1;
  int g = arg2;
  int b = arg3;
  int a = arg1;
  return gdImageColor(im, r, g, b, a) == 1;
}


TypedValue HHVM_FUNCTION(strpbrk,
                         const String& haystack,
                         const String& char_list) {
  return tvReturn(strpbrk_impl<false>(haystack, char_list));
}


inline void* StringData::payload() { return this + 1; }


String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

static const int npos = -1;

int find(char ch, int pos = 0, bool caseSensitive = true) const;

int find(const char *s, int pos = 0, bool caseSensitive = true) const;

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(char ch, int pos = 0, bool caseSensitive = true) const;

int rfind(const char *s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator == (const char* v) const = delete;

bool operator != (const char* v) const = delete;

bool operator >= (const char* v) const = delete;

bool operator <= (const char* v) const = delete;

bool operator >  (const char* v) const = delete;

bool operator <  (const char* v) const = delete;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

bool operator == (const Variant& v) const = delete;

bool operator != (const Variant& v) const = delete;

bool operator >= (const Variant& v) const = delete;

bool operator <= (const Variant& v) const = delete;

bool operator >  (const Variant& v) const = delete;

bool operator <  (const Variant& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;


inline strhash_t StringData::hash_unsafe(const char* s, size_t len) {
  return hash_string_i_unsafe(s, len);
}


String rval(int64_t key) const { return rvalImpl(key);}


char *string_bin2hex(const char *input, int len, char* result) {
  static char hexconvtab[] = "0123456789abcdef";

  assert(input);
  if (len == 0) {
    return nullptr;
  }

  int i, j;
  for (i = j = 0; i < len; i++) {
    result[j++] = hexconvtab[(unsigned char)input[i] >> 4];
    result[j++] = hexconvtab[(unsigned char)input[i] & 15];
  }
  result[j] = '\0';
  return result;
}


bool HHVM_FUNCTION(imagegif, const Resource& image,
    const String& filename /* = null_string */) {
  return _php_image_output_ctx(image, filename, -1, -1,
                               PHP_GDIMG_TYPE_GIF, "GIF",
                               (void (*)())gdImageGifCtx);
}


get_frees()
{
#ifdef USE_JEMALLOC
  return tl_heap->getDeallocated();
#endif
#ifdef USE_TCMALLOC
  if (MallocExtensionInstance) {
    size_t stat;
    MallocExtensionInstance()->GetNumericProperty(
           "generic.thread_bytes_freed", &stat);
    return stat;
  }
#endif
  return 0;
}


inline bool StringData::isame(const StringData* s) const {
  assertx(s);
  if (this == s) return true;
  if (m_len != s->m_len) return false;
  return bstrcaseeq(data(), s->data(), m_len);
}


static void init_local_extra(pcre_extra* local, pcre_extra* shared) {
  if (shared) {
    memcpy(local, shared, sizeof(pcre_extra));
  } else {
    memset(local, 0, sizeof(pcre_extra));
    local->flags = PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION;
  }
  local->match_limit = tl_pcre_globals->preg_backtrace_limit;
  local->match_limit_recursion = tl_pcre_globals->preg_recursion_limit;
}


static struct gfxinfo *php_handle_bmp(const req::ptr<File>& stream) {
  struct gfxinfo *result = nullptr;
  const unsigned char *s;
  int size;

  if (!stream->seek(11, SEEK_CUR)) return nullptr;

  String dim = stream->read(16);
  if (dim.length() != 16) return nullptr;
  s = (unsigned char *)dim.c_str();

  size = (((unsigned int)s[3]) << 24) +
         (((unsigned int)s[2]) << 16) +
         (((unsigned int)s[1]) << 8) +
         ((unsigned int)s[0]);
  if (size == 12) {
    result = (struct gfxinfo *)IM_CALLOC(1, sizeof(struct gfxinfo));
    CHECK_ALLOC_R(result, sizeof(struct gfxinfo), nullptr);
    result->width = (((unsigned int)s[5]) << 8) + ((unsigned int)s[4]);
    result->height = (((unsigned int)s[7]) << 8) + ((unsigned int)s[6]);
    result->bits = ((unsigned int)s[11]);
  } else if (size > 12 && (size <= 64 || size == 108 || size == 124)) {
    result = (struct gfxinfo *)IM_CALLOC(1, sizeof(struct gfxinfo));
    CHECK_ALLOC_R(result, sizeof(struct gfxinfo), nullptr);
    result->width = (((unsigned int)s[7]) << 24) +
                    (((unsigned int)s[6]) << 16) +
                    (((unsigned int)s[5]) << 8) +
                    ((unsigned int)s[4]);
    result->height = (((unsigned int)s[11]) << 24) +
                     (((unsigned int)s[10]) << 16) +
                     (((unsigned int)s[9]) << 8) +
                     ((unsigned int)s[8]);
    result->height = abs((int32_t)result->height);
    result->bits = (((unsigned int)s[15]) << 8) +
                   ((unsigned int)s[14]);
  } else {
    return nullptr;
  }

  return result;
}


Profiler::~Profiler() {
    if (m_has_affinity) {
      SET_AFFINITY(0, sizeof(cpu_set_t), &m_prev_mask);
    }

    endAllFrames();
    for (Frame *p = m_frame_free_list; p;) {
      Frame *cur = p;
      p = p->m_parent;
      delete cur;
    }
}

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


Variant HHVM_FUNCTION(imagecolorset, const Resource& image,
    int64_t index, int64_t red, int64_t green, int64_t blue) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  if (index >= 0 && index < gdImageColorsTotal(im)) {
    im->red[index] = red;
    im->green[index] = green;
    im->blue[index] = blue;
    return true;
  } else {
    return false;
  }
}


String rval(const String& key) const { return rvalImpl(key.toInt32());}


int64_t toInt64 () const { return m_str ? m_str->toInt64  () : 0;}


exif_process_user_comment(image_info_type* /*ImageInfo*/, char** pszInfoPtr,
                          char** pszEncoding, char* szValuePtr, int ByteCount) {
  int   a;
  *pszEncoding = nullptr;
  /* Copy the comment */
  if (ByteCount>=8) {
    if (!memcmp(szValuePtr, "UNICODE\0", 8)) {
      PHP_STRDUP(*pszEncoding, (const char*)szValuePtr);
      szValuePtr = szValuePtr+8;
      ByteCount -= 8;
      return exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
    } else
    if (!memcmp(szValuePtr, "ASCII\0\0\0", 8)) {
      PHP_STRDUP(*pszEncoding, (const char*)szValuePtr);
      szValuePtr = szValuePtr+8;
      ByteCount -= 8;
    } else
    if (!memcmp(szValuePtr, "JIS\0\0\0\0\0", 8)) {
      /* JIS should be tanslated to MB or we leave it to the user */
      PHP_STRDUP(*pszEncoding, (const char*)szValuePtr);
      szValuePtr = szValuePtr+8;
      ByteCount -= 8;
      return exif_process_string_raw(pszInfoPtr, szValuePtr, ByteCount);
    } else
    if (!memcmp(szValuePtr, "\0\0\0\0\0\0\0\0", 8)) {
      /* 8 NULL means undefined and should be ASCII... */
      PHP_STRDUP(*pszEncoding, "UNDEFINED");
      szValuePtr = szValuePtr+8;
      ByteCount -= 8;
    }
  }

  /* Olympus has this padded with trailing spaces.  Remove these first. */
  if (ByteCount>0) {
    for (a=ByteCount-1;a && szValuePtr[a]==' ';a--) {
      (szValuePtr)[a] = '\0';
    }
  }

  /* normal text without encoding */
  exif_process_string(pszInfoPtr, szValuePtr, ByteCount);
  return strlen(*pszInfoPtr);
}


String HHVM_FUNCTION(strtoupper,
                     const String& str) {
  return stringForEachFast(str, toupper);
}


void Strobelight::log(c_WaitableWaitHandle* wh) const {
  if (RuntimeOption::XenonForceAlwaysOn) {
    // Disable strobelight if Xenon forced on
    // TODO remove this when strobelight has its own surpriseFlag
    return;
  }

  if (getSurpriseFlag(XenonSignalFlag)) {
    // TODO remove this when strobelight has its own surpriseFlag
    clearSurpriseFlag(XenonSignalFlag);
  }

  TRACE(1, "Strobelight::log\n");
  if (active()) {
    // TODO We should filter only to hhvm samples which directly
    // caused a PMU event to fire. This is doable by storing hhvm
    // request IDs in a bpf map and checking for an entry here.
    auto bt = createBacktrace(BacktraceArgs()
                              .fromWaitHandle(wh)
                              // TODO
                              // .withMetadata()
                              .ignoreArgs());
    logToUSDT(bt);
  }
}


  void imFree(void *ptr
#ifdef IM_MEMORY_CHECK
, int ln
#endif
  ) {
    assertx(ptr);
    size_t size;
    void *sizePtr = (char *)ptr - sizeof(size);
    memcpy(&size, sizePtr, sizeof(size));
    m_mallocSize -= size;
#ifdef IM_MEMORY_CHECK
    void *lnPtr = (char *)sizePtr - sizeof(ln);
    int count = m_alloced.erase((char*)sizePtr - sizeof(ln));
    assertx(count == 1); // double free on failure
    assertx(m_mallocSize <= (size_t)RuntimeOption::ImageMemoryMaxBytes);
    local_free(lnPtr);
#else
    assertx(m_mallocSize <= (size_t)RuntimeOption::ImageMemoryMaxBytes);
    local_free(sizePtr);
#endif
  }


std::string toCppString() const { return std::string(c_str(), size()); }


TypedValue HHVM_FUNCTION(strcspn,
                         const String& str1,
                         const String& str2,
                         int start /* = 0 */,
                         int length /* = 0x7FFFFFFF */) {
  const char *s1 = str1.data();
  const char *s2 = str2.data();
  int s1_len = str1.size();
  int s2_len = str2.size();

  if (!string_strspn_check(s1_len, start, length)) {
    return make_tv<KindOfBoolean>(false);
  }

  s1 += start;
  for (int pos = 0; pos < length; ++pos) {
    if (memchr(s2, *(s1++), s2_len) != nullptr) {
      return make_tv<KindOfInt64>(pos);
    }
  }

  return make_tv<KindOfInt64>(length);
}


php_next_marker(const req::ptr<File>& file, int /*last_marker*/, int ff_read) {
  int a=0, marker;

  // get marker byte, swallowing possible padding
  if (!ff_read) {
    size_t extraneous = 0;

    while ((marker = file->getc()) != 0xff) {
      if (marker == EOF) {
        return M_EOI;/* we hit EOF */
      }
      extraneous++;
    }
    if (extraneous) {
      raise_warning("corrupt JPEG data: %zu extraneous bytes before marker",
                    extraneous);
    }
  }
  a = 1;
  do {
    if ((marker = file->getc()) == EOF)
    {
      return M_EOI;/* we hit EOF */
    }
    ++a;
  } while (marker == 0xff);
  if (a < 2)
  {
    return M_EOI; /* at least one 0xff is needed before marker code */
  }
  return (unsigned int)marker;
}


inline static void appendsimplestring(char **buffer, int *pos, int *size,
                                      const char *add, int len) {
  int req_size = *pos + len;

  if (req_size > *size) {
    while (req_size > *size) {
      *size <<= 1;
    }
    *buffer = (char *)realloc(*buffer, *size);
  }
  memcpy(&(*buffer)[*pos], add, len);
  *pos += len;
}

#define STR_TO_DEC(str, num) do {  \
  num = NUM(*str++);               \
  while (isdigit((int)*str)) {     \
    num *= 10;                     \
    num += NUM(*str++);            \
    if (num >= INT_MAX / 10) {     \
      while (isdigit((int)*str++)) \
        continue;                  \
      break;                       \
    }                              \
  }                                \
} while (0)

#define FIX_PRECISION(adjust, precision, s, s_len) do { \
  if (adjust)                                           \
    while (s_len < precision) {                         \
      *--s = '0';                                       \
      s_len++;                                          \
    }                                                   \
} while (0)

#define INT_NULL        ((int *)0)

static const char* s_null = "(null)";


String HHVM_FUNCTION(trim,
                     const String& str,
                     const String& charlist /* = k_HPHP_TRIM_CHARLIST */) {
  return stringTrim<true,true>(str, charlist);
}


  ~Key() override {
    if (m_key) EVP_PKEY_free(m_key);
  }

struct CSRequest : SweepableResourceData {
private:
  X509_REQ *m_csr;

public:
  explicit CSRequest(X509_REQ *csr) : m_csr(csr) {
    assertx(m_csr);
  }

  X509_REQ *csr() { return m_csr; }

  ~CSRequest() override {
    // X509_REQ_free(nullptr) is a no-op
    X509_REQ_free(m_csr);
  }

  CLASSNAME_IS("OpenSSL X.509 CSR");
  // overriding ResourceData
  const String& o_getClassNameHook() const override { return classnameof(); }

  DECLARE_RESOURCE_ALLOCATION(CSRequest)

  static req::ptr<CSRequest> Get(const Variant& var) {
    auto csr = cast_or_null<CSRequest>(GetRequest(var));
    if (!csr || !csr->m_csr) {
      raise_warning("cannot get CSR");
      return nullptr;
    }
    return csr;
  }

private:
  static req::ptr<CSRequest> GetRequest(const Variant& var) {
    if (var.isResource()) {
      return dyn_cast_or_null<CSRequest>(var);
    }
    if (var.isString() || var.isObject()) {
      BIO *in = Certificate::ReadData(var);
      if (in == nullptr) return nullptr;

      X509_REQ *csr = PEM_read_bio_X509_REQ(in, nullptr,nullptr,nullptr);
      BIO_free(in);
      if (csr) {
        return req::make<CSRequest>(csr);
      }
    }
    return nullptr;
  }
}


static int _php_image_type (char data[8]) {
  if (data == nullptr) {
    return -1;
  }

  if (!memcmp(data, php_sig_gd2, 3)) {
    return PHP_GDIMG_TYPE_GD2;
  } else if (!memcmp(data, php_sig_jpg, 3)) {
    return PHP_GDIMG_TYPE_JPG;
  } else if (!memcmp(data, php_sig_png, 3)) {
    if (!memcmp(data, php_sig_png, 8)) {
      return PHP_GDIMG_TYPE_PNG;
    }
  } else if (!memcmp(data, php_sig_gif, 3)) {
    return PHP_GDIMG_TYPE_GIF;
  }
  else {
    gdIOCtx *io_ctx;
    io_ctx = gdNewDynamicCtxEx(8, data, 0);
    if (io_ctx) {
      if (getmbi(io_ctx) == 0 &&
          skipheader(io_ctx) == 0 ) {
        io_ctx->gd_free(io_ctx);
        return PHP_GDIMG_TYPE_WBM;
      } else {
        io_ctx->gd_free(io_ctx);
      }
    }
  }
  return -1;
}


  /* implicit */ String(const char* s)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, CopyString)
                           : nullptr, NoIncRef{}) { }


Variant HHVM_FUNCTION(imagecreatefromwbmp, const String& filename) {
  gdImagePtr im =
    _php_image_create_from(filename, -1, -1, -1, -1,
                           PHP_GDIMG_TYPE_WBM, "WBMP",
                           (gdImagePtr(*)())gdImageCreateFromWBMP,
                           (gdImagePtr(*)())gdImageCreateFromWBMPCtx);
  if (im == nullptr) {
    return false;
  }
  return Variant(req::make<Image>(im));
}


    ~HierarchicalProfilerFrame() override {
    }


Variant HHVM_FUNCTION(imagecreatefromxbm, const String& filename) {
  gdImagePtr im =
    _php_image_create_from(filename, -1, -1, -1, -1,
                           PHP_GDIMG_TYPE_XBM, "XBM",
                           (gdImagePtr(*)())gdImageCreateFromXbm,
                           (gdImagePtr(*)())nullptr);
  if (im == nullptr) {
    return false;
  }
  return Variant(req::make<Image>(im));
}


bool HHVM_FUNCTION(mcrypt_module_is_block_mode, const String& mode,
                                   const String& lib_dir /* = null_string */) {
  String dir = lib_dir.empty() ? String(MCG(modes_dir)) : lib_dir;
  return mcrypt_module_is_block_mode((char*)mode.data(),
                                     (char*)dir.data()) == 1;
}


Variant HHVM_FUNCTION(hex2bin,
                      const String& str) {
  if (str.empty()) {
    return str;
  }

  if (str.size() % 2) {
    raise_warning("hex2bin: malformed input");
    return false;
  }

  StringBuffer ret(str.size() / 2 + 1);

  auto sl = str.slice();
  const char* src = sl.begin();
  const char* end = sl.end();

  for (; src != end; ++src) {
    int val;
    if (isdigit(*src))                   val = 16 * (*src++ - '0');
    else if ('a' <= *src && *src <= 'f') val = 16 * (*src++ - 'a' + 10);
    else if ('A' <= *src && *src <= 'F') val = 16 * (*src++ - 'A' + 10);
    else {
      raise_warning("hex2bin: malformed input");
      return false;
    }

    if (isdigit(*src))                   val += (*src - '0');
    else if ('a' <= *src && *src <= 'f') val += (*src - 'a' + 10);
    else if ('A' <= *src && *src <= 'F') val += (*src - 'A' + 10);
    else {
      raise_warning("hex2bin: malformed input");
      return false;
    }

    ret.append((char)val);
  }

  return ret.detach();
}


bool HHVM_FUNCTION(png2wbmp, const String& pngname, const String& wbmpname,
    int64_t dest_height, int64_t dest_width, int64_t threshold) {
  return _php_image_convert(pngname, wbmpname, dest_height, dest_width,
                            threshold, PHP_GDIMG_TYPE_PNG);
}


bool HHVM_FUNCTION(HH_is_list_like, const Variant& val) {
  if (val.isClsMeth() && RO::EvalIsCompatibleClsMethType) {
    raiseClsMethToVecWarningHelper();
    return true;
  }
  auto const& ty = val.getType();
  if (!isArrayLikeType(ty)) return false;
  if (isVecType(ty)) return true;
  auto const& arr = val.asCArrRef();
  return arr->isVectorData();
}


  TraceWalker()
    : m_arcBuffLen(200)
    , m_arcBuff((char*)malloc(200))
    , m_badArcCount(0)
  {};


static unsigned php_ifd_get32u(void *Long, int motorola_intel) {
  return (unsigned)php_ifd_get32s(Long, motorola_intel) & 0xffffffff;
}


php_image_filter_gaussian_blur(gdImagePtr im, int /*arg1*/ /* = 0 */,
                               int /*arg2*/ /* = 0 */, int /*arg3*/ /* = 0 */,
                               int /*arg4*/ /* = 0 */) {
  return gdImageGaussianBlur(im) == 1;
}


GdExtension() : Extension("gd", NO_EXTENSION_VERSION_YET) {}


Variant HHVM_FUNCTION(getimagesize, const String& filename,
                      Array& imageinfo) {
  if (auto stream = File::Open(filename, "rb")) {
    return getImageSize(stream, imageinfo);
  }
  return false;
}


  String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }


Variant preg_match(const StringData* pattern, const StringData* subject,
                   Variant* matches /* = nullptr */, int flags /* = 0 */,
                   int offset /* = 0 */) {
  return preg_match_impl(pattern, subject, matches, flags, offset, false);
}


static int getmbi(gdIOCtx *ctx) {
  int i, mbi = 0;

  do {
    i = (ctx->getC)(ctx);
    if (i < 0)
      return (-1);
    mbi = (mbi << 7) | (i & 0x7f);
  } while (i & 0x80);

  return (mbi);
}


int64_t HHVM_FUNCTION(strcmp,
                      const String& str1,
                      const String& str2) {
  return string_strcmp(str1.data(), str1.size(), str2.data(), str2.size());
}


bool HHVM_FUNCTION(imagecopy, const Resource& dst_im, const Resource& src_im,
    int64_t dst_x, int64_t dst_y,
    int64_t src_x, int64_t src_y, int64_t src_w, int64_t src_h) {
  gdImagePtr im_src = cast<Image>(src_im)->get();
  if (!im_src) return false;
  gdImagePtr im_dst = cast<Image>(dst_im)->get();
  if (!im_dst) return false;
  gdImageCopy(im_dst, im_src, dst_x, dst_y, src_x, src_y, src_w, src_h);
  return true;
}


inline int64_t StringData::size() const { return m_len; }


  static req::ptr<CSRequest> Get(const Variant& var) {
    auto csr = cast_or_null<CSRequest>(GetRequest(var));
    if (!csr || !csr->m_csr) {
      raise_warning("cannot get CSR");
      return nullptr;
    }
    return csr;
  }

const int64_t k_OPENSSL_RAW_DATA = 1;

const int64_t k_OPENSSL_ZERO_PADDING = 2;

const int64_t k_OPENSSL_NO_PADDING = 3;

const int64_t k_OPENSSL_PKCS1_OAEP_PADDING = 4;

const int64_t k_OPENSSL_SSLV23_PADDING = 2;

const int64_t k_OPENSSL_PKCS1_PADDING = 1;

static char default_ssl_conf_filename[PATH_MAX];

struct OpenSSLInitializer {
  OpenSSLInitializer() {
    SSL_library_init();
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();
    OpenSSL_add_all_algorithms();

// CCM ciphers are not added by default, so let's add them!
#if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && \
    OPENSSL_VERSION_NUMBER < 0x100020000
    EVP_add_cipher(EVP_aes_128_ccm());
    EVP_add_cipher(EVP_aes_192_ccm());
    EVP_add_cipher(EVP_aes_256_ccm());
#endif

    ERR_load_ERR_strings();
    ERR_load_crypto_strings();
    ERR_load_EVP_strings();

    /* Determine default SSL configuration file */
    char *config_filename = getenv("OPENSSL_CONF");
    if (config_filename == nullptr) {
      config_filename = getenv("SSLEAY_CONF");
    }

    /* default to 'openssl.cnf' if no environment variable is set */
    if (config_filename == nullptr) {
      snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename),
               "%s/%s", X509_get_default_cert_area(), "openssl.cnf");
    } else {
      always_assert(
        strlen(config_filename) < sizeof(default_ssl_conf_filename));
      strcpy(default_ssl_conf_filename, config_filename);
    }
  }

  ~OpenSSLInitializer() {
    EVP_cleanup();
  }
}

static OpenSSLInitializer s_openssl_initializer;


Variant HHVM_FUNCTION(mcrypt_get_cipher_name, const String& cipher) {
  MCRYPT td = mcrypt_module_open((char*)cipher.data(),
                                 (char*)MCG(algorithms_dir).data(),
                                 (char*)"ecb",
                                 (char*)MCG(modes_dir).data());
  if (td == MCRYPT_FAILED) {
    td = mcrypt_module_open((char*)cipher.data(),
                            (char*)MCG(algorithms_dir).data(),
                            (char*)"stream",
                            (char*)MCG(modes_dir).data());
    if (td == MCRYPT_FAILED) {
      MCRYPT_OPEN_MODULE_FAILED("mcrypt_get_cipher_name");
      return false;
    }
  }

  char *cipher_name = mcrypt_enc_get_algorithms_name(td);
  mcrypt_module_close(td);
  String ret(cipher_name, CopyString);
  mcrypt_free(cipher_name);
  return ret;
}


static bool add_oid_section(struct php_x509_request *req) {
  char *str = CONF_get_string(req->req_config, nullptr, "oid_section");
  if (str == nullptr) {
    return true;
  }

  STACK_OF(CONF_VALUE) *sktmp = CONF_get_section(req->req_config, str);
  if (sktmp == nullptr) {
    raise_warning("problem loading oid section %s", str);
    return false;
  }

  for (int i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
    CONF_VALUE *cnf = sk_CONF_VALUE_value(sktmp, i);
    if (OBJ_sn2nid(cnf->name) == NID_undef &&
      OBJ_ln2nid(cnf->name) == NID_undef &&
      OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
      raise_warning("problem creating object %s=%s", cnf->name, cnf->value);
      return false;
    }
  }
  return true;
}

static char default_ssl_conf_filename[PATH_MAX];

struct OpenSSLInitializer {
  OpenSSLInitializer() {
    SSL_library_init();
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();
    OpenSSL_add_all_algorithms();

// CCM ciphers are not added by default, so let's add them!
#if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && \
    OPENSSL_VERSION_NUMBER < 0x100020000
    EVP_add_cipher(EVP_aes_128_ccm());
    EVP_add_cipher(EVP_aes_192_ccm());
    EVP_add_cipher(EVP_aes_256_ccm());
#endif

    ERR_load_ERR_strings();
    ERR_load_crypto_strings();
    ERR_load_EVP_strings();

    /* Determine default SSL configuration file */
    char *config_filename = getenv("OPENSSL_CONF");
    if (config_filename == nullptr) {
      config_filename = getenv("SSLEAY_CONF");
    }

    /* default to 'openssl.cnf' if no environment variable is set */
    if (config_filename == nullptr) {
      snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename),
               "%s/%s", X509_get_default_cert_area(), "openssl.cnf");
    } else {
      always_assert(
        strlen(config_filename) < sizeof(default_ssl_conf_filename));
      strcpy(default_ssl_conf_filename, config_filename);
    }
  }

  ~OpenSSLInitializer() {
    EVP_cleanup();
  }
}

static OpenSSLInitializer s_openssl_initializer;


Variant strtr_fast(const String& str, const Array& arr,
                   int minlen, int maxlen) {
  using PatternMask = uint64_t[256];
  auto mask = req::calloc_raw_array<PatternMask>(maxlen);
  SCOPE_EXIT { req::free(mask); };

  int pattern_id = 0;
  for (ArrayIter iter(arr); iter; ++iter, pattern_id++) {
    auto const search = iter.first().toString();
    auto slice = search.slice();

    for (auto i = 0; i < slice.size(); i++) {
      mask[i][(unsigned char)slice.data()[i]] |= (1LL << pattern_id);
    }
  }
  auto s = str.data();
  auto slen = str.size();
  StringBuffer result(slen);
  String key(maxlen, ReserveString);

  for (auto i = 0; i < slen;) {
    if ((i + maxlen) > slen) {
      maxlen = slen - i;
    }
    uint64_t match = ~0x0ULL;
    bool possible_match = false;

    for (auto pos = 0; pos < maxlen; pos++) {
      match &= mask[pos][(unsigned char)s[i + pos]];
      if (!match) break;
      if (pos >= minlen - 1) {
        possible_match = true;
        break;
      }
    }
    bool found = false;
    if (possible_match) {
      found = strtr_slow(arr, result, key, s, i, minlen, maxlen);
    }
    if (!found) {
      result.append(s[i++]);
    }
  }
  return result.detach();
}


  void doTrace(const char *symbol, bool isFuncExit) {
    TraceEntry *te = nextTraceEntry();
    if (te != nullptr) {
      collectStats(symbol, isFuncExit, *te);
    }
  }


inline StringData* StringData::Make(folly::StringPiece s) {
  return Make(s.begin(), s.size(), CopyString);
}


TypedValue HHVM_FUNCTION(imageinterlace, const Resource& image,
                         TypedValue interlace /* = 0 */) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return make_tv<KindOfBoolean>(false);
  if (!tvIsNull(interlace)) {
    // has interlace argument
    gdImageInterlace(im, tvAssertInt(interlace));
  }
  return make_tv<KindOfInt64>(gdImageGetInterlaced(im));
}


  void moduleInit() override {
    HHVM_RC_STR(MCRYPT_3DES, "tripledes");
    HHVM_RC_STR(MCRYPT_ARCFOUR, "arcfour");
    HHVM_RC_STR(MCRYPT_ARCFOUR_IV, "arcfour-iv");
    HHVM_RC_STR(MCRYPT_BLOWFISH, "blowfish");
    HHVM_RC_STR(MCRYPT_BLOWFISH_COMPAT, "blowfish-compat");
    HHVM_RC_STR(MCRYPT_CAST_128, "cast-128");
    HHVM_RC_STR(MCRYPT_CAST_256, "cast-256");
    HHVM_RC_STR(MCRYPT_CRYPT, "crypt");
    HHVM_RC_INT(MCRYPT_DECRYPT, 1);
    HHVM_RC_STR(MCRYPT_DES, "des");
    HHVM_RC_INT(MCRYPT_DEV_RANDOM, RANDOM);
    HHVM_RC_INT(MCRYPT_DEV_URANDOM, URANDOM);
    HHVM_RC_INT(MCRYPT_ENCRYPT, 0);
    HHVM_RC_STR(MCRYPT_ENIGNA, "crypt");
    HHVM_RC_STR(MCRYPT_GOST, "gost");
    HHVM_RC_STR(MCRYPT_IDEA, "idea");
    HHVM_RC_STR(MCRYPT_LOKI97, "loki97");
    HHVM_RC_STR(MCRYPT_MARS, "mars");
    HHVM_RC_STR(MCRYPT_MODE_CBC, "cbc");
    HHVM_RC_STR(MCRYPT_MODE_CFB, "cfb");
    HHVM_RC_STR(MCRYPT_MODE_ECB, "ecb");
    HHVM_RC_STR(MCRYPT_MODE_NOFB, "nofb");
    HHVM_RC_STR(MCRYPT_MODE_OFB, "ofb");
    HHVM_RC_STR(MCRYPT_MODE_STREAM, "stream");
    HHVM_RC_STR(MCRYPT_PANAMA, "panama");
    HHVM_RC_INT(MCRYPT_RAND, RAND);
    HHVM_RC_STR(MCRYPT_RC2, "rc2");
    HHVM_RC_STR(MCRYPT_RC6, "rc6");
    HHVM_RC_STR(MCRYPT_RIJNDAEL_128, "rijndael-128");
    HHVM_RC_STR(MCRYPT_RIJNDAEL_192, "rijndael-192");
    HHVM_RC_STR(MCRYPT_RIJNDAEL_256, "rijndael-256");
    HHVM_RC_STR(MCRYPT_SAFER128, "safer-sk128");
    HHVM_RC_STR(MCRYPT_SAFER64, "safer-sk64");
    HHVM_RC_STR(MCRYPT_SAFERPLUS, "saferplus");
    HHVM_RC_STR(MCRYPT_SERPENT, "serpent");
    HHVM_RC_STR(MCRYPT_SKIPJACK, "skipjack");
    HHVM_RC_STR(MCRYPT_THREEWAY, "threeway");
    HHVM_RC_STR(MCRYPT_TRIPLEDES, "tripledes");
    HHVM_RC_STR(MCRYPT_TWOFISH, "twofish");
    HHVM_RC_STR(MCRYPT_WAKE, "wake");
    HHVM_RC_STR(MCRYPT_XTEA, "xtea");

    HHVM_FE(mcrypt_module_open);
    HHVM_FE(mcrypt_module_close);
    HHVM_FE(mcrypt_list_algorithms);
    HHVM_FE(mcrypt_list_modes);
    HHVM_FE(mcrypt_module_get_algo_block_size);
    HHVM_FE(mcrypt_module_get_algo_key_size);
    HHVM_FE(mcrypt_module_get_supported_key_sizes);
    HHVM_FE(mcrypt_module_is_block_algorithm_mode);
    HHVM_FE(mcrypt_module_is_block_algorithm);
    HHVM_FE(mcrypt_module_is_block_mode);
    HHVM_FE(mcrypt_module_self_test);
    HHVM_FE(mcrypt_create_iv);
    HHVM_FE(mcrypt_encrypt);
    HHVM_FE(mcrypt_decrypt);
    HHVM_FE(mcrypt_cbc);
    HHVM_FE(mcrypt_cfb);
    HHVM_FE(mcrypt_ecb);
    HHVM_FE(mcrypt_ofb);
    HHVM_FE(mcrypt_get_block_size);
    HHVM_FE(mcrypt_get_cipher_name);
    HHVM_FE(mcrypt_get_iv_size);
    HHVM_FE(mcrypt_get_key_size);
    HHVM_FE(mcrypt_enc_get_algorithms_name);
    HHVM_FE(mcrypt_enc_get_block_size);
    HHVM_FE(mcrypt_enc_get_iv_size);
    HHVM_FE(mcrypt_enc_get_key_size);
    HHVM_FE(mcrypt_enc_get_modes_name);
    HHVM_FE(mcrypt_enc_get_supported_key_sizes);
    HHVM_FE(mcrypt_enc_is_block_algorithm_mode);
    HHVM_FE(mcrypt_enc_is_block_algorithm);
    HHVM_FE(mcrypt_enc_is_block_mode);
    HHVM_FE(mcrypt_enc_self_test);
    HHVM_FE(mcrypt_generic_init);
    HHVM_FE(mcrypt_generic);
    HHVM_FE(mdecrypt_generic);
    HHVM_FE(mcrypt_generic_deinit);
    HHVM_FE(mcrypt_generic_end);

    loadSystemlib();
  }


String HHVM_FUNCTION(gettype, const Variant& v) {
  if (v.getType() == KindOfResource && v.toCResRef().isInvalid()) {
    return s_unknown_type;
  }
  /* Although getDataTypeString also handles the null type, it returns "null"
   * (lower case). Unfortunately, PHP returns "NULL" (upper case) for
   * gettype(). So we make an exception here. */
  if (v.isNull()) {
    return s_NULL;
  }

  // OH NO. This string could be used by logic in Hack, so we can't do the
  // sensible thing here and return "varray" or "darray" for dvarrays.
  if (isArrayType(v.getType())) {
    maybe_raise_array_serialization_notice(SerializationSite::Gettype,
                                           v.getArrayData());
    return s_array;
  }
  if (isArrayLikeType(v.getType()) && v.getArrayData()->isLegacyArray()) {
    return s_array;
  }
  if (RuntimeOption::EvalClassAsStringGetType &&
      (v.isLazyClass() || v.isClass())) {
    return s_string;
  }
  return getDataTypeString(v.getType());
}


static String exif_get_sectionname(int section) {
  switch(section) {
  case SECTION_FILE:      return s_FILE;
  case SECTION_COMPUTED:  return s_COMPUTED;
  case SECTION_ANY_TAG:   return s_ANY_TAG;
  case SECTION_IFD0:      return s_IFD0;
  case SECTION_THUMBNAIL: return s_THUMBNAIL;
  case SECTION_COMMENT:   return s_COMMENT;
  case SECTION_APP0:      return s_APP0;
  case SECTION_EXIF:      return s_EXIF;
  case SECTION_FPIX:      return s_FPIX;
  case SECTION_GPS:       return s_GPS;
  case SECTION_INTEROP:   return s_INTEROP;
  case SECTION_APP12:     return s_APP12;
  case SECTION_WINXP:     return s_WINXP;
  case SECTION_MAKERNOTE: return s_MAKERNOTE;
  }
  return empty_string();
}


Variant HHVM_FUNCTION(image_type_to_extension,
                     int64_t imagetype, bool include_dot /*=true */) {
  switch (imagetype) {
  case IMAGE_FILETYPE_GIF:
    return include_dot ? String(".gif") : String("gif");
  case IMAGE_FILETYPE_JPEG:
    return include_dot ? String(".jpeg") : String("jpeg");
  case IMAGE_FILETYPE_PNG:
    return include_dot ? String(".png") : String("png");
  case IMAGE_FILETYPE_SWF:
  case IMAGE_FILETYPE_SWC:
    return include_dot ? String(".swf") : String("swf");
  case IMAGE_FILETYPE_PSD:
    return include_dot ? String(".psd") : String("psd");
  case IMAGE_FILETYPE_BMP:
  case IMAGE_FILETYPE_WBMP:
    return include_dot ? String(".bmp") : String("bmp");
  case IMAGE_FILETYPE_TIFF_II:
  case IMAGE_FILETYPE_TIFF_MM:
    return include_dot ? String(".tiff") : String("tiff");
  case IMAGE_FILETYPE_IFF:
    return include_dot ? String(".iff") : String("iff");
  case IMAGE_FILETYPE_JPC:
    return include_dot ? String(".jpc") : String("jpc");
  case IMAGE_FILETYPE_JP2:
    return include_dot ? String(".jp2") : String("jp2");
  case IMAGE_FILETYPE_JPX:
    return include_dot ? String(".jpx") : String("jpx");
  case IMAGE_FILETYPE_JB2:
    return include_dot ? String(".jb2") : String("jb2");
  case IMAGE_FILETYPE_XBM:
    return include_dot ? String(".xbm") : String("xbm");
  case IMAGE_FILETYPE_ICO:
    return include_dot ? String(".ico") : String("ico");
  default:
    return false;
  }
}


Variant HHVM_FUNCTION(socket_sendto,
                      const Resource& socket,
                      const String& buf,
                      int64_t len,
                      int flags,
                      const String& addr,
                      int port /* = -1 */) {
  auto sock = cast<Socket>(socket);
  if (len < 0) return false;
  if (len > buf.size()) {
    len = buf.size();
  }
  int retval;
  switch (sock->getType()) {
  case AF_UNIX:
    {
#ifdef _MSC_VER
      retval = -1;
#else
      struct sockaddr_storage s_s;
      struct sockaddr* sa_ptr;
      size_t sa_size;
      if (!set_sockaddr(s_s, sock, addr, 0, sa_ptr, sa_size)) {
        return false;
      }

      retval = sendto(sock->fd(), buf.data(), (size_t)len, flags, sa_ptr,
                      sa_size);
#endif
    }
    break;
  case AF_INET:
    {
      if (port == -1) {
        throw_missing_arguments_nr("socket_sendto", 6, 5);
        return false;
      }

      struct sockaddr_in  sin;
      memset(&sin, 0, sizeof(sin));
      sin.sin_family = AF_INET;
      sin.sin_port = htons((unsigned short) port);
      if (!php_set_inet_addr(&sin, addr.c_str(), sock)) {
        return false;
      }

      retval = sendto(sock->fd(), buf.data(), (size_t)len, flags,
                      (struct sockaddr *)&sin, sizeof(sin));
    }
    break;
  case AF_INET6:
    {
      if (port == -1) {
        throw_missing_arguments_nr("socket_sendto", 6, 5);
        return false;
      }

      struct sockaddr_in6  sin6;
      memset(&sin6, 0, sizeof(sin6));
      sin6.sin6_family = AF_INET6;
      sin6.sin6_port = htons((unsigned short) port);

      if (!php_set_inet6_addr(&sin6, addr.c_str(), sock)) {
        return false;
      }

      retval = sendto(sock->fd(), buf.data(), (size_t)len, flags,
                      (struct sockaddr *)&sin6, sizeof(sin6));
    }
    break;
  default:
    raise_warning("Unsupported socket type %d", sock->getType());
    return false;
  }

  if (retval == -1) {
    SOCKET_ERROR(sock, "unable to write to socket", errno);
    return false;
  }

  return retval;
}


    Accessor& operator=(const pcre_cache_entry* ptr) {
      assertx(m_kind == Kind::Empty || m_kind == Kind::Ptr);
      m_kind = Kind::Ptr;
      m_u.ptr = ptr;
      return *this;
    }


inline folly::StringPiece StringData::slice() const {
  return folly::StringPiece{data(), m_len};
}


TypedValue HHVM_FUNCTION(strtok, const String& str, const Variant& token) {
  return tvReturn(strtok(str, token));
}


    const pcre_cache_entry* get() {
      switch (m_kind) {
        case Kind::Empty:    return nullptr;
        case Kind::Ptr:      return m_u.ptr;
        case Kind::SmartPtr: return m_u.smart_ptr.get();
        case Kind::AccessorKind: return m_u.accessor->get();
      }
      always_assert(false);
    }


  ~PCRECache() {
    if (m_kind == CacheKind::Static && m_staticCache.load()) {
      DestroyStatic(m_staticCache);
    }
  }


bool HHVM_FUNCTION(is_array, const Variant& v) {
  if (RuntimeOption::EvalLogOnIsArrayFunction) {
    raise_notice("call to deprecated builtin is_array()");
  }
  return is_any_array(v.asTypedValue());
}


void HHVM_FUNCTION(socket_clear_error,
                   const Variant& socket /* = null */) {
  if (!socket.isNull()) {
    cast<Socket>(socket)->setError(0);
  }
}


int64_t HHVM_FUNCTION(strlen,
                      StringArg str) {
  return str.get()->size();
}


String HHVM_FUNCTION(ltrim,
                     const String& str,
                     const String& charlist /* = k_HPHP_TRIM_CHARLIST */) {
  return stringTrim<true,false>(str, charlist);
}


static void exif_process_APP1(image_info_type *ImageInfo, char *CharBuf,
                              size_t length, size_t displacement) {
  /* Check the APP1 for Exif Identifier Code */
  char *end = CharBuf + length;
  static const
  unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
  CHECK_BUFFER(CharBuf+2, end, 6);
  if (length <= 8 || memcmp(CharBuf+2, ExifHeader, 6)) {
    raise_warning("Incorrect APP1 Exif Identifier Code");
    return;
  }
  exif_process_TIFF_in_JPEG(ImageInfo, CharBuf + 8, length - 8,
                            displacement+8);
}


Variant HHVM_FUNCTION(HH_first, const Variant& v) {
  // 1. array, vec, dict, keyset
  if (v.isArray() || v.isClsMeth()) {
    auto arr = v.toArray();
    if (arr->empty()) {
      return init_null();
    }
    return arr->getValue(arr->iter_begin());
  }

  if (v.isObject()) {
    auto obj = v.asCObjRef();
    // 2. collection
    if (obj->isCollection()) {
      // Pair
      if (obj->collectionType() == CollectionType::Pair) {
        auto const pair = static_cast<c_Pair*>(obj.get());
        return Variant::wrap(*pair->at(0));
      }

      // Vector, Map, Set, and Imm variants
      auto arr = collections::asArray(obj.get());
      if (arr->empty()) {
        return init_null();
      }
      return arr->getValue(arr->iter_begin());
    }
  }
  SystemLib::throwInvalidArgumentExceptionObject(
    "Argument 1 passed to HH\\Lib\\_Private\\Native\\first() "
     "must be a Container");
}


int preg_replace(Variant& result,
                 const Variant& pattern,
                 const Variant& replacement,
                 const Variant& subject,
                 int limit /* = -1 */) {
  int64_t count;
  result = preg_replace_impl(pattern, replacement, subject,
                             limit, &count, false, false);
  return count;
}


static void hp_trunc_time(struct timeval *tv, uint64_t intr) {
  uint64_t time_in_micro;

  // Convert to microsecs and trunc that first
  time_in_micro = (tv->tv_sec * 1000000) + tv->tv_usec;
  time_in_micro /= intr;
  time_in_micro *= intr;

  // Update tv
  tv->tv_sec  = (time_in_micro / 1000000);
  tv->tv_usec = (time_in_micro % 1000000);
}


String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;

struct StrNR {
private:
  StringData *m_px;

public:
  StrNR() : m_px(nullptr) {}
  explicit StrNR(StringData *sd) : m_px(sd) {}
  explicit StrNR(const StringData *sd) : m_px(const_cast<StringData*>(sd)) {}
  explicit StrNR(const String &s) : m_px(s.get()) {} // XXX
  explicit StrNR(const char*) = delete;

  ~StrNR() {
    if (debug) {
      m_px = reinterpret_cast<StringData*>(0xdeadbeeffaceb004);
    }
  }

  /* implicit */ operator

void init(const char* s, size_t len);

static std::vector<std::tuple<const char*, size_t, StaticString*>>*
    s_registered;

inline String& String::operator=(const StaticString& v)


static int exif_read_file(image_info_type *ImageInfo, String FileName,
                          bool read_thumbnail, bool read_all) {
  struct stat st;

  /* Start with an empty image information structure. */
  memset(ImageInfo, 0, sizeof(*ImageInfo));

  ImageInfo->motorola_intel = -1; /* flag as unknown */

  ImageInfo->infile = File::Open(FileName, "rb");
  if (!ImageInfo->infile) {
    raise_warning("Unable to open file %s", FileName.c_str());
    return 0;
  }
  auto plain_file = dyn_cast<PlainFile>(ImageInfo->infile);
  if (plain_file) {
    if (stat(FileName.c_str(), &st) >= 0) {
      if ((st.st_mode & S_IFMT) != S_IFREG) {
        raise_warning("Not a file");
        return 0;
      }
    }

    /* Store file date/time. */
    ImageInfo->FileDateTime = st.st_mtime;
    ImageInfo->FileSize = st.st_size;
  } else {
    if (!ImageInfo->FileSize) {
      ImageInfo->infile->seek(0, SEEK_END);
      ImageInfo->FileSize = ImageInfo->infile->tell();
      ImageInfo->infile->seek(0, SEEK_SET);
    }
  }

  ImageInfo->FileName = HHVM_FN(basename)(FileName);
  ImageInfo->read_thumbnail = read_thumbnail;
  ImageInfo->read_all = read_all;
  ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_UNKNOWN;

  PHP_STRDUP(ImageInfo->encode_unicode,    "ISO-8859-15");
  PHP_STRDUP(ImageInfo->decode_unicode_be, "UCS-2BE");
  PHP_STRDUP(ImageInfo->decode_unicode_le, "UCS-2LE");
  PHP_STRDUP(ImageInfo->encode_jis,        "");
  PHP_STRDUP(ImageInfo->decode_jis_be,     "JIS");
  PHP_STRDUP(ImageInfo->decode_jis_le,     "JIS");

  ImageInfo->ifd_nesting_level = 0;

  /* Scan the JPEG headers. */
  auto ret = exif_scan_FILE_header(ImageInfo);

  ImageInfo->infile->close();
  return ret;
}

#define IMAGE_TYPE_GIF 1

#define IMAGE_TYPE_JPEG 2

#define IMAGE_TYPE_PNG 4

#define IMAGE_FILTER_NEGATE         0

#define IMAGE_FILTER_GRAYSCALE      1

#define IMAGE_FILTER_COLORIZE       4

#define IMAGE_FILTER_MAX            11

#define IMAGE_FILTER_MAX_ARGS       6

#define IMAGE_TYPE_WBMP 8

#define IMAGE_TYPE_XPM 16

#define IMAGE_FILTER_BRIGHTNESS     2

#define IMAGE_FILTER_CONTRAST       3

#define IMAGE_FILTER_EDGEDETECT     5

#define IMAGE_FILTER_EMBOSS         6

#define IMAGE_FILTER_SELECTIVE_BLUR 8

#define IMAGE_FILTER_SMOOTH         10

#define IMAGE_FILTER_PIXELATE       11

#define IMAGE_FILTER_MEAN_REMOVAL   9

#define IMAGE_FILTER_GAUSSIAN_BLUR  7


inline bool StringData::empty() const { return size() == 0; }


String preg_quote(const String& str,
                  const String& delimiter /* = null_string */) {
  const char* in_str = str.data();
  const char* in_str_end = in_str + str.size();

  /* Nothing to do if we got an empty string */
  if (in_str == in_str_end) {
    return str;
  }

  char delim_char = 0;      /* Delimiter character to be quoted */
  bool quote_delim = false; /* Whether to quote additional delim char */
  if (!delimiter.empty()) {
    delim_char = delimiter.charAt(0);
    quote_delim = true;
  }

  /* Allocate enough memory so that even if each character
     is quoted, we won't run out of room */
  static_assert(
    (StringData::MaxSize * 4 + 1) < std::numeric_limits<int64_t>::max()
  );
  String ret(4 * str.size() + 1, ReserveString);
  char* out_str = ret.mutableData();

  /* Go through the string and quote necessary characters */
  const char* p;
  char* q;
  for (p = in_str, q = out_str; p != in_str_end; p++) {
    char c = *p;
    switch (c) {
    case '.': case '\\': case '+': case '*': case '?':
    case '[': case '^':  case ']': case '$': case '(':
    case ')': case '{':  case '}': case '=': case '!':
    case '>': case '<':  case '|': case ':': case '-':
    case '#':
      *q++ = '\\';
      *q++ = c;
      break;

    case '\0':
      *q++ = '\\';
      *q++ = '0';
      *q++ = '0';
      *q++ = '0';
      break;

    default:
      if (quote_delim && c == delim_char)
        *q++ = '\\';
      *q++ = c;
      break;
    }
  }
  *q = '\0';

  return ret.setSize(q - out_str);
}


  const std::string getPat() const {
    return pat;
  }


static void exif_thumbnail_extract(image_info_type *ImageInfo,
                                   char *offset, size_t length) {
  if (ImageInfo->Thumbnail.data) {
    raise_warning("Multiple possible thumbnails");
    return; /* Should not happen */
  }
  if (!ImageInfo->read_thumbnail) {
    return; /* ignore this call */
  }
  /* according to exif2.1, the thumbnail is not supposed to be greater
     than 64K */
  if (ImageInfo->Thumbnail.size >= 65536 ||
      ImageInfo->Thumbnail.size <= 0 ||
      ImageInfo->Thumbnail.offset <= 0) {
    raise_warning("Illegal thumbnail size/offset");
    return;
  }
  /* Check to make sure we are not going to go past the ExifLength */
  if ((ImageInfo->Thumbnail.offset + ImageInfo->Thumbnail.size) > length) {
    raise_warning("Thumbnail goes IFD boundary or end of file reached");
    return;
  }
  PHP_STRNDUP(ImageInfo->Thumbnail.data, offset + ImageInfo->Thumbnail.offset,
              ImageInfo->Thumbnail.size);
  exif_thumbnail_build(ImageInfo);
}


void PCRECache::insert(
  Accessor& accessor,
  const StringData* regex,
  TempKeyCache& keyCache,
  const pcre_cache_entry* ent
) {
  switch (m_kind) {
    case CacheKind::Static:
      {
        assertx(m_staticCache.load());
        // Clear the cache if we haven't refreshed it in a while
        if (time(nullptr) > m_expire) {
          clearStatic();
        }
        auto const cache = m_staticCache.load(std::memory_order_acquire);
        auto const key =
          regex->isStatic() ||
          (regex->isUncounted() && regex->uncountedIncRef()) ?
          regex : StringData::MakeUncounted(regex->slice());
        auto pair = cache->insert(StaticCachePair(key, ent));
        if (pair.second) {
          // Inserted, container owns the pointer
          accessor = ent;
        } else {
          // Not inserted, caller needs to own the pointer
          if (regex->isUncounted()) StringData::ReleaseUncounted(key);
          accessor = EntryPtr(ent);
        }
      }
      break;
    case CacheKind::Lru:
    case CacheKind::Scalable:
      {
        if (!keyCache) {
          keyCache.reset(new LRUCacheKey(regex->data(), regex->size()));
        }
        // Pointer ownership is shared between container and caller
        accessor = EntryPtr(ent);
        if (m_kind == CacheKind::Lru) {
          m_lruCache->insert(*keyCache, accessor.entryPtr());
        } else {
          m_scalableCache->insert(*keyCache, accessor.entryPtr());
        }
      }
      break;
  }
}


static char *php_image_type_to_mime_type(int image_type) {
  switch( image_type) {
  case IMAGE_FILETYPE_GIF:
    return "image/gif";
  case IMAGE_FILETYPE_JPEG:
    return "image/jpeg";
  case IMAGE_FILETYPE_PNG:
    return "image/png";
  case IMAGE_FILETYPE_SWF:
  case IMAGE_FILETYPE_SWC:
    return "application/x-shockwave-flash";
  case IMAGE_FILETYPE_PSD:
    return "image/psd";
  case IMAGE_FILETYPE_BMP:
    return "image/x-ms-bmp";
  case IMAGE_FILETYPE_TIFF_II:
  case IMAGE_FILETYPE_TIFF_MM:
    return "image/tiff";
  case IMAGE_FILETYPE_IFF:
    return "image/iff";
  case IMAGE_FILETYPE_WBMP:
    return "image/vnd.wap.wbmp";
  case IMAGE_FILETYPE_JPC:
    return "application/octet-stream";
  case IMAGE_FILETYPE_JP2:
    return "image/jp2";
  case IMAGE_FILETYPE_XBM:
    return "image/xbm";
  case IMAGE_FILETYPE_ICO:
    return "image/vnd.microsoft.icon";
  default:
  case IMAGE_FILETYPE_UNKNOWN:
    return "application/octet-stream"; /* suppose binary format */
  }
}


bool HHVM_FUNCTION(is_int, const Variant& v) {
  return is_int(v.asTypedValue());
}


Variant HHVM_FUNCTION(imagesx, const Resource& image) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageSX(im);
}


bool MemFile::rewind() {
  assertx(m_len != -1);
  m_cursor = 0;
  setWritePosition(0);
  setReadPosition(0);
  setPosition(0);
  return true;
}


Variant HHVM_FUNCTION(str_word_count,
                      const String& str,
                      int64_t format /* = 0 */,
                      const String& charlist /* = "" */) {
  int str_len = str.size();
  switch (format) {
  case 1:
  case 2:
    if (!str_len) {
      return empty_array();
    }
    break;
  case 0:
    if (!str_len) {
      return 0LL;
    }
    break;
  default:
    raise_invalid_argument_warning("format: %" PRId64, format);
    return false;
  }

  char ch[256];
  const char *char_list = charlist.data();
  if (*char_list) {
    string_charmask(char_list, charlist.size(), ch);
  } else {
    char_list = nullptr;
  }

  int word_count = 0;
  const char *s0 = str.data();
  const char *p = s0;
  const char *e = p + str_len;

  // first character cannot be ' or -, unless explicitly allowed by the user
  if ((*p == '\'' && (!char_list || !ch[(int)'\''])) ||
      (*p == '-' && (!char_list || !ch[(int)'-']))) {
    p++;
  }

  // last character cannot be -, unless explicitly allowed by the user
  if (*(e - 1) == '-' && (!char_list || !ch[(int)'-'])) {
    e--;
  }

  Array ret = Array::CreateDArray();
  while (p < e) {
    const char *s = p;
    while (p < e &&
           (isalpha(*p) || (char_list && ch[(unsigned char)*p]) ||
            *p == '\'' || *p == '-')) {
      p++;
    }
    if (p > s) {
      switch (format) {
      case 1:
        ret.append(String(s, p - s, CopyString));
        break;
      case 2:
        ret.set((int)(s - s0), String(s, p - s, CopyString));
        break;
      default:
        word_count++;
        break;
      }
    }
    p++;
  }

  if (!format) {
    return word_count;
  }
  return ret;
}


    const EntryPtr& entryPtr() const {
      assertx(m_kind == Kind::SmartPtr);
      return m_u.smart_ptr;
    }


void MemFile::unzip() {
  assertx(m_len != -1);
  assertx(!m_malloced);
  assertx(m_cursor == 0);
  int len = m_len;
  char *data = gzdecode(m_data, len);
  if (data == nullptr) {
    raise_fatal_error((std::string("cannot unzip mem stream: ") +
                               getName()).c_str());
  }
  m_data = data;
  m_malloced = true;
  m_len = len;
}


size_t PCRECache::size() const {
  switch (m_kind) {
    case CacheKind::Static:
      return m_staticCache.load(std::memory_order_acquire)->size();
    case CacheKind::Lru:
      return m_lruCache->size();
    case CacheKind::Scalable:
     return m_scalableCache->size();
  }
  always_assert(false);
}


char   toByte   () const { return m_str ? m_str->toByte   () : 0;}


explicit String(StringData *data) : m_str(data) { }

String(const StringData*) = delete;

String(const char *s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, mode) : nullptr, NoIncRef{}) {}

  // attach to binary malloc'ed string
  String(char* s, size_t length, AttachStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // make copy of binary binary string
  String(const char *s, size_t length, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s, length, mode)
                          : nullptr, NoIncRef{}) { }

  // force a copy of a String
  String(const String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}

  // make an empty string with cap reserve bytes, plus 1 for '\0'
  String(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}

  static String attach(StringData* sd) {
    return String(sd, NoIncRef{});

String substr(int start, int length = StringData::MaxSize) const {
    return String::attach(
      m_str ? m_str->substr(start, length) : staticEmptyString());
  }

  /**
   * Find a character or a substring and return its position. "pos" has to be
   * within current string and it's the start point for searching.
   */

int find(const String& s, int pos = 0, bool caseSensitive = true) const;

int rfind(const String& s, int pos = 0, bool caseSensitive = true) const;

friend String&& operator

friend String

String  operator |  (const String& v) const = delete;

String  operator &  (const String& v) const = delete;

String  operator ^  (const String& v) const = delete;

explicit operator bool() const { return (bool)m_str;

bool operator >= (const String& v) const = delete;

bool operator <= (const String& v) const = delete;

String rval(const Array& key) const = delete;

String rval(const Object& key) const = delete;

String rval(const Variant& key) const = delete;

extern const String null_string;

struct StrNR {
private:
  StringData *m_px;

public:
  StrNR() : m_px(nullptr) {}
  explicit StrNR(StringData *sd) : m_px(sd) {}
  explicit StrNR(const StringData *sd) : m_px(const_cast<StringData*>(sd)) {}
  explicit StrNR(const String &s) : m_px(s.get()) {} // XXX
  explicit StrNR(const char*) = delete;

  ~StrNR() {
    if (debug) {
      m_px = reinterpret_cast<StringData*>(0xdeadbeeffaceb004);
    }
  }

  /* implicit */ operator

inline String& String::operator=(const StaticString& v)