132 lines
3.4 KiB
C++
132 lines
3.4 KiB
C++
/* -*-c++-*-
|
|
* Copyright (C) 2010 Cedric Pinson <cedric.pinson@plopbyte.net>
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* 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
|
|
* OpenSceneGraph Public License for more details.
|
|
*
|
|
* Authors:
|
|
* Cedric Pinson <cedric.pinson@plopbyte.net>
|
|
*/
|
|
|
|
#ifndef JSON_STREAM
|
|
#define JSON_STREAM
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <cmath>
|
|
#include <limits>
|
|
|
|
#include <osgDB/fstream>
|
|
|
|
#include "utf8_string"
|
|
|
|
|
|
// A simple class wrapping ofstream calls to enable generic cleaning of json data.
|
|
// Especially 'standard' json should:
|
|
// * have utf-8 encoded string
|
|
// * disallow some control characters
|
|
// * does not support inf or nan values
|
|
|
|
#if defined(WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<=1700)
|
|
namespace std
|
|
{
|
|
inline int isfinite( double x ) { return _finite( x ); }
|
|
inline int isinf( double x ) { return !_finite( x ) && !_isnan( x ); }
|
|
}
|
|
#endif
|
|
|
|
|
|
class json_stream : public osgDB::ofstream {
|
|
public:
|
|
json_stream(const std::string& filename, bool strict=true) :
|
|
_stream(filename.c_str()),
|
|
_strict(strict)
|
|
{}
|
|
|
|
~json_stream() {
|
|
_stream.close();
|
|
}
|
|
|
|
operator bool() const {
|
|
return _stream.is_open();
|
|
}
|
|
|
|
// forward std::endl
|
|
typedef std::ostream& (*ostream_manipulator)(std::ostream&);
|
|
json_stream& operator<<(ostream_manipulator pf) {
|
|
if (_stream.is_open()) {
|
|
_stream << pf;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
json_stream& operator<<(const T& data) {
|
|
if (_stream.is_open()) {
|
|
_stream << sanitize(data);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
const T sanitize(const T& t) {
|
|
return t;
|
|
}
|
|
|
|
double sanitize(const float f) {
|
|
return sanitize(static_cast<double>(f));
|
|
}
|
|
|
|
double sanitize(const double d) {
|
|
if(_strict) {
|
|
return to_valid_float(d);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
double to_valid_float(const double d) {
|
|
if(std::isfinite(d)) {
|
|
return d;
|
|
}
|
|
else {
|
|
if(std::isinf(d)) {
|
|
return std::numeric_limits<double>::max();
|
|
}
|
|
// no much way to do better than replace invalid float NaN by 0
|
|
return 0.;
|
|
}
|
|
}
|
|
|
|
std::string sanitize(const std::string& s) {
|
|
if(_strict) {
|
|
return to_json_utf8(s);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
std::string sanitize(const char* s) {
|
|
return sanitize(std::string(s));
|
|
}
|
|
|
|
std::string to_json_utf8(const std::string& s) {
|
|
// TODO: try to decode latin1 if string is not valid utf8
|
|
// before actually fixing bad 'chars'
|
|
return utf8_string::sanitize(s);
|
|
}
|
|
|
|
|
|
protected:
|
|
std::ofstream _stream;
|
|
bool _strict;
|
|
};
|
|
|
|
|
|
#endif
|