1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "Resource.h" 18 #include "ResourceTable.h" 19 #include "StringPool.h" 20 #include "ValueVisitor.h" 21 #include "proto/ProtoHelpers.h" 22 #include "proto/ProtoSerialize.h" 23 #include "util/BigBuffer.h" 24 25 namespace aapt { 26 27 namespace { 28 29 class PbSerializerVisitor : public RawValueVisitor { 30 public: 31 using RawValueVisitor::visit; 32 33 /** 34 * Constructor to use when expecting to serialize any value. 35 */ 36 PbSerializerVisitor(StringPool* sourcePool, StringPool* symbolPool, pb::Value* outPbValue) : 37 mSourcePool(sourcePool), mSymbolPool(symbolPool), mOutPbValue(outPbValue), 38 mOutPbItem(nullptr) { 39 } 40 41 /** 42 * Constructor to use when expecting to serialize an Item. 43 */ 44 PbSerializerVisitor(StringPool* sourcePool, StringPool* symbolPool, pb::Item* outPbItem) : 45 mSourcePool(sourcePool), mSymbolPool(symbolPool), mOutPbValue(nullptr), 46 mOutPbItem(outPbItem) { 47 } 48 49 void visit(Reference* ref) override { 50 serializeReferenceToPb(*ref, getPbItem()->mutable_ref()); 51 } 52 53 void visit(String* str) override { 54 getPbItem()->mutable_str()->set_idx(str->value.getIndex()); 55 } 56 57 void visit(StyledString* str) override { 58 getPbItem()->mutable_str()->set_idx(str->value.getIndex()); 59 } 60 61 void visit(FileReference* file) override { 62 getPbItem()->mutable_file()->set_path_idx(file->path.getIndex()); 63 } 64 65 void visit(Id* id) override { 66 getPbItem()->mutable_id(); 67 } 68 69 void visit(RawString* rawStr) override { 70 getPbItem()->mutable_raw_str()->set_idx(rawStr->value.getIndex()); 71 } 72 73 void visit(BinaryPrimitive* prim) override { 74 android::Res_value val = {}; 75 prim->flatten(&val); 76 77 pb::Primitive* pbPrim = getPbItem()->mutable_prim(); 78 pbPrim->set_type(val.dataType); 79 pbPrim->set_data(val.data); 80 } 81 82 void visitItem(Item* item) override { 83 assert(false && "unimplemented item"); 84 } 85 86 void visit(Attribute* attr) override { 87 pb::Attribute* pbAttr = getPbCompoundValue()->mutable_attr(); 88 pbAttr->set_format_flags(attr->typeMask); 89 pbAttr->set_min_int(attr->minInt); 90 pbAttr->set_max_int(attr->maxInt); 91 92 for (auto& symbol : attr->symbols) { 93 pb::Attribute_Symbol* pbSymbol = pbAttr->add_symbols(); 94 serializeItemCommonToPb(symbol.symbol, pbSymbol); 95 serializeReferenceToPb(symbol.symbol, pbSymbol->mutable_name()); 96 pbSymbol->set_value(symbol.value); 97 } 98 } 99 100 void visit(Style* style) override { 101 pb::Style* pbStyle = getPbCompoundValue()->mutable_style(); 102 if (style->parent) { 103 serializeReferenceToPb(style->parent.value(), pbStyle->mutable_parent()); 104 serializeSourceToPb(style->parent.value().getSource(), 105 mSourcePool, 106 pbStyle->mutable_parent_source()); 107 } 108 109 for (Style::Entry& entry : style->entries) { 110 pb::Style_Entry* pbEntry = pbStyle->add_entries(); 111 serializeReferenceToPb(entry.key, pbEntry->mutable_key()); 112 113 pb::Item* pbItem = pbEntry->mutable_item(); 114 serializeItemCommonToPb(entry.key, pbEntry); 115 PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbItem); 116 entry.value->accept(&subVisitor); 117 } 118 } 119 120 void visit(Styleable* styleable) override { 121 pb::Styleable* pbStyleable = getPbCompoundValue()->mutable_styleable(); 122 for (Reference& entry : styleable->entries) { 123 pb::Styleable_Entry* pbEntry = pbStyleable->add_entries(); 124 serializeItemCommonToPb(entry, pbEntry); 125 serializeReferenceToPb(entry, pbEntry->mutable_attr()); 126 } 127 } 128 129 void visit(Array* array) override { 130 pb::Array* pbArray = getPbCompoundValue()->mutable_array(); 131 for (auto& value : array->items) { 132 pb::Array_Entry* pbEntry = pbArray->add_entries(); 133 serializeItemCommonToPb(*value, pbEntry); 134 PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbEntry->mutable_item()); 135 value->accept(&subVisitor); 136 } 137 } 138 139 void visit(Plural* plural) override { 140 pb::Plural* pbPlural = getPbCompoundValue()->mutable_plural(); 141 const size_t count = plural->values.size(); 142 for (size_t i = 0; i < count; i++) { 143 if (!plural->values[i]) { 144 // No plural value set here. 145 continue; 146 } 147 148 pb::Plural_Entry* pbEntry = pbPlural->add_entries(); 149 pbEntry->set_arity(serializePluralEnumToPb(i)); 150 pb::Item* pbElement = pbEntry->mutable_item(); 151 serializeItemCommonToPb(*plural->values[i], pbEntry); 152 PbSerializerVisitor subVisitor(mSourcePool, mSymbolPool, pbElement); 153 plural->values[i]->accept(&subVisitor); 154 } 155 } 156 157 private: 158 pb::Item* getPbItem() { 159 if (mOutPbValue) { 160 return mOutPbValue->mutable_item(); 161 } 162 return mOutPbItem; 163 } 164 165 pb::CompoundValue* getPbCompoundValue() { 166 assert(mOutPbValue); 167 return mOutPbValue->mutable_compound_value(); 168 } 169 170 template <typename T> 171 void serializeItemCommonToPb(const Item& item, T* pbItem) { 172 serializeSourceToPb(item.getSource(), mSourcePool, pbItem->mutable_source()); 173 if (!item.getComment().empty()) { 174 pbItem->set_comment(util::utf16ToUtf8(item.getComment())); 175 } 176 } 177 178 void serializeReferenceToPb(const Reference& ref, pb::Reference* pbRef) { 179 if (ref.id) { 180 pbRef->set_id(ref.id.value().id); 181 } 182 183 if (ref.name) { 184 StringPool::Ref symbolRef = mSymbolPool->makeRef(ref.name.value().toString()); 185 pbRef->set_symbol_idx(static_cast<uint32_t>(symbolRef.getIndex())); 186 } 187 188 pbRef->set_private_(ref.privateReference); 189 pbRef->set_type(serializeReferenceTypeToPb(ref.referenceType)); 190 } 191 192 StringPool* mSourcePool; 193 StringPool* mSymbolPool; 194 pb::Value* mOutPbValue; 195 pb::Item* mOutPbItem; 196 }; 197 198 } // namespace 199 200 std::unique_ptr<pb::ResourceTable> serializeTableToPb(ResourceTable* table) { 201 // We must do this before writing the resources, since the string pool IDs may change. 202 table->stringPool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool { 203 int diff = a.context.priority - b.context.priority; 204 if (diff < 0) return true; 205 if (diff > 0) return false; 206 diff = a.context.config.compare(b.context.config); 207 if (diff < 0) return true; 208 if (diff > 0) return false; 209 return a.value < b.value; 210 }); 211 table->stringPool.prune(); 212 213 std::unique_ptr<pb::ResourceTable> pbTable = util::make_unique<pb::ResourceTable>(); 214 serializeStringPoolToPb(table->stringPool, pbTable->mutable_string_pool()); 215 216 StringPool sourcePool, symbolPool; 217 218 for (auto& package : table->packages) { 219 pb::Package* pbPackage = pbTable->add_packages(); 220 if (package->id) { 221 pbPackage->set_package_id(package->id.value()); 222 } 223 pbPackage->set_package_name(util::utf16ToUtf8(package->name)); 224 225 for (auto& type : package->types) { 226 pb::Type* pbType = pbPackage->add_types(); 227 if (type->id) { 228 pbType->set_id(type->id.value()); 229 } 230 pbType->set_name(util::utf16ToUtf8(toString(type->type))); 231 232 for (auto& entry : type->entries) { 233 pb::Entry* pbEntry = pbType->add_entries(); 234 if (entry->id) { 235 pbEntry->set_id(entry->id.value()); 236 } 237 pbEntry->set_name(util::utf16ToUtf8(entry->name)); 238 239 // Write the SymbolStatus struct. 240 pb::SymbolStatus* pbStatus = pbEntry->mutable_symbol_status(); 241 pbStatus->set_visibility(serializeVisibilityToPb(entry->symbolStatus.state)); 242 serializeSourceToPb(entry->symbolStatus.source, &sourcePool, 243 pbStatus->mutable_source()); 244 pbStatus->set_comment(util::utf16ToUtf8(entry->symbolStatus.comment)); 245 246 for (auto& configValue : entry->values) { 247 pb::ConfigValue* pbConfigValue = pbEntry->add_config_values(); 248 serializeConfig(configValue->config, pbConfigValue->mutable_config()); 249 if (!configValue->product.empty()) { 250 pbConfigValue->mutable_config()->set_product(configValue->product); 251 } 252 253 pb::Value* pbValue = pbConfigValue->mutable_value(); 254 serializeSourceToPb(configValue->value->getSource(), &sourcePool, 255 pbValue->mutable_source()); 256 if (!configValue->value->getComment().empty()) { 257 pbValue->set_comment(util::utf16ToUtf8(configValue->value->getComment())); 258 } 259 260 if (configValue->value->isWeak()) { 261 pbValue->set_weak(true); 262 } 263 264 PbSerializerVisitor visitor(&sourcePool, &symbolPool, pbValue); 265 configValue->value->accept(&visitor); 266 } 267 } 268 } 269 } 270 271 serializeStringPoolToPb(sourcePool, pbTable->mutable_source_pool()); 272 serializeStringPoolToPb(symbolPool, pbTable->mutable_symbol_pool()); 273 return pbTable; 274 } 275 276 std::unique_ptr<pb::CompiledFile> serializeCompiledFileToPb(const ResourceFile& file) { 277 std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>(); 278 pbFile->set_resource_name(util::utf16ToUtf8(file.name.toString())); 279 pbFile->set_source_path(file.source.path); 280 serializeConfig(file.config, pbFile->mutable_config()); 281 282 for (const SourcedResourceName& exported : file.exportedSymbols) { 283 pb::CompiledFile_Symbol* pbSymbol = pbFile->add_exported_symbols(); 284 pbSymbol->set_resource_name(util::utf16ToUtf8(exported.name.toString())); 285 pbSymbol->set_line_no(exported.line); 286 } 287 return pbFile; 288 } 289 290 CompiledFileOutputStream::CompiledFileOutputStream(google::protobuf::io::ZeroCopyOutputStream* out, 291 pb::CompiledFile* pbFile) : 292 mOut(out), mPbFile(pbFile) { 293 } 294 295 bool CompiledFileOutputStream::ensureFileWritten() { 296 if (mPbFile) { 297 const uint64_t pbSize = mPbFile->ByteSize(); 298 mOut.WriteLittleEndian64(pbSize); 299 mPbFile->SerializeWithCachedSizes(&mOut); 300 const size_t padding = 4 - (pbSize & 0x03); 301 if (padding > 0) { 302 uint32_t zero = 0u; 303 mOut.WriteRaw(&zero, padding); 304 } 305 mPbFile = nullptr; 306 } 307 return !mOut.HadError(); 308 } 309 310 bool CompiledFileOutputStream::Write(const void* data, int size) { 311 if (!ensureFileWritten()) { 312 return false; 313 } 314 mOut.WriteRaw(data, size); 315 return !mOut.HadError(); 316 } 317 318 bool CompiledFileOutputStream::Finish() { 319 return ensureFileWritten(); 320 } 321 322 } // namespace aapt 323