Variant HHVM_FUNCTION(getaddrinfo,
                      const String& host,
                      const String& port,
                      int family /* = 0 */,
                      int socktype /* = 0 */,
                      int protocol /* = 0 */,
                      int flags /* = 0 */) {
  const char *hptr = NULL, *pptr = NULL;
  if (!host.empty()) {
    hptr = host.c_str();
  }
  if (!port.empty()) {
    pptr = port.c_str();
  }

  struct addrinfo hints, *res;
  struct addrinfo *res0 = NULL;
  int error;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = family;
  hints.ai_socktype = socktype;
  hints.ai_protocol = protocol;
  hints.ai_flags = flags;
  error = getaddrinfo(hptr, pptr, &hints, &res0);

  if (error) {
    raise_warning("%s", gai_strerror(error));

    if (res0) {
      freeaddrinfo(res0);
    }
    return false;
  }

  Array ret = Array::CreateVArray();

  for (res = res0; res; res = res->ai_next) {
    Array data = make_darray(
      s_family, res->ai_family,
      s_socktype, res->ai_socktype,
      s_protocol, res->ai_protocol
    );

    switch (res->ai_addr->sa_family) {
      case AF_INET:
      {
        struct sockaddr_in *a;
        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
        if (!buffer.empty()) {
          a = (struct sockaddr_in *)res->ai_addr;
          data.set(
            s_sockaddr,
            make_darray(
              s_address, buffer,
              s_port, ntohs(a->sin_port)
            )
          );
        }
        break;
      }
      case AF_INET6:
      {
        struct sockaddr_in6 *a;
        String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
        if (!buffer.empty()) {
          a = (struct sockaddr_in6 *)res->ai_addr;
          data.set(
            s_sockaddr,
            make_darray(
              s_address, buffer,
              s_port, ntohs(a->sin6_port),
              s_flow_info, (int32_t)a->sin6_flowinfo,
              s_scope_id, (int32_t)a->sin6_scope_id
            )
          );
        }
        break;
      }
      default:
        data.set(s_sockaddr, empty_array());
        break;
    }

    ret.append(data);
  }

  if (res0) {
    freeaddrinfo(res0);
  }

  return ret;
}


int preg_last_error() {
  return *rl_last_error_code;
}

security fixes

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


int64_t HHVM_FUNCTION(strnatcasecmp,
                      const String& str1,
                      const String& str2) {
  return string_natural_cmp(str1.data(), str1.size(), str2.data(), str2.size(),
                            true);
}

/* No explicit global definitions found. */


Variant HHVM_FUNCTION(imagecolorclosestalpha,
    const Resource& image,
    int64_t red, int64_t green, int64_t blue, int64_t alpha) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  return gdImageColorClosestAlpha(im, red, green, blue, alpha);
}

#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


Array HHVM_FUNCTION(mcrypt_list_modes,
                    const String& lib_dir /* = null_string */) {
  String dir = lib_dir.empty() ? String(MCG(modes_dir)) : lib_dir;

  int count = 0;
  char **modules = mcrypt_list_modes((char*)dir.data(), &count);
  if (count == 0) {
    raise_warning("No modes found in module dir");
  }
  VArrayInit ret(count);
  for (int i = 0; i < count; i++) {
    ret.append(String(modules[i], CopyString));
  }
  mcrypt_free_p(modules, count);
  return ret.toArray();
}


bool HHVM_FUNCTION(imagepng, const Resource& image,
    const String& filename /* = null_string */,
    int64_t quality /* = -1 */, int64_t filters /* = -1 */) {
  return _php_image_output_ctx(image, filename, quality, filters,
                               PHP_GDIMG_TYPE_PNG, "PNG",
                               (void (*)())gdImagePngCtxEx);
}


String HHVM_FUNCTION(htmlspecialchars,
                     const String& str,
                     int flags /* = k_ENT_HTML_QUOTE_DOUBLE */,
                     const String& charset /* = "UTF-8" */,
                     bool double_encode /* = true */) {
  // dropping double_encode parameters and see runtime/base/zend-html.h
  const char *scharset = charset.data();
  if (!*scharset) scharset = "ISO-8859-1";
  return StringUtil::HtmlEncode(str, StringUtil::toQuoteStyleBitmask(flags),
                                scharset, double_encode, false);
}


  static const StringData *GetIntegerStringData(int64_t n) {
    if (HasConverted(n)) {
      return *(converted_integers + n);
    }
    return nullptr;
  }

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;


static char *exif_get_sectionlist(int sectionlist) {
  int i, len, ml = 0;
  char *sections;

  for(i=0; i<SECTION_COUNT; i++) {
    ml += exif_get_sectionname(i).size() + 2;
  }
  sections = (char *)IM_MALLOC(ml + 1);
  CHECK_ALLOC_R(sections, ml + 1, nullptr);
  sections[0] = '\0';
  len = 0;
  for(i=0; i<SECTION_COUNT; i++) {
    if (sectionlist&(1<<i)) {
      snprintf(sections+len, ml-len, "%s, ", exif_get_sectionname(i).c_str());
      len = strlen(sections);
    }
  }
  if (len>2) {
    sections[len-2] = '\0';
  }
  return sections;
}


void Strobelight::init() {
#if !defined(__APPLE__) && !defined(_MSC_VER)
  signal(strobelight::kSignumCurrent, onStrobelightSignal);
  sync_signal(strobelight::kSignumAll, onStrobelightSignal);
#endif
}


Strobelight& Strobelight::getInstance() noexcept {
  static Strobelight instance;
  return instance;
}


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


to_usec(int64_t cycles, int64_t MHz, bool cpu_time = false)
{
  if (cpu_time) {
    return cycles / 1000;
  }
  return (cycles + MHz/2) / MHz;
}

#define HP_STACK_DELIM        "==>"

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


MemFile::MemFile(const String& wrapper, const String& stream)
  : File(false, wrapper, stream), m_data(nullptr), m_len(-1), m_cursor(0),
    m_malloced(false) {
  setIsLocal(true);
}


Variant HHVM_FUNCTION(socket_create,
                      int domain,
                      int type,
                      int protocol) {
  check_socket_parameters(domain, type);
  int socketId = socket(domain, type, protocol);
  if (socketId == -1) {
    SOCKET_ERROR(req::make<ConcreteSocket>(),
                 "Unable to create socket",
                 errno);
    return false;
  }
  return Variant(req::make<ConcreteSocket>(socketId, domain));
}

#define PHP_NORMAL_READ 0x0001

#define PHP_BINARY_READ 0x0002


void begin_profiler_frame(Profiler *p,
                          const char *symbol) {
  p->beginFrame(symbol);
}


bool HHVM_FUNCTION(socket_listen,
                   const Resource& socket,
                   int backlog /* = 0 */) {
  auto sock = cast<Socket>(socket);
  if (listen(sock->fd(), backlog) != 0) {
    SOCKET_ERROR(sock, "unable to listen on socket", errno);
    return false;
  }
  return true;
}


Variant HHVM_FUNCTION(socket_send,
                      const Resource& socket,
                      const String& buf,
                      int64_t len,
                      int flags) {
  auto sock = cast<Socket>(socket);
  if (len < 0) return false;
  if (len > buf.size()) {
    len = buf.size();
  }
  int retval = send(sock->fd(), buf.data(), (size_t)len, flags);
  if (retval == -1) {
    SOCKET_ERROR(sock, "unable to write to socket", errno);
    return false;
  }
  return retval;
}


bool HHVM_FUNCTION(imagefilledellipse, const Resource& image,
    int64_t cx, int64_t cy, int64_t width, int64_t height, int64_t color) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  gdImageFilledEllipse(im, cx, cy, width, height, color);
  return true;
}


size_t preg_pcre_cache_size() {
  return s_pcreCache.size();
}


Variant f_phprof_disable() {
  return s_profiler_factory->stop();
}


static Variant php_mcrypt_do_crypt(const String& cipher, const String& key,
                                   const String& data, const String& mode,
                                   const String& iv, bool dencrypt,
                                   char *name) {
  MCRYPT td = mcrypt_module_open((char*)cipher.data(),
                                 (char*)MCG(algorithms_dir).data(),
                                 (char*)mode.data(),
                                 (char*)MCG(modes_dir).data());
  if (td == MCRYPT_FAILED) {
    MCRYPT_OPEN_MODULE_FAILED(name);
    return false;
  }

  /* Checking for key-length */
  int max_key_length = mcrypt_enc_get_key_size(td);
  if (key.size() > max_key_length) {
    raise_warning("Size of key is too large for this algorithm");
  }
  int count;
  int *key_length_sizes = mcrypt_enc_get_supported_key_sizes(td, &count);
  int use_key_length;
  char *key_s = nullptr;
  if (count == 0 && key_length_sizes == nullptr) { // all lengths 1 - k_l_s = OK
    use_key_length = key.size();
    key_s = (char*)malloc(use_key_length);
    memcpy(key_s, key.data(), use_key_length);
  } else if (count == 1) {  /* only m_k_l = OK */
    key_s = (char*)malloc(key_length_sizes[0]);
    memset(key_s, 0, key_length_sizes[0]);
    memcpy(key_s, key.data(), MIN(key.size(), key_length_sizes[0]));
    use_key_length = key_length_sizes[0];
  } else { /* determine smallest supported key > length of requested key */
    use_key_length = max_key_length; /* start with max key length */
    for (int i = 0; i < count; i++) {
      if (key_length_sizes[i] >= key.size() &&
          key_length_sizes[i] < use_key_length) {
        use_key_length = key_length_sizes[i];
      }
    }
    key_s = (char*)malloc(use_key_length);
    memset(key_s, 0, use_key_length);
    memcpy(key_s, key.data(), MIN(key.size(), use_key_length));
  }
  mcrypt_free(key_length_sizes);

  /* Check IV */
  char *iv_s = nullptr;
  int iv_size = mcrypt_enc_get_iv_size(td);

  /* IV is required */
  if (mcrypt_enc_mode_has_iv(td) == 1) {
    if (!iv.empty()) {
      if (iv_size != iv.size()) {
        raise_warning("%s(): The IV parameter must be as long as "
                      "the blocksize", name);
      } else {
        iv_s = (char*)malloc(iv_size + 1);
        memcpy(iv_s, iv.data(), iv_size);
      }
    } else {
      raise_warning("%s(): The IV parameter must be as long as "
                    "the blocksize", name);
      iv_s = (char*)malloc(iv_size + 1);
      memset(iv_s, 0, iv_size + 1);
    }
  }

  int block_size;
  unsigned long int data_size;
  String s;
  char *data_s;
  /* Check blocksize */
  if (mcrypt_enc_is_block_mode(td) == 1) { /* It's a block algorithm */
    block_size = mcrypt_enc_get_block_size(td);
    data_size = (((data.size() - 1) / block_size) + 1) * block_size;
    s = String(data_size, ReserveString);
    data_s = (char*)s.mutableData();
    memset(data_s, 0, data_size);
    memcpy(data_s, data.data(), data.size());
  } else { /* It's not a block algorithm */
    data_size = data.size();
    s = String(data_size, ReserveString);
    data_s = (char*)s.mutableData();
    memcpy(data_s, data.data(), data.size());
  }

  if (mcrypt_generic_init(td, key_s, use_key_length, iv_s) < 0) {
    raise_warning("Mcrypt initialisation failed");
    return false;
  }
  if (dencrypt) {
    mdecrypt_generic(td, data_s, data_size);
  } else {
    mcrypt_generic(td, data_s, data_size);
  }

  /* freeing vars */
  mcrypt_generic_end(td);
  if (key_s != nullptr) {
    free(key_s);
  }
  if (iv_s != nullptr) {
    free(iv_s);
  }
  s.setSize(data_size);
  return s;
}


