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();
}

security fixes

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


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


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


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();
  }
}


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


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


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


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 String& s, CopyStringMode mode)
  : m_str(LIKELY((bool)s) ? StringData::Make(s.c_str(), s.size(), mode)
                          : nullptr, NoIncRef{}) {}


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;
    }
}


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;
}


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);
  }


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;
  }


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;
}


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(size_t cap, ReserveStringMode /*mode*/)
      : m_str(StringData::Make(cap), NoIncRef{}) {}


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;
}


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& operator=(req::ptr<StringData>&& src) {
    m_str = std::move(src);
    return *this;
  }


static req::ptr<MCrypt> get_valid_mcrypt_resource(const Resource& td) {
  auto pm = dyn_cast_or_null<MCrypt>(td);

  if (pm == nullptr || pm->isInvalid()) {
    raise_warning("supplied argument is not a valid MCrypt resource");
    return nullptr;
  }

  return pm;
}


inline StringData* StringData::modifyChar(int offset, char c) {
  assertx(offset >= 0 && offset < size());
  assertx(!hasMultipleRefs());

  auto const sd = isProxy() ? escalate(size()) : this;
  sd->mutableData()[offset] = c;
  sd->m_hash = 0;
  return sd;
}


int spprintf(char **pbuf, size_t max_len, const char *format, ...)
{
  int cc;
  va_list ap;

  va_start(ap, format);
  cc = vspprintf(pbuf, max_len, format, ap);
  va_end(ap);
  return (cc);
}


static void* exif_ifd_make_value(image_info_data *info_data,
                                 int motorola_intel) {
  size_t  byte_count;
  char *value_ptr, *data_ptr;
  size_t  i;

  image_info_value  *info_value;

  byte_count =
    get_php_tiff_bytes_per_format(info_data->format) * info_data->length;
  size_t malloc_size = byte_count > 4 ? byte_count : 4;
  value_ptr = (char *)IM_MALLOC(malloc_size);
  CHECK_ALLOC_R(value_ptr, malloc_size, nullptr);
  memset(value_ptr, 0, 4);
  if (!info_data->length) {
    return value_ptr;
  }
  if (info_data->format == TAG_FMT_UNDEFINED ||
      info_data->format == TAG_FMT_STRING ||
      (byte_count>1 && (info_data->format == TAG_FMT_BYTE ||
                        info_data->format == TAG_FMT_SBYTE))) {
    memmove(value_ptr, info_data->value.s, byte_count);
    return value_ptr;
  } else if (info_data->format == TAG_FMT_BYTE) {
    *value_ptr = info_data->value.u;
    return value_ptr;
  } else if (info_data->format == TAG_FMT_SBYTE) {
    *value_ptr = info_data->value.i;
    return value_ptr;
  } else {
    data_ptr = value_ptr;
    for(i=0; i<info_data->length; i++) {
      if (info_data->length==1) {
        info_value = &info_data->value;
      } else {
        info_value = &info_data->value.list[i];
      }
      switch(info_data->format) {
      case TAG_FMT_USHORT:
        php_ifd_set16u(data_ptr, info_value->u, motorola_intel);
        data_ptr += 2;
        break;
      case TAG_FMT_ULONG:
        php_ifd_set32u(data_ptr, info_value->u, motorola_intel);
        data_ptr += 4;
        break;
      case TAG_FMT_SSHORT:
        php_ifd_set16u(data_ptr, info_value->i, motorola_intel);
        data_ptr += 2;
        break;
      case TAG_FMT_SLONG:
        php_ifd_set32u(data_ptr, info_value->i, motorola_intel);
        data_ptr += 4;
        break;
      case TAG_FMT_URATIONAL:
        php_ifd_set32u(data_ptr,   info_value->sr.num, motorola_intel);
        php_ifd_set32u(data_ptr+4, info_value->sr.den, motorola_intel);
        data_ptr += 8;
        break;
      case TAG_FMT_SRATIONAL:
        php_ifd_set32u(data_ptr,   info_value->ur.num, motorola_intel);
        php_ifd_set32u(data_ptr+4, info_value->ur.den, motorola_intel);
        data_ptr += 8;
        break;
      case TAG_FMT_SINGLE:
        memmove(data_ptr, &info_value->f, 4);
        data_ptr += 4;
        break;
      case TAG_FMT_DOUBLE:
        memmove(data_ptr, &info_value->d, 8);
        data_ptr += 8;
        break;
      }
    }
  }
  return value_ptr;
}


bool HHVM_FUNCTION(imagesetbrush,
    const Resource& image, const Resource& brush) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  gdImagePtr tile = get_valid_image_resource(brush);
  if (!tile) return false;
  gdImageSetBrush(im, tile);
  unsafe_cast_or_null<Image>(image)->m_brush =
    unsafe_cast_or_null<Image>(brush);
  return true;
}