Home | History | Annotate | Download | only in ibus
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos/dbus/ibus/ibus_object.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/values.h"
      9 #include "chromeos/dbus/ibus/ibus_property.h"
     10 #include "chromeos/dbus/ibus/ibus_text.h"
     11 #include "dbus/message.h"
     12 #include "dbus/values_util.h"
     13 
     14 namespace chromeos {
     15 
     16 ///////////////////////////////////////////////////////////////////////////////
     17 // IBusObjectReader
     18 IBusObjectReader::IBusObjectReader(const std::string& type_name,
     19                                    dbus::MessageReader* reader)
     20     : type_name_(type_name),
     21       original_reader_(reader),
     22       check_result_(IBUS_OBJECT_NOT_CHECKED) {}
     23 
     24 IBusObjectReader::~IBusObjectReader() {
     25   for (std::map<std::string, base::Value*>::iterator ite = attachments_.begin();
     26        ite != attachments_.end(); ++ite)
     27     delete ite->second;
     28 }
     29 
     30 bool IBusObjectReader::Init() {
     31   DCHECK(original_reader_);
     32   DCHECK_EQ(IBUS_OBJECT_NOT_CHECKED, check_result_);
     33 
     34   top_variant_reader_.reset(new dbus::MessageReader(NULL));
     35   contents_reader_.reset(new dbus::MessageReader(NULL));
     36   check_result_ = IBUS_OBJECT_INVALID;
     37 
     38   // IBus object has a variant on top-level.
     39   if (!original_reader_->PopVariant(top_variant_reader_.get())) {
     40     LOG(ERROR) << "Invalid object structure[" << type_name_ << "]: "
     41                << "can not find top variant field.";
     42     return false;
     43   }
     44 
     45   // IBus object has struct on second level.
     46   if (!top_variant_reader_->PopStruct(contents_reader_.get())) {
     47     LOG(ERROR) << "Invalid object structure["  << type_name_ << "]: "
     48                << "can not find top struct field.";
     49     return false;
     50   }
     51 
     52   // IBus object has type key at the first element.
     53   std::string type_name;
     54   if (!contents_reader_->PopString(&type_name)) {
     55     LOG(ERROR) << "Invalid object structure[" << type_name_ << "]: "
     56                << "Can not get type name field.";
     57     return false;
     58   }
     59 
     60   if (type_name != type_name_) {
     61     LOG(ERROR) << "Type check failed: Given variant is not " << type_name_
     62                << " and actual type is " << type_name << ".";
     63     return false;
     64   }
     65 
     66   dbus::MessageReader attachment_reader(NULL);
     67 
     68   // IBus object has array object at the second element, which is used in
     69   // attaching additional information.
     70   if (!contents_reader_->PopArray(&attachment_reader)) {
     71     LOG(ERROR) << "Invalid object structure[" << type_name_ << "] "
     72                << "can not find attachment array field.";
     73     return false;
     74   }
     75 
     76   while (attachment_reader.HasMoreData()) {
     77     dbus::MessageReader dictionary_reader(NULL);
     78     if (!attachment_reader.PopDictEntry(&dictionary_reader)) {
     79       LOG(ERROR) << "Invalid attachment structure: "
     80                  << "The attachment field is array of dictionary entry.";
     81       return false;
     82     }
     83 
     84     std::string key;
     85     if (!dictionary_reader.PopString(&key)) {
     86       LOG(ERROR) << "Invalid attachment structure: "
     87                  << "The 1st dictionary entry should be string.";
     88       return false;
     89     }
     90 
     91     if (key.empty()) {
     92       LOG(ERROR) << "Invalid attachment key: key is empty.";
     93       return false;
     94     }
     95 
     96     dbus::MessageReader variant_reader(NULL);
     97     if (!dictionary_reader.PopVariant(&variant_reader)) {
     98       LOG(ERROR) << "Invalid attachment structure: "
     99                  << "The 2nd dictionary entry should be variant.";
    100       return false;
    101     }
    102 
    103     dbus::MessageReader sub_variant_reader(NULL);
    104     if (!variant_reader.PopVariant(&sub_variant_reader)) {
    105       LOG(ERROR) << "Invalid attachment structure: "
    106                  << "The 2nd variant entry should contain variant.";
    107       return false;
    108     }
    109 
    110     attachments_[key] =  dbus::PopDataAsValue(&sub_variant_reader);
    111   }
    112   check_result_ = IBUS_OBJECT_VALID;
    113   return true;
    114 }
    115 
    116 bool IBusObjectReader::InitWithParentReader(dbus::MessageReader* reader) {
    117   original_reader_ = reader;
    118   return Init();
    119 }
    120 
    121 bool IBusObjectReader::PopString(std::string* out) {
    122   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    123   DCHECK(contents_reader_.get());
    124   return IsValid() && contents_reader_->PopString(out);
    125 }
    126 
    127 bool IBusObjectReader::PopUint32(uint32* out) {
    128   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    129   DCHECK(contents_reader_.get());
    130   return IsValid() && contents_reader_->PopUint32(out);
    131 }
    132 
    133 bool IBusObjectReader::PopInt32(int32* out) {
    134   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    135   DCHECK(contents_reader_.get());
    136   return IsValid() && contents_reader_->PopInt32(out);
    137 }
    138 
    139 bool IBusObjectReader::PopBool(bool* out) {
    140   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    141   DCHECK(contents_reader_.get());
    142   return IsValid() && contents_reader_->PopBool(out);
    143 }
    144 
    145 bool IBusObjectReader::PopArray(dbus::MessageReader* reader) {
    146   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    147   DCHECK(contents_reader_.get());
    148   return IsValid() && contents_reader_->PopArray(reader);
    149 }
    150 
    151 bool IBusObjectReader::PopIBusText(IBusText* text) {
    152   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    153   DCHECK(contents_reader_.get());
    154   return IsValid() && chromeos::PopIBusText(contents_reader_.get(), text);
    155 }
    156 
    157 bool IBusObjectReader::PopStringFromIBusText(std::string* text) {
    158   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    159   DCHECK(contents_reader_.get());
    160   return IsValid() && chromeos::PopStringFromIBusText(
    161       contents_reader_.get(), text);
    162 }
    163 
    164 bool IBusObjectReader::PopIBusProperty(IBusProperty* property) {
    165   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    166   DCHECK(contents_reader_.get());
    167   return IsValid() && chromeos::PopIBusProperty(contents_reader_.get(),
    168                                                       property);
    169 }
    170 
    171 bool IBusObjectReader::PopIBusPropertyList(IBusPropertyList* properties) {
    172   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    173   DCHECK(contents_reader_.get());
    174   return IsValid() && chromeos::PopIBusPropertyList(
    175       contents_reader_.get(), properties);
    176 }
    177 
    178 const base::Value* IBusObjectReader::GetAttachment(const std::string& key) {
    179   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    180   DCHECK(contents_reader_.get());
    181   if (!IsValid())
    182     return NULL;
    183   std::map<std::string, base::Value*>::iterator it = attachments_.find(key);
    184   if (it == attachments_.end())
    185     return NULL;
    186   return it->second;
    187 }
    188 
    189 bool IBusObjectReader::HasMoreData() {
    190   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    191   DCHECK(contents_reader_.get());
    192   return IsValid() && contents_reader_->HasMoreData();
    193 }
    194 
    195 bool IBusObjectReader::PopIBusObject(IBusObjectReader* reader) {
    196   DCHECK(contents_reader_.get());
    197   if (!IsValid())
    198     return false;
    199   return reader->InitWithParentReader(contents_reader_.get());
    200 }
    201 
    202 bool IBusObjectReader::IsValid() const {
    203   DCHECK_NE(IBUS_OBJECT_NOT_CHECKED, check_result_);
    204   return check_result_ == IBUS_OBJECT_VALID;
    205 }
    206 
    207 ///////////////////////////////////////////////////////////////////////////////
    208 //  IBusObjectWriter
    209 IBusObjectWriter::IBusObjectWriter(const std::string& type_name,
    210                                    const std::string& signature,
    211                                    dbus::MessageWriter* writer)
    212     : type_name_(type_name),
    213       signature_(signature),
    214       original_writer_(writer),
    215       state_(NOT_INITIALZED) {
    216   if (original_writer_)
    217     Init();
    218 }
    219 
    220 IBusObjectWriter::~IBusObjectWriter() {
    221 }
    222 
    223 void IBusObjectWriter::AppendString(const std::string& input) {
    224   DCHECK_EQ(state_, INITIALIZED);
    225   contents_writer_->AppendString(input);
    226 }
    227 
    228 void IBusObjectWriter::AppendUint32(uint32 input) {
    229   DCHECK_EQ(state_, INITIALIZED);
    230   contents_writer_->AppendUint32(input);
    231 }
    232 
    233 void IBusObjectWriter::AppendInt32(int32 input) {
    234   DCHECK_EQ(state_, INITIALIZED);
    235   contents_writer_->AppendInt32(input);
    236 }
    237 
    238 void IBusObjectWriter::AppendBool(bool input) {
    239   DCHECK_EQ(state_, INITIALIZED);
    240   contents_writer_->AppendBool(input);
    241 }
    242 
    243 void IBusObjectWriter::OpenArray(const std::string& signature,
    244                                  dbus::MessageWriter* writer) {
    245   DCHECK_EQ(state_, INITIALIZED);
    246   contents_writer_->OpenArray(signature, writer);
    247 }
    248 
    249 void IBusObjectWriter::AppendIBusText(const IBusText& text) {
    250   DCHECK_EQ(state_, INITIALIZED);
    251   chromeos::AppendIBusText(text, contents_writer_.get());
    252 }
    253 
    254 void IBusObjectWriter::AppendStringAsIBusText(const std::string& text) {
    255   DCHECK_EQ(state_, INITIALIZED);
    256   chromeos::AppendStringAsIBusText(text, contents_writer_.get());
    257 }
    258 
    259 void IBusObjectWriter::AppendIBusProperty(const IBusProperty& property) {
    260   DCHECK_EQ(state_, INITIALIZED);
    261   chromeos::AppendIBusProperty(property, contents_writer_.get());
    262 }
    263 
    264 void IBusObjectWriter::AppendIBusPropertyList(
    265     const IBusPropertyList& property_list) {
    266   DCHECK_EQ(state_, INITIALIZED);
    267   chromeos::AppendIBusPropertyList(property_list, contents_writer_.get());
    268 }
    269 
    270 void IBusObjectWriter::CloseContainer(dbus::MessageWriter* writer) {
    271   DCHECK_EQ(state_, INITIALIZED);
    272   contents_writer_->CloseContainer(writer);
    273 }
    274 
    275 void IBusObjectWriter::AppendIBusObject(IBusObjectWriter* writer) {
    276   DCHECK_EQ(state_, INITIALIZED);
    277   writer->InitWithParentWriter(contents_writer_.get());
    278 }
    279 
    280 void IBusObjectWriter::Init() {
    281   DCHECK(original_writer_);
    282   DCHECK_EQ(state_, NOT_INITIALZED);
    283 
    284   top_variant_writer_.reset(new dbus::MessageWriter(NULL));
    285   contents_writer_.reset(new dbus::MessageWriter(NULL));
    286   attachment_writer_.reset(new dbus::MessageWriter(NULL));
    287 
    288   const std::string ibus_signature = "(sa{sv}" + signature_ + ")";
    289   original_writer_->OpenVariant(ibus_signature, top_variant_writer_.get());
    290   top_variant_writer_->OpenStruct(contents_writer_.get());
    291 
    292   contents_writer_->AppendString(type_name_);
    293 
    294   contents_writer_->OpenArray("{sv}", attachment_writer_.get());
    295   state_ = HEADER_OPEN;
    296 }
    297 
    298 void IBusObjectWriter::InitWithParentWriter(dbus::MessageWriter* writer) {
    299   DCHECK_EQ(state_, NOT_INITIALZED) << "Already initialized.";
    300   original_writer_ = writer;
    301   Init();
    302 }
    303 
    304 void IBusObjectWriter::CloseAll() {
    305   DCHECK(original_writer_);
    306   DCHECK_NE(state_, NOT_INITIALZED);
    307   if (state_ == HEADER_OPEN)
    308     CloseHeader();
    309 
    310   top_variant_writer_->CloseContainer(contents_writer_.get());
    311   original_writer_->CloseContainer(top_variant_writer_.get());
    312   top_variant_writer_.reset();
    313   contents_writer_.reset();
    314 }
    315 
    316 void IBusObjectWriter::CloseHeader() {
    317   DCHECK_EQ(state_, HEADER_OPEN) << "Header is already closed.";
    318   contents_writer_->CloseContainer(attachment_writer_.get());
    319   state_ = INITIALIZED;
    320 }
    321 
    322 bool IBusObjectWriter::AddAttachment(const std::string& key,
    323                                      const base::Value& value) {
    324   DCHECK_NE(state_, NOT_INITIALZED) << "Do not call before Init();";
    325   DCHECK_NE(state_, INITIALIZED) << "Do not call after CloseHeader().";
    326   DCHECK(attachment_writer_.get());
    327   DCHECK(!key.empty());
    328   DCHECK(!value.IsType(base::Value::TYPE_NULL));
    329 
    330   dbus::MessageWriter dict_writer(NULL);
    331   attachment_writer_->OpenDictEntry(&dict_writer);
    332   dict_writer.AppendString(key);
    333   dbus::MessageWriter variant_writer(NULL);
    334   dict_writer.OpenVariant("v", &variant_writer);
    335 
    336   dbus::AppendBasicTypeValueDataAsVariant(&variant_writer, value);
    337   dict_writer.CloseContainer(&variant_writer);
    338   attachment_writer_->CloseContainer(&variant_writer);
    339   return true;
    340 }
    341 
    342 }  // namespace chromeos
    343