bool HHVM_FUNCTION(socket_shutdown,
                   const Resource& socket,
                   int how /* = 0 */) {
  /* For some operations that are conceptually a socket operation
   * (eg fopen('http://...)) we actually complete it and store the result in
   * a memfile. As the fact that it's not really a socket is an implementation
   * detail, user code needs to be able to call shutdown on it.
   */
  if (socket->instanceof<MemFile>()) {
    return true;
  }
  auto sock = cast<Socket>(socket);
  if (shutdown(sock->fd(), how) != 0) {
    SOCKET_ERROR(sock, "unable to shutdown socket", errno);
    return false;
  }
  return true;
}


int MemFile::getc() {
  assertx(m_len != -1);
  return File::getc();
}


static void exif_iif_add_str(image_info_type *image_info,
                             int section_index, char *name, char *value) {
  image_info_data  *info_data;
  image_info_data  *list;

  if (value) {
    size_t realloc_size = (image_info->info_list[section_index].count+1) *
                          sizeof(image_info_data);
    list = (image_info_data *)
      IM_REALLOC(image_info->info_list[section_index].list, realloc_size);
    CHECK_ALLOC(list, realloc_size);
    image_info->info_list[section_index].list = list;
    info_data = &image_info->info_list[section_index].
                list[image_info->info_list[section_index].count];
    memset(info_data, 0, sizeof(image_info_data));
    info_data->tag = (unsigned short)TAG_NONE;
    info_data->format = TAG_FMT_STRING;
    info_data->length = 1;
    PHP_STRDUP(info_data->name, name);
    // TODO
    // if (PG(magic_quotes_runtime)) {
    //   info_data->value.s = php_addslashes(value, strlen(value), nullptr, 0);
    // } else {
    PHP_STRDUP(info_data->value.s, value);
    image_info->sections_found |= 1<<section_index;
    image_info->info_list[section_index].count++;
  }
}


const HtmlBasicEntity* get_basic_table(bool all, entity_doctype doctype) {
  if (doctype == entity_doctype::xhtml) {
    return all ? basic_entities_noapos : basic_entities_apos;
  }

  if (doctype == entity_doctype::html401) {
    return basic_entities_noapos;
  }

  return basic_entities_apos;
}


Variant HHVM_FUNCTION(mcrypt_decrypt, const String& cipher, const String& key,
                                      const String& data, const String& mode,
                                      const Variant& viv /* = null_string */) {
  String iv = viv.toString();
  return php_mcrypt_do_crypt(cipher, key, data, mode, iv, true,
                             "mcrypt_decrypt");
}


static void _php_image_bw_convert(gdImagePtr im_org, gdIOCtx *out,
                                  int threshold) {
  gdImagePtr im_dest;
  int white, black;
  int color, color_org, median;
  int dest_height = gdImageSY(im_org);
  int dest_width = gdImageSX(im_org);
  int x, y;

  im_dest = gdImageCreate(dest_width, dest_height);
  if (im_dest == nullptr) {
    raise_warning("Unable to allocate temporary buffer");
    return;
  }

  white = gdImageColorAllocate(im_dest, 255, 255, 255);
  if (white == -1) {
    raise_warning("Unable to allocate the colors for "
                    "the destination buffer");
    return;
  }

  black = gdImageColorAllocate(im_dest, 0, 0, 0);
  if (black == -1) {
    raise_warning("Unable to allocate the colors for "
                    "the destination buffer");
    return;
  }

  if (im_org->trueColor) {
    gdImageTrueColorToPalette(im_org, 1, 256);
  }

  for (y = 0; y < dest_height; y++) {
    for (x = 0; x < dest_width; x++) {
      color_org = gdImageGetPixel(im_org, x, y);
      median = (im_org->red[color_org] +
                im_org->green[color_org] +
                im_org->blue[color_org]) / 3;
      if (median < threshold) {
        color = black;
      } else {
        color = white;
      }
      gdImageSetPixel (im_dest, x, y, color);
    }
  }
  gdImageWBMPCtx (im_dest, black, out);
}


PCREglobals::PCREglobals() {
  jit_stack = pcre_jit_stack_alloc(32768, 524288);
  // Set these to handle uses of pcre prior to PcreExtension::threadInit
  // In particular, for matching tier overrides during RuntimeOption::Load
  preg_backtrace_limit = RuntimeOption::PregBacktraceLimit;
  preg_recursion_limit = RuntimeOption::PregRecursionLimit;
}


    LRUCache::ConstAccessor& resetToLRU() {
      switch (m_kind) {
        case Kind::SmartPtr:
          m_u.smart_ptr.~EntryPtr();
        case Kind::Empty:
        case Kind::Ptr:
          m_kind = Kind::AccessorKind;
          new (&m_u.accessor) LRUCache::ConstAccessor();
          break;
        case Kind::AccessorKind:
          break;
      }
      return m_u.accessor;
    }


  bool valid() const {
    if (s_globalInit) {
      assertx(m_str);
      return true;
    }
    return false;
  }


Variant HHVM_FUNCTION(mcrypt_generic, const Resource& td, const String& data) {
  return mcrypt_generic(td, data, false);
}


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


explicit FormatValue(const HPHP::StaticString& str) : m_val(str) {}


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


  void collectStats(TraceData& te) {
    te.wall_time = cpuCycles();
    te.cpu = 0;
    if (m_flags & TrackCPU) {
      te.cpu = cpuTime(m_MHz);
    }
    if (m_flags & TrackMemory) {
      auto const stats = tl_heap->getStats();
      te.memory = stats.usage();
      te.peak_memory = stats.peakUsage;
    } else if (m_flags & TrackMalloc) {
      te.memory = get_allocs();
      te.peak_memory = get_frees();
    } else {
      te.memory = 0;
      te.peak_memory = 0;
    }
  }


Variant preg_replace_impl(const Variant& pattern, const Variant& replacement,
                          const Variant& subject, int limit, int64_t* count,
                          bool is_callable, bool is_filter) {
  assertx(!(is_callable && is_filter));
  if (!is_callable &&
      replacement.isArray() && !pattern.isArray()) {
    raise_warning("Parameter mismatch, pattern is a string while "
                    "replacement is an array");
    return preg_return_internal_error(false);
  }

  int replace_count = 0;
  if (!isContainer(subject)) {
    auto ret = php_replace_in_subject(pattern, replacement, subject.toString(),
                                      limit, is_callable, &replace_count);

    if (ret.isNull()) return ret; // php_replace_in_subject already set error
    assertx(ret.isString());
    if (count) *count = replace_count;
    if (is_filter && replace_count == 0) {
      return preg_return_internal_error(init_null());
    }
    return preg_return_no_error(std::move(ret));
  }

  Array return_value = Array::CreateDArray();
  Array arrSubject = subject.toDArray();
  for (ArrayIter iter(arrSubject); iter; ++iter) {
    auto old_replace_count = replace_count;
    String subject_entry = iter.second().toString();
    auto ret = php_replace_in_subject(pattern, replacement, subject_entry,
                                      limit, is_callable, &replace_count);

    if (ret.isString() && (!is_filter || replace_count > old_replace_count)) {
      return_value.set(iter.first(), ret.asStrRef());
    }
  }
  if (count) *count = replace_count;
  return preg_return_no_error(std::move(return_value));
}


static long get_us_interval(struct timeval *start, struct timeval *end) {
  return (((end->tv_sec - start->tv_sec) * 1000000)
          + (end->tv_usec - start->tv_usec));
}


  void writeStats(Array &ret) override {
    TraceData my_begin;
    collectStats(my_begin);
    walkTrace(m_traceBuffer, m_traceBuffer + m_nextTraceEntry, &m_finalEntry,
              m_stats);
    if (m_overflowCalls) {
      m_stats["(trace buffer terminated)"].count += m_overflowCalls/2;
    }
    extractStats(ret, m_stats, m_flags, m_MHz);
    CountedTraceData allocStats;
    allocStats.count = 0;
    allocStats.peak_memory = allocStats.memory =
      m_nextTraceEntry * sizeof(*m_traceBuffer);
    returnVals(ret, "(trace buffer alloc)", allocStats, m_flags, m_MHz);
    if (m_flags & MeasureXhprofDisable) {
      CountedTraceData my_end;
      collectStats(my_end);
      my_end.count = 1;
      my_end.cpu -= my_begin.cpu;
      my_end.wall_time -= my_begin.wall_time;
      my_end.memory -= my_begin.memory;
      my_end.peak_memory -= my_begin.peak_memory;
      returnVals(ret, "xhprof_post_processing()", my_end, m_flags, m_MHz);
    }
  }

#define HP_STACK_DELIM_LEN    (sizeof(HP_STACK_DELIM) - 1)


