void VariableSerializer::writeArrayHeader()

in hphp/runtime/base/variable-serializer.cpp [837:1088]


void VariableSerializer::writeArrayHeader(int size, bool isVectorData,
                                          VariableSerializer::ArrayKind kind) {
  m_arrayInfos.push_back(ArrayInfo());
  ArrayInfo &info = m_arrayInfos.back();
  info.first_element = true;
  info.indent_delta = 0;
  info.size = size;

  switch (m_type) {
  case Type::DebuggerDump:
  case Type::PrintR:
    if (!m_rsrcName.empty()) {
      m_buf->append("Resource id #");
      m_buf->append(m_rsrcId);
      if (m_type == Type::DebuggerDump) {
        m_buf->append(" of type ");
        m_buf->append(m_rsrcName);
      }
      break;
    } else if (!m_objClass.empty()) {
      m_buf->append(m_objClass);
      m_buf->append(" Object\n");
    } else {
      switch (kind) {
      case ArrayKind::Dict:
        m_buf->append("Dict\n");
        break;
      case ArrayKind::Vec:
        m_buf->append("Vec\n");
        break;
      case ArrayKind::Keyset:
        m_buf->append("Keyset\n");
        break;
      case ArrayKind::PHP:
      case ArrayKind::VArray:
      case ArrayKind::DArray:
      case ArrayKind::MarkedVArray:
      case ArrayKind::MarkedDArray:
        m_buf->append("Array\n");
        break;
      }
    }
    if (m_indent > 0) {
      m_indent += 4;
      indent();
    }
    m_buf->append("(\n");
    m_indent += (info.indent_delta = 4);
    break;
  case Type::VarExport:
  case Type::PHPOutput:
    if (m_indent > 0 && m_rsrcName.empty() && m_keyPrinted) {
      m_buf->append('\n');
      indent();
    }
    if (!m_objClass.empty()) {
      m_buf->append(m_objClass);
      if (m_objCode == 'O') {
        m_buf->append("::__set_state(darray[\n");
      } else {
        assertx(m_objCode == 'V' || m_objCode == 'K');
        m_buf->append(" {\n");
      }
    } else if (!m_rsrcName.empty()) {
      m_buf->append("NULL");
    } else {
      switch (kind) {
      case ArrayKind::Dict:
        m_buf->append("dict [\n");
        break;
      case ArrayKind::Vec:
        m_buf->append("vec [\n");
        break;
      case ArrayKind::Keyset:
        m_buf->append("keyset [\n");
        break;
      case ArrayKind::PHP:
        m_buf->append("array (\n");
        break;
      case ArrayKind::VArray: {
        auto const dvarray = RO::EvalHackArrDVArrVarExport ||
                             m_type == Type::PHPOutput;
        m_buf->append(dvarray ? "varray [\n" : "array (\n");
        break;
      }
      case ArrayKind::DArray: {
        auto const dvarray = RO::EvalHackArrDVArrVarExport ||
                             m_type == Type::PHPOutput;
        m_buf->append(dvarray ? "darray [\n" : "array (\n");
        break;
      }
      case ArrayKind::MarkedVArray:
      case ArrayKind::MarkedDArray:
        always_assert(0);
      }
    }
    m_indent += (info.indent_delta = 2);
    break;
  case Type::VarDump:
  case Type::DebugDump:
    indent();
    if (!m_rsrcName.empty()) {
      m_buf->append("resource(");
      m_buf->append(m_rsrcId);
      m_buf->append(") of type (");
      m_buf->append(m_rsrcName);
      m_buf->append(")\n");
      break;
    } else if (!m_objClass.empty()) {
      m_buf->append("object(");
      m_buf->append(m_objClass);
      m_buf->append(") ");
    } else {
      auto const header = [&]() {
        switch (kind) {
          case ArrayKind::Dict:
            return "dict";
          case ArrayKind::Vec:
            return "vec";
          case ArrayKind::Keyset:
            return "keyset";
          case ArrayKind::PHP:
            return "array";
          case ArrayKind::VArray:
          case ArrayKind::MarkedVArray:
            return "varray";
          case ArrayKind::DArray:
          case ArrayKind::MarkedDArray:
            return "darray";
        }
        not_reached();
      }();
      m_buf->append(header);
    }
    m_buf->append('(');
    m_buf->append(size);
    m_buf->append(')');

    // ...so to strictly follow PHP's output
    if (m_type == Type::VarDump) {
      m_buf->append(' ');
    } else {
      writeRefCount();
    }

    m_buf->append("{\n");
    m_indent += (info.indent_delta = 2);
    break;
  case Type::Serialize:
  case Type::Internal:
  case Type::APCSerialize:
  case Type::DebuggerSerialize:
    if (!m_rsrcName.empty() && m_type == Type::DebuggerSerialize) {
      m_buf->append("L:");
      m_buf->append(m_rsrcId);
      m_buf->append(":");
      m_buf->append((int)m_rsrcName.size());
      m_buf->append(":\"");
      m_buf->append(m_rsrcName);
      m_buf->append("\"{");
    } else if (!m_objClass.empty()) {
      m_buf->append(m_objCode);
      m_buf->append(":");
      m_buf->append((int)m_objClass.size());
      m_buf->append(":\"");
      m_buf->append(m_objClass);
      m_buf->append("\":");
      m_buf->append(size);
      m_buf->append(":{");
    } else {
      switch (kind) {
      case ArrayKind::Dict:
        m_buf->append("D:");
        break;
      case ArrayKind::Vec:
        m_buf->append("v:");
        break;
      case ArrayKind::MarkedVArray:
        m_buf->append("x:");
        break;
      case ArrayKind::MarkedDArray:
        m_buf->append("X:");
        break;
      case ArrayKind::Keyset:
        m_buf->append("k:");
        break;
      case ArrayKind::PHP:
        m_buf->append("a:");
        break;
      case ArrayKind::VArray:
        m_buf->append("y:");
        break;
      case ArrayKind::DArray:
        m_buf->append("Y:");
        break;
      }
      m_buf->append(size);
      m_buf->append(":{");
    }
    break;
  case Type::JSON:
    info.is_vector =
      (m_objClass.empty() || m_objCode == 'V' || m_objCode == 'K') &&
      isVectorData &&
      kind != ArrayKind::Dict;

    if (info.is_vector && m_type == Type::JSON) {
      info.is_vector = (m_option & k_JSON_FORCE_OBJECT)
                       ? false : info.is_vector;
    }

    if (info.is_vector || kind == ArrayKind::Keyset) {
      if (UNLIKELY(RuntimeOption::EvalHackArrCompatSerializeNotices) &&
          kind == ArrayKind::DArray) {
        if (size == 0 && m_edWarn && !m_hasEDWarned) {
          raise_hackarr_compat_notice("JSON encoding empty darray");
          m_hasEDWarned = true;
        } else if (size != 0 && m_vdWarn && !m_hasVDWarned) {
          raise_hackarr_compat_notice("JSON encoding vec-like darray");
          m_hasVDWarned = true;
        }
      }
      m_buf->append('[');
    } else {
      if (UNLIKELY(RuntimeOption::EvalHackArrCompatSerializeNotices) &&
          kind == ArrayKind::DArray && m_ddWarn && !m_hasDDWarned) {
        raise_hackarr_compat_notice("JSON encoding dict-like darray");
        m_hasDDWarned = true;
      }
      m_buf->append('{');
    }

    if (m_type == Type::JSON && (m_option & k_JSON_PRETTY_PRINT) &&
        info.size > 0) {
      m_buf->append("\n");
      m_indent += (info.indent_delta = 4);
    }

    break;
  default:
    assertx(false);
    break;
  }

  // ...so we don't mess up next array output
  if (!m_objClass.empty() || !m_rsrcName.empty()) {
    m_objClass.clear();
    info.is_object = true;
  } else {
    info.is_object = false;
  }
}