• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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