Variant HHVM_FUNCTION(exif_read_data,
    const String& filename, const String& sections /*="" */,
    bool arrays /*=false */, bool thumbnail /*=false */) {
  int i, ret, sections_needed=0;
  image_info_type ImageInfo;
  char tmp[64], *sections_str, *s;

  memset(&ImageInfo, 0, sizeof(ImageInfo));
  if (!sections.empty()) {
    php_vspprintf(&sections_str, 0, ",%s,", sections.c_str());

    /* sections_str DOES start with , and SPACES are NOT allowed in names */
    s = sections_str;
    while(*++s) {
      if (*s==' ') {
        *s = ',';
      }
    }
    for (i=0; i<SECTION_COUNT; i++) {
      snprintf(tmp, sizeof(tmp), ",%s,", exif_get_sectionname(i).c_str());
      if (strstr(sections_str, tmp)) {
        sections_needed |= 1<<i;
      }
    }
    if (sections_str) IM_FREE(sections_str);
  }
  ret = exif_read_file(&ImageInfo, filename, thumbnail, 0);
  sections_str = exif_get_sectionlist(ImageInfo.sections_found);
  /* do not inform about in debug*/
  ImageInfo.sections_found |= FOUND_COMPUTED|FOUND_FILE;
  if (ret==0|| (sections_needed &&
                !(sections_needed&ImageInfo.sections_found))) {
    exif_discard_imageinfo(&ImageInfo);
    if (sections_str) IM_FREE(sections_str);
    return false;
  }
  /* now we can add our information */
  exif_iif_add_str(&ImageInfo, SECTION_FILE, "FileName",
                   (char *)ImageInfo.FileName.c_str());
  exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileDateTime",
                   ImageInfo.FileDateTime);
  exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileSize",
                   ImageInfo.FileSize);
  exif_iif_add_int(&ImageInfo, SECTION_FILE, "FileType",
                   ImageInfo.FileType);
  exif_iif_add_str(&ImageInfo, SECTION_FILE, "MimeType",
                   (char*)php_image_type_to_mime_type(ImageInfo.FileType));
  exif_iif_add_str(&ImageInfo, SECTION_FILE, "SectionsFound",
                   sections_str ? sections_str : (char *)"NONE");

  if (ImageInfo.Width>0 &&  ImageInfo.Height>0) {
    exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "html",
                     "width=\"%d\" height=\"%d\"",
                     ImageInfo.Width, ImageInfo.Height);
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Height",
                     ImageInfo.Height);
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Width",
                     ImageInfo.Width);
  }
  exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "IsColor",
                   ImageInfo.IsColor);
  if (ImageInfo.motorola_intel != -1) {
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "ByteOrderMotorola",
                     ImageInfo.motorola_intel);
  }
  if (ImageInfo.FocalLength) {
    exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "FocalLength",
                     "%4.1Fmm", ImageInfo.FocalLength);
    if (ImageInfo.CCDWidth) {
      exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "35mmFocalLength",
                       "%dmm",
                       (int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35+0.5));
    }
  }
  if (ImageInfo.CCDWidth) {
    exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "CCDWidth",
                     "%dmm", (int)ImageInfo.CCDWidth);
  }
  if (ImageInfo.ExposureTime>0) {
    float recip_exposure_time = 0.5f + 1.0f/ImageInfo.ExposureTime;
    if (ImageInfo.ExposureTime <= 0.5 && recip_exposure_time < INT_MAX) {
      exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ExposureTime", "%0.3F s (1/%d)",
                       ImageInfo.ExposureTime, (int) recip_exposure_time);
    } else {
      exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ExposureTime",
                       "%0.3F s", ImageInfo.ExposureTime);
    }
  }
  if (ImageInfo.ApertureFNumber) {
    exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "ApertureFNumber",
                     "f/%.1F", ImageInfo.ApertureFNumber);
  }
  if (ImageInfo.Distance) {
    if (ImageInfo.Distance<0) {
      exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "FocusDistance",
                       "Infinite");
    } else {
      exif_iif_add_fmt(&ImageInfo, SECTION_COMPUTED, "FocusDistance",
                       "%0.2Fm", ImageInfo.Distance);
    }
  }
  if (ImageInfo.UserComment) {
    exif_iif_add_buffer(&ImageInfo, SECTION_COMPUTED, "UserComment",
                        ImageInfo.UserCommentLength, ImageInfo.UserComment);
    if (ImageInfo.UserCommentEncoding &&
        strlen(ImageInfo.UserCommentEncoding)) {
      exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "UserCommentEncoding",
                       ImageInfo.UserCommentEncoding);
    }
  }

  exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright",
                   ImageInfo.Copyright);
  exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright.Photographer",
                   ImageInfo.CopyrightPhotographer);
  exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Copyright.Editor",
                   ImageInfo.CopyrightEditor);

  for (i=0; i<ImageInfo.xp_fields.count; i++) {
    exif_iif_add_str(&ImageInfo, SECTION_WINXP,
                     exif_get_tagname(ImageInfo.xp_fields.list[i].tag,
                     nullptr, 0, exif_get_tag_table(SECTION_WINXP)),
                     ImageInfo.xp_fields.list[i].value);
  }
  if (ImageInfo.Thumbnail.size) {
    if (thumbnail) {
      /* not exif_iif_add_str : this is a buffer */
      exif_iif_add_tag(&ImageInfo, SECTION_THUMBNAIL, "THUMBNAIL",
                       TAG_NONE, TAG_FMT_UNDEFINED, ImageInfo.Thumbnail.size,
                       ImageInfo.Thumbnail.data);
    }
    if (!ImageInfo.Thumbnail.width || !ImageInfo.Thumbnail.height) {
      /* try to evaluate if thumbnail data is present */
      exif_scan_thumbnail(&ImageInfo);
    }
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.FileType",
                     ImageInfo.Thumbnail.filetype);
    exif_iif_add_str(&ImageInfo, SECTION_COMPUTED, "Thumbnail.MimeType",
      (char*)php_image_type_to_mime_type(ImageInfo.Thumbnail.filetype));
  }
  if (ImageInfo.Thumbnail.width && ImageInfo.Thumbnail.height) {
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.Height",
                     ImageInfo.Thumbnail.height);
    exif_iif_add_int(&ImageInfo, SECTION_COMPUTED, "Thumbnail.Width",
                     ImageInfo.Thumbnail.width);
  }
  if (sections_str) IM_FREE(sections_str);

  Array retarr;
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_FILE);
  add_assoc_image_info(retarr, true, &ImageInfo,
                       SECTION_COMPUTED);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_ANY_TAG);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_IFD0);
  add_assoc_image_info(retarr, true, &ImageInfo,
                       SECTION_THUMBNAIL);
  add_assoc_image_info(retarr, true, &ImageInfo,
                       SECTION_COMMENT);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_EXIF);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_GPS);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_INTEROP);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_FPIX);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_APP12);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_WINXP);
  add_assoc_image_info(retarr, arrays, &ImageInfo,
                       SECTION_MAKERNOTE);

  exif_discard_imageinfo(&ImageInfo);
  return retarr;
}


gdImagePtr _php_image_create_from_string(const String& image, char *tn,
                                         gdImagePtr (*ioctx_func_p)()) {
  VMRegAnchor _;
  gdIOCtx *io_ctx;

  io_ctx = gdNewDynamicCtxEx(image.length(), (char *)image.c_str(), 0);

  if (!io_ctx) {
    return nullptr;
  }

  gdImagePtr im = (*(gdImagePtr (*)(gdIOCtx *))ioctx_func_p)(io_ctx);
  if (!im) {
    raise_warning("Passed data is not in '%s' format", tn);
    io_ctx->gd_free(io_ctx);
    return nullptr;
  }

  io_ctx->gd_free(io_ctx);

  return im;
}


static int exif_process_IFD_in_MAKERNOTE(image_info_type *ImageInfo,
                                         char * value_ptr, int value_len,
                                         char *offset_base, size_t IFDlength,
                                         size_t displacement) {
  int de, section_index = SECTION_MAKERNOTE;
  int NumDirEntries, old_motorola_intel, offset_diff;
  const maker_note_type *maker_note;
  char *dir_start;
  char *value_end = value_ptr + value_len;

  for (unsigned int i=0;
       i<=sizeof(maker_note_array)/sizeof(maker_note_type); i++) {
    if (i==sizeof(maker_note_array)/sizeof(maker_note_type))
      return 0;
    maker_note = maker_note_array+i;

    if (maker_note->make &&
        (!ImageInfo->make || strcmp(maker_note->make, ImageInfo->make))) {
      continue;
    }
    if (maker_note->model &&
        (!ImageInfo->model || strcmp(maker_note->model, ImageInfo->model))) {
      continue;
    }
    if (maker_note->id_string &&
        strncmp(maker_note->id_string, value_ptr,
                (maker_note->id_string_len < value_len ?
                 maker_note->id_string_len : value_len))) {
      continue;
    }
    break;
  }

  if (value_len < 2 || maker_note->offset >= value_len - 1) {
    raise_warning("IFD data too short: 0x%04X offset 0x%04X", value_len, maker_note->offset);
    return 0;
  }

  dir_start = value_ptr + maker_note->offset;
  ImageInfo->sections_found |= FOUND_MAKERNOTE;

  old_motorola_intel = ImageInfo->motorola_intel;
  switch (maker_note->byte_order) {
    case MN_ORDER_INTEL:
      ImageInfo->motorola_intel = 0;
      break;
    case MN_ORDER_MOTOROLA:
      ImageInfo->motorola_intel = 1;
      break;
    default:
    case MN_ORDER_NORMAL:
      break;
  }
  if (value_end - dir_start < 2) return 0;
  NumDirEntries = php_ifd_get16u(dir_start, ImageInfo->motorola_intel);

  switch (maker_note->offset_mode) {
    case MN_OFFSET_MAKER:
      offset_base = value_ptr;
      break;
    case MN_OFFSET_GUESS:
      if (value_end - (dir_start+10) < 4) return 0;
      offset_diff = 2 + NumDirEntries*12 + 4 -
                    php_ifd_get32u(dir_start+10, ImageInfo->motorola_intel);
      if (offset_diff < 0 || offset_diff >= value_len) return 0;
      offset_base = value_ptr + offset_diff;
      break;
    default:
    case MN_OFFSET_NORMAL:
      break;
  }

  if ((2+NumDirEntries*12) > value_len) {
    raise_warning("Illegal IFD size: 2 + x%04X*12 = x%04X > x%04X",
                    NumDirEntries, 2+NumDirEntries*12, value_len);
    return 0;
  }
  if ((dir_start - value_ptr) > value_len - (2+NumDirEntries*12)) {
    raise_warning("Illegal IFD size: 0x%04lX > 0x%04X",
                  (dir_start - value_ptr) + (2+NumDirEntries*12),
                  value_len);
    return 0;
  }

  for (de=0;de<NumDirEntries;de++) {
    if (!exif_process_IFD_TAG(ImageInfo, dir_start + 2 + 12 * de,
                              offset_base, value_end, IFDlength, displacement,
                              section_index, 0, maker_note->tag_table)) {
      return 0;
    }
  }
  ImageInfo->motorola_intel = old_motorola_intel;
  return 0;
}


const char* c_str() const { return data(); }


static int php_read_APP(const req::ptr<File>& stream,
                        unsigned int marker,
                        Array& info) {
  unsigned short length;
  unsigned char markername[16];

  length = php_read2(stream);
  if (length < 2) {
    return 0;
  }
  length -= 2;                /* length includes itself */

  String buffer;
  if (length == 0) {
    // avoid stream reads of length 0, they trigger a notice
    buffer = empty_string();
  } else {
    buffer = stream->read(length);
  }
  if (buffer.length() != length) {
    return 0;
  }

  snprintf((char*)markername, sizeof(markername), "APP%d", marker - M_APP0);

  if (!info.exists(String((const char *)markername))) {
    /* XXX we only catch the 1st tag of it's kind! */
    info.set(String((char*)markername, CopyString), buffer);
  }

  return 1;
}


