static VALUE get_value(const char* buffer, int* position, int type) { VALUE value; switch (type) { case -1: { value = rb_class_new_instance(0, NULL, MinKey); break; } case 1: { double d; memcpy(&d, buffer + *position, 8); value = rb_float_new(d); *position += 8; break; } case 2: case 13: { int value_length; value_length = *(int*)(buffer + *position) - 1; *position += 4; value = STR_NEW(buffer + *position, value_length); *position += value_length + 1; break; } case 3: { int size; memcpy(&size, buffer + *position, 4); if (strcmp(buffer + *position + 5, "$ref") == 0) { // DBRef int offset = *position + 10; VALUE argv[2]; int collection_length = *(int*)(buffer + offset) - 1; char id_type; offset += 4; argv[0] = STR_NEW(buffer + offset, collection_length); offset += collection_length + 1; id_type = buffer[offset]; offset += 5; argv[1] = get_value(buffer, &offset, (int)id_type); value = rb_class_new_instance(2, argv, DBRef); } else { value = elements_to_hash(buffer + *position + 4, size - 5); } *position += size; break; } case 4: { int size, end; memcpy(&size, buffer + *position, 4); end = *position + size - 1; *position += 4; value = rb_ary_new(); while (*position < end) { int type = (int)buffer[(*position)++]; int key_size = (int)strlen(buffer + *position); VALUE to_append; *position += key_size + 1; // just skip the key, they're in order. to_append = get_value(buffer, position, type); rb_ary_push(value, to_append); } (*position)++; break; } case 5: { int length, subtype; VALUE data, st; VALUE argv[2]; memcpy(&length, buffer + *position, 4); subtype = (unsigned char)buffer[*position + 4]; if (subtype == 2) { data = rb_str_new(buffer + *position + 9, length - 4); } else { data = rb_str_new(buffer + *position + 5, length); } st = INT2FIX(subtype); argv[0] = data; argv[1] = st; value = rb_class_new_instance(2, argv, Binary); *position += length + 5; break; } case 6: { value = Qnil; break; } case 7: { VALUE str = rb_str_new(buffer + *position, 12); VALUE oid = rb_funcall(str, unpack_method, 1, rb_str_new2("C*")); value = rb_class_new_instance(1, &oid, ObjectId); *position += 12; break; } case 8: { value = buffer[(*position)++] ? Qtrue : Qfalse; break; } case 9: { int64_t millis; memcpy(&millis, buffer + *position, 8); // Support 64-bit time values in 32 bit environments in Ruby > 1.9 // Note: rb_time_num_new is not available pre Ruby 1.9 #if RUBY_API_VERSION_CODE >= 10900 #define add(x,y) (rb_funcall((x), '+', 1, (y))) #define mul(x,y) (rb_funcall((x), '*', 1, (y))) #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y))) VALUE d, timev; d = LL2NUM(1000LL); timev = add(LL2NUM(millis / 1000), quo(LL2NUM(millis % 1000), d)); value = rb_time_num_new(timev, Qnil); #else value = rb_time_new(millis / 1000, (millis % 1000) * 1000); #endif value = rb_funcall(value, utc_method, 0); *position += 8; break; } case 10: { value = Qnil; break; } case 11: { int pattern_length = (int)strlen(buffer + *position); VALUE pattern = STR_NEW(buffer + *position, pattern_length); int flags_length, flags = 0, i = 0; VALUE argv[3]; *position += pattern_length + 1; flags_length = (int)strlen(buffer + *position); for (i = 0; i < flags_length; i++) { char flag = buffer[*position + i]; if (flag == 'i') { flags |= IGNORECASE; } else if (flag == 'm') { flags |= MULTILINE; } else if (flag == 's') { flags |= MULTILINE; } else if (flag == 'x') { flags |= EXTENDED; } } argv[0] = pattern; argv[1] = INT2FIX(flags); value = rb_class_new_instance(2, argv, Regexp); *position += flags_length + 1; break; } case 12: { int collection_length; VALUE collection, str, oid, id, argv[2]; collection_length = *(int*)(buffer + *position) - 1; *position += 4; collection = STR_NEW(buffer + *position, collection_length); *position += collection_length + 1; str = rb_str_new(buffer + *position, 12); oid = rb_funcall(str, unpack_method, 1, rb_str_new2("C*")); id = rb_class_new_instance(1, &oid, ObjectId); *position += 12; argv[0] = collection; argv[1] = id; value = rb_class_new_instance(2, argv, DBRef); break; } case 14: { int value_length; memcpy(&value_length, buffer + *position, 4); value = ID2SYM(rb_intern(buffer + *position + 4)); *position += value_length + 4; break; } case 15: { int code_length, scope_size; VALUE code, scope, argv[2]; *position += 4; code_length = *(int*)(buffer + *position) - 1; *position += 4; code = STR_NEW(buffer + *position, code_length); *position += code_length + 1; memcpy(&scope_size, buffer + *position, 4); scope = elements_to_hash(buffer + *position + 4, scope_size - 5); *position += scope_size; argv[0] = code; argv[1] = scope; value = rb_class_new_instance(2, argv, Code); break; } case 16: { int i; memcpy(&i, buffer + *position, 4); value = LL2NUM(i); *position += 4; break; } case 17: { unsigned int sec, inc; VALUE argv[2]; memcpy(&inc, buffer + *position, 4); memcpy(&sec, buffer + *position + 4, 4); argv[0] = UINT2NUM(sec); argv[1] = UINT2NUM(inc); value = rb_class_new_instance(2, argv, Timestamp); *position += 8; break; } case 18: { long long ll; memcpy(&ll, buffer + *position, 8); value = LL2NUM(ll); *position += 8; break; } case 127: { value = rb_class_new_instance(0, NULL, MaxKey); break; } default: { rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type); break; } } return value; }
template <> RubyValue Conversion<QDateTime>::to(const QDateTime &dateTime) { RubyValue sec = rb_rational_new(RubyValue::from(dateTime.toMSecsSinceEpoch()), RubyValue::from(1000)); RubyValue time = rb_time_num_new(sec, RubyValue::from(dateTime.offsetFromUtc())); return time.send(RUBYQML_INTERN("to_datetime")); }