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// MemoryImageReader, class for reading a memory image.
18
19#ifndef LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_MEMORY_IMAGE_READER_H_
20#define LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_MEMORY_IMAGE_READER_H_
21
22#include <string>
23#include <vector>
24
25#include "common/memory_image/memory-image-common.h"
26#include "common/memory_image/memory-image.pb.h"
27#include "util/base/integral_types.h"
28#include "util/base/logging.h"
29#include "util/base/macros.h"
30
31namespace libtextclassifier {
32namespace nlp_core {
33
34// General, non-templatized class, to reduce code duplication.
35//
36// Given a memory area (pointer to start + size in bytes) parses a memory image
37// from there into (1) MemoryImageHeader proto (it includes the serialized form
38// of the trimmed down original proto) and (2) a list of void* pointers to the
39// beginning of all data blobs.
40//
41// In case of parsing errors, we prefer to log the error and set the
42// success_status() to false, instead of CHECK-failing .  This way, the client
43// has the option of performing error recovery or crashing.  Some mobile apps
44// don't like crashing (a restart is very slow) so, if possible, we try to avoid
45// that.
46class GeneralMemoryImageReader {
47 public:
48  // Constructs this object.  See class-level comments.  Note: the memory area
49  // pointed to by start should not be deallocated while this object is used:
50  // this object does not copy it; instead, it keeps pointers inside that memory
51  // area.
52  GeneralMemoryImageReader(const void *start, uint64 num_bytes)
53      : start_(start), num_bytes_(num_bytes) {
54    success_ = ReadMemoryImage();
55  }
56
57  virtual ~GeneralMemoryImageReader() {}
58
59  // Returns true if reading the memory image has been successful.  If this
60  // returns false, then none of the other accessors should be used.
61  bool success_status() const { return success_; }
62
63  // Returns number of data blobs from the memory image.
64  int num_data_blobs() const {
65    return data_blob_views_.size();
66  }
67
68  // Returns pointer to the beginning of the data blob #i.
69  DataBlobView data_blob_view(int i) const {
70    if ((i < 0) || (i >= num_data_blobs())) {
71      TC_LOG(ERROR) << "Blob index " << i << " outside range [0, "
72                    << num_data_blobs() << "); will return empty data chunk";
73      return DataBlobView();
74    }
75    return data_blob_views_[i];
76  }
77
78  // Returns std::string with binary serialization of the original proto, but
79  // trimmed of the large fields (those were placed in the data blobs).
80  std::string trimmed_proto_str() const {
81    return trimmed_proto_serialization_.ToString();
82  }
83
84  const MemoryImageHeader &header() { return header_; }
85
86 protected:
87  void set_as_failed() {
88    success_ = false;
89  }
90
91 private:
92  bool ReadMemoryImage();
93
94  // Pointer to beginning of memory image.  Not owned.
95  const void *const start_;
96
97  // Number of bytes in the memory image.  This class will not read more bytes.
98  const uint64 num_bytes_;
99
100  // MemoryImageHeader parsed from the memory image.
101  MemoryImageHeader header_;
102
103  // Binary serialization of the trimmed version of the original proto.
104  // Represented as a DataBlobView backed up by the underlying memory image
105  // bytes.
106  DataBlobView trimmed_proto_serialization_;
107
108  // List of DataBlobView objects for all data blobs from the memory image (in
109  // order).
110  std::vector<DataBlobView> data_blob_views_;
111
112  // Memory reading success status.
113  bool success_;
114
115  TC_DISALLOW_COPY_AND_ASSIGN(GeneralMemoryImageReader);
116};
117
118// Like GeneralMemoryImageReader, but has knowledge about the type of the
119// original proto.  As such, it can parse it (well, the trimmed version) and
120// offer access to it.
121//
122// Template parameter T should be the type of the original proto.
123template<class T>
124class MemoryImageReader : public GeneralMemoryImageReader {
125 public:
126  MemoryImageReader(const void *start, uint64 num_bytes)
127      : GeneralMemoryImageReader(start, num_bytes) {
128    if (!trimmed_proto_.ParseFromString(trimmed_proto_str())) {
129      TC_LOG(INFO) << "Unable to parse the trimmed proto";
130      set_as_failed();
131    }
132  }
133
134  // Returns const reference to the trimmed version of the original proto.
135  // Useful for retrieving the many small fields that are not converted into
136  // data blobs.
137  const T &trimmed_proto() const { return trimmed_proto_; }
138
139 private:
140  T trimmed_proto_;
141
142  TC_DISALLOW_COPY_AND_ASSIGN(MemoryImageReader);
143};
144
145}  // namespace nlp_core
146}  // namespace libtextclassifier
147
148#endif  // LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_MEMORY_IMAGE_READER_H_
149