Files
pip/libs/main/text/pitextstream.h
2023-09-06 20:26:38 +03:00

469 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! \file pitextstream.h
* \ingroup Text
* \~\brief
* \~english Text serialization functionality over PIBinaryStream
* \~russian Функциональность текстовой сериализации поверх PIBinaryStream
*/
/*
PIP - Platform Independent Primitives
Text serialization functionality over PIBinaryStream
Ivan Pelipenko peri4ko@yandex.ru
This program 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 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 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 <http://www.gnu.org/licenses/>.
*/
#ifndef PITEXTSTREAM_H
#define PITEXTSTREAM_H
#include "pistring.h"
//! \ingroup Text
//! \~\brief
//! \~english Text serialization functionality over PIBinaryStream.
//! \~russian Функциональность текстовой сериализации поверх PIBinaryStream.
template<typename P>
class PITextStream {
public:
//! \~english Floating-point numbers write format
//! \~russian Формат записи чисел с плавающей точкой
enum FloatFormat {
DecimalFormat /** \~english Decimal format, "*.*" \~russian Десятичный формат, "*.*" */ = 'f',
ExponentFormat /** \~english Exponential format, "*e+-<E>" \~russian Экспонентный формат, "*e+-<E>" */ = 'e'
};
//! \~english String encoding
//! \~russian Кодировка строк
enum Encoding {
System /** \~english System encoding \~russian Системная кодировка */,
UTF8 /** \~english UTF-8 encoding \~russian Кодировка UTF-8 */,
};
//! \~english Construct text stream binded to "stream_"
//! \~russian Возвращает привязанный к "stream_" текстовый поток
PITextStream(PIBinaryStream<P> * stream_) { setStream(stream_); }
//! \~english Returns binded PIBinaryStream
//! \~russian Возвращает привязанный PIBinaryStream
PIBinaryStream<P> * stream() const { return s; }
void setStream(PIBinaryStream<P> * stream_) {
s = stream_;
is_end = false;
}
//! \~english Returns if end of stream reached
//! \~russian Возвращает достигнут ли конец потока
bool isEnd() const { return is_end; }
//! \~english Returns read/write encoding
//! \~russian Возвращает кодировку чтения/записи
Encoding encoding() const { return enc; }
//! \~english Set read/write encoding, default UTF8
//! \~russian Устанавливает кодировку чтения/записи, по умолчанию UTF8
void setEncoding(Encoding e) { enc = e; }
//! \~english Returns float numbers write format
//! \~russian Возвращает формат записи чисел с плавающей точкой
FloatFormat floatFormat() const { return format_; }
//! \~english Set float numbers write format, default DecimalFormat
//! \~russian Устанавливает формат записи чисел с плавающей точкой, по умолчанию DecimalFormat
void setFloatFormat(FloatFormat format) { format_ = format; }
//! \~english Returns float numbers write precision
//! \~russian Возвращает точность записи чисел с плавающей точкой
int floatPrecision() const { return prec_; }
//! \~english Set float numbers write precision to "prec_" digits, default 5
//! \~russian Устанавливает точность записи чисел с плавающей точкой, по умолчанию 5
void setFloatPrecision(int prec) { prec_ = prec; }
//! \~english Append space
//! \~russian Добавляет пробел
PITextStream<P> & space() {
s->binaryStreamAppend(' ');
return *this;
}
//! \~english Append new line
//! \~russian Добавляет новую строку
PITextStream<P> & newLine() {
s->binaryStreamAppend('\n');
return *this;
}
//! \~english Append "v" string
//! \~russian Добавляет строку "v"
void append(const PIString & v) {
if (v.isEmpty()) return;
PIByteArray d;
switch (enc) {
case System: d = v.toSystem(); break;
case UTF8: d = v.toUTF8(); break;
}
s->binaryStreamAppend(d.data(), d.size());
}
//! \~english Append "v" as ASCII
//! \~russian Добавляет "v" как ASCII
void append(const PIConstChars & v) {
if (!v.isEmpty()) s->binaryStreamAppend(v.data(), v.size());
}
//! \~english Append "v" char as character
//! \~russian Добавляет "v" как символ
void append(char v) { s->binaryStreamAppend(v); }
//! \~english Append "v" as ASCII
//! \~russian Добавляет "v" как ASCII
void append(const char * v) { append(PIConstChars(v)); }
//! \~english Append boolean, "true" of "false"
//! \~russian Добавляет логическое, "true" of "false"
void append(bool v) { append(v ? "true" : "false"); }
//! \~english Append integer
//! \~russian Добавляет целое
void append(int v) { append(PIString::fromNumber(v)); }
//! \~english Append integer
//! \~russian Добавляет целое
void append(llong v) { append(PIString::fromNumber(v)); }
//! \~english Append floating-point number, using \a floatFormat() and \a floatPrecision()
//! \~russian Добавляет число с плавающей точкой, используя \a floatFormat() и \a floatPrecision()
void append(float v) { append(PIString::fromNumber(v, (char)format_, prec_)); }
//! \~english Append floating-point number, using \a floatFormat() and \a floatPrecision()
//! \~russian Добавляет число с плавающей точкой, используя \a floatFormat() и \a floatPrecision()
void append(double v) { append(PIString::fromNumber(v, (char)format_, prec_)); }
//! \~english Read character
//! \~russian Читает символ
char readChar(bool * rok) {
char ret;
bool ok = s->binaryStreamTake(&ret, sizeof(ret));
if (!ok) is_end = true;
if (rok) *rok = ok;
return ret;
}
//! \~english Read line
//! \~russian Читает строку
PIString readLine() {
PIByteArray ret;
bool ok = true;
for (;;) {
char b = readChar(&ok);
if (!ok || b == '\n') break;
if (b != '\r') ret.append((uchar)b);
}
return fromBytes(ret);
}
//! \~english Read word, skip leading whitespaces, until next whitespace
//! \~russian Читает слово, пропуская начальные пробельные символы, до следующего пробельного символа
PIString readWord() {
static PIConstChars spaces(" \t\n\r");
return readUntil(spaces);
}
//! \~english Read C-word, skip leading and until non C-identifier
//! \~russian Читает C-слово, пропуская начальные и до следующих символов, не являющихся C-идентификаторами
PIString readCWord() {
static PIConstChars chars(" \t\n\r:;%$&#@!?~/*-+=.,\\\"'`[](){}<>");
return readUntil(chars);
}
private:
PIString fromBytes(const PIByteArray & ba) {
switch (enc) {
case System: return PIString::fromSystem(ba);
case UTF8: return PIString::fromUTF8(ba);
}
return PIString();
}
PIString readUntil(const PIConstChars & chars) {
// static PIConstChars spaces(" \t\n\r");
bool ok = true;
char c = skipWhile(chars, &ok);
if (!ok) return PIString();
PIByteArray ret;
ret.append((uchar)c);
for (;;) {
c = readChar(&ok);
if (!ok || chars.contains(c)) break;
ret.append((uchar)c);
}
return fromBytes(ret);
}
// returns first non-"chars" char
char skipWhile(const PIConstChars & chars, bool * rok) {
bool ok = true;
char c = 0;
for (;;) {
c = readChar(&ok);
if (!ok || !chars.contains(c)) break;
}
if (rok) *rok = ok;
return c;
}
PIBinaryStream<P> * s;
Encoding enc = UTF8;
FloatFormat format_ = DecimalFormat;
bool is_end = false;
int prec_ = 5;
};
//! \~english Returns PITextStream for binary stream "stream"
//! \~russian Возвращает PITextStream для бинарного потока "stream"
template<typename P>
inline PITextStream<P> createPITextStream(PIBinaryStream<P> * stream) {
return PITextStream<P>(stream);
}
//! \~english Append boolean
//! \~russian Добавляет логическое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, bool v) {
s.append(v);
return s;
}
//! \~english Append character
//! \~russian Добавляет символ
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, char v) {
s.append(v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, uchar v) {
s.append((int)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, short v) {
s.append((int)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, ushort v) {
s.append((int)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, int v) {
s.append((int)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, uint v) {
s.append((int)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, llong v) {
s.append((llong)v);
return s;
}
//! \~english Append integer
//! \~russian Добавляет целое
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, ullong v) {
s.append((llong)v);
return s;
}
//! \~english Append floating-point number
//! \~russian Добавляет число с плавающей точкой
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, float v) {
s.append(v);
return s;
}
//! \~english Append floating-point number
//! \~russian Добавляет число с плавающей точкой
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, double v) {
s.append(v);
return s;
}
//! \~english Append string
//! \~russian Добавляет строку
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, const char * v) {
s.append(v);
return s;
}
//! \~english Append string
//! \~russian Добавляет строку
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, const PIConstChars & v) {
s.append(v);
return s;
}
//! \~english Append string
//! \~russian Добавляет строку
template<typename P>
inline PITextStream<P> & operator<<(PITextStream<P> & s, const PIString & v) {
s.append(v);
return s;
}
//! \~english Read word as bool
//! \~russian Читает слово как логическое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, bool & v) {
v = s.readWord().toBool();
return s;
}
//! \~english Read character
//! \~russian Читает символ
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, char & v) {
v = s.readChar();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, uchar & v) {
v = s.readWord().toUInt();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, short & v) {
v = s.readWord().toInt();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, ushort & v) {
v = s.readWord().toUInt();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, int & v) {
v = s.readWord().toInt();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, uint & v) {
v = s.readWord().toUInt();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, long & v) {
v = s.readWord().toLong();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, ulong & v) {
v = s.readWord().toULong();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, llong & v) {
v = s.readWord().toLLong();
return s;
}
//! \~english Read word as integer
//! \~russian Читает слово как целое
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, ullong & v) {
v = s.readWord().toULLong();
return s;
}
//! \~english Read word as floating-point number
//! \~russian Читает слово как число с плавающей точкой
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, float & v) {
v = s.readWord().toFloat();
return s;
}
//! \~english Read word as floating-point number
//! \~russian Читает слово как число с плавающей точкой
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, double & v) {
v = s.readWord().toDouble();
return s;
}
//! \~english Read word
//! \~russian Читает слово
template<typename P>
inline PITextStream<P> & operator>>(PITextStream<P> & s, PIString & v) {
v = s.readWord();
return s;
}
#endif