version 3.14.0

PIBinaryStream::wasReadError() method, remove incomplete read asserts
This commit is contained in:
2023-08-30 12:18:04 +03:00
parent c86ec0ae82
commit 0907a3eb13
5 changed files with 118 additions and 48 deletions

View File

@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP) project(PIP)
set(PIP_MAJOR 3) set(PIP_MAJOR 3)
set(PIP_MINOR 13) set(PIP_MINOR 14)
set(PIP_REVISION 2) set(PIP_REVISION 0)
set(PIP_SUFFIX ) set(PIP_SUFFIX )
set(PIP_COMPANY SHS) set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS) set(PIP_DOMAIN org.SHS)

View File

@@ -2,6 +2,7 @@
\~russian \page iostream Поток ввода/вывода \~russian \page iostream Поток ввода/вывода
\~english \~english
\~russian \~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации. %PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или Не может быть использован в чистом виде, только в виде миксина или
@@ -115,3 +116,10 @@ for (int i = 0; i < 10; ++i)
0.8 0.8
0.9 0.9
\endcode \endcode
\~english
\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

View File

@@ -44,7 +44,10 @@ public:
//! \~english Assign "device" device //! \~english Assign "device" device
//! \~russian Назначает устройство "device" //! \~russian Назначает устройство "device"
void setDevice(PIIODevice * device) { dev = device; } void setDevice(PIIODevice * device) {
dev = device;
resetReadError();
}
bool binaryStreamAppendImp(const void * d, size_t s) { bool binaryStreamAppendImp(const void * d, size_t s) {
if (!dev) return false; if (!dev) return false;

View File

@@ -65,6 +65,7 @@
template<typename P> template<typename P>
class PIBinaryStream { class PIBinaryStream {
public: public:
//! \~english Write data
//! \~russian Записать данные //! \~russian Записать данные
bool binaryStreamAppend(const void * d, size_t s) { bool binaryStreamAppend(const void * d, size_t s) {
if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) { if (!static_cast<P *>(this)->binaryStreamAppendImp(d, s)) {
@@ -73,32 +74,50 @@ public:
} }
return true; return true;
} }
//! \~english Read data
//! \~russian Прочитать данные //! \~russian Прочитать данные
bool binaryStreamTake(void * d, size_t s) { bool binaryStreamTake(void * d, size_t s) {
if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) { if (!static_cast<P *>(this)->binaryStreamTakeImp(d, s)) {
_was_read_error_ = true;
return false; return false;
printf("[PIBinaryStream] binaryStreamTake() error\n"); printf("[PIBinaryStream] binaryStreamTake() error\n");
} }
return true; return true;
} }
//! \~russian Узнать оставшийся размер //! \~english Returns remain size
//!\~\details //! \~russian Возвращает оставшийся размер
//!\~russian Возвращает -1 если нет информации о размере //! \~\details
//! \~english Returns -1 if no information about size
//! \~russian Возвращает -1 если нет информации о размере
ssize_t binaryStreamSize() const { return static_cast<const P *>(this)->binaryStreamSizeImp(); } ssize_t binaryStreamSize() const { return static_cast<const P *>(this)->binaryStreamSizeImp(); }
//! \~english Write data
//! \~russian Записать данные //! \~russian Записать данные
template<typename T> template<typename T>
void binaryStreamAppend(T v) { void binaryStreamAppend(T v) {
binaryStreamAppend(&v, sizeof(v)); binaryStreamAppend(&v, sizeof(v));
} }
//! \~english Read int
//! \~russian Прочитать int //! \~russian Прочитать int
int binaryStreamTakeInt() { int binaryStreamTakeInt() {
int r = 0; int r = 0;
binaryStreamTake(&r, sizeof(r)); binaryStreamTake(&r, sizeof(r));
return r; return r;
} }
//! \~english Returns whether there has been an incomplete read since last \a resetReadError() or after the stream was created
//! \~russian Возвращает было ли неполное чтение с момента последнего вызова \a resetReadError()
bool wasReadError() const { return _was_read_error_; }
//! \~english Reset incomplete read flag
//! \~russian Сбрасывает флаг неполного чтения
void resetReadError() { _was_read_error_ = false; }
private:
bool _was_read_error_ = false;
}; };
@@ -305,7 +324,6 @@ template<typename P,
inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) { inline PIBinaryStreamTrivialRef<P> operator>>(PIBinaryStream<P> & s, T & v) {
if (!s.binaryStreamTake(&v, sizeof(v))) { if (!s.binaryStreamTake(&v, sizeof(v))) {
printf("error with %s\n", __PIP_TYPENAME__(T)); printf("error with %s\n", __PIP_TYPENAME__(T));
assert(false);
} }
return s; return s;
} }
@@ -322,25 +340,41 @@ template<typename P,
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
// piCout << ">> vector trivial default"; // piCout << ">> vector trivial default";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz); v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) { if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T)); printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(false); v.clear();
} }
return s; return s;
} }
template<typename P, template<typename P,
typename T, typename T,
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< typename std::enable_if<
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, !std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
int>::type = 0> int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
// piCout << ">> vector trivial custom"; // piCout << ">> vector trivial custom";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz); v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i) {
s >> v[i]; s >> v[i];
if (s.wasReadError()) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s; return s;
} }
@@ -348,33 +382,49 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
//! \~english Restore operator for PIDeque of any trivial copyable type //! \~english Restore operator for PIDeque of any trivial copyable type
//! \~russian Оператор извлечения для PIDeque тривиальных типов //! \~russian Оператор извлечения для PIDeque тривиальных типов
template<typename P, template<typename P,
typename T, typename T,
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< typename std::enable_if<
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
int>::type = 0> int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
// piCout << ">> deque trivial default"; // piCout << ">> deque trivial default";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz); v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) { if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T)); printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(false); v.clear();
} }
return s; return s;
} }
template<typename P, template<typename P,
typename T, typename T,
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< typename std::enable_if<
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, !std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
int>::type = 0> int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
// piCout << ">> deque trivial custom"; // piCout << ">> deque trivial custom";
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
if (s.wasReadError()) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(sz); v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i) {
s >> v[i]; s >> v[i];
if (s.wasReadError()) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s; return s;
} }
@@ -382,9 +432,9 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
//! \~english Restore operator for PIVector2D of any trivial copyable type //! \~english Restore operator for PIVector2D of any trivial copyable type
//! \~russian Оператор извлечения для PIVector2D тривиальных типов //! \~russian Оператор извлечения для PIVector2D тривиальных типов
template<typename P, template<typename P,
typename T, typename T,
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< typename std::enable_if<
std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
int>::type = 0> int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
@@ -392,17 +442,22 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v)
int r, c; int r, c;
r = s.binaryStreamTakeInt(); r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt(); c = s.binaryStreamTakeInt();
if (s.wasReadError()) {
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
v._resizeRaw(r, c); v._resizeRaw(r, c);
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) { if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T)); printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
assert(false); v.clear();
} }
return s; return s;
} }
template<typename P, template<typename P,
typename T, typename T,
typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< typename std::enable_if<
!std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, !std::is_same<decltype(std::declval<PIBinaryStream<P> &>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value,
int>::type = 0> int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
@@ -481,14 +536,15 @@ inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIVector2D<T>
//! \~russian Оператор извлечения для PIVector сложных типов //! \~russian Оператор извлечения для PIVector сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0> template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
// piCout << ">> vector complex";
/*if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
v.resize(s.binaryStreamTakeInt()); v.resize(s.binaryStreamTakeInt());
for (size_t i = 0; i < v.size(); ++i) for (size_t i = 0; i < v.size(); ++i) {
s >> v[i]; s >> v[i];
if (s.wasReadError()) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s; return s;
} }
@@ -497,14 +553,15 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector<T> & v) {
//! \~russian Оператор извлечения для PIDeque сложных типов //! \~russian Оператор извлечения для PIDeque сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0> template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
// piCout << ">> deque complex";
/*if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
v.resize(s.binaryStreamTakeInt()); v.resize(s.binaryStreamTakeInt());
for (size_t i = 0; i < v.size(); ++i) for (size_t i = 0; i < v.size(); ++i) {
s >> v[i]; s >> v[i];
if (s.wasReadError()) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
v.clear();
return s;
}
}
return s; return s;
} }
@@ -513,11 +570,6 @@ inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<T> & v) {
//! \~russian Оператор извлечения для PIVector2D сложных типов //! \~russian Оператор извлечения для PIVector2D сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0> template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
// piCout << ">> vector2d complex";
/*if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}*/
int r, c; int r, c;
PIVector<T> tmp; PIVector<T> tmp;
r = s.binaryStreamTakeInt(); r = s.binaryStreamTakeInt();
@@ -549,19 +601,25 @@ inline PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key, T>
//! \~russian Оператор извлечения //! \~russian Оператор извлечения
template<typename P, typename Key, typename T> template<typename P, typename Key, typename T>
inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) { inline PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
/*if (s.size_s() < 4) {
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
int sz = s.binaryStreamTakeInt(); int sz = s.binaryStreamTakeInt();
v.pim_index.resize(sz); v.pim_index.resize(sz);
int ind = 0; int ind = 0;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
ind = s.binaryStreamTakeInt(); ind = s.binaryStreamTakeInt();
s >> v.pim_index[i].key; s >> v.pim_index[i].key;
if (s.wasReadError()) {
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear();
return s;
}
v.pim_index[i].index = ind; v.pim_index[i].index = ind;
} }
s >> v.pim_content; s >> v.pim_content;
if (s.wasReadError()) {
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
v.clear();
return s;
}
if (v.pim_content.size_s() != v.pim_index.size_s()) { if (v.pim_content.size_s() != v.pim_index.size_s()) {
piCout << "Warning: loaded invalid PIMap, clear"; piCout << "Warning: loaded invalid PIMap, clear";
v.clear(); v.clear();

View File

@@ -1820,6 +1820,7 @@ BINARY_STREAM_WRITE(PIString) {
//! \~russian Оператор извлечения. //! \~russian Оператор извлечения.
BINARY_STREAM_READ(PIString) { BINARY_STREAM_READ(PIString) {
s >> v.d; s >> v.d;
if (s.wasReadError()) v.clear();
return s; return s;
} }