protobuf_v8.cpp revision 6464068a31ff890d42d3da9cdf580d07c9c630d8
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(...) ALOGD(__VA_ARGS__)
38
39#else
40
41#define DBG(...)
42
43#endif
44
45using google::protobuf::Descriptor;
46using google::protobuf::DescriptorPool;
47using google::protobuf::DynamicMessageFactory;
48using google::protobuf::FieldDescriptor;
49using google::protobuf::FileDescriptorSet;
50using google::protobuf::Message;
51using google::protobuf::Reflection;
52
53//using ObjectWrap;
54//using Buffer;
55
56using std::map;
57using std::string;
58
59using v8::Array;
60using v8::AccessorInfo;
61using v8::Arguments;
62using v8::Boolean;
63using v8::Context;
64using v8::External;
65using v8::Function;
66using v8::FunctionTemplate;
67using v8::Integer;
68using v8::Handle;
69using v8::HandleScope;
70using v8::InvocationCallback;
71using v8::Local;
72using v8::NamedPropertyGetter;
73using v8::Number;
74using v8::Object;
75using v8::ObjectTemplate;
76using v8::Persistent;
77using v8::Script;
78using v8::String;
79using v8::Value;
80using v8::V8;
81
82namespace 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_->GetInternalField(2).As<Function>();
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 =
168          Script::Compile(String::New(from.str().c_str()))->Run().As<Function>();
169        constructor->SetHiddenValue(String::New("type"), self);
170
171        Handle<Function> bind =
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().As<Function>();
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              array->Set(j, ToJs(instance, reflection, field, child_type, j));
269            }
270            value = array;
271          } else {
272            value = ToJs(instance, reflection, field, child_type, -1);
273          }
274
275          DBG("Type::ToJs: set property[%d]=%s", i, ToCString(value));
276          properties->Set(i, value);
277        }
278
279        DBG("Type::ToJs(Message) X:");
280        return NewObject(properties);
281      }
282
283      static Handle<Value> Parse(const Arguments& args) {
284        DBG("Type::Parse(args) E:");
285        Type* type = UnwrapThis<Type>(args);
286        Buffer* buf = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
287
288        Message* message = type->NewMessage();
289        message->ParseFromArray(buf->data(), buf->length());
290        Handle<Object> result = type->ToJs(*message);
291        delete message;
292
293        DBG("Type::Parse(args) X:");
294        return result;
295      }
296
297#define SET(TYPE, EXPR)                                                 \
298      if (repeated) reflection->Add##TYPE(instance, field, EXPR);       \
299      else reflection->Set##TYPE(instance, field, EXPR)
300
301      static bool ToProto(Message* instance,
302                          const FieldDescriptor* field,
303                          Handle<Value> value,
304                          const Type* type,
305                          bool repeated) {
306        DBG("Type::ToProto(instance, field, value, type, repeated) E:");
307        bool ok = true;
308        HandleScope scope;
309
310        DBG("Type::ToProto field->name()=%s", field->name().c_str());
311        const Reflection* reflection = instance->GetReflection();
312        switch (field->cpp_type()) {
313        case FieldDescriptor::CPPTYPE_MESSAGE:
314          DBG("Type::ToProto CPPTYPE_MESSAGE");
315          ok = type->ToProto(repeated ?
316                                reflection->AddMessage(instance, field) :
317                                reflection->MutableMessage(instance, field),
318                                    value.As<Object>());
319          break;
320        case FieldDescriptor::CPPTYPE_STRING: {
321          DBG("Type::ToProto CPPTYPE_STRING");
322          String::AsciiValue ascii(value);
323          SET(String, string(*ascii, ascii.length()));
324          break;
325        }
326        case FieldDescriptor::CPPTYPE_INT32:
327          DBG("Type::ToProto CPPTYPE_INT32");
328          SET(Int32, value->NumberValue());
329          break;
330        case FieldDescriptor::CPPTYPE_UINT32:
331          DBG("Type::ToProto CPPTYPE_UINT32");
332          SET(UInt32, value->NumberValue());
333          break;
334        case FieldDescriptor::CPPTYPE_INT64:
335          DBG("Type::ToProto CPPTYPE_INT64");
336          SET(Int64, value->NumberValue());
337          break;
338        case FieldDescriptor::CPPTYPE_UINT64:
339          DBG("Type::ToProto CPPTYPE_UINT64");
340          SET(UInt64, value->NumberValue());
341          break;
342        case FieldDescriptor::CPPTYPE_FLOAT:
343          DBG("Type::ToProto CPPTYPE_FLOAT");
344          SET(Float, value->NumberValue());
345          break;
346        case FieldDescriptor::CPPTYPE_DOUBLE:
347          DBG("Type::ToProto CPPTYPE_DOUBLE");
348          SET(Double, value->NumberValue());
349          break;
350        case FieldDescriptor::CPPTYPE_BOOL:
351          DBG("Type::ToProto CPPTYPE_BOOL");
352          SET(Bool, value->BooleanValue());
353          break;
354        case FieldDescriptor::CPPTYPE_ENUM:
355          DBG("Type::ToProto CPPTYPE_ENUM");
356
357          // Don't use SET as vd can be NULL
358          char error_buff[256];
359          const google::protobuf::EnumValueDescriptor* vd;
360          int i32_value = 0;
361          const char *str_value = NULL;
362          const google::protobuf::EnumDescriptor* ed = field->enum_type();
363
364          if (value->IsNumber()) {
365            i32_value = value->Int32Value();
366            vd = ed->FindValueByNumber(i32_value);
367            if (vd == NULL) {
368              snprintf(error_buff, sizeof(error_buff),
369                  "Type::ToProto Bad enum value, %d is not a member of enum %s",
370                      i32_value, ed->full_name().c_str());
371            }
372          } else {
373            str_value = ToCString(value);
374            // TODO: Why can str_value be corrupted sometimes?
375            ALOGD("str_value=%s", str_value);
376            vd = ed->FindValueByName(str_value);
377            if (vd == NULL) {
378              snprintf(error_buff, sizeof(error_buff),
379                  "Type::ToProto Bad enum value, %s is not a member of enum %s",
380                      str_value, ed->full_name().c_str());
381            }
382          }
383          if (vd != NULL) {
384            if (repeated) {
385               reflection->AddEnum(instance, field, vd);
386            } else {
387               reflection->SetEnum(instance, field, vd);
388            }
389          } else {
390            v8::ThrowException(String::New(error_buff));
391            ok = false;
392          }
393          break;
394        }
395        DBG("Type::ToProto(instance, field, value, type, repeated) X: ok=%d", ok);
396        return ok;
397      }
398#undef SET
399
400      bool ToProto(Message* instance, Handle<Object> src) const {
401        DBG("ToProto(Message *, Handle<Object>) E:");
402
403        Handle<Function> to_array = handle_->GetInternalField(3).As<Function>();
404        Handle<Array> properties = to_array->Call(src, 0, NULL).As<Array>();
405        bool ok = true;
406        for (int i = 0; ok && (i < descriptor_->field_count()); i++) {
407          Handle<Value> value = properties->Get(i);
408          if (value->IsUndefined()) continue;
409
410          const FieldDescriptor* field = descriptor_->field(i);
411          const Type* child_type =
412            (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
413            schema_->GetType(field->message_type()) : NULL;
414          if (field->is_repeated()) {
415            if(!value->IsArray()) {
416              ok = ToProto(instance, field, value, child_type, true);
417            } else {
418              Handle<Array> array = value.As<Array>();
419              int length = array->Length();
420              for (int j = 0; ok && (j < length); j++) {
421                ok = ToProto(instance, field, array->Get(j), child_type, true);
422              }
423            }
424          } else {
425            ok = ToProto(instance, field, value, child_type, false);
426          }
427        }
428        DBG("ToProto(Message *, Handle<Object>) X: ok=%d", ok);
429        return ok;
430      }
431
432      static Handle<Value> Serialize(const Arguments& args) {
433        Handle<Value> result;
434        DBG("Serialize(Arguments&) E:");
435        if (!args[0]->IsObject()) {
436          DBG("Serialize(Arguments&) X: not an object");
437          return v8::ThrowException(args[0]);
438        }
439
440        Type* type = UnwrapThis<Type>(args);
441        Message* message = type->NewMessage();
442        if (type->ToProto(message, args[0].As<Object>())) {
443          int length = message->ByteSize();
444          Buffer* buffer = Buffer::New(length);
445          message->SerializeWithCachedSizesToArray((google::protobuf::uint8*)buffer->data());
446          delete message;
447
448          result = buffer->handle_;
449        } else {
450          result = v8::Undefined();
451        }
452        DBG("Serialize(Arguments&) X");
453        return result;
454      }
455
456      static Handle<Value> ToString(const Arguments& args) {
457        return String::New(UnwrapThis<Type>(args)->descriptor_->full_name().c_str());
458      }
459    };
460
461    Message* NewMessage(const Descriptor* descriptor) {
462      DBG("Schema::NewMessage(descriptor) EX:");
463      return factory_.GetPrototype(descriptor)->New();
464    }
465
466    Type* GetType(const Descriptor* descriptor) {
467      DBG("Schema::GetType(descriptor) E:");
468      Type* result = types_[descriptor];
469      if (result) return result;
470
471      result = types_[descriptor] =
472        new Type(this, descriptor, TypeTemplate->GetFunction()->NewInstance());
473
474      // managed schema->[type] link
475      Handle<Array> types = handle_->GetInternalField(1).As<Array>();
476      types->Set(types->Length(), result->handle_);
477      DBG("Schema::GetType(descriptor) X:");
478      return result;
479    }
480
481    const DescriptorPool* pool_;
482    map<const Descriptor*, Type*> types_;
483    DynamicMessageFactory factory_;
484
485    static Handle<Value> GetType(const Local<String> name,
486                                 const AccessorInfo& args) {
487      DBG("Schema::GetType(name, args) E:");
488      Schema* schema = UnwrapThis<Schema>(args);
489      const Descriptor* descriptor =
490        schema->pool_->FindMessageTypeByName(*String::AsciiValue(name));
491
492      DBG("Schema::GetType(name, args) X:");
493      return descriptor ?
494        schema->GetType(descriptor)->Constructor() :
495        Handle<Function>();
496    }
497
498    static Handle<Value> NewSchema(const Arguments& args) {
499      DBG("Schema::NewSchema E: args.Length()=%d", args.Length());
500      if (!args.Length()) {
501        return (new Schema(args.This(),
502                           DescriptorPool::generated_pool()))->handle_;
503      }
504
505      Buffer* buf = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
506
507      FileDescriptorSet descriptors;
508      if (!descriptors.ParseFromArray(buf->data(), buf->length())) {
509        DBG("Schema::NewSchema X: bad descriptor");
510        return v8::ThrowException(String::New("Malformed descriptor"));
511      }
512
513      DescriptorPool* pool = new DescriptorPool;
514      for (int i = 0; i < descriptors.file_size(); i++) {
515        pool->BuildFile(descriptors.file(i));
516      }
517
518      DBG("Schema::NewSchema X");
519      return (new Schema(args.This(), pool))->handle_;
520    }
521  };
522
523  void Init() {
524    DBG("Init E:");
525    HandleScope handle_scope;
526
527    TypeTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New());
528    TypeTemplate->SetClassName(String::New("Type"));
529    // native self
530    // owning schema (so GC can manage our lifecyle)
531    // constructor
532    // toArray
533    TypeTemplate->InstanceTemplate()->SetInternalFieldCount(4);
534
535    SchemaTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::NewSchema));
536    SchemaTemplate->SetClassName(String::New("Schema"));
537    // native self
538    // array of types (so GC can manage our lifecyle)
539    SchemaTemplate->InstanceTemplate()->SetInternalFieldCount(2);
540    SchemaTemplate->InstanceTemplate()->SetNamedPropertyHandler(Schema::GetType);
541
542    ParseTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::Type::Parse));
543    SerializeTemplate = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Schema::Type::Serialize));
544
545    DBG("Init X:");
546  }
547
548}  // namespace protobuf_v8
549
550extern "C" void SchemaObjectTemplateInit(Handle<ObjectTemplate> target) {
551  DBG("SchemaObjectTemplateInit(target) EX:");
552  target->Set(String::New("Schema"), protobuf_v8::SchemaTemplate);
553}
554