/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_ #define LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_ #include <string.h> #include <string> #include "base.h" #include "common/memory_image/memory-image-common.h" #include "util/base/integral_types.h" #include "util/base/logging.h" namespace libtextclassifier { namespace nlp_core { class LowLevelMemReader { public: // Constructs a MemReader instance that reads at most num_available_bytes // starting from address start. LowLevelMemReader(const void *start, uint64 num_available_bytes) : current_(reinterpret_cast<const char *>(start)), // 0 bytes available if start == nullptr num_available_bytes_(start ? num_available_bytes : 0), num_loaded_bytes_(0) { } // Copies length bytes of data to address target. Advances current position // and returns true on success and false otherwise. bool Read(void *target, uint64 length) { if (length > num_available_bytes_) { TC_LOG(WARNING) << "Not enough bytes: available " << num_available_bytes_ << " < required " << length; return false; } memcpy(target, current_, length); Advance(length); return true; } // Reads the string encoded at the current position. The bytes starting at // current position should contain (1) little-endian uint32 size (in bytes) of // the actual string and next (2) the actual bytes of the string. Advances // the current position and returns true if successful, false otherwise. // // On success, sets *view to be a view of the relevant bytes: view.data() // points to the beginning of the string bytes, and view.size() is the number // of such bytes. bool ReadString(DataBlobView *view) { uint32 size; if (!Read(&size, sizeof(size))) { TC_LOG(ERROR) << "Unable to read std::string size"; return false; } size = LittleEndian::ToHost32(size); if (size > num_available_bytes_) { TC_LOG(WARNING) << "Not enough bytes: " << num_available_bytes_ << " available < " << size << " required "; return false; } *view = DataBlobView(current_, size); Advance(size); return true; } // Like ReadString(DataBlobView *) but reads directly into a C++ string, // instead of a DataBlobView (StringPiece-like object). bool ReadString(std::string *target) { DataBlobView view; if (!ReadString(&view)) { return false; } *target = view.ToString(); return true; } // Returns current position. const char *GetCurrent() const { return current_; } // Returns remaining number of available bytes. uint64 GetNumAvailableBytes() const { return num_available_bytes_; } // Returns number of bytes read ("loaded") so far. uint64 GetNumLoadedBytes() const { return num_loaded_bytes_; } // Advance the current read position by indicated number of bytes. Returns // true on success, false otherwise (e.g., if there are not enough available // bytes to advance num_bytes). bool Advance(uint64 num_bytes) { if (num_bytes > num_available_bytes_) { return false; } // Next line never results in an underflow of the unsigned // num_available_bytes_, due to the previous if. num_available_bytes_ -= num_bytes; current_ += num_bytes; num_loaded_bytes_ += num_bytes; return true; } // Advance current position to nearest multiple of alignment. Returns false // if not enough bytes available to do that, true (success) otherwise. bool SkipToAlign(int alignment) { int num_extra_bytes = num_loaded_bytes_ % alignment; if (num_extra_bytes == 0) { return true; } return Advance(alignment - num_extra_bytes); } private: // Current position in the in-memory data. Next call to Read() will read from // this address. const char *current_; // Number of available bytes we can still read. uint64 num_available_bytes_; // Number of bytes read ("loaded") so far. uint64 num_loaded_bytes_; }; } // namespace nlp_core } // namespace libtextclassifier #endif // LIBTEXTCLASSIFIER_COMMON_MEMORY_IMAGE_LOW_LEVEL_MEMORY_READER_H_