diff options
Diffstat (limited to 'files/include/android/goldfish/IniFile.h')
-rw-r--r-- | files/include/android/goldfish/IniFile.h | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/files/include/android/goldfish/IniFile.h b/files/include/android/goldfish/IniFile.h new file mode 100644 index 0000000..d4fe1d3 --- /dev/null +++ b/files/include/android/goldfish/IniFile.h @@ -0,0 +1,173 @@ +// Copyright 2015 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. + +#pragma once + +#include <inttypes.h> + +#include <filesystem> +#include <iosfwd> +#include <string> +#include <string_view> +#include <unordered_map> +#include <utility> +#include <vector> + +#include "aemu/base/Compiler.h" + +namespace android::goldfish { + +class IniFile { + DISALLOW_COPY_AND_ASSIGN(IniFile); + +public: + using DiskSize = uint64_t; + using MapType = std::unordered_map<std::string, std::string>; + using ElementOrderList = std::vector<const MapType::value_type *>; + + // A custom iterator to return the keys in original order. + class const_iterator : public ElementOrderList::const_iterator { + public: + using value_type = std::string; + + explicit const_iterator(ElementOrderList::const_iterator keyIterator) + : ElementOrderList::const_iterator(keyIterator) {} + + const value_type &operator*() const { + return ElementOrderList::const_iterator::operator*()->first; + } + const value_type *operator->() const { return &**this; } + }; + + // Note that the constructor _does not_ read data from the backing file. + // Call |Read| to read the data. + // When created without a backing file, all |read|/|write*| operations will + // fail unless |setBackingFile| is called to point to a valid file path. + explicit IniFile(std::filesystem::path backingFilePath = {}) + : mBackingFilePath(backingFilePath) {} + + // This constructor reads the data from memory at |data| of |size| bytes. + IniFile(const char *data, int size); + + // Set a new backing file. This does not read data from the file. Call + // |read| to refresh data from the new backing file. + void setBackingFile(std::filesystem::path filePath); + const std::string &getBackingFile() const { return mBackingFilePath; } + + // Reads data into IniFile from the backing file, overwriting any + // existing data. + bool read(bool keepComments = true); + // Same thing, but parses an already read file data. + // Note: write operations fail unless there's a backing file set + bool readFromMemory(std::string_view data); + + // Write the current IniFile to the backing file. + bool write(); + // Write the current IniFile to backing file. Discard any keys that have + // empty values. + bool writeDiscardingEmpty(); + // An optimized write. + // - Advantage: We don't write if there have been no updates since last + // write. + // - Disadvantage: Not safe if something else might be changing the ini + // file -- your view of the file is no longer consistent. Actually, this + // "bug" can be considered a "feature", if the ini file changed unbeknown + // to you, you're probably doing wrong in overwriting the changes without + // any update on your side. + bool writeIfChanged(); + + // Gets the number of (key,value) pairs in the file. + int size() const; + // Check if a certain key exists in the file. + bool hasKey(std::string_view key) const; + + // Make sure the string can be used as a valid key/value + static std::string makeValidKey(std::string_view str); + static std::string makeValidValue(std::string_view str); + + // ///////////////////// Value Getters + // ////////////////////////////////////// + // The IniFile has no knowledge about the type of the values. + // |defaultValue| is returned if the key doesn't exist or the value is badly + // formatted for the requested type. + // + // For some value types where the disk format is significantly more useful + // for human-parsing, overloads are provided that accept default values as + // strings to be parsed just like the backing ini file. + // - This has the benefit that default values can be stored in a separate + // file in human friendly form, and used directly. + // - The disadvantage is that behaviour is undefined if we fail to parse the + // default value. + std::string getString(const std::string &key, + std::string_view defaultValue) const; + int getInt(const std::string &key, int defaultValue) const; + int64_t getInt64(const std::string &key, int64_t defaultValue) const; + double getDouble(const std::string &key, double defaultValue) const; + // The serialized format for a bool acceepts the following values: + // True: "1", "yes", "YES". + // False: "0", "no", "NO". + bool getBool(const std::string &key, bool defaultValue) const; + bool getBool(const std::string &key, std::string_view defaultValueStr) const; + bool getBool(const std::string &key, const char *defaultValue) const { + return getBool(key, std::string_view(defaultValue)); + } + // Parses a string as disk size. The serialized format is [0-9]+[kKmMgG]. + // The + // suffixes correspond to KiB, MiB and GiB multipliers. + // Note: We consider 1K = 1024, not 1000. + DiskSize getDiskSize(const std::string &key, DiskSize defaultValue) const; + DiskSize getDiskSize(const std::string &key, + std::string_view defaultValue) const; + + // ///////////////////// Value Setters + // ////////////////////////////////////// + void setString(const std::string &key, std::string_view value); + void setInt(const std::string &key, int value); + void setInt64(const std::string &key, int64_t value); + void setDouble(const std::string &key, double value); + void setBool(const std::string &key, bool value); + void setDiskSize(const std::string &key, DiskSize value); + + // //////////////////// Iterators + // /////////////////////////////////////////// + // You can iterate through (string) keys in this IniFile, and then use the + // correct |get*| function to obtain the corresponding value. + // The order of keys is guaranteed to be an extension of the order in the + // backing file: + // - For keys that exist in the backing file, order is maintained. + // - Rest of the keys are appended in the end, in the order they were + // first added. + // Only const_iterator is provided. Use |set*| functions to modify the + // IniFile. + const_iterator begin() const { + return const_iterator(std::begin(mOrderList)); + } + const_iterator end() const { return const_iterator(std::end(mOrderList)); } + +protected: + void parseStream(std::istream *inFile, bool keepComments); + void updateData(const std::string &key, std::string &&value); + bool writeCommon(bool discardEmpty); + +private: + bool writeCommonImpl(bool discardEmpty, const std::string &filepath); + + MapType mData; + ElementOrderList mOrderList; + std::vector<std::pair<int, std::string>> mComments; + std::string mBackingFilePath; + bool mDirty = true; +}; + +} // namespace android::goldfish
\ No newline at end of file |