1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*******************************************************************************
Copyright (c) 2012, Jonathan Hiller
This file is part of the AMF Tools suite. http://amf.wikispaces.com/
AMF Tools 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.
AMF Tools 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.
See <http://www.opensource.org/licenses/lgpl-3.0.html> for license details.
*******************************************************************************/
#ifndef CXMLSTREAM_H
#define CXMLSTREAM_H
#include "rapidxml/rapidxml.h"
#include <vector>
#include <stdio.h>
#include <string>
static const char Ind[49] = " "; //maximum indent: 24 levels of nesting...
//for quick run-through xml encoding
//Code by Jonathan Hiller. jdh74@cornell.edu
//turn off case-sensitivity...?
//CDATA handling for all read strings...
class CXmlStreamRead
{
public:
CXmlStreamRead(); //std::string FilePathToRead);
~CXmlStreamRead(void);
//for loading
rapidxml::xml_document<> doc;
std::vector <rapidxml::xml_node<>*> ElStack;
std::vector <std::string> StrStack; //used on loading to keep track of which tags were last looked for
std::vector<char> data; //buffer for reading/writing that won't go out of scope.
// std::string filename;
std::string tmp; //temporary string (to avoid creating a bunch of these...)
rapidxml::xml_attribute<>* pTmpAtt;
rapidxml::xml_node<>* pTmpNode;
bool LoadFile(std::string filename);
std::string LastError; //last error encountered in the loading process...
std::string LastTagSearched; //keep track of which tag we last looks for. if new query same as last, look for siblings.
bool OpenElement(std::string tag, bool RepeatingTag = false); //Find a child node. Subsequent calls will find children of this node with the same name. if RepeatingTag=true, calling repeatedly until it returns false will automatically close the last element it found.
void CloseElement(void); //call to return to parent element level
//looks for and (if finds) loads entire element with the provided tag
bool GetElementS(std::string tag, std::string* pStringReturn, bool RepeatingTag = false);
inline bool GetElementD(std::string tag, double* pDoubleReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pDoubleReturn = atof(tmp.c_str()); return true;} return false;}
inline bool GetElementF(std::string tag, float* pFloatReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pFloatReturn = (float)atof(tmp.c_str()); return true;}return false;}
inline bool GetElementI(std::string tag, int* pIntReturn, bool RepeatingTag = false) {if (GetElementS(tag, &tmp, RepeatingTag)){*pIntReturn = atoi(tmp.c_str()); return true;} return false;}
inline bool GetElementB(std::string tag, bool* pBoolReturn, bool RepeatingTag = false) {int tmpInt; if (!GetElementI(tag, &tmpInt, RepeatingTag)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;}
//looks for and (if finds) loads attributes of the open element
//CDATA!!!
bool GetElAttS(std::string Att, std::string* pStringReturn);/* {
*pStringReturn = std::string(ElStack.back()->first_attribute(Att.c_str(), 0, false)->value());
return ("" == (*pStringReturn))?false:true;
}*/
inline bool GetElAttD(std::string Att, double* pDoubleReturn) {if (!GetElAttS(Att, &tmp)) return false; *pDoubleReturn = atof(tmp.c_str()); return true;}
inline bool GetElAttF(std::string Att, float* pFloatReturn) {if (!GetElAttS(Att, &tmp)) return false; *pFloatReturn = (float)atof(tmp.c_str()); return true;}
inline bool GetElAttI(std::string Att, int* pIntReturn) {if(!GetElAttS(Att, &tmp)) return false; *pIntReturn = atoi(tmp.c_str()); return true;}
inline bool GetElAttB(std::string Att, bool* pBoolReturn) {int tmpInt; if (!GetElAttI(Att, &tmpInt)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;}
//looks for and (if finds) loads attributes of the open element
bool GetElDataS(std::string* pStringReturn); // {*pStringReturn = std::string(ElStack.back()->first_node()->value()); return (*pStringReturn == "")?false:true;}
inline bool GetElDataD(double* pDoubleReturn) {if (!GetElDataS(&tmp)) return false; *pDoubleReturn = atof(tmp.c_str()); return true;}
inline bool GetElDataF(float* pFloatReturn) {if (!GetElDataS(&tmp)) return false; *pFloatReturn = (float)atof(tmp.c_str()); return true;}
inline bool GetElDataI(int* pIntReturn) {if(!GetElDataS(&tmp)) return false; *pIntReturn = atoi(tmp.c_str()); return true;}
inline bool GetElDataB(bool* pBoolReturn) {int tmpInt; if (!GetElDataI(&tmpInt)) return false; *pBoolReturn=(tmpInt == 0)?false:true; return true;}
};
class CXmlStreamWrite
{
//todo: enforce open/closing of tags at CloseElement() and Save()
//seperate opening of file to kick back error if no file was created...
//anytowrite can be changes to "needendtag/line, string removed...
public:
CXmlStreamWrite(); //opens the file for writing
~CXmlStreamWrite(void) {};
bool BeginXmlFile(std::string FilePathToWrite, bool Compressed = false);
bool EndXmlFile();
int CurIndent; //for formatting...
FILE* fp;
std::string filename;
std::string LastError; //last error encountered in the loading process...
bool AnyToWrite;
bool IndentNextClose;
std::string ToWrite; //Buffer to hold closing parts of tags until next tag opened (mostly to allow for writting of attributes)
std::vector <std::string> StrStack; //used on loading to keep track of which tags were last looked for
void OpenElement(std::string tag);
void CloseElement(void);
//should be only called directly after OpenElement()!
inline void SetElAttS(std::string Att, std::string Value) {if(fp) fprintf(fp," %s=\"%s\"", Att.c_str(), Value.c_str());} //adds an attribute to the current element in the stack
inline void SetElAttD(std::string Att, double Value) {if(fp) fprintf(fp," %s=\"%g\"", Att.c_str(), Value);}
inline void SetElAttF(std::string Att, float Value) {if(fp) fprintf(fp," %s=\"%g\"", Att.c_str(), Value);}
inline void SetElAttI(std::string Att, int Value) {if(fp) fprintf(fp," %s=\"%d\"", Att.c_str(), Value);}
inline void SetElAttB(std::string Att, bool Value) {
if(fp) {
if(Value)
fprintf(fp," %s=\"1\"", Att.c_str());
else fprintf(fp," %s=\"0\"", Att.c_str());
}
}
//should be only called directly after OpenElement() and any SetElAttribute()'s! Must be followed directly by CloseElement()!
inline void SetElDataS(std::string Value, bool CDATA = false) {if(fp){if (CDATA) fprintf(fp,"><![CDATA[%s]]>", Value.c_str()); else fprintf(fp,">%s", Value.c_str()); AnyToWrite = false; IndentNextClose = false;}}
inline void SetElDataD(double Value) {if(fp){ fprintf(fp,">%g", Value); AnyToWrite = false; IndentNextClose = false;}}
inline void SetElDataF(float Value) {if(fp){ fprintf(fp,">%g", Value);AnyToWrite = false; IndentNextClose = false;}}
inline void SetElDataI(int Value) {if(fp){ fprintf(fp,">%d", Value); AnyToWrite = false; IndentNextClose = false;}}
inline void SetElDataB(bool Value) {if(fp){if(Value) fprintf(fp,">1"); else fprintf(fp,">0"); AnyToWrite = false; IndentNextClose = false;}}
//writes a complete Data element
inline void SetElementS(std::string tag, std::string Value, bool CDATA = false) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); if (CDATA) fprintf(fp,"<%s><![CDATA[%s]]></%s>\n", tag.c_str(), Value.c_str(), tag.c_str()); else fprintf(fp,"<%s>%s</%s>\n", tag.c_str(), Value.c_str(), tag.c_str()); AnyToWrite = false;}}
inline void SetElementD(std::string tag, double Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%g</%s>\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}}
inline void SetElementF(std::string tag, float Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%g</%s>\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}}
inline void SetElementI(std::string tag, int Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); fprintf(fp,"<%s>%d</%s>\n", tag.c_str(), Value, tag.c_str()); AnyToWrite = false;}}
inline void SetElementB(std::string tag, bool Value) {if(fp){if (AnyToWrite) fprintf(fp,"%s", ToWrite.c_str()); fwrite(Ind, 1, CurIndent, fp); if (Value) fprintf(fp,"<%s>1</%s>\n", tag.c_str(), tag.c_str()); else fprintf(fp,"<%s>0</%s>\n", tag.c_str(), tag.c_str()); AnyToWrite = false;}}
protected:
bool WantCompressed;
};
#endif //CXMLSTREAM_H
|