Variant php_split(const String& spliton, const String& str, int count,
                  bool icase) {
  const char* strp = str.data();
  const char* endp = strp + str.size();

  regex_t re;
  int copts = icase ? REG_ICASE : 0;
  int err = regcomp(&re, spliton.data(), REG_EXTENDED | copts);
  if (err) {
    php_reg_eprint(err, &re);
    return false;
  }

  Array return_value = Array::CreateVArray();
  regmatch_t subs[1];

  /* churn through str, generating array entries as we go */
  while ((count == -1 || count > 1) &&
         !(err = regexec(&re, strp, 1, subs, 0))) {
    if (subs[0].rm_so == 0 && subs[0].rm_eo) {
      /* match is at start of string, return empty string */
      return_value.append("");
      /* skip ahead the length of the regex match */
      strp += subs[0].rm_eo;
    } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
      /* No more matches */
      regfree(&re);
      raise_warning("Invalid Regular Expression to split()");
      return false;
    } else {
      /* On a real match */

      /* make a copy of the substring */
      int size = subs[0].rm_so;

      /* add it to the array */
      return_value.append(String(strp, size, CopyString));

      /* point at our new starting point */
      strp = strp + subs[0].rm_eo;
    }

    /* if we're only looking for a certain number of points,
       stop looking once we hit it */
    if (count != -1) {
      count--;
    }
  }

  /* see if we encountered an error */
  if (err && err != REG_NOMATCH) {
    php_reg_eprint(err, &re);
    regfree(&re);
    return false;
  }

  /* otherwise we just have one last element to add to the array */
  int size = endp - strp;
  return_value.append(String(strp, size, CopyString));

  regfree(&re);
  return return_value;
}


static bool get_pcre_fullinfo(pcre_cache_entry* pce) {
  pcre_extra extra;
  init_local_extra(&extra, pce->extra);

  /* Calculate the size of the offsets array*/
  int rc = pcre_fullinfo(pce->re, &extra, PCRE_INFO_CAPTURECOUNT,
                         &pce->num_subpats);
  if (rc < 0) {
    raise_warning("Internal pcre_fullinfo() error %d", rc);
    return false;
  }
  pce->num_subpats++;
  return true;
}


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;


  void moduleInit() override {
    HHVM_FE(exif_imagetype);
    HHVM_FE(exif_read_data);
    HHVM_FE(exif_tagname);
    HHVM_FE(exif_thumbnail);

    loadSystemlib();
  }


php_image_filter_pixelate(gdImagePtr im, int arg1 /* = 0 */, int arg2 /* = 0 */,
                          int /*arg3*/ /* = 0 */, int /*arg4*/ /* = 0 */) {
  int blocksize = arg1;
  unsigned mode = arg2;
  return gdImagePixelate(im, blocksize, mode) == 1;
}


bool HHVM_FUNCTION(socket_getsockname,
                   const Resource& socket,
                   Variant& address,
                   Variant& port) {
  auto sock = cast<Socket>(socket);

  sockaddr_storage sa_storage;
  socklen_t salen = sizeof(sockaddr_storage);
  struct sockaddr *sa = (struct sockaddr *)&sa_storage;
  if (getsockname(sock->fd(), sa, &salen) < 0) {
    SOCKET_ERROR(sock, "unable to retrieve peer name", errno);
    return false;
  }
  Variant a, p;
  auto ret = get_sockaddr(sa, salen, a, p);
  address = a;
  port = p;
  return ret;
}


Variant preg_grep(const String& pattern, const Array& input, int flags /* = 0 */) {
  PCRECache::Accessor accessor;
  if (!pcre_get_compiled_regex_cache(accessor, pattern.get())) {
    return preg_return_bad_regex_error(false);
  }
  const pcre_cache_entry* pce = accessor.get();

  int size_offsets = 0;
  int* offsets = create_offset_array(pce, size_offsets);
  if (offsets == nullptr) {
    return preg_return_internal_error(false);
  }
  SmartFreeHelper freer(offsets);

  const bool hackArrOutput = flags & PREG_FB_HACK_ARRAYS;

  /* Initialize return array */
  auto ret = hackArrOutput ? Array::CreateDict() : Array::CreateDArray();

  /* Go through the input array */
  bool invert = (flags & PREG_GREP_INVERT);
  pcre_extra extra;
  init_local_extra(&extra, pce->extra);

  for (ArrayIter iter(input); iter; ++iter) {
    String entry = iter.second().toString();

    /* Perform the match */
    int count = pcre_exec(pce->re, &extra, entry.data(), entry.size(),
                          0, 0, offsets, size_offsets);

    /* Check for too many substrings condition. */
    if (count == 0) {
      raise_warning("Matched, but too many substrings");
      count = size_offsets / 3;
    } else if (count < 0 && count != PCRE_ERROR_NOMATCH) {
      if (pcre_need_log_error(count)) {
        pcre_log_error(__FUNCTION__, __LINE__, count,
                       pattern.data(), pattern.size(),
                       entry.data(), entry.size(),
                       "", 0,
                       flags);
      }
      // NOTE: this returns an error together with a partial result :-(
      return preg_return_pcre_error(count, std::move(ret));
    }

    /* If the entry fits our requirements */
    if ((count > 0 && !invert) ||
        (count == PCRE_ERROR_NOMATCH && invert)) {

      /* Add to return array */
      ret.set(iter.first(), entry);
    }
  }

  return preg_return_no_error(std::move(ret));
}


  void sample_stack() {
    char symbol[5120];
    m_stack->getStack(INT_MAX, symbol, sizeof(symbol));

    auto time = std::make_pair((int64_t)m_last_sample_time.tv_sec,
                               (int64_t)m_last_sample_time.tv_usec);
    m_samples.push_back(std::make_pair(time, symbol));
  }


static bool get_sockaddr(sockaddr *sa, socklen_t salen,
                         Variant &address, Variant &port) {
  switch (sa->sa_family) {
  case AF_INET6:
    {
      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
      try {
        folly::SocketAddress addr;
        addr.setFromSockaddr(sin6);

        address = String(addr.getAddressStr(), CopyString);
        port = addr.getPort();
      } catch (...) {
        address = s_2colons;
        port = 0;
      }
    }
    return true;
  case AF_INET:
    {
      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
      try {
        folly::SocketAddress addr;
        addr.setFromSockaddr(sin);

        address = String(addr.getAddressStr(), CopyString);
        port = addr.getPort();
      } catch (...) {
        address = s_0_0_0_0;
        port = 0;
      }
    }
    return true;
  case AF_UNIX:
    {
#ifdef _MSC_VER
      address = String("Unsupported");
#else
      // NB: an unnamed socket has no path, and sun_path should not be
      // inspected. In that case the length is just the size of the
      // struct without sun_path.
      struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
      if (salen > offsetof(sockaddr_un, sun_path)) {
        // - `sun_path` MAY have trailing nulls
        // - `sun_len` MAY include that trailing null on Linux.
        const auto max_path_len = salen - offsetof(struct sockaddr_un, sun_path);
        const auto actual_path_len = ::strnlen(s_un->sun_path, max_path_len);
        address = String(s_un->sun_path, actual_path_len, CopyString);
      } else {
        address = empty_string();
      }
#endif
    }
    return true;

  default:
    break;
  }

  raise_warning("Unsupported address family %d", sa->sa_family);
  return false;
}


  char *mutableData() const {
    return m_str->mutableData();
  }


  String& operator=(String&& src) {
    m_str = std::move(src.m_str);
    return *this;
  }

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


static char *php_strndup_impl(const char* s, uint32_t length
#ifdef IM_MEMORY_CHECK
, int ln
#endif
  ) {
  char *p;

#ifdef IM_MEMORY_CHECK
  p = (char *)s_ima->imMalloc((length+1), ln);
#else
  p = (char *)s_ima->imMalloc((length+1));
#endif
  CHECK_ALLOC_R(p, length+1, nullptr);
  memcpy(p, s, length);
  p[length] = 0;
  return p;
}


static struct gfxinfo *php_handle_wbmp(const req::ptr<File>& stream) {
  struct gfxinfo *result =
   (struct gfxinfo *)IM_CALLOC(1, sizeof(struct gfxinfo));
  CHECK_ALLOC_R(result, (sizeof(struct gfxinfo)), nullptr);

  if (!php_get_wbmp(stream, &result, 0)) {
    IM_FREE(result);
    return nullptr;
  }

  return result;
}


static int php_getimagetype(const req::ptr<File>& file) {
  String fileType = file->read(3);
  if (fileType.length() != 3) {
    raise_notice("Read error!");
    return IMAGE_FILETYPE_UNKNOWN;
  }

  /* BYTES READ: 3 */
  if (!memcmp(fileType.c_str(), php_sig_gif, 3)) {
    return IMAGE_FILETYPE_GIF;
  } else if (!memcmp(fileType.c_str(), php_sig_jpg, 3)) {
    return IMAGE_FILETYPE_JPEG;
  } else if (!memcmp(fileType.c_str(), php_sig_png, 3)) {
    String data = file->read(5);
    if (data.length() != 5) {
      raise_notice("Read error!");
      return IMAGE_FILETYPE_UNKNOWN;
    }
    if (!memcmp((fileType + data).c_str(), php_sig_png, 8)) {
      return IMAGE_FILETYPE_PNG;
    } else {
      raise_warning("PNG file corrupted by ASCII conversion");
      return IMAGE_FILETYPE_UNKNOWN;
    }
  } else if (!memcmp(fileType.c_str(), php_sig_swf, 3)) {
    return IMAGE_FILETYPE_SWF;
  } else if (!memcmp(fileType.c_str(), php_sig_swc, 3)) {
    return IMAGE_FILETYPE_SWC;
  } else if (!memcmp(fileType.c_str(), php_sig_psd, 3)) {
    return IMAGE_FILETYPE_PSD;
  } else if (!memcmp(fileType.c_str(), php_sig_bmp, 2)) {
    return IMAGE_FILETYPE_BMP;
  } else if (!memcmp(fileType.c_str(), php_sig_jpc, 3)) {
    return IMAGE_FILETYPE_JPC;
  }

  String data = file->read(1);
  if (data.length() != 1) {
    raise_notice("Read error!");
    return IMAGE_FILETYPE_UNKNOWN;
  }

  /* BYTES READ: 4 */
  fileType += data;
  if (!memcmp(fileType.c_str(), php_sig_tif_ii, 4)) {
    return IMAGE_FILETYPE_TIFF_II;
  } else if (!memcmp(fileType.c_str(), php_sig_tif_mm, 4)) {
    return IMAGE_FILETYPE_TIFF_MM;
  } else if (!memcmp(fileType.c_str(), php_sig_iff, 4)) {
    return IMAGE_FILETYPE_IFF;
  } else if (!memcmp(fileType.c_str(), php_sig_ico, 4)) {
    return IMAGE_FILETYPE_ICO;
  }

  data = file->read(8);
  if (data.length() != 8) {
    raise_notice("Read error!");
    return IMAGE_FILETYPE_UNKNOWN;
  }

  /* BYTES READ: 12 */
  fileType += data;
  if (!memcmp(fileType.c_str(), php_sig_jp2, 12)) {
    return IMAGE_FILETYPE_JP2;
  }

  /* AFTER ALL ABOVE FAILED */
  if (php_get_wbmp(file, nullptr, 1)) {
    return IMAGE_FILETYPE_WBMP;
  }
  if (php_get_xbm(file, nullptr)) {
    return IMAGE_FILETYPE_XBM;
  }
  return IMAGE_FILETYPE_UNKNOWN;
}


