• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
UnwrapThis(const Arguments & args)85   static T* UnwrapThis(const Arguments& args) {
86     return ObjectWrap::Unwrap<T>(args.This());
87   }
88 
89   template <typename T>
UnwrapThis(const AccessorInfo & args)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:
Schema(Handle<Object> self,const DescriptorPool * pool)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 
~Schema()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 
NewMessage() const122       Message* NewMessage() const {
123         DBG("Type::NewMessage() EX:");
124         return schema_->NewMessage(descriptor_);
125       }
126 
Constructor() const127       Handle<Function> Constructor() const {
128         DBG("Type::Constrocutor() EX:");
129         return Handle<Function>::Cast(handle_->GetInternalField(2));
130       }
131 
NewObject(Handle<Value> properties) const132       Local<Object> NewObject(Handle<Value> properties) const {
133         DBG("Type::NewObjext(properties) EX:");
134         return Constructor()->NewInstance(1, &properties);
135       }
136 
Type(Schema * schema,const Descriptor * descriptor,Handle<Object> self)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 
ToJs(const Message & instance,const Reflection * reflection,const FieldDescriptor * field,const Type * message_type,int index)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 
ToJs(const Message & instance) const239       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 
Parse(const Arguments & args)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 
ToProto(Message * instance,const FieldDescriptor * field,Handle<Value> value,const Type * type,bool repeated)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 
ToProto(Message * instance,Handle<Object> src) const402       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 
Serialize(const Arguments & args)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 
ToString(const Arguments & args)458       static Handle<Value> ToString(const Arguments& args) {
459         return String::New(UnwrapThis<Type>(args)->descriptor_->full_name().c_str());
460       }
461     };
462 
NewMessage(const Descriptor * descriptor)463     Message* NewMessage(const Descriptor* descriptor) {
464       DBG("Schema::NewMessage(descriptor) EX:");
465       return factory_.GetPrototype(descriptor)->New();
466     }
467 
GetType(const Descriptor * descriptor)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 
GetType(const Local<String> name,const AccessorInfo & args)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 
NewSchema(const Arguments & args)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 
Init()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 
SchemaObjectTemplateInit(Handle<ObjectTemplate> target)553 extern "C" void SchemaObjectTemplateInit(Handle<ObjectTemplate> target) {
554   DBG("SchemaObjectTemplateInit(target) EX:");
555   target->Set(String::New("Schema"), protobuf_v8::SchemaTemplate);
556 }
557