Example #1
0
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval** value, HashTable* fieldspec) {
    // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload.
    switch (thrift_typeID) {
    case T_STOP:
    case T_VOID:
        return;
    case T_STRUCT: {
        TSRMLS_FETCH();
        if (Z_TYPE_PP(value) != IS_OBJECT) {
            throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA);
        }
        zval* spec = zend_read_static_property(zend_get_class_entry(*value TSRMLS_CC), "_TSPEC", 6, false TSRMLS_CC);
        binary_serialize_spec(*value, transport, Z_ARRVAL_P(spec));
    }
    return;
    case T_BOOL:
        if (Z_TYPE_PP(value) != IS_BOOL) convert_to_boolean(*value);
        transport.writeI8(Z_BVAL_PP(value) ? 1 : 0);
        return;
    case T_BYTE:
        if (Z_TYPE_PP(value) != IS_LONG) convert_to_long(*value);
        transport.writeI8(Z_LVAL_PP(value));
        return;
    case T_I16:
        if (Z_TYPE_PP(value) != IS_LONG) convert_to_long(*value);
        transport.writeI16(Z_LVAL_PP(value));
        return;
    case T_I32:
        if (Z_TYPE_PP(value) != IS_LONG) convert_to_long(*value);
        transport.writeI32(Z_LVAL_PP(value));
        return;
    case T_I64:
    case T_U64:
        if (Z_TYPE_PP(value) != IS_LONG) convert_to_long(*value);
        transport.writeI64(Z_LVAL_PP(value));
        return;
    case T_DOUBLE: {
        union {
            int64_t c;
            double d;
        } a;
        if (Z_TYPE_PP(value) != IS_DOUBLE) convert_to_double(*value);
        a.d = Z_DVAL_PP(value);
        transport.writeI64(a.c);
    }
    return;
    //case T_UTF7:
    case T_UTF8:
    case T_UTF16:
    case T_STRING:
        if (Z_TYPE_PP(value) != IS_STRING) convert_to_string(*value);
        transport.writeString(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
        return;
    case T_MAP: {
        if (Z_TYPE_PP(value) != IS_ARRAY) convert_to_array(*value);
        if (Z_TYPE_PP(value) != IS_ARRAY) {
            throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA);
        }
        HashTable* ht = Z_ARRVAL_PP(value);
        zval** val_ptr;

        zend_hash_find(fieldspec, "ktype", 6, (void**)&val_ptr);
        if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
        uint8_t keytype = Z_LVAL_PP(val_ptr);
        transport.writeI8(keytype);
        zend_hash_find(fieldspec, "vtype", 6, (void**)&val_ptr);
        if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
        uint8_t valtype = Z_LVAL_PP(val_ptr);
        transport.writeI8(valtype);

        zend_hash_find(fieldspec, "val", 4, (void**)&val_ptr);
        HashTable* valspec = Z_ARRVAL_PP(val_ptr);

        transport.writeI32(zend_hash_num_elements(ht));
        HashPosition key_ptr;
        for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
            binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
            binary_serialize(valtype, transport, val_ptr, valspec);
        }
    }
    return;
    case T_LIST: {
        if (Z_TYPE_PP(value) != IS_ARRAY) convert_to_array(*value);
        if (Z_TYPE_PP(value) != IS_ARRAY) {
            throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA);
        }
        HashTable* ht = Z_ARRVAL_PP(value);
        zval** val_ptr;

        zend_hash_find(fieldspec, "etype", 6, (void**)&val_ptr);
        if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
        uint8_t valtype = Z_LVAL_PP(val_ptr);
        transport.writeI8(valtype);

        zend_hash_find(fieldspec, "elem", 5, (void**)&val_ptr);
        HashTable* valspec = Z_ARRVAL_PP(val_ptr);

        transport.writeI32(zend_hash_num_elements(ht));
        HashPosition key_ptr;
        for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
            binary_serialize(valtype, transport, val_ptr, valspec);
        }
    }
    return;
    case T_SET: {
        if (Z_TYPE_PP(value) != IS_ARRAY) convert_to_array(*value);
        if (Z_TYPE_PP(value) != IS_ARRAY) {
            throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA);
        }
        HashTable* ht = Z_ARRVAL_PP(value);
        zval** val_ptr;

        zend_hash_find(fieldspec, "etype", 6, (void**)&val_ptr);
        if (Z_TYPE_PP(val_ptr) != IS_LONG) convert_to_long(*val_ptr);
        uint8_t keytype = Z_LVAL_PP(val_ptr);
        transport.writeI8(keytype);

        transport.writeI32(zend_hash_num_elements(ht));
        HashPosition key_ptr;
        for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr); zend_hash_get_current_data_ex(ht, (void**)&val_ptr, &key_ptr) == SUCCESS; zend_hash_move_forward_ex(ht, &key_ptr)) {
            binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
        }
    }
    return;
    };
    char errbuf[128];
    sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
    throw_tprotocolexception(errbuf, INVALID_DATA);
}
Example #2
0
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport,
                      const Variant& value, const Array& fieldspec) {
  // At this point the typeID (and field num, if applicable) should've already
  // been written to the output so all we need to do is write the payload.
  switch (thrift_typeID) {
    case T_STOP:
    case T_VOID:
      return;
    case T_STRUCT: {
      if (!value.is(KindOfObject)) {
        throw_tprotocolexception("Attempt to send non-object "
                                 "type as a T_STRUCT", INVALID_DATA);
      }
      binary_serialize_spec(value.toObject(), transport,
                            HHVM_FN(hphp_get_static_property)(value.toObject()->
                                                       getClassName(),
                                                       s_TSPEC,
                                                       false).toArray());
    } return;
    case T_BOOL:
      transport.writeI8(value.toBoolean() ? 1 : 0);
      return;
    case T_BYTE:
      transport.writeI8(value.toByte());
      return;
    case T_I16:
      transport.writeI16(value.toInt16());
      return;
    case T_I32:
      transport.writeI32(value.toInt32());
      return;
    case T_I64:
    case T_U64:
      transport.writeI64(value.toInt64());
      return;
    case T_DOUBLE: {
      union {
        int64_t c;
        double d;
      } a;
      a.d = value.toDouble();
      transport.writeI64(a.c);
    } return;
    case T_FLOAT: {
      union {
        int32_t c;
        float d;
      } a;
      a.d = (float)value.toDouble();
      transport.writeI32(a.c);
    } return;
    //case T_UTF7:
    case T_UTF8:
    case T_UTF16:
    case T_STRING: {
        String sv = value.toString();
        transport.writeString(sv.data(), sv.size());
    } return;
    case T_MAP: {
      Array ht = value.toArray();
      uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_ktype,
                                         AccessFlags::Error_Key).toByte();
      transport.writeI8(keytype);
      uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_vtype,
                                         AccessFlags::Error_Key).toByte();
      transport.writeI8(valtype);

      Array valspec = fieldspec.rvalAt(PHPTransport::s_val,
                                       AccessFlags::Error_Key).toArray();

      transport.writeI32(ht.size());
      for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) {
        binary_serialize_hashtable_key(keytype, transport, key_ptr.first());
        binary_serialize(valtype, transport, key_ptr.second(), valspec);
      }
    } return;
    case T_LIST: {
      Array ht = value.toArray();
      Variant val;

      uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_etype,
                                         AccessFlags::Error_Key).toInt64();
      transport.writeI8(valtype);
      Array valspec = fieldspec.rvalAt(PHPTransport::s_elem,
                                       AccessFlags::Error_Key).toArray();
      transport.writeI32(ht.size());
      for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) {
        binary_serialize(valtype, transport, key_ptr.second(), valspec);
      }
    } return;
    case T_SET: {
      Array ht = value.toArray();

      uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_etype,
                                         AccessFlags::Error_Key).toByte();
      transport.writeI8(keytype);

      transport.writeI32(ht.size());
      for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) {
        binary_serialize_hashtable_key(keytype, transport, key_ptr.first());
      }
    } return;
  };
  char errbuf[128];
  sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID);
  throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA);
}
Example #3
0
static
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, zval* value, HashTable* fieldspec) {
  // At this point the typeID (and field num, if applicable) should've already been written to the output so all we need to do is write the payload.
  switch (thrift_typeID) {
    case T_STOP:
    case T_VOID:
      return;
    case T_STRUCT: {
      if (Z_TYPE_P(value) != IS_OBJECT) {
        throw_tprotocolexception("Attempt to send non-object type as a T_STRUCT", INVALID_DATA);
      }
      zval* spec = zend_read_static_property(Z_OBJCE_P(value), "_TSPEC", sizeof("_TSPEC")-1, false);
      if (Z_TYPE_P(spec) != IS_ARRAY) {
        throw_tprotocolexception("Attempt to send non-Thrift object as a T_STRUCT", INVALID_DATA);
      }
      binary_serialize_spec(value, transport, Z_ARRVAL_P(spec));
    } return;
    case T_BOOL:
      if (!zval_is_bool(value)) convert_to_boolean(value);
      transport.writeI8(Z_TYPE_INFO_P(value) == IS_TRUE ? 1 : 0);
      return;
    case T_BYTE:
      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
      transport.writeI8(Z_LVAL_P(value));
      return;
    case T_I16:
      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
      transport.writeI16(Z_LVAL_P(value));
      return;
    case T_I32:
      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
      transport.writeI32(Z_LVAL_P(value));
      return;
    case T_I64:
    case T_U64: {
      int64_t l_data;
#if defined(_LP64) || defined(_WIN64)
      if (Z_TYPE_P(value) != IS_LONG) convert_to_long(value);
      l_data = Z_LVAL_P(value);
#else
      if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value);
      l_data = (int64_t)Z_DVAL_P(value);
#endif
      transport.writeI64(l_data);
    } return;
    case T_DOUBLE: {
      union {
        int64_t c;
        double d;
      } a;
      if (Z_TYPE_P(value) != IS_DOUBLE) convert_to_double(value);
      a.d = Z_DVAL_P(value);
      transport.writeI64(a.c);
    } return;
    case T_UTF8:
    case T_UTF16:
    case T_STRING:
      if (Z_TYPE_P(value) != IS_STRING) convert_to_string(value);
      transport.writeString(Z_STRVAL_P(value), Z_STRLEN_P(value));
      return;
    case T_MAP: {
      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
      if (Z_TYPE_P(value) != IS_ARRAY) {
        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_MAP)", INVALID_DATA);
      }
      HashTable* ht = Z_ARRVAL_P(value);
      zval* val_ptr;

      val_ptr = zend_hash_str_find(fieldspec, "ktype", sizeof("ktype")-1);
      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
      uint8_t keytype = Z_LVAL_P(val_ptr);
      transport.writeI8(keytype);
      val_ptr = zend_hash_str_find(fieldspec, "vtype", sizeof("vtype")-1);
      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
      uint8_t valtype = Z_LVAL_P(val_ptr);
      transport.writeI8(valtype);

      val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1);
      HashTable* valspec = Z_ARRVAL_P(val_ptr);

      transport.writeI32(zend_hash_num_elements(ht));
      HashPosition key_ptr;
      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
           (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
           zend_hash_move_forward_ex(ht, &key_ptr)) {
        binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
        binary_serialize(valtype, transport, val_ptr, valspec);
      }
    } return;
    case T_LIST: {
      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
      if (Z_TYPE_P(value) != IS_ARRAY) {
        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_LIST)", INVALID_DATA);
      }
      HashTable* ht = Z_ARRVAL_P(value);
      zval* val_ptr;

      val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1);
      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
      uint8_t valtype = Z_LVAL_P(val_ptr);
      transport.writeI8(valtype);

      val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1);
      HashTable* valspec = Z_ARRVAL_P(val_ptr);

      transport.writeI32(zend_hash_num_elements(ht));
      HashPosition key_ptr;
      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
           (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
           zend_hash_move_forward_ex(ht, &key_ptr)) {
        binary_serialize(valtype, transport, val_ptr, valspec);
      }
    } return;
    case T_SET: {
      if (Z_TYPE_P(value) != IS_ARRAY) convert_to_array(value);
      if (Z_TYPE_P(value) != IS_ARRAY) {
        throw_tprotocolexception("Attempt to send an incompatible type as an array (T_SET)", INVALID_DATA);
      }
      HashTable* ht = Z_ARRVAL_P(value);
      zval* val_ptr;

      val_ptr = zend_hash_str_find(fieldspec, "etype", sizeof("etype")-1);
      if (Z_TYPE_P(val_ptr) != IS_LONG) convert_to_long(val_ptr);
      uint8_t keytype = Z_LVAL_P(val_ptr);
      transport.writeI8(keytype);

      transport.writeI32(zend_hash_num_elements(ht));
      HashPosition key_ptr;
      for (zend_hash_internal_pointer_reset_ex(ht, &key_ptr);
           (val_ptr = zend_hash_get_current_data_ex(ht, &key_ptr)) != nullptr;
           zend_hash_move_forward_ex(ht, &key_ptr)) {
        binary_serialize_hashtable_key(keytype, transport, ht, key_ptr);
      }
    } return;
  };

  char errbuf[128];
  snprintf(errbuf, 128, "Unknown thrift typeID %d", thrift_typeID);
  throw_tprotocolexception(errbuf, INVALID_DATA);
}