Home | History | Annotate | Download | only in memory_image
      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