char * ap_php_conv_10(register int64_t num, register bool is_unsigned,
                      register int * is_negative, char *buf_end,
                      register int *len) {
  register char *p = buf_end;
  register uint64_t magnitude;

  if (is_unsigned) {
    magnitude = (uint64_t) num;
    *is_negative = 0;
  } else {
    *is_negative = (num < 0);

    /*
     * On a 2's complement machine, negating the most negative integer
     * results in a number that cannot be represented as a signed integer.
     * Here is what we do to obtain the number's magnitude:
     *      a. add 1 to the number
     *      b. negate it (becomes positive)
     *      c. convert it to unsigned
     *      d. add 1
     */
    if (*is_negative) {
      int64_t t = num + 1;
      magnitude = ((uint64_t) - t) + 1;
    } else {
      magnitude = (uint64_t) num;
    }
  }

  /*
   * We use a do-while loop so that we write at least 1 digit
   */
  do {
    register uint64_t new_magnitude = magnitude / 10;

    *--p = (char)(magnitude - new_magnitude * 10 + '0');
    magnitude = new_magnitude;
  }
  while (magnitude);

  *len = buf_end - p;
  return (p);
}

#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 INT_NULL        ((int *)0)

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


static int exif_scan_FILE_header(image_info_type *ImageInfo) {
  unsigned char *file_header;
  int ret = 0;

  ImageInfo->FileType = IMAGE_FILETYPE_UNKNOWN;

  if (ImageInfo->FileSize >= 2) {
    ImageInfo->infile->seek(0, SEEK_SET);
    String fileHeader = ImageInfo->infile->read(2);
    if (fileHeader.length() != 2) {
      return 0;
    }
    file_header = (unsigned char *)fileHeader.c_str();
    if ((file_header[0]==0xff) && (file_header[1]==M_SOI)) {
      ImageInfo->FileType = IMAGE_FILETYPE_JPEG;
      if (exif_scan_JPEG_header(ImageInfo)) {
        ret = 1;
      } else {
        raise_warning("Invalid JPEG file");
      }
    } else if (ImageInfo->FileSize >= 8) {
      String str = ImageInfo->infile->read(6);
      if (str.length() != 6) {
        return 0;
      }
      fileHeader += str;
      file_header = (unsigned char *)fileHeader.c_str();
      if (!memcmp(file_header, "II\x2A\x00", 4)) {
        ImageInfo->FileType = IMAGE_FILETYPE_TIFF_II;
        ImageInfo->motorola_intel = 0;
        ImageInfo->sections_found |= FOUND_IFD0;
        if (exif_process_IFD_in_TIFF(ImageInfo,
            php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel),
                           SECTION_IFD0)) {
          ret = 1;
        } else {
          raise_warning("Invalid TIFF file");
        }
      } else if (!memcmp(file_header, "MM\x00\x2a", 4)) {
        ImageInfo->FileType = IMAGE_FILETYPE_TIFF_MM;
        ImageInfo->motorola_intel = 1;
        ImageInfo->sections_found |= FOUND_IFD0;
        if (exif_process_IFD_in_TIFF(ImageInfo,
            php_ifd_get32u(file_header + 4, ImageInfo->motorola_intel),
                           SECTION_IFD0)) {
          ret = 1;
        } else {
          raise_warning("Invalid TIFF file");
        }
      } else {
        raise_warning("File not supported");
        return 0;
      }
    }
  } else {
    raise_warning("File too small (%lu)", ImageInfo->FileSize);
  }
  return ret;
}


bool HHVM_FUNCTION(imagesetpixel, const Resource& image,
    int64_t x, int64_t y, int64_t color) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  gdImageSetPixel(im, x, y, color);
  return true;
}


StringData* get() const { return m_str.get(); }


bool HHVM_FUNCTION(HH_is_dict_or_darray, const Variant& val) {
  return is_dict_or_darray(val.asTypedValue());
}


Array HHVM_FUNCTION(mcrypt_list_algorithms,
                    const String& lib_dir /* = null_string */) {
  String dir = lib_dir.empty() ? String(MCG(algorithms_dir)) : lib_dir;

  int count = 0;
  char **modules = mcrypt_list_algorithms((char*)dir.data(), &count);
  if (count == 0) {
    raise_warning("No algorithms found in module dir");
  }
  VArrayInit ret(count);
  for (int i = 0; i < count; i++) {
    ret.append(String(modules[i], CopyString));
  }
  mcrypt_free_p(modules, count);
  return ret.toArray();
}


exif_process_unicode(image_info_type* /*ImageInfo*/, xp_field_type* xp_field,
                     int tag, char* szValuePtr, int ByteCount) {
  xp_field->tag = tag;
  xp_field->value = nullptr;

  /* Copy the comment */
  xp_field->size =
    exif_process_string_raw(&xp_field->value, szValuePtr, ByteCount);
  return xp_field->size;
}


  static req::ptr<Key> Get(const Variant& var, bool public_key,
                           const char *passphrase = nullptr) {
    if (var.isArray()) {
      Array arr = var.toArray();
      if (!arr.exists(int64_t(0)) || !arr.exists(int64_t(1))) {
        raise_warning("key array must be of the form "
                        "array(0 => key, 1 => phrase)");
        return nullptr;
      }

      String zphrase = arr[1].toString();
      return GetHelper(arr[0], public_key, zphrase.data());
    }
    return GetHelper(var, public_key, passphrase);
  }

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;


static void exif_iif_add_buffer(image_info_type *image_info,
                                int section_index, char *name,
                                int length, char *value) {
  image_info_data *info_data;
  image_info_data *list;

  if (value) {
    size_t realloc_size = (image_info->info_list[section_index].count+1) *
                          sizeof(image_info_data);
    list = (image_info_data *)
      IM_REALLOC(image_info->info_list[section_index].list, realloc_size);
    CHECK_ALLOC(list, realloc_size);
    image_info->info_list[section_index].list = list;
    info_data = &image_info->info_list[section_index].
                list[image_info->info_list[section_index].count];
    memset(info_data, 0, sizeof(image_info_data));
    info_data->tag = (unsigned short)TAG_NONE;
    info_data->format = TAG_FMT_UNDEFINED;
    info_data->length = length;
    PHP_STRDUP(info_data->name, name);
    // if (PG(magic_quotes_runtime)) {
    //   info_data->value.s = php_addslashes(value, length, &length, 0);
    //   info_data->length = length;
    // } else {
    info_data->value.s = (char *)IM_MALLOC(length + 1);
    if (!info_data->value.s) info_data->length = 0;
    CHECK_ALLOC(info_data->value.s, length + 1);
    memcpy(info_data->value.s, value, length);
    info_data->value.s[length] = 0;
    image_info->sections_found |= 1<<section_index;
    image_info->info_list[section_index].count++;
  }
}


inline size_t StringData::heapSize() const {
  return isFlat()
    ? isRefCounted()
      ? MemoryManager::sizeIndex2Size(m_aux16)
      : size() + kStringOverhead
    : sizeof(StringData) + sizeof(Proxy);
}

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


explicit operator std::string () const { return toCppString(); }

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;


entity_doctype determine_doctype(int flags) {
  int mask = flags & ENT_HTML_DOC_TYPE_MASK;
  switch (mask) {
    case ENT_HTML_DOC_HTML401: return entity_doctype::html401;
    case ENT_HTML_DOC_XML1: return entity_doctype::xml1;
    case ENT_HTML_DOC_XHTML: return entity_doctype::xhtml;
    case ENT_HTML_DOC_HTML5: return entity_doctype::html5;
  }
  not_reached();
}


Array MemFile::getMetaData() {
  Array ret = File::getMetaData();
  ret.set(s_unread_bytes, m_len - m_cursor);
  return ret;
}


char *string_crypt(const char *key, const char *salt) {
  assertx(key);
  assertx(salt);

  char random_salt[12];
  if (!*salt) {
    memcpy(random_salt,"$1$",3);
    ito64(random_salt+3,rand(),8);
    random_salt[11] = '\0';
    return string_crypt(key, random_salt);
  }

  auto const saltLen = strlen(salt);
  if ((saltLen > sizeof("$2X$00$")) &&
    (salt[0] == '$') &&
    (salt[1] == '2') &&
    (salt[2] >= 'a') && (salt[2] <= 'z') &&
    (salt[3] == '$') &&
    (salt[4] >= '0') && (salt[4] <= '3') &&
    (salt[5] >= '0') && (salt[5] <= '9') &&
    (salt[6] == '$')) {
    // Bundled blowfish crypt()
    char output[61];

    static constexpr size_t maxSaltLength = 123;
    char paddedSalt[maxSaltLength + 1];
    paddedSalt[0] = paddedSalt[maxSaltLength] = '\0';

    memset(&paddedSalt[1], '$', maxSaltLength - 1);
    memcpy(paddedSalt, salt, std::min(maxSaltLength, saltLen));
    paddedSalt[std::min(maxSaltLength, saltLen)] = '\0';

    if (php_crypt_blowfish_rn(key, paddedSalt, output, sizeof(output))) {
      return strdup(output);
    }

  } else {
    // System crypt() function
#ifdef USE_PHP_CRYPT_R
    return php_crypt_r(key, salt);
#else
    static Mutex mutex;
    Lock lock(mutex);
    char *crypt_res = crypt(key,salt);

    if (crypt_res) {
      return strdup(crypt_res);
    }
#endif
  }

  return ((salt[0] == '*') && (salt[1] == '0'))
                  ? strdup("*1") : strdup("*0");
}


MemFile::MemFile(const char *data, int64_t len,
                 const String& wrapper, const String& stream)
  : File(false, wrapper, stream), m_data(nullptr), m_len(len), m_cursor(0),
    m_malloced(true) {
  m_data = (char*)malloc(len + 1);
  if (m_data && len) {
    memcpy(m_data, data, len);
  }
  m_data[len] = '\0';
  setIsLocal(true);
}


