/******************************************************************************** * * * I N I R e a d e r & W r i t e r * * * ********************************************************************************* * Copyright (C) 2022,2024 by Jeroen van der Zijp. All Rights Reserved. * ********************************************************************************* * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This library 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 Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see * ********************************************************************************/ #ifndef FXINI_H #define FXINI_H #ifndef FXPARSEBUFFER_H #include "FXParseBuffer.h" #endif namespace FX { /** * The FXINI class loads or saves an FXVariant to an .INI text file. * The FXVariant structure is subject to some limits: * * - Must be a map of maps, of the form variant[SECTION][KEY] where * SECTION and KEY are both strings. * * - Each KEY maps to boolean, integer, double, or string type, or * be empty (equal to FXVariant::null). * * - The variant tree may contain other items, but only items of the * aforementioned types will be serialized to the .INI file. * * When saving, numeric values are printed with configurable precision; * (default=15 digits which results in minimal information loss for * real numbers). * * Values may be arbitrary strings, and this includes any legal UTF8- * encoded value. When saving, strings may be escaped to ensure the * information may be read back in unchanged. The following applies * to when strings are escaped: * * - Escape mode 0: UTF8 characters are passed unescaped. * - Escape mode 1: UTF8 characters are escaped as \xXX. * - Escape mode 2: UTF8 will be escaped using Unicode escape * sequences of the for \uXXXX or \uXXXX\uXXXX (two surrogate- * pairs escape codes for code points exceeding 16 bits). * * The default setting is to allow UTF8 characters in the output. */ class FXAPI FXINI : public FXParseBuffer { public: enum Error { ErrOK, /// No errors ErrSave, /// Unable to save ErrLoad, /// Unable to load ErrToken, /// Illegal token ErrColon, /// Expected colon ':' ErrComma, /// Expected comma ',' ErrBracket, /// Expected closing bracket ErrBrace, /// Expected closing brace ErrQuotes, /// Expected closing quotes ErrQuote, /// Expected closing quote ErrNumber, /// Numeric conversion ErrEnd /// Unexpected end of file }; protected: FXlong offset; // Position from start FXint token; // Current token FXint column; // Current column FXint indent; // Indentation level FXint line; // Line number FXuchar state; // Parse state FXuchar prec; // Numeric precision FXuchar fmt; // Numeric format FXuchar esc; // Escape mode private: FXint next(); Error loadVariant(FXVariant& var); Error saveVariant(const FXVariant& section); Error saveSection(const FXString& str); Error saveEntry(const FXVariant& var); Error saveString(const FXString& str); private: static const FXchar *const errors[]; private: FXINI(const FXINI&); FXINI &operator=(const FXINI&); public: /** * Initialize INI parser. */ FXINI(); /** * Initialize INI parser with buffer of size and direction. * Text location (column, line number, byte offset) is reset. */ FXINI(FXchar* buffer,FXuval sz=8192,Direction d=Load); /** * Open INI parse buffer with given size and direction. * Text location (column, line number, byte offset) is reset. */ FXbool open(FXchar* buffer,FXuval sz=8192,Direction d=Load); /** * Return current line number. */ FXint getLine() const { return line; } /** * Return current column number. */ FXint getColumn() const { return column; } /** * Return offset from begin of file. */ FXlong getOffset() const { return offset; } /** * Load a variant from stream. * Return false if stream wasn't opened for loading, or syntax error. */ Error load(FXVariant& variant); /** * Save a variant to stream. * Return false if stream wasn't opened for saving, or disk was full. */ Error save(const FXVariant& variant); /** * Returns error code for given error. */ static const FXchar* getError(Error err){ return errors[err]; } /** * Floating point output precision control. * This controls the number of significant digits written to * the output. The default is 15. */ void setNumericPrecision(FXuchar p){ prec=p; } FXuchar getNumericPrecision() const { return prec; } /** * Floating point output format control. * The format mode is interpreted as follows: * * 0 No exponent. * 1 Exponent. * 2 Output exponent when required. * * The default mode is 2. */ void setNumericFormat(FXuchar f){ fmt=f; } FXuchar getNumericFormat() const { return fmt; } /** * Change string escape mode; 0=don't escape unicode in strings; * 1=escape unicode as \xHH, 2=escape UTF8 multi-byte characters * as \uXXXX or \uXXXX\uXXXX. * Default is to escape control characters only. */ void setEscapeMode(FXuchar e){ esc=e; } FXuchar getEscapeMode() const { return esc; } /** * Close INI parser. * To permit diagnostics, text location not reset. */ FXbool close(); /** * Close INI parser and clean up. */ virtual ~FXINI(); }; } #endif