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.
ReadAndCheckSignature(LowLevelMemReader * mem_reader)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.
ParseMemoryImageHeader(LowLevelMemReader * mem_reader,MemoryImageHeader * header)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
ReadMemoryImage()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