Variant HHVM_FUNCTION(socket_write,
                      const Resource& socket,
                      const String& buffer,
                      int64_t length /* = 0 */) {
  auto sock = cast<Socket>(socket);
  if (length < 0) return false;
  if (length == 0 || length > buffer.size()) {
    length = buffer.size();
  }
  int retval = write(sock->fd(), buffer.data(), (size_t)length);
  if (retval < 0) {
    SOCKET_ERROR(sock, "unable to write to socket", errno);
    return false;
  }
  return retval;
}


    bool operator()(const StringData* s1, const StringData* s2) {
      // ahm uses -1, -2, -3 as magic values
      return int64_t(s1) > 0 && (s1 == s2 || s1->same(s2));
    }


bool Strobelight::active() {
  if (rds::isFullyInitialized() && isXenonActive()) {
    // if Xenon owns this request, back off
    return false;
  }

  // return true if a USDT probe function is listening
  return FOLLY_SDT_IS_ENABLED(hhvm, hhvm_stack);
}


  void requestInit() override {
#ifdef IM_MEMORY_CHECK
    void *ptrs[1000];
    int n = 1000;
    if (m_mallocSize) imDump(ptrs, n);
#endif
    assertx(m_mallocSize == 0);
    m_mallocSize = 0;
  }


struct gfxinfo *php_handle_jpeg(const req::ptr<File>& file, Array& info) {
  struct gfxinfo *result = nullptr;
  unsigned int marker = M_PSEUDO;
  unsigned short length, ff_read=1;

  for (;;) {
    marker = php_next_marker(file, marker, ff_read);
    ff_read = 0;
    switch (marker) {
    case M_SOF0:
    case M_SOF1:
    case M_SOF2:
    case M_SOF3:
    case M_SOF5:
    case M_SOF6:
    case M_SOF7:
    case M_SOF9:
    case M_SOF10:
    case M_SOF11:
    case M_SOF13:
    case M_SOF14:
    case M_SOF15:
      if (result == nullptr) {
        /* handle SOFn block */
        result = (struct gfxinfo *)IM_CALLOC(1, sizeof(struct gfxinfo));
        CHECK_ALLOC_R(result, sizeof (struct gfxinfo), nullptr);
        length = php_read2(file);
        result->bits = file->getc();
        result->height = php_read2(file);
        result->width = php_read2(file);
        result->channels = file->getc();
        if (info.isNull() || length < 8) {
          /* if we don't want an extanded info -> return */
          return result;
        }
        if (!file->seek(length - 8, SEEK_CUR)) {
          /* file error after info */
          return result;
        }
      } else {
        if (!php_skip_variable(file)) {
          return result;
        }
      }
      break;

    case M_APP0:
    case M_APP1:
    case M_APP2:
    case M_APP3:
    case M_APP4:
    case M_APP5:
    case M_APP6:
    case M_APP7:
    case M_APP8:
    case M_APP9:
    case M_APP10:
    case M_APP11:
    case M_APP12:
    case M_APP13:
    case M_APP14:
    case M_APP15:
      if (!info.isNull()) {
        if (!php_read_APP(file, marker, info)) {
          /* read all the app markes... */
          return result;
        }
      } else {
        if (!php_skip_variable(file)) {
          return result;
        }
      }
      break;

    case M_SOS:
    case M_EOI:
      /* we're about to hit image data, or are at EOF. stop processing. */
      return result;

    default:
      if (!php_skip_variable(file)) {
        /* anything else isn't interesting */
        return result;
      }
      break;
    }
  }

  return result; /* perhaps image broken -> no info but size */
}


bool MemFile::open(const String& filename, const String& mode) {
  assertx(m_len == -1);
  // mem files are read-only
  const char* mode_str = mode.c_str();
  if (strchr(mode_str, '+') || strchr(mode_str, 'a') || strchr(mode_str, 'w')) {
    return false;
  }
  int len = INT_MIN;
  bool compressed = false;
  char *data =
    StaticContentCache::TheFileCache->read(filename.c_str(), len, compressed);
  // -1: PHP file; -2: directory
  if (len != INT_MIN && len != -1 && len != -2) {
    assertx(len >= 0);
    if (compressed) {
      assertx(RuntimeOption::EnableOnDemandUncompress);
      data = gzdecode(data, len);
      if (data == nullptr) {
        raise_fatal_error("cannot unzip compressed data");
      }
      m_data = data;
      m_malloced = true;
      m_len = len;
      return true;
    }
    setName(filename.toCppString());
    m_data = data;
    m_len = len;
    return true;
  }
  if (len != INT_MIN) {
    Logger::Error("Cannot open a PHP file or a directory as MemFile: %s",
                  filename.c_str());
  }
  return false;
}


static int64_t* get_cpu_frequency_from_file(const char *file, int ncpus)
{
  std::ifstream cpuinfo(file);
  if (cpuinfo.fail()) {
    return nullptr;
  }
  char line[MAX_LINELENGTH];
  int64_t* freqs = new int64_t[ncpus];
  for (int i = 0; i < ncpus; ++i) {
    freqs[i] = 0;
  }
  int processor = -1;

  while (cpuinfo.getline(line, sizeof(line))) {
    if (sscanf(line, "processor : %d", &processor) == 1) {
      continue;
    }
    float freq;
    if ((sscanf(line, "cpu MHz : %f", &freq) == 1) ||
        (sscanf(line, "clock         : %f", &freq) == 1)) {
      if (processor != -1 && processor < ncpus) {
         freqs[processor] = nearbyint(freq);
         processor = -1;
      }
    }
  }
  for (int i = 0; i < ncpus; ++i) {
    if (freqs[i] == 0) {
      delete[] freqs;
      return nullptr;
    }
  }
  return freqs;
}


bool HHVM_FUNCTION(mcrypt_enc_is_block_algorithm, const Resource& td) {
  auto pm = get_valid_mcrypt_resource(td);
  if (!pm) {
    return false;
  }

  return mcrypt_enc_is_block_algorithm(pm->m_td) == 1;
}


bool HHVM_FUNCTION(HH_global_key_exists, StringArg key) {
  return g_context->m_globalNVTable->lookup(key.get()) != nullptr;
}


size_t Frame::getName(char *result_buf, size_t result_len) {
  if (result_len <= 1) {
    return 0; // Insufficient result_bug. Bail!
  }

  // Add '@recurse_level' if required
  // NOTE: Dont use snprintf's return val as it is compiler dependent
  if (m_recursion) {
    snprintf(result_buf, result_len, "%s@%d", m_name, m_recursion);
  } else {
    snprintf(result_buf, result_len, "%s", m_name);
  }

  // Force null-termination at MAX
  result_buf[result_len - 1] = 0;
  return strlen(result_buf);
}


bool HHVM_FUNCTION(imagewbmp, const Resource& image,
    const String& filename /* = null_string */,
    int64_t foreground /* = -1 */) {
  return _php_image_output_ctx(image, filename, foreground, -1,
                               PHP_GDIMG_TYPE_WBM, "WBMP",
                               (void (*)())gdImageWBMPCtx);
}


static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) {
  return(__cvt(value, ndigit, decpt, sign, 1, 1));
}

#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 INT_NULL        ((int *)0)

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


String HHVM_FUNCTION(strval, const Variant& v) {
  return v.toString();
}


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


Variant preg_match_all(const String& pattern, const String& subject,
                       Variant* matches /* = nullptr */,
                       int flags /* = 0 */, int offset /* = 0 */) {
  return preg_match_all(pattern.get(), subject.get(), matches, flags, offset);
}


inline bool StringData::isFlat() const { return m_data == payload(); }


static void exif_iif_free(image_info_type *image_info, int section_index) {
  int  i;
  void *f; /* faster */

  if (image_info->info_list[section_index].count) {
    for (i=0; i < image_info->info_list[section_index].count; i++) {
      if ((f=image_info->info_list[section_index].list[i].name) != nullptr) {
        IM_FREE(f);
      }
      switch(image_info->info_list[section_index].list[i].format) {
      case TAG_FMT_SBYTE:
      case TAG_FMT_BYTE:
        /* in contrast to strings bytes do not need to allocate
           buffer for nullptr if length==0 */
        if (image_info->info_list[section_index].list[i].length<1)
          break;
      default:
      case TAG_FMT_UNDEFINED:
      case TAG_FMT_STRING:
        if ((f=image_info->info_list[section_index].list[i].value.s)
             != nullptr) {
          IM_FREE(f);
        }
        break;

      case TAG_FMT_USHORT:
      case TAG_FMT_ULONG:
      case TAG_FMT_URATIONAL:
      case TAG_FMT_SSHORT:
      case TAG_FMT_SLONG:
      case TAG_FMT_SRATIONAL:
      case TAG_FMT_SINGLE:
      case TAG_FMT_DOUBLE:
        /* nothing to do here */
        if (image_info->info_list[section_index].list[i].length > 1) {
          if ((f=image_info->info_list[section_index].list[i].value.list)
              != nullptr) {
            IM_FREE(f);
          }
        }
        break;
      }
    }
  }
  if (image_info->info_list[section_index].list) {
    IM_FREE(image_info->info_list[section_index].list);
  }
}


Variant HHVM_FUNCTION(exif_thumbnail, const String& filename,
                         int64_t& width,
                         int64_t& height,
                         int64_t& imagetype) {
  image_info_type ImageInfo;

  memset(&ImageInfo, 0, sizeof(ImageInfo));

  int ret = exif_read_file(&ImageInfo, filename.c_str(), 1, 0);
  if (ret==0) {
    exif_discard_imageinfo(&ImageInfo);
    return false;
  }

  if (!ImageInfo.Thumbnail.data || !ImageInfo.Thumbnail.size) {
    exif_discard_imageinfo(&ImageInfo);
    return false;
  }

  if (!ImageInfo.Thumbnail.width || !ImageInfo.Thumbnail.height) {
    if (!exif_scan_thumbnail(&ImageInfo)) {
      ImageInfo.Thumbnail.width = ImageInfo.Thumbnail.height = 0;
    }
  }
  width = ImageInfo.Thumbnail.width;
  height = ImageInfo.Thumbnail.height;
  imagetype = ImageInfo.Thumbnail.filetype;
  String str(ImageInfo.Thumbnail.data, ImageInfo.Thumbnail.size, CopyString);
  exif_discard_imageinfo(&ImageInfo);
  return str;
}


bool HHVM_FUNCTION(HH_is_php_array, const Variant& v) {
  // We want this set to false as this is meant to be the "this can receive
  // both PHP and Hack arrays" version of `is_array`.
  return is_php_array(v.asTypedValue());
}


