1 /* 2 * Copyright (C) 2017 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 "common/memory_image/memory-image-reader.h" 18 19 #include <string> 20 21 #include "base.h" 22 #include "common/memory_image/low-level-memory-reader.h" 23 #include "common/memory_image/memory-image-common.h" 24 #include "common/memory_image/memory-image.pb.h" 25 #include "util/base/logging.h" 26 27 namespace libtextclassifier { 28 namespace nlp_core { 29 30 namespace { 31 32 // Checks that the memory area read by mem_reader starts with the expected 33 // signature. Advances mem_reader past the signature and returns success 34 // status. 35 bool ReadAndCheckSignature(LowLevelMemReader *mem_reader) { 36 const std::string expected_signature = MemoryImageConstants::kSignature; 37 const int signature_size = expected_signature.size(); 38 if (mem_reader->GetNumAvailableBytes() < signature_size) { 39 TC_LOG(ERROR) << "Not enough bytes to check signature"; 40 return false; 41 } 42 const std::string actual_signature(mem_reader->GetCurrent(), signature_size); 43 if (!mem_reader->Advance(signature_size)) { 44 TC_LOG(ERROR) << "Failed to advance past signature"; 45 return false; 46 } 47 if (actual_signature != expected_signature) { 48 TC_LOG(ERROR) << "Different signature: actual \"" << actual_signature 49 << "\" != expected \"" << expected_signature << "\""; 50 return false; 51 } 52 return true; 53 } 54 55 // Parses MemoryImageHeader from mem_reader. Advances mem_reader past it. 56 // Returns success status. 57 bool ParseMemoryImageHeader( 58 LowLevelMemReader *mem_reader, MemoryImageHeader *header) { 59 std::string header_proto_str; 60 if (!mem_reader->ReadString(&header_proto_str)) { 61 TC_LOG(ERROR) << "Unable to read header_proto_str"; 62 return false; 63 } 64 if (!header->ParseFromString(header_proto_str)) { 65 TC_LOG(ERROR) << "Unable to parse MemoryImageHeader"; 66 return false; 67 } 68 return true; 69 } 70 71 } // namespace 72 73 bool GeneralMemoryImageReader::ReadMemoryImage() { 74 LowLevelMemReader mem_reader(start_, num_bytes_); 75 76 // Read and check signature. 77 if (!ReadAndCheckSignature(&mem_reader)) { 78 return false; 79 } 80 81 // Parse MemoryImageHeader header_. 82 if (!ParseMemoryImageHeader(&mem_reader, &header_)) { 83 return false; 84 } 85 86 // Check endianness. 87 if (header_.is_little_endian() != LittleEndian::IsLittleEndian()) { 88 // TODO(salcianu): implement conversion: it will take time, but it's better 89 // than crashing. Not very urgent: [almost] all current Android phones are 90 // little-endian. 91 TC_LOG(ERROR) << "Memory image is " 92 << (header_.is_little_endian() ? "little" : "big") 93 << " endian. " 94 << "Local system is different and we don't currently support " 95 << "conversion between the two."; 96 return false; 97 } 98 99 // Read binary serialization of trimmed original proto. 100 if (!mem_reader.ReadString(&trimmed_proto_serialization_)) { 101 TC_LOG(ERROR) << "Unable to read trimmed proto binary serialization"; 102 return false; 103 } 104 105 // Fill vector of pointers to beginning of each data blob. 106 for (int i = 0; i < header_.blob_info_size(); ++i) { 107 const MemoryImageDataBlobInfo &blob_info = header_.blob_info(i); 108 if (!mem_reader.SkipToAlign(header_.alignment())) { 109 TC_LOG(ERROR) << "Unable to align for blob #i" << i; 110 return false; 111 } 112 data_blob_views_.emplace_back( 113 mem_reader.GetCurrent(), 114 blob_info.num_bytes()); 115 if (!mem_reader.Advance(blob_info.num_bytes())) { 116 TC_LOG(ERROR) << "Not enough bytes for blob #i" << i; 117 return false; 118 } 119 } 120 121 return true; 122 } 123 124 } // namespace nlp_core 125 } // namespace libtextclassifier 126