/**************************************************************************************/ /* */ /* Visualization Library */ /* http://visualizationlibrary.org */ /* */ /* Copyright (c) 2005-2020, Michele Bosi */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without modification, */ /* are permitted provided that the following conditions are met: */ /* */ /* - Redistributions of source code must retain the above copyright notice, this */ /* list of conditions and the following disclaimer. */ /* */ /* - Redistributions in binary form must reproduce the above copyright notice, this */ /* list of conditions and the following disclaimer in the documentation and/or */ /* other materials provided with the distribution. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /**************************************************************************************/ #ifndef VLXVisitorExportToVLT_INCLUDE_ONCE #define VLXVisitorExportToVLT_INCLUDE_ONCE #include #include #include namespace vlX { /** Translates a VLX hierarchy into VLT notation. */ class VisitorExportToVLT: public Visitor { VL_INSTRUMENT_CLASS(vlX::VisitorExportToVLT, Visitor) public: VisitorExportToVLT() { mIndent = 0; mAssign = false; mIDSet = NULL; mFormatBuffer.resize(4096); } bool isUsed(const std::string& uid) { if (mIDSet) { std::map< std::string, int >::iterator it = mIDSet->find(uid); if (it != mIDSet->end()) return it->second > 1; else { // should not happen VL_TRAP() return false; } } else return true; } void indent() { if (mAssign) mAssign = false; else { switch(mIndent) { case 0: break; case 1: output("\t"); break; case 2: output("\t\t"); break; case 3: output("\t\t\t"); break; case 4: output("\t\t\t\t"); break; case 5: output("\t\t\t\t\t"); break; case 6: output("\t\t\t\t\t\t"); break; case 7: output("\t\t\t\t\t\t\t"); break; case 8: output("\t\t\t\t\t\t\t\t"); break; case 9: output("\t\t\t\t\t\t\t\t\t"); break; default: output("\t\t\t\t\t\t\t\t\t"); for(int i=9; iacceptVisitor(this); break; case VLXValue::List: value.getList()->acceptVisitor(this); break; case VLXValue::ArrayInteger: value.getArrayInteger()->acceptVisitor(this); break; case VLXValue::ArrayReal: value.getArrayReal()->acceptVisitor(this); break; /* case VLXValue::ArrayString: value.getArrayString()->acceptVisitor(this); break; case VLXValue::ArrayIdentifier: value.getArrayIdentifier()->acceptVisitor(this); break; case VLXValue::ArrayID: value.getArrayID()->acceptVisitor(this); break; */ case VLXValue::RawtextBlock: { VLXRawtextBlock* fblock = value.getRawtextBlock(); if (!fblock->tag().empty()) format("%s", fblock->tag().c_str()); output("\n"); indent(); format("{<\n%s>}\n", rawtextEncode(fblock->value().c_str()).c_str()); } break; case VLXValue::String: indent(); format("\"%s\"\n", stringEncode( value.getString().c_str() ).c_str() ); break; case VLXValue::Identifier: indent(); format("%s\n", value.getIdentifier().c_str() ); VL_CHECK( !value.getIdentifier().empty() ) break; case VLXValue::ID: indent(); format("%s\n", value.getID().c_str()); VL_CHECK( !value.getID().empty() ) break; case VLXValue::Bool: indent(); format("%s\n", value.getBool() ? "true" : "false"); break; case VLXValue::Integer: indent(); format("%lld\n", value.getInteger()); break; case VLXValue::Real: indent(); format("%f\n", value.getReal()); break; } } virtual void visitStructure(VLXStructure* obj) { if (isVisited(obj)) { indent(); format("%s\n", obj->uid().c_str()); return; } // header tag if (obj->tag().empty()) { if (mAssign) { mAssign = false; output("\n"); } } else { indent(); format("%s", obj->tag().c_str()); output("\n"); } indent(); output("{\n"); mIndent++; if ( obj->uid().length() && obj->uid() != "#NULL" && isUsed(obj->uid()) ) { indent(); format("ID = %s\n", obj->uid().c_str()); } for(size_t i=0; ivalue().size(); ++i) { indent(); format("%s = ", obj->value()[i].key().c_str()); mAssign = true; visitValue(obj->value()[i].value()); } mIndent--; indent(); output("}\n"); } virtual void visitList(VLXList* list) { // this should happen only if the user manually creates loops if (isVisited(list)) { vl::Log::warning("VisitorExportToVLT: cycle detected on VLXList.\n"); return; } if (list->value().size() == 0) { indent(); output("[ ]\n"); return; } // header tag if (list->tag().empty()) { if (mAssign) { mAssign = false; output("\n"); } } else { indent(); format("%s", list->tag().c_str()); output("\n"); } indent(); output("[\n"); mIndent++; for(size_t i=0; ivalue().size(); ++i) visitValue(list->value()[i]); mIndent--; indent(); output("]\n"); } virtual void visitArray(VLXArrayInteger* arr) { indent(); if (!arr->tag().empty()) format("%s ", arr->tag().c_str()); output("( "); // output in chunks of 10 numbers int i = 0; int size = (int)arr->value().size() - 10; for( ; i < size; i += 10) { format("%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld ", arr->value()[i+0], arr->value()[i+1], arr->value()[i+2], arr->value()[i+3], arr->value()[i+4], arr->value()[i+5], arr->value()[i+6], arr->value()[i+7], arr->value()[i+8], arr->value()[i+9] ); } for( ; i < (int)arr->value().size(); ++i ) format("%lld ", arr->value()[i]); VL_CHECK( i == (int)arr->value().size() ) output(")\n"); } virtual void visitArray(VLXArrayReal* arr) { indent(); if (!arr->tag().empty()) format("%s ", arr->tag().c_str()); output("( "); // output in chunks of 10 numbers int i = 0; int size = (int)arr->value().size() - 10; for( ; i < size; i += 10) { format("%f %f %f %f %f %f %f %f %f %f ", arr->value()[i+0], arr->value()[i+1], arr->value()[i+2], arr->value()[i+3], arr->value()[i+4], arr->value()[i+5], arr->value()[i+6], arr->value()[i+7], arr->value()[i+8], arr->value()[i+9] ); } for( ; i < (int)arr->value().size(); ++i ) format("%f ", arr->value()[i]); VL_CHECK( i == (int)arr->value().size() ) output(")\n"); } /* virtual void visitArray(VLXArrayString* arr) { indent(); if (!arr->tag().empty()) format("%s ", arr->tag().c_str()); output("( "); for(size_t i=0 ;ivalue().size(); ++i) output(std::string("\"") + stringEncode(arr->value()[i].c_str()) + "\" "); output(")\n"); } virtual void visitArray(VLXArrayIdentifier* arr) { indent(); if (!arr->tag().empty()) format("%s ", arr->tag().c_str()); output("( "); for(size_t i=0 ;ivalue().size(); ++i) format("%s ", arr->value()[i].c_str()); output(")\n"); } virtual void visitArray(VLXArrayID* arr) { indent(); if (!arr->tag().empty()) format("%s ", arr->tag().c_str()); output("( "); for(size_t i=0 ;ivalue().size(); ++i) format("%s ", arr->value()[i].uid()); output(")\n"); } */ std::string rawtextEncode(const char* str) { std::string out; out.reserve(32); for(size_t i=0; str[i]; ++i) { if ( str[i] == '}' && !out.empty() && out[ out.size()-1 ] == '>') { out.resize( out.size() - 1 ); out += "\\>}"; } else out.push_back( str[i] ); } return out; } // mic fixme: support \xHH hex notation both input and output. std::string stringEncode(const char* str) { std::string out; for(size_t i=0; str[i]; ++i) { if (str[i] == '"') out += "\\\""; else if (str[i] == '\\') out += "\\\\"; else if (str[i] == '\b') out += "\\b"; else if (str[i] == '\f') out += "\\f"; else if (str[i] == '\n') out += "\\n"; else if (str[i] == '\r') out += "\\r"; else if (str[i] == '\t') out += "\\t"; else out += str[i]; } return out; } const std::string& text() const { return mText; } std::string& text() { return mText; } virtual void output(const std::string& str) { output(str.c_str()); } virtual void output(const char* str) { // printf(str); mText += str; } void writeHeader() { mText = vl::String::printf("VLX version=%d encoding=ascii\n\n", VL_SERIALIZER_VERSION).toStdString(); } void setIDSet(std::map< std::string, int >* uids) { mIDSet = uids; } std::map< std::string, int >* uidSet() { return mIDSet; } const std::map< std::string, int >* uidSet() const { return mIDSet; } private: int mIndent; bool mAssign; std::string mText; std::map< std::string, int >* mIDSet; std::vector mFormatBuffer; }; } #endif