static Variant new_socket_connect(const HostURL &hosturl, double timeout,
                                  const req::ptr<StreamContext>& streamctx,
                                  Variant& errnum, Variant& errstr) {
  int domain = AF_UNSPEC;
  int type = SOCK_STREAM;
  auto const& scheme = hosturl.getScheme();
  req::ptr<Socket> sock;
  req::ptr<SSLSocket> sslsock;
  std::string sockerr;
  int error;

  if (scheme == "udp" || scheme == "udg") {
    type = SOCK_DGRAM;
  }

  if (scheme == "unix" || scheme == "udg") {
    domain = AF_UNIX;
  }

  int fd = -1;
  if (domain == AF_UNIX) {
    sockaddr_storage sa_storage;
    struct sockaddr *sa_ptr;
    size_t sa_size;

    fd = socket(domain, type, 0);
    sock = req::make<StreamSocket>(
      fd, domain, hosturl.getHost().c_str(), hosturl.getPort(),
      0, empty_string_ref, false);

    if (!set_sockaddr(sa_storage, sock, hosturl.getHost(),
                      hosturl.getPort(), sa_ptr, sa_size)) {
      // set_sockaddr raises its own warning on failure
      return false;
    }
    if (connect_with_timeout(fd, sa_ptr, sa_size, timeout,
                             hosturl, sockerr, error) != 0) {
      SOCKET_ERROR(sock, sockerr.c_str(), error);
      errnum = sock->getLastError();
      errstr = HHVM_FN(socket_strerror)(sock->getLastError());
      return false;
    }
  } else {
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family   = domain;
    hints.ai_socktype = type;

    auto port = folly::to<std::string>(hosturl.getPort());
    auto host = hosturl.getHost();

    struct addrinfo *aiHead;
    int errcode = getaddrinfo(host.c_str(), port.c_str(), &hints, &aiHead);
    if (errcode != 0) {
      errstr = String(gai_strerror(errcode), CopyString);
      return false;
    }
    SCOPE_EXIT { freeaddrinfo(aiHead); };

    for (struct addrinfo *ai = aiHead; ai != nullptr; ai = ai->ai_next) {
      domain = ai->ai_family;
      fd = socket(domain, ai->ai_socktype, ai->ai_protocol);
      if (fd == -1) {
        continue;
      }

      if (connect_with_timeout(fd, ai->ai_addr, ai->ai_addrlen, timeout,
                               hosturl, sockerr, error) == 0) {
        break;
      }
      close(fd);
      fd = -1;
    }

    sslsock = SSLSocket::Create(fd, domain, hosturl, timeout, streamctx, false);
    if (sslsock) {
      sock = sslsock;
    } else {
      sock = req::make<StreamSocket>(fd,
                                     domain,
                                     hosturl.getHost().c_str(),
                                     hosturl.getPort(),
                                     0,
                                     empty_string_ref,
                                     false);
    }
  }

  if (!sock->valid()) {
    SOCKET_ERROR(sock,
        sockerr.empty() ? "unable to create socket" : sockerr.c_str(), error);
    errnum = sock->getLastError();
    errstr = HHVM_FN(socket_strerror)(sock->getLastError());
    return false;
  }

  if (sslsock && !sslsock->onConnect()) {
    raise_warning("Failed to enable crypto");
    return false;
  }

  return Variant(std::move(sock));
}


String rval(bool    key) const { return rvalImpl(key ? 1 : 0);}


Variant sockopen_impl(const HostURL &hosturl, Variant& errnum,
                      Variant& errstr, double timeout, bool persistent,
                      const Variant& context) {
  errnum = 0;
  errstr = empty_string();
  std::string key;
  if (persistent) {
    key = hosturl.getHostURL() + ":" +
          folly::to<std::string>(hosturl.getPort());

    // Check our persistent storage and determine if it's an SSLSocket
    // or just a regular socket.
    auto sockItr = s_sockets->find(key);
    if (sockItr != s_sockets->end()) {
      req::ptr<Socket> sock;
      if (auto sslSocketData =
          std::dynamic_pointer_cast<SSLSocketData>(sockItr->second)) {
        sock = req::make<SSLSocket>(sslSocketData);
      } else {
        sock = req::make<StreamSocket>(sockItr->second);
      }

      if (sock->getError() == 0 && sock->checkLiveness()) {
        return Variant(sock);
      }

      // socket had an error earlier, we need to close it, remove it from
      // persistent storage, and create a new one (in that order)
      sock->close();
      s_sockets->erase(sockItr);
    }
  }

  if (timeout < 0) {
    timeout = RequestInfo::s_requestInfo.getNoCheck()->
      m_reqInjectionData.getSocketDefaultTimeout();
  }

  req::ptr<StreamContext> streamctx;
  if (context.isResource()) {
    streamctx = cast<StreamContext>(context.toResource());
  }
  auto socket = new_socket_connect(hosturl, timeout, streamctx, errnum, errstr);
  if (!socket.isResource()) {
    return false;
  }

  if (persistent) {
    assertx(!key.empty());
    (*s_sockets)[key] = cast<Socket>(socket)->getData();
    assertx((*s_sockets)[key]);
  }

  return socket;
}


void Strobelight::surpriseAll() {
  RequestInfo::ExecutePerRequest(
    [] (RequestInfo* t) {
      // TODO: get a dedicated surprise flag to avoid colliding with xenon
      // Set the strobelight flag to collect a sample
      // TODO: isXenonActive() needs to check the request thread and not the
      // current thread (which may not even be a request)
      if (!isXenonActive()) {
        // Xenon has first crack at profiling requests. If a request
        // is marked as being profiled, we do not allow strobelight to
        // interfere with Xenon's profiling. In practice, collisions
        // should be extremely rare.
        t->m_reqInjectionData.setFlag(XenonSignalFlag);
      }
    }
  );
}


bool HHVM_FUNCTION(imagefilledrectangle, const Resource& image,
    int64_t x1, int64_t y1, int64_t x2, int64_t y2, int64_t color) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  gdImageFilledRectangle(im, x1, y1, x2, y2, color);
  return true;
}


  endFrameEx(const TypedValue* /*retvalue*/, const char* /*symbol*/) override {
    sample_check();
  }


Variant str_replace(const Variant& search, const Variant& replace,
                    const Variant& subject, int64_t& count) {
  Variant ret;
  count = 0;
  if (LIKELY(search.isString() && replace.isString() && subject.isString())) {
    int icount;
    // Short-cut for the most common (and simplest) case
    ret = string_replace(subject.asCStrRef(), search.asCStrRef(),
                         replace.asCStrRef(), icount, true);
    count = icount;
  } else {
    // search, replace, and subject can all be arrays. str_replace() reduces all
    // the valid combinations to multiple string_replace() calls.
    ret = str_replace(search, replace, subject, count, true);
  }
  return ret;
}


String HHVM_FUNCTION(socket_strerror,
                     int errnum) {
  /*
   * PHP5 encodes both the h_errno and errno values into a single int:
   * < -10000: transformed h_errno value
   * >= -10000: errno value
   */
  if (errnum < -10000) {
    errnum = (-errnum) - 10000;
#if HAVE_HSTRERROR
    return String(hstrerror(errnum), CopyString);
#endif
    return folly::format("Host lookup error {}", errnum).str();
  }

  return String(folly::errnoStr(errnum));
}


Variant HHVM_FUNCTION(imagecreatefromjpeg, const String& filename) {
  gdImagePtr im =
    _php_image_create_from(filename, -1, -1, -1, -1,
                           PHP_GDIMG_TYPE_JPG, "JPEG",
                           (gdImagePtr(*)())gdImageCreateFromJpeg,
                           (gdImagePtr(*)())gdImageCreateFromJpegCtx);
  if (im == nullptr) {
    return false;
  }
  return Variant(req::make<Image>(im));
}


void Profiler::endAllFrames() {
    while (m_stack) {
      endFrame(nullptr, nullptr, true);
    }
}


int64_t MemFile::readImpl(char *buffer, int64_t length) {
  assertx(m_len != -1);
  assertx(length > 0);
  assertx(m_cursor >= 0);
  int64_t remaining = m_len - m_cursor;
  if (remaining < length) length = remaining;
  if (length > 0) {
    memcpy(buffer, (const void *)(m_data + m_cursor), length);
    m_cursor += length;
    return length;
  }
  return 0;
}


bool HHVM_FUNCTION(HH_is_darray, const Variant& val) {
  return is_darray(val.asTypedValue());
}


void HHVM_FUNCTION(parse_str,
                   const String& str,
                   Array& arr) {
  arr = Array::CreateDArray();
  HttpProtocol::DecodeParameters(arr, str.data(), str.size());
}


static void check_socket_parameters(int &domain, int &type) {
  if (domain != AF_UNIX && domain != AF_INET6 && domain != AF_INET) {
    raise_warning("invalid socket domain [%d] specified for argument 1, "
                    "assuming AF_INET", domain);
    domain = AF_INET;
  }

  if (type > 10) {
    raise_warning("invalid socket type [%d] specified for argument 2, "
                    "assuming SOCK_STREAM", type);
    type = SOCK_STREAM;
  }
}


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


Variant HHVM_FUNCTION(socket_select,
                      Variant& read,
                      Variant& write,
                      Variant& except,
                      const Variant& vtv_sec,
                      int tv_usec /* = 0 */) {
  int count = 0;
  if (!read.isNull()) {
    if (!read.isArray()) {
      raise_warning("socket_select() expects parameter 1 to be array()");
      return init_null();
    }
    count += read.asCArrRef().size();
  }
  if (!write.isNull()) {
    if (!write.isArray()) {
      raise_warning("socket_select() expects parameter 2 to be array()");
      return init_null();
    }
    count += write.asCArrRef().size();
  }
  if (!except.isNull()) {
    if (!except.isArray()) {
      raise_warning("socket_select() expects parameter 3 to be array()");
      return init_null();
    }
    count += except.asCArrRef().size();
  }
  if (!count) {
    return false;
  }

  std::vector<pollfd> fds;
  fds.reserve(count);
  if (!read.isNull()) {
    sock_array_to_fd_set(read.asCArrRef(), fds, POLLIN);
  }
  if (!write.isNull()) {
    sock_array_to_fd_set(write.asCArrRef(), fds, POLLOUT);
  }
  if (!except.isNull()) {
    sock_array_to_fd_set(except.asCArrRef(), fds, POLLPRI);
  }
  if (fds.empty()) {
    raise_warning("no resource arrays were passed to select");
    return false;
  }

  IOStatusHelper io("socket_select");
  int timeout_ms = -1;
  if (!vtv_sec.isNull()) {
    timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000;
  }

  /* slight hack to support buffered data; if there is data sitting in the
   * read buffer of any of the streams in the read array, let's pretend
   * that we selected, but return only the readable sockets */
  if (!read.isNull()) {
    // sock_array_from_fd_set can set a sparsely indexed array, so
    // we use darray everywhere.
    auto hasData = Array::CreateDArray();
    IterateVNoInc(
      read.asCArrRef().get(),
      [&](TypedValue v) {
        assertx(v.m_type == KindOfResource);
        auto file = static_cast<File*>(v.m_data.pres->data());
        if (file->bufferedLen() > 0) {
          hasData.append(v);
        }
      }
    );
    if (hasData.size() > 0) {
      write = empty_darray();
      except = empty_darray();
      read = hasData;
      return hasData.size();
    }
  }

  int retval = poll(fds.data(), fds.size(), timeout_ms);
  if (retval == -1) {
    raise_warning("unable to select [%d]: %s", errno,
                  folly::errnoStr(errno).c_str());
    return false;
  }

  count = 0;
  int nfds = 0;
  if (!read.isNull()) {
    sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR|POLLHUP);
  }
  if (!write.isNull()) {
    sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR);
  }
  if (!except.isNull()) {
    sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR);
  }

  return count;
}


