1 // Copyright 2010 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you 4 // may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 #include "protobuf_v8.h" 16 17 #include <map> 18 #include <string> 19 #include <iostream> 20 #include <sstream> 21 22 #include <google/protobuf/dynamic_message.h> 23 #include <google/protobuf/descriptor.h> 24 #include <google/protobuf/descriptor.pb.h> 25 26 #include "logging.h" 27 #include "util.h" 28 29 #include "node_buffer.h" 30 #include "node_object_wrap.h" 31 32 #include "node_util.h" 33 34 //#define PROTOBUF_V8_DEBUG 35 #ifdef PROTOBUF_V8_DEBUG 36 37 #define DBG(...) LOGD(__VA_ARGS__) 38 39 #else 40 41 #define DBG(...) 42 43 #endif 44 45 using google::protobuf::Descriptor; 46 using google::protobuf::DescriptorPool; 47 using google::protobuf::DynamicMessageFactory; 48 using google::protobuf::FieldDescriptor; 49 using google::protobuf::FileDescriptorSet; 50 using google::protobuf::Message; 51 using google::protobuf::Reflection; 52 53 //using ObjectWrap; 54 //using Buffer; 55 56 using std::map; 57 using std::string; 58 59 using v8::Array; 60 using v8::AccessorInfo; 61 using v8::Arguments; 62 using v8::Boolean; 63 using v8::Context; 64 using v8::External; 65 using v8::Function; 66 using v8::FunctionTemplate; 67 using v8::Integer; 68 using v8::Handle; 69 using v8::HandleScope; 70 using v8::InvocationCallback; 71 using v8::Local; 72 using v8::NamedPropertyGetter; 73 using v8::Number; 74 using v8::Object; 75 using v8::ObjectTemplate; 76 using v8::Persistent; 77 using v8::Script; 78 using v8::String; 79 using v8::Value; 80 using v8::V8; 81 82 namespace protobuf_v8 { 83 84 template <typename T> 85 static T* UnwrapThis(const Arguments& args) { 86 return ObjectWrap::Unwrap<T>(args.This()); 87 } 88 89 template <typename T> 90 static T* UnwrapThis(const AccessorInfo& args) { 91 return ObjectWrap::Unwrap<T>(args.This()); 92 } 93 94 Persistent<FunctionTemplate> SchemaTemplate; 95 Persistent<FunctionTemplate> TypeTemplate; 96 Persistent<FunctionTemplate> ParseTemplate; 97 Persistent<FunctionTemplate> SerializeTemplate; 98 99 class Schema : public ObjectWrap { 100 public: 101 Schema(Handle<Object> self, const DescriptorPool* pool) 102 : pool_(pool) { 103 DBG("Schema::Schema E:"); 104 factory_.SetDelegateToGeneratedFactory(true); 105 self->SetInternalField(1, Array::New()); 106 Wrap(self); 107 DBG("Schema::Schema X:"); 108 } 109 110 virtual ~Schema() { 111 DBG("~Schema::Schema E:"); 112 if (pool_ != DescriptorPool::generated_pool()) 113 delete pool_; 114 DBG("~Schema::Schema X:"); 115 } 116 117 class Type : public ObjectWrap { 118 public: 119 Schema* schema_; 120 const Descriptor* descriptor_; 121 122 Message* NewMessage() const { 123 DBG("Type::NewMessage() EX:"); 124 return schema_->NewMessage(descriptor_); 125 } 126 127 Handle<Function> Constructor() const { 128 DBG("Type::Constrocutor() EX:"); 129 return Handle<Function>::Cast(handle_->GetInternalField(2)); 130 } 131 132 Local<Object> NewObject(Handle<Value> properties) const { 133 DBG("Type::NewObjext(properties) EX:"); 134 return Constructor()->NewInstance(1, &properties); 135 } 136 137 Type(Schema* schema, const Descriptor* descriptor, Handle<Object> self) 138 : schema_(schema), descriptor_(descriptor) { 139 DBG("Type::Type(schema, descriptor, self) E:"); 140 // Generate functions for bulk conversion between a JS object 141 // and an array in descriptor order: 142 // from = function(arr) { this.f0 = arr[0]; this.f1 = arr[1]; ... } 143 // to = function() { return [ this.f0, this.f1, ... ] } 144 // This is faster than repeatedly calling Get/Set on a v8::Object. 145 std::ostringstream from, to; 146 from << "(function(arr) { if(arr) {"; 147 to << "(function() { return [ "; 148 149 for (int i = 0; i < descriptor->field_count(); i++) { 150 from << 151 "var x = arr[" << i << "]; " 152 "if(x !== undefined) this['" << 153 descriptor->field(i)->camelcase_name() << 154 "'] = x; "; 155 156 if (i > 0) to << ", "; 157 to << "this['" << descriptor->field(i)->camelcase_name() << "']"; 158 DBG("field name=%s", descriptor->field(i)->name().c_str()); 159 } 160 161 from << " }})"; 162 to << " ]; })"; 163 164 // managed type->schema link 165 self->SetInternalField(1, schema_->handle_); 166 167 Handle<Function> constructor = Handle<Function>::Cast( 168 Script::Compile(String::New(from.str().c_str()))->Run()); 169 constructor->SetHiddenValue(String::New("type"), self); 170 171 Handle<Function> bind = Handle<Function>::Cast( 172 Script::Compile(String::New( 173 "(function(self) {" 174 " var f = this;" 175 " return function(arg) {" 176 " return f.call(self, arg);" 177 " };" 178 "})"))->Run()); 179 Handle<Value> arg = self; 180 constructor->Set(String::New("parse"), bind->Call(ParseTemplate->GetFunction(), 1, &arg)); 181 constructor->Set(String::New("serialize"), bind->Call(SerializeTemplate->GetFunction(), 1, &arg)); 182 self->SetInternalField(2, constructor); 183 self->SetInternalField(3, Script::Compile(String::New(to.str().c_str()))->Run()); 184 185 Wrap(self); 186 DBG("Type::Type(schema, descriptor, self) X:"); 187 } 188 189 #define GET(TYPE) \ 190 (index >= 0 ? \ 191 reflection->GetRepeated##TYPE(instance, field, index) : \ 192 reflection->Get##TYPE(instance, field)) 193 194 static Handle<Value> ToJs(const Message& instance, 195 const Reflection* reflection, 196 const FieldDescriptor* field, 197 const Type* message_type, 198 int index) { 199 DBG("Type::ToJs(instance, refelction, field, message_type) E:"); 200 switch (field->cpp_type()) { 201 case FieldDescriptor::CPPTYPE_MESSAGE: 202 DBG("Type::ToJs CPPTYPE_MESSAGE"); 203 return message_type->ToJs(GET(Message)); 204 case FieldDescriptor::CPPTYPE_STRING: { 205 DBG("Type::ToJs CPPTYPE_STRING"); 206 const string& value = GET(String); 207 return String::New(value.data(), value.length()); 208 } 209 case FieldDescriptor::CPPTYPE_INT32: 210 DBG("Type::ToJs CPPTYPE_INT32"); 211 return Integer::New(GET(Int32)); 212 case FieldDescriptor::CPPTYPE_UINT32: 213 DBG("Type::ToJs CPPTYPE_UINT32"); 214 return Integer::NewFromUnsigned(GET(UInt32)); 215 case FieldDescriptor::CPPTYPE_INT64: 216 DBG("Type::ToJs CPPTYPE_INT64"); 217 return Number::New(GET(Int64)); 218 case FieldDescriptor::CPPTYPE_UINT64: 219 DBG("Type::ToJs CPPTYPE_UINT64"); 220 return Number::New(GET(UInt64)); 221 case FieldDescriptor::CPPTYPE_FLOAT: 222 DBG("Type::ToJs CPPTYPE_FLOAT"); 223 return Number::New(GET(Float)); 224 case FieldDescriptor::CPPTYPE_DOUBLE: 225 DBG("Type::ToJs CPPTYPE_DOUBLE"); 226 return Number::New(GET(Double)); 227 case FieldDescriptor::CPPTYPE_BOOL: 228 DBG("Type::ToJs CPPTYPE_BOOL"); 229 return Boolean::New(GET(Bool)); 230 case FieldDescriptor::CPPTYPE_ENUM: 231 DBG("Type::ToJs CPPTYPE_ENUM"); 232 return String::New(GET(Enum)->name().c_str()); 233 } 234 235 return Handle<Value>(); // NOTREACHED 236 } 237 #undef GET 238 239 Handle<Object> ToJs(const Message& instance) const { 240 DBG("Type::ToJs(Message) E:"); 241 const Reflection* reflection = instance.GetReflection(); 242 const Descriptor* descriptor = instance.GetDescriptor(); 243 244 Handle<Array> properties = Array::New(descriptor->field_count()); 245 for (int i = 0; i < descriptor->field_count(); i++) { 246 HandleScope scope; 247 248 const FieldDescriptor* field = descriptor->field(i); 249 bool repeated = field->is_repeated(); 250 if (repeated && !reflection->FieldSize(instance, field)) { 251 DBG("Ignore repeated field with no size in reflection data"); 252 continue; 253 } 254 if (!repeated && !reflection->HasField(instance, field)) { 255 DBG("Ignore field with no field in relfection data"); 256 continue; 257 } 258 259 const Type* child_type = 260 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? 261 schema_->GetType(field->message_type()) : NULL; 262 263 Handle<Value> value; 264 if (field->is_repeated()) { 265 int size = reflection->FieldSize(instance, field); 266 Handle<Array> array = Array::New(size); 267 for (int j = 0; j < size; j++) { 268 Handle<Value> index = Number::New(i); 269 array->Set(index, ToJs(instance, reflection, field, child_type, j)); 270 } 271 value = array; 272 } else { 273 value = ToJs(instance, reflection, field, child_type, -1); 274 } 275 276 DBG("Type::ToJs: set property[%d]=%s", i, ToCString(value)); 277 Handle<Value> key = Number::New(i); 278 properties->Set(key, value); 279 } 280 281 DBG("Type::ToJs(Message) X:"); 282 return NewObject(properties); 283 } 284 285 static Handle<Value> Parse(const Arguments& args) { 286 DBG("Type::Parse(args) E:"); 287 Type* type = UnwrapThis<Type>(args); 288 Buffer* buf = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); 289 290 Message* message = type->NewMessage(); 291 message->ParseFromArray(buf->data(), buf->length()); 292 Handle<Object> result = type->ToJs(*message); 293 delete message; 294 295 DBG("Type::Parse(args) X:"); 296 return result; 297 } 298 299 #define SET(TYPE, EXPR) \ 300 if (repeated) reflection->Add##TYPE(instance, field, EXPR); \ 301 else reflection->Set##TYPE(instance, field, EXPR) 302 303 static bool ToProto(Message* instance, 304 const FieldDescriptor* field, 305 Handle<Value> value, 306 const Type* type, 307 bool repeated) { 308 DBG("Type::ToProto(instance, field, value, type, repeated) E:"); 309 bool ok = true; 310 HandleScope scope; 311 312 DBG("Type::ToProto field->name()=%s", field->name().c_str()); 313 const Reflection* reflection = instance->GetReflection(); 314 switch (field->cpp_type()) { 315 case FieldDescriptor::CPPTYPE_MESSAGE: 316 DBG("Type::ToProto CPPTYPE_MESSAGE"); 317 ok = type->ToProto(repeated ? 318 reflection->AddMessage(instance, field) : 319 reflection->MutableMessage(instance, field), 320 Handle<Object>::Cast(value)); 321 break; 322 case FieldDescriptor::CPPTYPE_STRING: { 323 DBG("Type::ToProto CPPTYPE_STRING"); 324 String::AsciiValue ascii(value); 325 SET(String, string(*ascii, ascii.length())); 326 break; 327 } 328 case FieldDescriptor::CPPTYPE_INT32: 329 DBG("Type::ToProto CPPTYPE_INT32"); 330 SET(Int32, value->NumberValue()); 331 break; 332 case FieldDescriptor::CPPTYPE_UINT32: 333 DBG("Type::ToProto CPPTYPE_UINT32"); 334 SET(UInt32, value->NumberValue()); 335 break; 336 case FieldDescriptor::CPPTYPE_INT64: 337 DBG("Type::ToProto CPPTYPE_INT64"); 338 SET(Int64, value->NumberValue()); 339 break; 340 case FieldDescriptor::CPPTYPE_UINT64: 341 DBG("Type::ToProto CPPTYPE_UINT64"); 342 SET(UInt64, value->NumberValue()); 343 break; 344 case FieldDescriptor::CPPTYPE_FLOAT: 345 DBG("Type::ToProto CPPTYPE_FLOAT"); 346 SET(Float, value->NumberValue()); 347 break; 348 case FieldDescriptor::CPPTYPE_DOUBLE: 349 DBG("Type::ToProto CPPTYPE_DOUBLE"); 350 SET(Double, value->NumberValue()); 351 break; 352 case FieldDescriptor::CPPTYPE_BOOL: 353 DBG("Type::ToProto CPPTYPE_BOOL"); 354 SET(Bool, value->BooleanValue()); 355 break; 356 case FieldDescriptor::CPPTYPE_ENUM: 357 DBG("Type::ToProto CPPTYPE_ENUM"); 358 359 // Don't use SET as vd can be NULL 360 char error_buff[256]; 361 const google::protobuf::EnumValueDescriptor* vd; 362 int i32_value = 0; 363 const char *str_value = NULL; 364 const google::protobuf::EnumDescriptor* ed = field->enum_type(); 365 366 if (value->IsNumber()) { 367 i32_value = value->Int32Value(); 368 vd = ed->FindValueByNumber(i32_value); 369 if (vd == NULL) { 370 snprintf(error_buff, sizeof(error_buff), 371 "Type::ToProto Bad enum value, %d is not a member of enum %s", 372 i32_value, ed->full_name().c_str()); 373 } 374 } else { 375 str_value = ToCString(value); 376 // TODO: Why can str_value be corrupted sometimes? 377 LOGD("str_value=%s", str_value); 378 vd = ed->FindValueByName(str_value); 379 if (vd == NULL) { 380 snprintf(error_buff, sizeof(error_buff), 381 "Type::ToProto Bad enum value, %s is not a member of enum %s", 382 str_value, ed->full_name().c_str()); 383 } 384 } 385 if (vd != NULL) { 386 if (repeated) { 387 reflection->AddEnum(instance, field, vd); 388 } else { 389 reflection->SetEnum(instance, field, vd); 390 } 391 } else { 392 v8::ThrowException(String::New(error_buff)); 393 ok = false; 394 } 395 break; 396 } 397 DBG("Type::ToProto(instance, field, value, type, repeated) X: ok=%d", ok); 398 return ok; 399 } 400 #undef SET 401 402 bool ToProto(Message* instance, Handle<Object> src) const { 403 DBG("ToProto(Message *, Handle<Object>) E:"); 404 405 Handle<Function> to_array = Handle<Function>::Cast(handle_->GetInternalField(3)); 406 Handle<Array> properties = Handle<Array>::Cast(to_array->Call(src, 0, NULL)); 407 bool ok = true; 408 for (int i = 0; ok && (i < descriptor_->field_count()); i++) { 409 Handle<Value> value = properties->Get(Number::New(i)); 410 if (value->IsUndefined()) continue; 411 412 const FieldDescriptor* field = descriptor_->field(i); 413 const Type* child_type = 414 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? 415 schema_->GetType(field->message_type()) : NULL; 416 if (field->is_repeated()) { 417 if(!value->IsArray()) { 418 ok = ToProto(instance, field, value, child_type, true); 419 } else { 420 Handle<Array> array = Handle<Array>::Cast(value); 421 int length = array->Length(); 422 for (int j = 0; ok && (j < length); j++) { 423 ok = ToProto(instance, field, array->Get(Number::New(j)), child_type, true); 424 } 425 } 426 } else { 427 ok = ToProto(instance, field, value, child_type, false); 428 } 429 } 430 DBG("ToProto(Message *, Handle<Object>) X: ok=%d", ok); 431 return ok; 432 } 433 434 static Handle<Value> Serialize(const Arguments& args) { 435 Handle<Value> result; 436 DBG("Serialize(Arguments&) E:"); 437 if (!args[0]->IsObject()) { 438 DBG("Serialize(Arguments&) X: not an object"); 439 return v8::ThrowException(args[0]); 440 } 441 442 Type* type = UnwrapThis<Type>(args); 443 Message* message = type->NewMessage(); 444 if (type->ToProto(message, Handle<Object>::Cast(args[0]))) { 445 int length = message->ByteSize(); 446 Buffer* buffer = Buffer::New(length); 447 message->SerializeWithCachedSizesToArray((google::protobuf::uint8*)buffer->data()); 448 delete message; 449 450 result = buffer->handle_; 451 } else { 452 result = v8::Undefined(); 453 } 454 DBG("Serialize(Arguments&) X"); 455 return result; 456 } 457 458 static Handle<Value> ToString(const Arguments& args) { 459 return String::New(UnwrapThis<Type>(args)->descriptor_->full_name().c_str()); 460 } 461 }; 462 463 Message* NewMessage(const Descriptor* descriptor) { 464 DBG("Schema::NewMessage(descriptor) EX:"); 465 return factory_.GetPrototype(descriptor)->New(); 466 } 467 468 Type* GetType(const Descriptor* descriptor) { 469 DBG("Schema::GetType(descriptor) E:"); 470 Type* result = types_[descriptor]; 471 if (result) return result; 472 473 result = types_[descriptor] = 474 new Type(this, descriptor, TypeTemplate->GetFunction()->NewInstance()); 475 476 // managed schema->[type] link 477 Handle<Array> types = Handle<Array>::Cast(handle_->GetInternalField(1)); 478 Handle<Value> key = Number::New(types->Length()); 479 types->Set(key, result->handle_); 480 DBG("Schema::GetType(descriptor) X:"); 481 return result; 482 } 483 484 const DescriptorPool* pool_; 485 map<const Descriptor*, Type*> types_; 486 DynamicMessageFactory factory_; 487 488 static Handle<Value> GetType(const Local<String> name, 489 const AccessorInfo& args) { 490 DBG("Schema::GetType(name, args) E:"); 491 Schema* schema = UnwrapThis<Schema>(args); 492 const Descriptor* descriptor = 493 schema->pool_->FindMessageTypeByName(*String::AsciiValue(name)); 494 495 DBG("Schema::GetType(name, args) X:"); 496 return descriptor ? 497 schema->GetType(descriptor)->Constructor() : 498 Handle<Function>(); 499 } 500 501 static Handle<Value> NewSchema(const Arguments& args) { 502 DBG("Schema::NewSchema E: args.Length()=%d", args.Length()); 503 if (!args.Length()) { 504 return (new Schema(args.This(), 505 DescriptorPool::generated_pool()))->handle_; 506 } 507 508 Buffer* buf = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); 509 510 FileDescriptorSet descriptors; 511 if (!descriptors.ParseFromArray(buf->data(), buf->length())) { 512 DBG("Schema::NewSchema X: bad descriptor"); 513 return v8::ThrowException(String::New("Malformed descriptor")); 514 } 515 516 DescriptorPool* pool = new DescriptorPool; 517 for (int i = 0; i < descriptors.file_size(); i++) { 518 pool->BuildFile(descriptors.file(i)); 519 } 520 521 DBG("Schema::NewSchema X"); 522 return (new Schema(args.This(), pool))->handle_; 523 } 524 }; 525 526 void Init() { 527 DBG("Init E:"); 528 HandleScope handle_scope; 529 530 TypeTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New()); 531 TypeTemplate->SetClassName(String::New("Type")); 532 // native self 533 // owning schema (so GC can manage our lifecyle) 534 // constructor 535 // toArray 536 TypeTemplate->InstanceTemplate()->SetInternalFieldCount(4); 537 538 SchemaTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::NewSchema)); 539 SchemaTemplate->SetClassName(String::New("Schema")); 540 // native self 541 // array of types (so GC can manage our lifecyle) 542 SchemaTemplate->InstanceTemplate()->SetInternalFieldCount(2); 543 SchemaTemplate->InstanceTemplate()->SetNamedPropertyHandler(Schema::GetType); 544 545 ParseTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::Type::Parse)); 546 SerializeTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::Type::Serialize)); 547 548 DBG("Init X:"); 549 } 550 551 } // namespace protobuf_v8 552 553 extern "C" void SchemaObjectTemplateInit(Handle<ObjectTemplate> target) { 554 DBG("SchemaObjectTemplateInit(target) EX:"); 555 target->Set(String::New("Schema"), protobuf_v8::SchemaTemplate); 556 } 557