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