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