#include "tstream.h" #include "tpersist.h" #include "tfilepath_io.h" #include "tconvert.h" #include "tsystem.h" #include "tutil.h" #if defined(LZ4_STATIC) #include "lz4frame_static.h" #else #include "lz4frame.h" #endif #include #include using namespace std; //=============================================================== namespace { string escape(string v) { int i = 0; for (;;) { i = v.find_first_of("\\\'\"", i); if (i == (int)string::npos) break; string h = "\\" + v[i]; v.insert(i, "\\"); i = i + 2; } return v; } //=============================================================== void writeCompressedFile(TFilePath dst, const string &str) { } //=================================================================== void readCompressedFile(string &str, TFilePath src) { TFileStatus status(src); if (!status.doesExist()) return; size_t in_len = status.getSize(); char *in = (char *)malloc(in_len); { Tifstream is(src); is.read((char *)in, in_len); } LZ4F_decompressionContext_t lz4dctx; LZ4F_errorCode_t err = LZ4F_createDecompressionContext(&lz4dctx, LZ4F_VERSION); if (LZ4F_isError(err)) return; size_t in_len_read = 0; size_t out_len = 1000000, out_len_written, out_len_moved = 0; void *out = (void *)malloc(out_len); while (in_len_read < in_len) { out_len_written = out_len; size_t remaining = LZ4F_decompress(lz4dctx, out, &out_len_written, in, &in_len, NULL); if (LZ4F_isError(remaining)) break; str.resize(out_len_moved + out_len_written); memcpy((void *)(str.c_str() + out_len_moved), (void *)out, out_len_written); out_len_moved += out_len_written; } LZ4F_freeDecompressionContext(lz4dctx); free(in); free(out); } namespace { // TODO: Unify with tcodec.cpp's version bool lz4decompress(LZ4F_decompressionContext_t lz4dctx, char *out, size_t *out_len_res, const char *in, size_t in_len) { size_t out_len = *out_len_res, in_read, out_written; *out_len_res = 0; while (in_len) { out_written = out_len; in_read = in_len; size_t res = LZ4F_decompress( lz4dctx, (void *)out, &out_written, (const void *)in, &in_read, NULL); if (LZ4F_isError(res)) return false; *out_len_res += out_written; out += out_written; out_len -= out_written; in += in_read; in_len -= in_read; } return true; } } // namespace //=============================================================== class StreamTag { public: string m_name; std::map m_attributes; enum Type { BeginTag, EndTag, BeginEndTag }; Type m_type; StreamTag() : m_type(BeginTag) {} operator bool() const { return m_name != ""; } void dump() { cout << "name = '" << m_name << "'" << endl; cout << "type = "; switch (m_type) { case BeginTag: cout << "begin Tag"; break; case EndTag: cout << "end Tag"; break; case BeginEndTag: cout << "begin/end Tag"; break; default: cout << "**bad Tag**"; break; } cout << endl; std::map::iterator it; for (it = m_attributes.begin(); it != m_attributes.end(); ++it) { cout << " '" << it->first << "' = '" << it->second << "'" << endl; } } }; //-------------------------------- class TPersistFactory { typedef std::map Table; static TPersistFactory *m_factory; Table m_table; TPersistFactory() {} public: static TPersistFactory *instance() { if (!m_factory) m_factory = new TPersistFactory; return m_factory; } void add(string name, TPersistDeclaration *decl) { m_table[name] = decl; } TPersist *create(string name) { Table::iterator it = m_table.find(name); if (it != m_table.end()) return (it->second)->create(); else return 0; } }; //-------------------------------- TPersistFactory *TPersistFactory::m_factory = 0; } // namespace //-------------------------------- TPersistDeclaration::TPersistDeclaration(const string &id) : m_id(id) { TPersistFactory::instance()->add(id, this); } //=============================================================== TPersist *TPersist::create(const string &name) { return TPersistFactory::instance()->create(name); } //=============================================================== class TOStream::Imp { public: ostream *m_os; bool m_chanOwner; bool m_compressed; ostrstream m_ostrstream; vector m_tagStack; int m_tab; bool m_justStarted; typedef map PersistTable; PersistTable m_table; int m_maxId; TFilePath m_filepath; Imp() : m_os(0), m_chanOwner(false), m_tab(0), m_justStarted(true), m_maxId(0), m_compressed(false) {} }; //--------------------------------------------------------------- TOStream::TOStream(const TFilePath &fp, bool compressed) : m_imp(new Imp) { m_imp->m_filepath = fp; if (compressed) { m_imp->m_os = &m_imp->m_ostrstream; m_imp->m_compressed = true; m_imp->m_chanOwner = false; } else { std::auto_ptr os(new Tofstream(fp)); m_imp->m_os = os->isOpen() ? os.release() : 0; m_imp->m_chanOwner = true; } m_imp->m_justStarted = true; } //--------------------------------------------------------------- TOStream::TOStream(Imp *imp) : m_imp(imp) { assert(!imp->m_tagStack.empty()); ostream &os = *m_imp->m_os; if (m_imp->m_justStarted == false) cr(); os << "<" << m_imp->m_tagStack.back() << ">"; m_imp->m_tab++; cr(); m_imp->m_justStarted = true; } //--------------------------------------------------------------- TOStream::~TOStream() { try { if (!m_imp->m_tagStack.empty()) { string tagName = m_imp->m_tagStack.back(); m_imp->m_tagStack.pop_back(); assert(tagName != ""); ostream &os = *m_imp->m_os; m_imp->m_tab--; if (!m_imp->m_justStarted) cr(); os << ""; cr(); m_imp->m_justStarted = true; } else { if (m_imp->m_compressed) { const void *in = (const void *)m_imp->m_ostrstream.str(); size_t in_len = strlen((char *)in); size_t out_len = LZ4F_compressFrameBound(in_len, NULL); void *out = malloc(out_len); out_len = LZ4F_compressFrame(out, out_len, in, in_len, NULL); if (!LZ4F_isError(out_len)) { Tofstream os(m_imp->m_filepath); // TNZC os.write("TABc", 4); TINT32 v; v = 0x0A0B0C0D; os.write((char *)&v, sizeof v); v = in_len; os.write((char *)&v, sizeof v); v = out_len; os.write((char *)&v, sizeof v); os.write((char *)out, out_len); m_imp->m_ostrstream.freeze(0); } free(out); } if (m_imp->m_chanOwner) delete m_imp->m_os; delete m_imp; } } catch (...) { } } //--------------------------------------------------------------- TFilePath TOStream::getFilePath() { return m_imp->m_filepath; } //--------------------------------------------------------------- TFilePath TOStream::getRepositoryPath() { TFilePath fp = m_imp->m_filepath; return fp.getParentDir() + (fp.getName() + "_files"); } //--------------------------------------------------------------- TOStream &TOStream::operator<<(int v) { *(m_imp->m_os) << v << " "; m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(double v) { if (areAlmostEqual(v, 0)) //con valori molto piccoli (es. 1.4e-310) non riesce a rileggerli! v = 0; *(m_imp->m_os) << v << " "; m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(string v) { ostream &os = *(m_imp->m_os); int len = v.length(); if (len == 0) { os << "\"\"" << " "; m_imp->m_justStarted = false; return *this; } int i; for (i = 0; i < len; i++) if (!iswalnum(v[i]) && v[i] != '_' && v[i] != '%') break; if (i == len) os << v << " "; else { os << '"' << escape(v) << '"'; } m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(QString _v) { string v = _v.toStdString(); ostream &os = *(m_imp->m_os); int len = v.length(); if (len == 0) { os << "\"\"" << " "; m_imp->m_justStarted = false; return *this; } int i; for (i = 0; i < len; i++) if (!iswalnum(v[i]) && v[i] != '_' && v[i] != '%') break; if (i == len) os << v << " "; else { os << '"' << escape(v) << '"'; } m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(wstring v) { return operator<<(toString(v)); /* ostream &os = *(m_imp->m_os); int len = v.length(); if(len==0) { os << "\"" << "\"" << " "; m_imp->m_justStarted = false; return *this; } int i; for(i=0;im_justStarted = false; return *this; */ } //--------------------------------------------------------------- TOStream &TOStream::operator<<(const TFilePath &v) { return operator<<(v.getWideString()); } //--------------------------------------------------------------- TOStream &TOStream::operator<<(const TPixel32 &v) { ostream &os = *(m_imp->m_os); os << (int)v.r << " " << (int)v.g << " " << (int)v.b << " " << (int)v.m << " "; m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(const TPixel64 &v) { ostream &os = *(m_imp->m_os); os << (int)v.r << " " << (int)v.g << " " << (int)v.b << " " << (int)v.m << " "; m_imp->m_justStarted = false; return *this; } //--------------------------------------------------------------- void TOStream::cr() { *(m_imp->m_os) << endl; for (int i = 0; i < m_imp->m_tab; i++) *(m_imp->m_os) << " "; m_imp->m_justStarted = false; } //--------------------------------------------------------------- TOStream::operator bool() const { return (m_imp->m_os && *m_imp->m_os); } //--------------------------------------------------------------- TOStream TOStream::child(string tagName) { assert(tagName != ""); m_imp->m_tagStack.push_back(tagName); return TOStream(m_imp); } //--------------------------------------------------------------- void TOStream::openChild(string tagName) { assert(tagName != ""); m_imp->m_tagStack.push_back(tagName); if (m_imp->m_justStarted == false) cr(); *(m_imp->m_os) << "<" << m_imp->m_tagStack.back() << ">"; m_imp->m_tab++; cr(); m_imp->m_justStarted = true; } //--------------------------------------------------------------- void TOStream::openChild(string tagName, const map &attributes) { assert(tagName != ""); m_imp->m_tagStack.push_back(tagName); if (m_imp->m_justStarted == false) cr(); *(m_imp->m_os) << "<" << m_imp->m_tagStack.back(); for (std::map::const_iterator it = attributes.begin(); it != attributes.end(); ++it) { *(m_imp->m_os) << " " << it->first << "=\"" << escape(it->second) << "\""; } *(m_imp->m_os) << ">"; m_imp->m_tab++; cr(); m_imp->m_justStarted = true; } //--------------------------------------------------------------- void TOStream::closeChild() { assert(!m_imp->m_tagStack.empty()); string tagName = m_imp->m_tagStack.back(); m_imp->m_tagStack.pop_back(); assert(tagName != ""); //ostream &os = *m_imp->m_os; //os non e' usato m_imp->m_tab--; if (!m_imp->m_justStarted) cr(); *(m_imp->m_os) << ""; cr(); m_imp->m_justStarted = true; } //--------------------------------------------------------------- void TOStream::openCloseChild(string tagName, const map &attributes) { assert(tagName != ""); // m_imp->m_tagStack.push_back(tagName); if (m_imp->m_justStarted == false) cr(); *(m_imp->m_os) << "<" << tagName; for (std::map::const_iterator it = attributes.begin(); it != attributes.end(); ++it) { *(m_imp->m_os) << " " << it->first << "=\"" << escape(it->second) << "\""; } *(m_imp->m_os) << "/>"; //m_imp->m_tab++; cr(); m_imp->m_justStarted = true; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(TPersist &v) { v.saveData(*this); return *this; } //--------------------------------------------------------------- TOStream &TOStream::operator<<(TPersist *v) { Imp::PersistTable::iterator it = m_imp->m_table.find(v); if (it != m_imp->m_table.end()) { *(m_imp->m_os) << "<" << v->getStreamTag() << " id='" << it->second << "'/>"; m_imp->m_justStarted = false; } else { int id = ++m_imp->m_maxId; m_imp->m_table[v] = id; *(m_imp->m_os) << "<" << v->getStreamTag() << " id='" << id << "'>"; m_imp->m_tab++; cr(); v->saveData(*this); m_imp->m_tab--; cr(); *(m_imp->m_os) << "getStreamTag() << ">"; cr(); } return *this; } //--------------------------------------------------------------- bool TOStream::checkStatus() const { if (!m_imp->m_os) return false; m_imp->m_os->flush(); return m_imp->m_os->rdstate() == ios_base::goodbit; } //=============================================================== /*! This class contains TIStream's attributes. It is created by memory allocation in the TIStream's constructor. */ class TIStream::Imp { public: istream *m_is; bool m_chanOwner; int m_line; string m_strbuffer; bool m_compressed; vector m_tagStack; typedef map PersistTable; PersistTable m_table; StreamTag m_currentTag; TFilePath m_filepath; VersionNumber m_versionNumber; Imp() : m_is(0), m_chanOwner(false), m_line(0), m_compressed(false), m_versionNumber(0, 0) {} // update m_line if necessary; returns -e if eof int getNextChar(); inline void skipBlanks(); bool matchTag(); inline bool match(char c); bool matchIdent(string &ident); bool matchValue(string &value); void skipCurrentTag(); }; //--------------------------------------------------------------- TFilePath TIStream::getFilePath() { return m_imp->m_filepath; } //--------------------------------------------------------------- TFilePath TIStream::getRepositoryPath() { TFilePath fp = m_imp->m_filepath; return fp.getParentDir() + (fp.getName() + "_files"); } //--------------------------------------------------------------- int TIStream::Imp::getNextChar() { char c; m_is->get(c); if (m_is->eof()) return -1; if (c == '\r') m_line++; return c; } //--------------------------------------------------------------- void TIStream::Imp::skipBlanks() { istream &is = *m_is; istream::int_type c; while (c = is.peek(), (isspace(c) || c == '\r')) getNextChar(); } //--------------------------------------------------------------- bool TIStream::Imp::match(char c) { if (m_is->peek() == c) { getNextChar(); return true; } else return false; } //--------------------------------------------------------------- bool TIStream::Imp::matchIdent(string &ident) { istream &is = *m_is; if (!isalnum(is.peek())) return false; ident = ""; char c; is.get(c); ident.append(1, c); while (c = is.peek(), isalnum(c) || c == '_' || c == '.' || c == '-') { is.get(c); ident.append(1, c); } return true; } //--------------------------------------------------------------- bool TIStream::Imp::matchValue(string &str) { istream &is = *m_is; char quote = is.peek(); char c; if (!is || (quote != '\'' && quote != '\"')) return false; is.get(c); str = ""; for (;;) { is.get(c); if (!is) throw TException("expected '\"'"); if (c == quote) break; if (c == '\\') { is.get(c); if (!is) throw TException("unexpected EOF"); if (c != '\'' && c != '\"' && c != '\\') throw TException("bad escape sequence"); } str.append(1, c); } if (c != quote) throw TException("missing '\"'"); return true; } //--------------------------------------------------------------- bool TIStream::Imp::matchTag() { if (m_currentTag) return true; StreamTag &tag = m_currentTag; tag = StreamTag(); skipBlanks(); if (!match('<')) return false; skipBlanks(); if (match('!')) { skipBlanks(); if (!match('-') || !match('-')) throw TException("expected '