blob: c2187be55cf2ebc5b08fd4a26b9a620bee43b54d [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#pragma once
#include "android/base/Compiler.h"
#include "android/base/StringView.h"
#include <iosfwd>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <inttypes.h>
namespace android {
namespace base {
class IniFile {
public:
typedef int64_t DiskSize;
typedef std::unordered_map<std::string, std::string> MapType;
typedef std::vector<std::string> KeyListType;
// Note that the constructor _does not_ read data from the backing file.
// Call |Read| to read the data.
IniFile(const std::string& backingFilePath)
: mDirty(true), mBackingFilePath(backingFilePath) {}
// When created without a backing file, all |read|/|write*| operations will
// fail unless |setBackingFile| is called to point to a valid file path.
IniFile() : mDirty(true) {}
// 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(const std::string& filePath);
const std::string& getBackingFile() const { return mBackingFilePath; }
// Reads data into IniFile from the the backing file, overwriting any
// existing data.
bool read();
// 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(const std::string& key) const;
// Make sure the string can be used as a valid key
static std::string makeValidKey(StringView 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,
const std::string& 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 getBoolStr(const std::string& kye,
const std::string& defaultValueStr) const;
// 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 getDiskSizeStr(const std::string& key,
const std::string& defaultValueStr) const;
// ///////////////////// Value Setters
// //////////////////////////////////////
void setString(const std::string& key, const std::string& 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.
typedef KeyListType::const_iterator const_iterator;
const_iterator begin() const { return std::begin(mKeys); }
const_iterator end() const { return std::end(mKeys); }
protected:
// Helper functions.
void parseFile(std::istream* inFile);
void updateData(const std::string& key, const std::string& value);
bool writeCommon(bool discardEmpty);
private:
bool mDirty;
MapType mData;
KeyListType mKeys;
std::vector<std::pair<int, std::string>> mComments;
std::string mBackingFilePath;
DISALLOW_COPY_AND_ASSIGN(IniFile);
};
} // namespace base
} // namespace android