• 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 #ifndef LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
18 #define LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
19 
20 #include <string.h>
21 
22 #include <string>
23 
24 #include "base.h"
25 #include "common/memory_image/memory-image-common.h"
26 #include "util/base/integral_types.h"
27 #include "util/base/logging.h"
28 
29 namespace libtextclassifier {
30 namespace nlp_core {
31 
32 class LowLevelMemReader {
33  public:
34   // Constructs a MemReader instance that reads at most num_available_bytes
35   // starting from address start.
LowLevelMemReader(const void * start,uint64 num_available_bytes)36   LowLevelMemReader(const void *start, uint64 num_available_bytes)
37       : current_(reinterpret_cast<const char *>(start)),
38         // 0 bytes available if start == nullptr
39         num_available_bytes_(start ? num_available_bytes : 0),
40         num_loaded_bytes_(0) {
41   }
42 
43   // Copies length bytes of data to address target.  Advances current position
44   // and returns true on success and false otherwise.
Read(void * target,uint64 length)45   bool Read(void *target, uint64 length) {
46     if (length > num_available_bytes_) {
47       TC_LOG(WARNING) << "Not enough bytes: available " << num_available_bytes_
48                       << " < required " << length;
49       return false;
50     }
51     memcpy(target, current_, length);
52     Advance(length);
53     return true;
54   }
55 
56   // Reads the string encoded at the current position.  The bytes starting at
57   // current position should contain (1) little-endian uint32 size (in bytes) of
58   // the actual string and next (2) the actual bytes of the string.  Advances
59   // the current position and returns true if successful, false otherwise.
60   //
61   // On success, sets *view to be a view of the relevant bytes: view.data()
62   // points to the beginning of the string bytes, and view.size() is the number
63   // of such bytes.
ReadString(DataBlobView * view)64   bool ReadString(DataBlobView *view) {
65     uint32 size;
66     if (!Read(&size, sizeof(size))) {
67       TC_LOG(ERROR) << "Unable to read std::string size";
68       return false;
69     }
70     size = LittleEndian::ToHost32(size);
71     if (size > num_available_bytes_) {
72       TC_LOG(WARNING) << "Not enough bytes: " << num_available_bytes_
73                       << " available < " << size << " required ";
74       return false;
75     }
76     *view = DataBlobView(current_, size);
77     Advance(size);
78     return true;
79   }
80 
81   // Like ReadString(DataBlobView *) but reads directly into a C++ string,
82   // instead of a DataBlobView (StringPiece-like object).
ReadString(std::string * target)83   bool ReadString(std::string *target) {
84     DataBlobView view;
85     if (!ReadString(&view)) {
86       return false;
87     }
88     *target = view.ToString();
89     return true;
90   }
91 
92   // Returns current position.
GetCurrent()93   const char *GetCurrent() const { return current_; }
94 
95   // Returns remaining number of available bytes.
GetNumAvailableBytes()96   uint64 GetNumAvailableBytes() const { return num_available_bytes_; }
97 
98   // Returns number of bytes read ("loaded") so far.
GetNumLoadedBytes()99   uint64 GetNumLoadedBytes() const { return num_loaded_bytes_; }
100 
101   // Advance the current read position by indicated number of bytes.  Returns
102   // true on success, false otherwise (e.g., if there are not enough available
103   // bytes to advance num_bytes).
Advance(uint64 num_bytes)104   bool Advance(uint64 num_bytes) {
105     if (num_bytes > num_available_bytes_) {
106       return false;
107     }
108 
109     // Next line never results in an underflow of the unsigned
110     // num_available_bytes_, due to the previous if.
111     num_available_bytes_ -= num_bytes;
112     current_ += num_bytes;
113     num_loaded_bytes_ += num_bytes;
114     return true;
115   }
116 
117   // Advance current position to nearest multiple of alignment.  Returns false
118   // if not enough bytes available to do that, true (success) otherwise.
SkipToAlign(int alignment)119   bool SkipToAlign(int alignment) {
120     int num_extra_bytes = num_loaded_bytes_ % alignment;
121     if (num_extra_bytes == 0) {
122       return true;
123     }
124     return Advance(alignment - num_extra_bytes);
125   }
126 
127  private:
128   // Current position in the in-memory data.  Next call to Read() will read from
129   // this address.
130   const char *current_;
131 
132   // Number of available bytes we can still read.
133   uint64 num_available_bytes_;
134 
135   // Number of bytes read ("loaded") so far.
136   uint64 num_loaded_bytes_;
137 };
138 
139 }  // namespace nlp_core
140 }  // namespace libtextclassifier
141 
142 #endif  // LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_
143