Variant HHVM_FUNCTION(convert_uuencode,
                      const String& data) {
  if (data.empty()) return false;
  return StringUtil::UUEncode(data);
}


  void *imRealloc(void *ptr, size_t size
#ifdef IM_MEMORY_CHECK
, int ln
#endif
  ) {
    assertx(m_mallocSize <= (size_t)RuntimeOption::ImageMemoryMaxBytes);

#ifdef IM_MEMORY_CHECK
    if (!ptr) return imMalloc(size, ln);
    if (!size) {
      imFree(ptr, ln);
      return nullptr;
    }
#else
    if (!ptr) return imMalloc(size);
    if (!size) {
      imFree(ptr);
      return nullptr;
    }
#endif
    void *sizePtr = (char *)ptr - sizeof(size);
    size_t oldSize = 0;
    if (ptr) memcpy(&oldSize, sizePtr, sizeof(oldSize));
    ssize_t diff = size - oldSize;
    void *tmp;

#ifdef IM_MEMORY_CHECK
    void *lnPtr = (char *)sizePtr - sizeof(ln);
    if (size > (size_t)RuntimeOption::ImageMemoryMaxBytes ||
        m_mallocSize + diff > (size_t)RuntimeOption::ImageMemoryMaxBytes ||
        !(tmp = local_realloc(lnPtr, sizeof(ln) + sizeof(size) + size))) {
      int count = m_alloced.erase(ptr);
      assertx(count == 1); // double free on failure
      local_free(lnPtr);
      return nullptr;
    }
    memcpy(tmp, &ln, sizeof(ln));
    memcpy((char*)tmp + sizeof(ln), &size, sizeof(size));
    m_mallocSize += diff;
    if (tmp != lnPtr) {
      int count = m_alloced.erase(lnPtr);
      assertx(count == 1);
      m_alloced.insert(tmp);
    }
    return ((char *)tmp + sizeof(ln) + sizeof(size));
#else
    if (size > (size_t)RuntimeOption::ImageMemoryMaxBytes ||
        m_mallocSize + diff > (size_t)RuntimeOption::ImageMemoryMaxBytes ||
        !(tmp = local_realloc(sizePtr, sizeof(size) + size))) {
      local_free(sizePtr);
      return nullptr;
    }
    memcpy(tmp, &size, sizeof(size));
    m_mallocSize += diff;
    return ((char *)tmp + sizeof(size));
#endif
  }


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;


char *php_gcvt(double value, int ndigit, char dec_point,
                      char exponent, char *buf) {
  char *digits, *dst, *src;
  int i, decpt, sign;

  digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, nullptr);
  if (decpt == 9999) {
    /*
     * Infinity or NaN, convert to inf or nan with sign.
     * We assume the buffer is at least ndigit long.
     */
    snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "",
             *digits == 'I' ? "INF" : "NAN");
    zend_freedtoa(digits);
    return (buf);
  }

  dst = buf;
  if (sign) {
    *dst++ = '-';
  }

  if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
    /* exponential format (e.g. 1.2345e+13) */
    if (--decpt < 0) {
      sign = 1;
      decpt = -decpt;
    } else {
      sign = 0;
    }
    src = digits;
    *dst++ = *src++;
    *dst++ = dec_point;
    if (*src == '\0') {
      *dst++ = '0';
    } else {
      do {
        *dst++ = *src++;
      } while (*src != '\0');
    }
    *dst++ = exponent;
    if (sign) {
      *dst++ = '-';
    } else {
      *dst++ = '+';
    }
    if (decpt < 10) {
      *dst++ = '0' + decpt;
      *dst = '\0';
    } else {
      /* XXX - optimize */
      for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
        continue;
      dst[i + 1] = '\0';
      while (decpt != 0) {
        dst[i--] = '0' + decpt % 10;
        decpt /= 10;
      }
    }
  } else if (decpt < 0) {
    /* standard format 0. */
    *dst++ = '0';   /* zero before decimal point */
    *dst++ = dec_point;
    do {
      *dst++ = '0';
    } while (++decpt < 0);
    src = digits;
    while (*src != '\0') {
      *dst++ = *src++;
    }
    *dst = '\0';
  } else {
    /* standard format */
    for (i = 0, src = digits; i < decpt; i++) {
      if (*src != '\0') {
        *dst++ = *src++;
      } else {
        *dst++ = '0';
      }
    }
    if (*src != '\0') {
      if (src == digits) {
        *dst++ = '0';   /* zero before decimal point */
      }
      *dst++ = dec_point;
      for (i = decpt; digits[i] != '\0'; i++) {
        *dst++ = digits[i];
      }
    }
    *dst = '\0';
  }
  zend_freedtoa(digits);
  return (buf);
}

#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 serialize_keep_dvarrays(const Variant& value) {
  SerializeOptions opts;
  opts.keepDVArrays = true;
  return serialize_impl(value, opts);
}


bool MemFile::eof() {
  assertx(m_len != -1);
  int64_t avail = bufferedLen();
  if (avail > 0) {
    return false;
  }
  return m_cursor == m_len;
}


CountMap() : count(0), wall_time(0), cpu(0), memory(0), peak_memory(0) {}


static int* create_offset_array(const pcre_cache_entry* pce,
                                int& size_offsets) {
  /* Allocate memory for the offsets array */
  size_offsets = pce->num_subpats * 3;
  return (int *)req::malloc_noptrs(size_offsets * sizeof(int));
}


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


Variant HHVM_FUNCTION(imagecolorat,
    const Resource& image, int64_t x, int64_t y) {
  gdImagePtr im = get_valid_image_resource(image);
  if (!im) return false;
  if (gdImageTrueColor(im)) {
    if (im->tpixels && gdImageBoundsSafe(im, x, y)) {
      return gdImageTrueColorPixel(im, x, y);
    } else {
      raise_notice("%" PRId64 ",%" PRId64 " is out of bounds", x, y);
      return false;
    }
  } else {
    if (im->pixels && gdImageBoundsSafe(im, x, y)) {
      return (im->pixels[y][x]);
    } else {
      raise_notice("%" PRId64 ",%" PRId64 " is out of bounds", x, y);
      return false;
    }
  }
}


void Profiler::returnVals(phpret& ret, const Name& name, const Counts& counts,
                          int flags, int64_t MHz)
{
    ArrayInit arr(5, ArrayInit::Map{});
    arr.set(s_ct,  counts.count);
    arr.set(s_wt,  to_usec(counts.wall_time, MHz));
    if (flags & TrackCPU) {
      arr.set(s_cpu, to_usec(counts.cpu, MHz, true));
    }
    if (flags & TrackMemory) {
      arr.set(s_mu,  counts.memory);
      arr.set(s_pmu, counts.peak_memory);
    } else if (flags & TrackMalloc) {
      arr.set(s_alloc, counts.memory);
      arr.set(s_free, counts.peak_memory);
    }
    ret.set(String(name), arr.toArray());
}


inline folly::MutableStringPiece StringData::bufferSlice() {
  assertx(!isImmutable());
  return folly::MutableStringPiece{mutableData(), capacity()};
}


void f_hotprofiler_enable(int ikind) {
  auto kind = static_cast<ProfilerKind>(ikind);
  long flags = 0;
  if (kind == ProfilerKind::Hierarchical) {
    flags = NoTrackBuiltins;
  } else if (kind == ProfilerKind::Memory) {
    kind = ProfilerKind::Hierarchical;
    flags = NoTrackBuiltins | TrackMemory;
  }
  if (RuntimeOption::EnableHotProfiler) {
    s_profiler_factory->start(kind, flags);
  }
}


size_t Frame::getStack(int level, char *result_buf, size_t result_len) {
  // End recursion if we dont need deeper levels or
  // we dont have any deeper levels
  if (!m_parent || level <= 1) {
    return getName(result_buf, result_len);
  }

  // Take care of all ancestors first
  size_t len = m_parent->getStack(level - 1, result_buf, result_len);
  if (result_len < (len + HP_STACK_DELIM_LEN)) {
    return len; // Insufficient result_buf. Bail out!
  }

  // Add delimiter only if entry had ancestors
  if (len) {
    strncat(result_buf + len, HP_STACK_DELIM, result_len - len);
    len += HP_STACK_DELIM_LEN;
  }

  // Append the current function name
  return len + getName(result_buf + len, result_len - len);
}


bool HHVM_FUNCTION(socket_set_block,
                   const Resource& socket) {
  return cast<Socket>(socket)->setBlocking(true);
}


Variant HHVM_FUNCTION(var_export, const Variant& expression,
                                  bool ret /* = false */) {
  Variant res;
  try {
    VariableSerializer vs(VariableSerializer::Type::VarExport);
    if (ret) {
      res = vs.serialize(expression, ret);
    } else {
      vs.serialize(expression, ret);
      res = true;
    }
  } catch (StringBufferLimitException& e) {
    raise_notice("var_export() exceeded max bytes limit");
  }
  return res;
}


bool HHVM_FUNCTION(imagedestroy, const Resource& image) {
  auto img_res = cast<Image>(image);
  gdImagePtr im = img_res->get();
  if (!im) return false;
  img_res->reset();
  return true;
}


static void sock_array_to_fd_set(const Array& sockets, std::vector<pollfd>& fds,
                                 const short flag) {
  IterateVNoInc(
    sockets.get(),
    [&](TypedValue v) {
      assertx(v.m_type == KindOfResource);
      auto const intfd = static_cast<File*>(v.m_data.pres->data())->fd();
      if (intfd < 0) {
        raise_warning(
          "cannot represent a stream of type user-space as a file descriptor"
        );
        return;
      }
      fds.emplace_back();
      auto& fd = fds.back();
      fd.fd = intfd;
      fd.events = flag;
      fd.revents = 0;
    }
  );
}