diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index beef3797a97da0566e5384aaf5a23195f61dc40c..a53744a7c2d37bacea03d251cb1da569828400c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,7 +25,6 @@ configure-linux: script: - mkdir -p build - cd build - - which git - cmake -DCMAKE_BUILD_TYPE=Debug .. - echo "configure | ${CI_PROJECT_DIR}" stage: configure diff --git a/Analysis.cpp b/Analysis.cpp index b6736b8877f73e45a992d95cf064a68874459fc0..ff25423d7fd385d22e5e6e713323f1934d61363d 100644 --- a/Analysis.cpp +++ b/Analysis.cpp @@ -37,6 +37,7 @@ #include "methods/Method_B.h" #include "methods/Method_C.h" #include "methods/Method_D.h" +#include "methods/Method_I.h" #include "methods/PedData.h" #include <iostream> @@ -58,7 +59,7 @@ #endif - +using boost::geometry::dsv; using namespace std; OutputHandler* Log = new STDIOHandler(); @@ -118,6 +119,11 @@ std::string Analysis::GetFilename (const std::string& str) void Analysis::InitArgs(ArgumentParser* args) { string s = "Parameter:\n"; + _building = new Building(); + _building->LoadGeometry(args->GetGeometryFilename()); + // create the polygons + _building->InitGeometry(); + // _building->AddSurroundingRoom(); if(args->GetIsMethodA()) { _DoesUseMethodA = true; @@ -139,7 +145,7 @@ void Analysis::InitArgs(ArgumentParser* args) } } - if(args ->GetIsMethodC()) { + if(args->GetIsMethodC()) { _DoesUseMethodC = true; vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodC(); for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++) @@ -149,7 +155,7 @@ void Analysis::InitArgs(ArgumentParser* args) _plotTimeseriesC=args->GetIsPlotTimeSeriesC(); } - if(args ->GetIsMethodD()) { + if(args->GetIsMethodD()) { _DoesUseMethodD = true; vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodD(); for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++) @@ -160,8 +166,27 @@ void Analysis::InitArgs(ArgumentParser* args) _StopFramesMethodD = args->GetStopFramesMethodD(); _IndividualFDFlags = args->GetIndividualFDFlags(); _plotTimeseriesD=args->GetIsPlotTimeSeriesD(); + _geoPoly = ReadGeometry(args->GetGeometryFilename(), _areaForMethod_D); + } + if(args->GetIsMethodI()) { + _DoesUseMethodI = true; + vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodI(); + for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++) + { + _areaForMethod_I.push_back(dynamic_cast<MeasurementArea_B*>( args->GetMeasurementArea(Measurement_Area_IDs[i]))); + } + _StartFramesMethodI = args->GetStartFramesMethodI(); + _StopFramesMethodI = args->GetStopFramesMethodI(); + _IndividualFDFlags = args->GetIndividualFDFlags(); + _plotTimeseriesI=args->GetIsPlotTimeSeriesI(); + _geoPoly = ReadGeometry(args->GetGeometryFilename(), _areaForMethod_I); } + if( _DoesUseMethodD && _DoesUseMethodI) + { + Log->Write("Warning:\t Using both method D and I is not safe!"); + // because ReadGeomtry() may be called twice + } _deltaF = args->GetDelatT_Vins(); _cutByCircle = args->GetIsCutByCircle(); _getProfile = args->GetIsGetProfile(); @@ -173,7 +198,6 @@ void Analysis::InitArgs(ArgumentParser* args) _IgnoreBackwardMovement =args->GetIgnoreBackwardMovement(); _grid_size_X = int(args->GetGridSizeX()); _grid_size_Y = int(args->GetGridSizeY()); - _geoPoly = ReadGeometry(args->GetGeometryFilename(), _areaForMethod_D); _geometryFileName=args->GetGeometryFilename(); _projectRootDir=args->GetProjectRootDir(); _trajFormat=args->GetFileFormat(); @@ -186,12 +210,7 @@ void Analysis::InitArgs(ArgumentParser* args) std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, const std::vector<MeasurementArea_B*>& areas) { - - _building = new Building(); - _building->LoadGeometry(geometryFile.string()); - // create the polygons - _building->InitGeometry(); - + Log->Write("INFO:\tReadGeometry with %s", geometryFile.string().c_str()); double geo_minX = FLT_MAX; double geo_minY = FLT_MAX; double geo_maxX = -FLT_MAX; @@ -208,10 +227,8 @@ std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, c for (auto&& it_sub : it_room.second->GetAllSubRooms()) { SubRoom* subroom = it_sub.second.get(); - point_2d point(0,0); boost::geometry::centroid(area->_poly,point); - //check if the area is contained in the obstacle if(subroom->IsInSubRoom(Point(point.x()/M2CM,point.y()/M2CM))) { @@ -232,7 +249,6 @@ std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, c geoPoly[area->_id].inners().resize(k++); geoPoly[area->_id].inners().back(); model::ring<point_2d>& inner = geoPoly[area->_id].inners().back(); - for(auto&& tmp_point:obst->GetPolygon()) { append(inner, make<point_2d>(tmp_point._x*M2CM, tmp_point._y*M2CM)); @@ -241,12 +257,12 @@ std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, c } } } - } + }//room if(geoPoly.count(area->_id)==0) { Log->Write("ERROR: \t No polygon containing the measurement id [%d]", area->_id); - exit(1); + geoPoly[area->_id] = area->_poly; } } @@ -254,9 +270,6 @@ std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, c _highVertexY = geo_maxY; _lowVertexX = geo_minX; _lowVertexY = geo_minY; - // using boost::geometry::dsv; - // cout<<"INFO: \tGeometry polygon is:\t" << dsv(geoPoly[1])<<endl; - return geoPoly; } @@ -275,7 +288,7 @@ int Analysis::RunAnalysis(const fs::path& filename, const fs::path& path) for(int frameNr = 0; frameNr < data.GetNumFrames(); frameNr++ ) { vector<int> ids=_peds_t[frameNr]; - vector<int> IdInFrame = data.GetIdInFrame(ids); + vector<int> IdInFrame = data.GetIdInFrame(frameNr, ids); vector<double> XInFrame = data.GetXInFrame(frameNr, ids); vector<double> YInFrame = data.GetYInFrame(frameNr, ids); for( unsigned int i=0;i<IdInFrame.size();i++) @@ -441,6 +454,61 @@ int Analysis::RunAnalysis(const fs::path& filename, const fs::path& path) } } } + + if(_DoesUseMethodI) //method_I + { + if(_areaForMethod_I.empty()) + { + Log->Write("ERROR: Method I selected with no measurement area!"); + exit(EXIT_FAILURE); + } + +#pragma omp parallel for + for(long unsigned int i=0; i<_areaForMethod_I.size(); i++) + { + Method_I method_I; + method_I.SetStartFrame(_StartFramesMethodI[i]); + method_I.SetStopFrame(_StopFramesMethodI[i]); + method_I.SetCalculateIndividualFD(_IndividualFDFlags[i]); + method_I.SetGeometryPolygon(_geoPoly[_areaForMethod_I[i]->_id]); + method_I.SetGeometryFileName(_geometryFileName); + method_I.SetGeometryBoundaries(_lowVertexX, _lowVertexY, _highVertexX, _highVertexY); + method_I.SetGridSize(_grid_size_X, _grid_size_Y); + method_I.SetOutputVoronoiCellData(_outputGraph); + method_I.SetPlotVoronoiGraph(_plotGraph); + method_I.SetPlotVoronoiIndex(_plotIndex); + method_I.SetDimensional(_isOneDimensional); + method_I.SetCalculateProfiles(_getProfile); + method_I.SetTrajectoriesLocation(path); + if(_cutByCircle) + { + method_I.Setcutbycircle(_cutRadius, _circleEdges); + } + method_I.SetMeasurementArea(_areaForMethod_I[i]); + bool result_I = method_I.Process(data,_scriptsLocation, _areaForMethod_I[i]->_zPos); + if(result_I) + { + Log->Write("INFO:\tSuccess with Method I using measurement area id %d!\n",_areaForMethod_I[i]->_id); + std::cout << "INFO:\tSuccess with Method I using measurement area id "<< _areaForMethod_I[i]->_id << "\n"; + if(_plotTimeseriesI[i]) + { + string parameters_Timeseries= " " +_scriptsLocation.string()+"/_Plot_timeseries_rho_v.py -p "+ _projectRootDir.string()+VORO_LOCATION + " -n "+filename.string()+ + " -f "+boost::lexical_cast<std::string>(data.GetFps()); + parameters_Timeseries = PYTHON + parameters_Timeseries; + std::cout << parameters_Timeseries << "\n;"; + + int res=system(parameters_Timeseries.c_str()); + Log->Write("INFO:\t time series result: %d ",res); + } + } + else + { + Log->Write("INFO:\tFailed with Method I using measurement area id %d!\n",_areaForMethod_I[i]->_id); + } + } + } + + return 0; } diff --git a/Analysis.h b/Analysis.h index d4e8c5e8f8e0dfb6fe4826255b35959fd7334d1a..6f89efd5e8ebe68d4da8f7ca3e0bbbb44101b924 100644 --- a/Analysis.h +++ b/Analysis.h @@ -125,8 +125,14 @@ private: bool _DoesUseMethodB; // Method B (Zhang2011a) bool _DoesUseMethodC; // Method C //calculate and save results of classic in separate file bool _DoesUseMethodD; // Method D--Voronoi method + bool _DoesUseMethodI; // Method I--Voronoi method modified + // no measurement are) std::vector<int> _StartFramesMethodD; std::vector<int> _StopFramesMethodD; + + std::vector<int> _StartFramesMethodI; + std::vector<int> _StopFramesMethodI; + std::vector<bool> _IndividualFDFlags; bool _cutByCircle; //Adjust whether cut each original voronoi cell by a circle double _cutRadius; @@ -141,6 +147,7 @@ private: std::vector<bool> _plotTimeseriesA; std::vector<bool> _plotTimeseriesC; std::vector<bool> _plotTimeseriesD; + std::vector<bool> _plotTimeseriesI; bool _isOneDimensional; bool _calcIndividualFD; //Adjust whether analyze the individual density and velocity of each pedestrian in stationary state (ALWAYS VORONOI-BASED) std::string _vComponent; // to mark whether x, y or x and y coordinate are used when calculating the velocity @@ -156,6 +163,10 @@ private: std::vector<MeasurementArea_B*> _areaForMethod_B; std::vector<MeasurementArea_B*> _areaForMethod_C; std::vector<MeasurementArea_B*> _areaForMethod_D; + std::vector<MeasurementArea_B*> _areaForMethod_I; // we still need to know + // the zpos of the + // measurement are, even + // if we don't use its polygon }; #endif /*ANALYSIS_H_*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 637671e72c0ed8769fd211bf6e1b0f209f43892e..410a2c5e0d5346f19f5e76d1c9fabb0febdcd6dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,7 @@ set(methods methods/Method_B.cpp methods/Method_C.cpp methods/Method_D.cpp + methods/Method_I.cpp ) set(source_files Analysis.cpp @@ -211,6 +212,7 @@ set ( header_files methods/Method_B.h methods/Method_C.h methods/Method_D.h + methods/Method_I.h IO/OutputHandler.h general/ArgumentParser.h general/Macros.h @@ -310,14 +312,14 @@ endif() #message (STATUS "PSAPI: ${PSAPI}") #endif() -add_library ( geometrycore STATIC ${source_files} ) +add_library ( geometrycore SHARED ${source_files} ${methods}) set_property(TARGET geometrycore PROPERTY CXX_STANDARD 17) set_property(TARGET geometrycore PROPERTY CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) target_link_libraries(geometrycore stdc++fs) add_executable( - jpsreport main.cpp ${methods} + jpsreport main.cpp ) set_property(TARGET jpsreport PROPERTY CXX_STANDARD 17) @@ -381,12 +383,6 @@ if(BUILD_TESTING) ) - foreach (test_src ${test_files}) - GET_FILENAME_COMPONENT(test ${test_src} NAME_WE) - add_executable( ${test} ${test_src}) - target_link_libraries (${test} geometrycore) - add_test(NAME ${test} COMMAND ${test}) - endforeach(test_src ${test_files}) # set(Python_ADDITIONAL_VERSIONS 3.0) diff --git a/IO/OutputHandler.cpp b/IO/OutputHandler.cpp index cf33f15606c0f65abb757a46c85b7a32d7171302..070d18e227bab59b3536e04ae9ae420e0ff6ef2c 100644 --- a/IO/OutputHandler.cpp +++ b/IO/OutputHandler.cpp @@ -116,6 +116,35 @@ void OutputHandler::Write(const char* message,...) } } +void STDIOHandler::Write(const char* message,...) +{ + char msg[CLENGTH]=""; + va_list ap; + va_start(ap, message); + vsprintf(msg, message, ap); + va_end(ap); + + string str(msg); + + if (str.find("ERROR") != string::npos) + { + cerr << msg << endl; + cerr.flush(); + incrementErrors(); + } + else if (str.find("WARNING") != string::npos) + { + cerr << msg << endl; + cerr.flush(); + incrementWarnings(); + } + else + { // infos + cout << msg << endl; + cout.flush(); + } +} + void STDIOHandler::Write(const string& str) { if (str.find("ERROR") != string::npos) diff --git a/IO/OutputHandler.h b/IO/OutputHandler.h index 77faaa590df9aa12e4043cd372cbea2854ed34cf..5b334e0a775be92612d2e004b49f3c64a59f8c37 100644 --- a/IO/OutputHandler.h +++ b/IO/OutputHandler.h @@ -61,6 +61,7 @@ public: class STDIOHandler : public OutputHandler { public: void Write(const std::string& str); + void Write(const char *string,...); }; class FileHandler : public OutputHandler { diff --git a/README.md b/README.md index 630825d27203bb3ac2c8254b6ee6345753a41e51..f86531db6ddcac58f8c8cc5745bb9f427233234e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ `JuPedSim` is an open source framework for simulation, analyzing and visualizing pedestrian dynamics. It consists of four modules which are loosely coupled and can be used independently at the moment. For more information, please visit the [JuPedSim website](https://www.jupedsim.org). -`JPSreport` is a tool for analyzing the trajectories of pedestrians. It implements different measurement methods to analyze pedestrian movement in different aspects and scales. +`JPSreport` is a tool for analyzing the trajectories of pedestrians. It implements different measurement methods to analyze pedestrian movement in different aspects and scales. Here are some useful links: diff --git a/general/ArgumentParser.cpp b/general/ArgumentParser.cpp index 0bcc4e097f1d28d2109d364a4df9a88d09c54fcc..fab7793d634397afe5d1392afe7d5975b63466b3 100644 --- a/general/ArgumentParser.cpp +++ b/general/ArgumentParser.cpp @@ -129,6 +129,7 @@ ArgumentParser::ArgumentParser() _isMethodB = false; _isMethodC =false; _isMethodD = false; + _isMethodI= false; _isCutByCircle = false; _isOutputGraph= false; _isPlotGraph= false; @@ -212,19 +213,15 @@ bool ArgumentParser::ParseIniFile(const string& inifile) { Logs(); Log->Write("INFO: \tParsing the ini file <%s>",inifile.c_str()); - //extract and set the project root dir fs::path p(inifile); - _projectRootDir = canonical(p.parent_path()); - + _projectRootDir = canonical(p).parent_path(); TiXmlDocument doc(inifile); if (!doc.LoadFile()) { Log->Write("ERROR: \t%s", doc.ErrorDesc()); Log->Write("ERROR: \tCould not parse the ini file"); return false; } - - TiXmlElement* xMainNode = doc.RootElement(); if( ! xMainNode ) { Log->Write("ERROR:\tRoot element does not exist"); @@ -236,7 +233,6 @@ bool ArgumentParser::ParseIniFile(const string& inifile) Log->Write("ERROR:\tRoot element value is not 'JPSreport'."); return false; } - if (xMainNode->FirstChild("logfile")) { fs::path logfile(xMainNode->FirstChild("logfile")->FirstChild()->Value()); logfile = GetProjectRootDir() / logfile; @@ -269,13 +265,11 @@ bool ArgumentParser::ParseIniFile(const string& inifile) { Logs(); } - - //geometry if(xMainNode->FirstChild("geometry")) { - fs::path p(xMainNode->FirstChildElement("geometry")->Attribute("file")); - _geometryFileName = GetProjectRootDir() / p; + fs::path pathGeo(xMainNode->FirstChildElement("geometry")->Attribute("file")); + _geometryFileName = GetProjectRootDir() / pathGeo; if(!fs::exists(_geometryFileName)){ Log->Write("ERROR: \tGeometry File <%s> does not exist", _geometryFileName.string().c_str()); return false; @@ -341,9 +335,9 @@ bool ArgumentParser::ParseIniFile(const string& inifile) } else { - fs::path p(GetProjectRootDir()); - p = canonical(p); - _trajectoriesLocation=p.string(); + fs::path path_root(GetProjectRootDir()); + path_root = canonical(path_root); + _trajectoriesLocation=path_root.string(); } Log->Write("INFO: \tInput directory for loading trajectory is <%s>", _trajectoriesLocation.string().c_str()); @@ -353,9 +347,9 @@ bool ArgumentParser::ParseIniFile(const string& inifile) if(exists(_trajectoriesLocation)) { /* print all the files and directories within directory */ - fs::path p(GetTrajectoriesLocation()); - p = canonical(p); - for (auto& filename : boost::make_iterator_range(fs::directory_iterator(p), {})) + fs::path path_traj(GetTrajectoriesLocation()); + path_traj = canonical(path_traj); + for (auto& filename : boost::make_iterator_range(fs::directory_iterator(path_traj), {})) { string s = filename.path().string(); if (boost::algorithm::ends_with(s, fmt)) @@ -452,7 +446,9 @@ bool ArgumentParser::ParseIniFile(const string& inifile) //measurement area if(xMainNode->FirstChild("measurement_areas")) { - string unit = xMainNode->FirstChildElement("measurement_areas")->Attribute("unit"); + string unit =""; + if(xMainNode->FirstChildElement("measurement_areas")->Attribute("unit")) + unit = xMainNode->FirstChildElement("measurement_areas")->Attribute("unit"); if(unit!="m") { Log->Write("WARNING: \tonly <m> unit is supported. Convert your units."); @@ -480,14 +476,57 @@ bool ArgumentParser::ParseIniFile(const string& inifile) { areaB->_zPos=10000001.0; } + std::map<int, polygon_2d> geoPoly; polygon_2d poly; Log->Write("INFO: \tMeasure area id <%d> with type <%s>",areaB->_id, areaB->_type.c_str()); + int num_verteces = 0; for(TiXmlElement* xVertex=xMeasurementArea_B->FirstChildElement("vertex"); xVertex; xVertex=xVertex->NextSiblingElement("vertex") ) { double box_px = xmltof(xVertex->Attribute("x"))*M2CM; double box_py = xmltof(xVertex->Attribute("y"))*M2CM; boost::geometry::append(poly, boost::geometry::make<point_2d>(box_px, box_py)); Log->Write("\t\tMeasure area points < %.3f, %.3f>",box_px*CMtoM,box_py*CMtoM); + num_verteces++; + } + if(num_verteces < 3 && num_verteces > 0) + Log->Write("\tWARNING: Less than 3 measure area points given (%d). At least 3 or nothing at all!!", num_verteces); + if(num_verteces == 0) // big bounding box + { + Log->Write("\tWARNING: NO measure area points given (%d). default BB!!", num_verteces); + // get bounding box + // loading geometry is done in analysis.cpp + // so this is done twice, which is not nice. + // For big geometries it could be slow. + Building* building = new Building(); + building->LoadGeometry(GetGeometryFilename().string()); + building->InitGeometry(); + building->AddSurroundingRoom(); // this is a big reactagle + // slightly bigger than the + // geometry boundaries + double geo_minX = building->_xMin; + double geo_minY = building->_yMin; + double geo_maxX = building->_xMax; + double geo_maxY = building->_yMax; + Log->Write("INFO: \tBounding box:\n \t\tminX = %.2f\n \t\tmaxX = %.2f \n \t\tminY = %.2f \n\t\tmaxY = %.2f", geo_minX, geo_maxX, geo_minY, geo_maxY); + + + + //1 + double box_px = geo_minX*M2CM; + double box_py = geo_minY*M2CM; + boost::geometry::append(poly, boost::geometry::make<point_2d>(box_px, box_py)); + //2 + box_px = geo_minX*M2CM; + box_py = geo_maxY*M2CM; + boost::geometry::append(poly, boost::geometry::make<point_2d>(box_px, box_py)); + //3 + box_px = geo_maxX*M2CM; + box_py = geo_maxY*M2CM; + boost::geometry::append(poly, boost::geometry::make<point_2d>(box_px, box_py)); + //4 + box_px = geo_maxX*M2CM; + box_py = geo_minY*M2CM; + boost::geometry::append(poly, boost::geometry::make<point_2d>(box_px, box_py)); } correct(poly); // in the case the Polygone is not closed areaB->_poly=poly; @@ -662,8 +701,21 @@ bool ArgumentParser::ParseIniFile(const string& inifile) for(TiXmlElement* xMeasurementArea=xMainNode->FirstChildElement("method_A")->FirstChildElement("measurement_area"); xMeasurementArea; xMeasurementArea = xMeasurementArea->NextSiblingElement("measurement_area")) { - _areaIDforMethodA.push_back(xmltoi(xMeasurementArea->Attribute("id"))); - Log->Write("INFO: \tMeasurement area id <%d> will be used for analysis", xmltoi(xMeasurementArea->Attribute("id"))); + int id = xmltoi(xMeasurementArea->Attribute("id")); + + if( _measurementAreas[id]->_type == "Line") + { + _areaIDforMethodA.push_back(id); + Log->Write("INFO: \tMeasurement area id <%d> will be used for analysis", id); + } + else + { + Log->Write("WARNING: \tMeasurement area id <%d> will NOT be used for analysis (Type <%s> is not Line)", id, _measurementAreas[id]->_type.c_str()); + } + + + + if(xMeasurementArea->Attribute("frame_interval")) { @@ -897,8 +949,159 @@ bool ArgumentParser::ParseIniFile(const string& inifile) } } } + // method I + TiXmlElement* xMethod_I=xMainNode->FirstChildElement("method_I"); + if(xMethod_I) { + if(string(xMethod_I->Attribute("enabled"))=="true") + { + _isMethodI = true; + Log->Write("INFO: \tMethod I is selected" ); + + for(TiXmlElement* xMeasurementArea=xMainNode->FirstChildElement("method_I")->FirstChildElement("measurement_area"); + xMeasurementArea; xMeasurementArea = xMeasurementArea->NextSiblingElement("measurement_area")) + { + _areaIDforMethodI.push_back(xmltoi(xMeasurementArea->Attribute("id"))); + Log->Write("INFO: \tMeasurement area id <%d> will be used for analysis", xmltoi(xMeasurementArea->Attribute("id"))); + if(xMeasurementArea->Attribute("start_frame")) + { + if(string(xMeasurementArea->Attribute("start_frame"))!="None") + { + _start_frames_MethodD.push_back(xmltoi(xMeasurementArea->Attribute("start_frame"))); + Log->Write("\tthe analysis starts from frame <%d>",xmltoi(xMeasurementArea->Attribute("start_frame"))); + } + else + { + _start_frames_MethodI.push_back(-1); + } + } + else + { + _start_frames_MethodI.push_back(-1); + } + if(xMeasurementArea->Attribute("stop_frame")) + { + if(string(xMeasurementArea->Attribute("stop_frame"))!="None") + { + _stop_frames_MethodI.push_back(xmltoi(xMeasurementArea->Attribute("stop_frame"))); + Log->Write("\tthe analysis stops from frame <%d>", xmltoi(xMeasurementArea->Attribute("stop_frame"))); + } + else + { + _stop_frames_MethodI.push_back(-1); + } + } + else + { + _stop_frames_MethodI.push_back(-1); + } + + if(xMeasurementArea->Attribute("get_individual_FD")) + { + if(string(xMeasurementArea->Attribute("get_individual_FD"))=="true") + { + _individual_FD_flags.push_back(true); + Log->Write("INFO: \tIndividual FD will be output"); + } + else + { + _individual_FD_flags.push_back(false); + } + } + else + { + _individual_FD_flags.push_back(false); + } + if(xMeasurementArea->Attribute("plot_time_series")) + { + if(string(xMeasurementArea->Attribute("plot_time_series"))=="true") + { + _isPlotTimeSeriesI.push_back(true); + Log->Write("\tThe Time series will be plotted!! "); + } + else + { + _isPlotTimeSeriesI.push_back(false); + } + } + else + { + _isPlotTimeSeriesI.push_back(false); + } + + } + if (xMethod_I->FirstChildElement("one_dimensional")) + { + if ( string(xMethod_I->FirstChildElement("one_dimensional")->Attribute("enabled"))=="true") + { + _isOneDimensional=true; + Log->Write("INFO: \tThe data will be analyzed with one dimensional way!!"); + } + } + + if ( xMethod_I->FirstChildElement("cut_by_circle")) + { + if ( string(xMethod_I->FirstChildElement("cut_by_circle")->Attribute("enabled"))=="true") + { + _isCutByCircle=true; + _cutRadius=xmltof(xMethod_I->FirstChildElement("cut_by_circle")->Attribute("radius"))*M2CM; + _circleEdges=xmltoi(xMethod_I->FirstChildElement("cut_by_circle")->Attribute("edges")); + Log->Write("INFO: \tEach Voronoi cell will be cut by a circle with the radius of < %f > m!!", _cutRadius*CMtoM); + Log->Write("INFO: \tThe circle is discretized to a polygon with < %d> edges!!", _circleEdges); + } + } + + if ( xMethod_I->FirstChildElement("output_voronoi_cells")) + { + auto enabled = xMethod_I->FirstChildElement("output_voronoi_cells")->Attribute("enabled"); + if(enabled) + if ( string(enabled)=="true") + { + _isOutputGraph=true; + Log->Write("INFO: \tData of voronoi diagram is asked to output" ); + auto plot_graphs = xMethod_I->FirstChildElement("output_voronoi_cells")->Attribute("plot_graphs"); + if(plot_graphs) + { + if (string(plot_graphs)=="true") + { + _isPlotGraph = true; + Log->Write("INFO: \tGraph of voronoi diagram will be plotted"); + } + auto plot_index = xMethod_I->FirstChildElement("output_voronoi_cells")->Attribute( + "plot_index"); + if (plot_index) + if (string(plot_index)=="true") + { + _isPlotIndex = true; + Log->Write( + "INFO: \tVoronoi diagram will be plotted with index of pedestrians"); + } // plot_index + } // plot_graphs + }// enabled + } + + if ( xMethod_I->FirstChildElement("steadyState")) + { + _steadyStart =xmltof(xMethod_I->FirstChildElement("steadyState")->Attribute("start")); + _steadyEnd =xmltof(xMethod_I->FirstChildElement("steadyState")->Attribute("end")); + Log->Write("INFO: \tthe steady state is from <%f> to <%f> frames", _steadyStart, _steadyEnd); + } + + if(xMethod_I->FirstChildElement("profiles")) + { + if ( string(xMethod_I->FirstChildElement("profiles")->Attribute("enabled"))=="true") + { + _isGetProfile = true; + _grid_size_X =xmltof(xMethod_I->FirstChildElement("profiles")->Attribute("grid_size_x"))*M2CM; + _grid_size_Y =xmltof(xMethod_I->FirstChildElement("profiles")->Attribute("grid_size_y"))*M2CM; + Log->Write("INFO: \tProfiles will be calculated" ); + Log->Write("INFO: \tThe discretized grid size in x, y direction is: < %f >m by < %f >m ",_grid_size_X*CMtoM, _grid_size_Y*CMtoM); + } + } + } + } + Log->Write("INFO: \tFinish parsing inifile"); - if(!(_isMethodA || _isMethodB || _isMethodC || _isMethodD)) + if(!(_isMethodA || _isMethodB || _isMethodC || _isMethodD || _isMethodI)) { Log->Write("WARNING: No measurement method enabled. Nothing to do."); exit(EXIT_SUCCESS); @@ -986,6 +1189,10 @@ bool ArgumentParser::GetIsMethodD() const { return _isMethodD; } +bool ArgumentParser::GetIsMethodI() const +{ + return _isMethodI; +} bool ArgumentParser::GetIsCutByCircle() const { @@ -1031,6 +1238,11 @@ vector<bool> ArgumentParser::GetIsPlotTimeSeriesD() const return _isPlotTimeSeriesD; } +vector<bool> ArgumentParser::GetIsPlotTimeSeriesI() const +{ + return _isPlotTimeSeriesI; +} + bool ArgumentParser::GetIsOneDimensional() const { return _isOneDimensional; @@ -1082,16 +1294,31 @@ vector<int> ArgumentParser::GetAreaIDforMethodD() const return _areaIDforMethodD; } +vector<int> ArgumentParser::GetAreaIDforMethodI() const +{ + return _areaIDforMethodI; +} + vector<int> ArgumentParser::GetStartFramesMethodD() const { return _start_frames_MethodD; } +vector<int> ArgumentParser::GetStartFramesMethodI() const +{ + return _start_frames_MethodI; +} + vector<int> ArgumentParser::GetStopFramesMethodD() const { return _stop_frames_MethodD; } +vector<int> ArgumentParser::GetStopFramesMethodI() const +{ + return _stop_frames_MethodI; +} + vector<bool> ArgumentParser::GetIndividualFDFlags() const { return _individual_FD_flags; diff --git a/general/ArgumentParser.h b/general/ArgumentParser.h index c64236ef9ba36dbd8eadee20717acd42b4b7851e..e80d0f0e5db309faae2a1942253c95231a6ac932 100644 --- a/general/ArgumentParser.h +++ b/general/ArgumentParser.h @@ -69,6 +69,7 @@ private: bool _isMethodB; bool _isMethodC; bool _isMethodD; + bool _isMethodI; bool _isCutByCircle; double _cutRadius; int _circleEdges; @@ -88,15 +89,19 @@ private: std::vector<int> _areaIDforMethodB; std::vector<int> _areaIDforMethodC; std::vector<int> _areaIDforMethodD; + std::vector<int> _areaIDforMethodI; float _grid_size_X; float _grid_size_Y; int _log; std::vector<int> _start_frames_MethodD; std::vector<int> _stop_frames_MethodD; + std::vector<int> _start_frames_MethodI; + std::vector<int> _stop_frames_MethodI; std::vector<bool> _individual_FD_flags; std::vector<bool> _isPlotTimeSeriesA; std::vector<bool> _isPlotTimeSeriesC; std::vector<bool> _isPlotTimeSeriesD; + std::vector<bool> _isPlotTimeSeriesI; std::vector<int> _timeIntervalA; @@ -131,12 +136,16 @@ public: bool GetIsMethodB() const; bool GetIsMethodC() const; bool GetIsMethodD() const; + bool GetIsMethodI() const; std::vector<int> GetAreaIDforMethodA() const; std::vector<int> GetAreaIDforMethodB() const; std::vector<int> GetAreaIDforMethodC() const; std::vector<int> GetAreaIDforMethodD() const; + std::vector<int> GetAreaIDforMethodI() const; std::vector<int> GetStartFramesMethodD() const; std::vector<int> GetStopFramesMethodD() const; + std::vector<int> GetStartFramesMethodI() const; + std::vector<int> GetStopFramesMethodI() const; std::vector<bool> GetIndividualFDFlags() const; bool GetIsCutByCircle() const; double GetCutRadius() const; @@ -147,6 +156,7 @@ public: std::vector<bool> GetIsPlotTimeSeriesA() const; std::vector<bool> GetIsPlotTimeSeriesC() const; std::vector<bool> GetIsPlotTimeSeriesD() const; + std::vector<bool> GetIsPlotTimeSeriesI() const; bool GetIsOneDimensional() const; bool GetIsIndividualFD() const; polygon_2d GetAreaIndividualFD() const; diff --git a/general/Macros.h b/general/Macros.h index 689e97117b4ff4d4e43e4d7ed93732a44029e2e9..52f5f3e846845b55421da7f6a200f3590db1d716 100644 --- a/general/Macros.h +++ b/general/Macros.h @@ -38,6 +38,36 @@ #include <sstream> #include <iostream> +#include <boost/polygon/voronoi.hpp> +using boost::polygon::voronoi_builder; +using boost::polygon::voronoi_diagram; + +#include <boost/geometry.hpp> +#include <boost/geometry/geometry.hpp> +#include <boost/geometry/geometries/point_xy.hpp> +#include <boost/geometry/geometries/polygon.hpp> +#include <boost/geometry/geometries/adapted/c_array.hpp> +#include <boost/geometry/geometries/ring.hpp> +#include <boost/geometry/algorithms/intersection.hpp> +#include <boost/geometry/algorithms/within.hpp> +#include <boost/foreach.hpp> +//#include "../general/Macros.h" + +typedef boost::geometry::model::d2::point_xy<double, boost::geometry::cs::cartesian> point_2d; +typedef boost::geometry::model::polygon<point_2d> polygon_2d; +typedef std::vector<polygon_2d > polygon_list; +typedef boost::geometry::model::segment<boost::geometry::model::d2::point_xy<double> > segment; + +typedef boost::polygon::point_data<double> point_type2; +typedef double coordinate_type; +typedef boost::polygon::voronoi_diagram<double> VD; +typedef VD::edge_type edge_type; +typedef VD::cell_type cell_type; +typedef VD::cell_type::source_index_type source_index_type; + + + + #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -174,6 +204,37 @@ inline char xmltoc(const char * t, const char v = '\0') return v; } +inline std::string polygon_to_string(const polygon_2d & polygon) +{ + std::string polygon_str = "(("; + for(auto point: boost::geometry::exterior_ring(polygon) ) + { + double x = boost::geometry::get<0>(point); + double y = boost::geometry::get<1>(point); + polygon_str.append("("); + polygon_str.append(std::to_string(x)); + polygon_str.append(", "); + polygon_str.append(std::to_string(y)); + polygon_str.append("), "); + } + for(auto pRing: boost::geometry::interior_rings(polygon) ) + { + for(auto point: pRing ) + { + double x = boost::geometry::get<0>(point); + double y = boost::geometry::get<1>(point); + polygon_str.append("("); + polygon_str.append(std::to_string(x)); + polygon_str.append(", "); + polygon_str.append(std::to_string(y)); + polygon_str.append("), "); + } + } + polygon_str.pop_back(); polygon_str.pop_back(); //remove last komma + polygon_str.append("))"); + return polygon_str; +} + /** * @return true if the element is present in the vector */ diff --git a/geometry/Building.cpp b/geometry/Building.cpp index 6722ea018fa07328d5e16a2e3d8ffc1cf9af496d..c7b2c0fe1ff850dfadd0127e53f22e42e2874853 100644 --- a/geometry/Building.cpp +++ b/geometry/Building.cpp @@ -217,6 +217,26 @@ void Building::AddSurroundingRoom() y_max = (ymax >= y_max) ? ymax : y_max; y_min = (ymin <= y_min) ? ymin : y_min; } + for(auto&& obs:itr_subroom.second->GetAllObstacles()) + { + for(auto&& wall: obs->GetAllWalls()) + { + double x1 = wall.GetPoint1().GetX(); + double y1 = wall.GetPoint1().GetY(); + double x2 = wall.GetPoint2().GetX(); + double y2 = wall.GetPoint2().GetY(); + + double xmax = (x1 > x2) ? x1 : x2; + double xmin = (x1 > x2) ? x2 : x1; + double ymax = (y1 > y2) ? y1 : y2; + double ymin = (y1 > y2) ? y2 : y1; + + x_min = (xmin <= x_min) ? xmin : x_min; + x_max = (xmax >= x_max) ? xmax : x_max; + y_max = (ymax >= y_max) ? ymax : y_max; + y_min = (ymin <= y_min) ? ymin : y_min; + } + } } } @@ -245,20 +265,30 @@ void Building::AddSurroundingRoom() x_max = x_max + 10.0; y_min = y_min - 10.0; y_max = y_max + 10.0; - + Log->Write("INFO: \tAdding surrounding room X: %f, Y: %f -- %f, %f\n", x_min, x_max, y_min, y_max); SubRoom* bigSubroom = new NormalSubRoom(); + bigSubroom->SetType("Subroom"); + bigSubroom->SetPlanEquation(0,0,1); //@todo: dummy values + bigSubroom->SetRoomID(_rooms.size()); bigSubroom->SetSubRoomID(0); // should be the single subroom bigSubroom->AddWall(Wall(Point(x_min, y_min), Point(x_min, y_max))); bigSubroom->AddWall(Wall(Point(x_min, y_max), Point(x_max, y_max))); bigSubroom->AddWall(Wall(Point(x_max, y_max), Point(x_max, y_min))); bigSubroom->AddWall(Wall(Point(x_max, y_min), Point(x_min, y_min))); + vector<Line*> goals = vector<Line*>(); // dummy vector + bigSubroom->ConvertLineToPoly(goals); Room * bigRoom = new Room(); bigRoom->AddSubRoom(bigSubroom); bigRoom->SetCaption("outside"); bigRoom->SetID(_rooms.size()); + bigRoom->SetZPos(0); //@todo: dummy value AddRoom(bigRoom); + _xMin = x_min; + _xMax = x_max; + _yMin = y_min; + _yMax = y_max; } @@ -1411,5 +1441,3 @@ bool Building::SaveGeometry(const std::string &filename) } #endif // _SIMULATOR - - diff --git a/geometry/Building.h b/geometry/Building.h index 109d79866c9a867e2e0939d01d95c3649d593b1d..a2e163305bf61ebd7f607e6688240908c7c95a92 100644 --- a/geometry/Building.h +++ b/geometry/Building.h @@ -24,7 +24,7 @@ * * **/ - + #ifndef _BUILDING_H #define _BUILDING_H @@ -206,6 +206,11 @@ public: * output user specific informations. */ bool SanityCheck(); + // --- + double _xMin; + double _xMax; + double _yMin; + double _yMax; private: diff --git a/geometry/SubRoom.cpp b/geometry/SubRoom.cpp index 37c9e02cc2aba3a7b295196bd2a81f76def56a8e..58de0fb8e94add765941c30f1ae77d68a77d169e 100644 --- a/geometry/SubRoom.cpp +++ b/geometry/SubRoom.cpp @@ -379,8 +379,8 @@ bool SubRoom::IsVisible(const Line &wall, const Point &position) return wall_is_vis; } -// p1 and p2 are supposed to be pedestrian's positions. This function does not work properly -// for visibility checks with walls, since the line connecting the pedestrian's position +// p1 and p2 are supposed to be pedestrian's positions. This function does not work properly +// for visibility checks with walls, since the line connecting the pedestrian's position // with the nearest point on the wall IS intersecting with the wall. bool SubRoom::IsVisible(const Point& p1, const Point& p2, bool considerHlines) { @@ -744,13 +744,13 @@ string NormalSubRoom::WriteSubRoom() const s.append("\t\t</wall>\n"); } - const Point& pos = obst->GetCentroid(); + const Point& posCenter = obst->GetCentroid(); //add the obstacle caption - char tmp[CLENGTH]; - sprintf(tmp, "\t\t<label centerX=\"%.2f\" centerY=\"%.2f\" centerZ=\"%.2f\" text=\"%d\" color=\"100\" />\n" - , pos.GetX() * FAKTOR, pos.GetY() * FAKTOR,GetElevation(pos)*FAKTOR ,obst->GetId()); - s.append(tmp); + char Tmp[CLENGTH]; + sprintf(Tmp, "\t\t<label centerX=\"%.2f\" centerY=\"%.2f\" centerZ=\"%.2f\" text=\"%d\" color=\"100\" />\n" + , posCenter.GetX() * FAKTOR, posCenter.GetY() * FAKTOR,GetElevation(posCenter)*FAKTOR ,obst->GetId()); + s.append(Tmp); } return s; diff --git a/methods/Method_A.cpp b/methods/Method_A.cpp index 3d91592f9f537d5a84d8577c370449430d49c18c..4a4195c072c06f654795e865d5a6aa9af02f03a0 100644 --- a/methods/Method_A.cpp +++ b/methods/Method_A.cpp @@ -38,8 +38,8 @@ Method_A::Method_A() { _classicFlow = 0; _vDeltaT = 0; - ub::matrix<double> _xCor(0,0); - ub::matrix<double> _yCor(0,0); + //_xCor(0,0); + //_yCor(0,0); _firstFrame = nullptr; _passLine = nullptr; _deltaT = 100; diff --git a/methods/Method_B.cpp b/methods/Method_B.cpp index 45909935a46c472051a34b4b6a895ceb4b6cbb1d..524b08c2beff6b9818992404936d19cc92e412c0 100644 --- a/methods/Method_B.cpp +++ b/methods/Method_B.cpp @@ -34,8 +34,8 @@ using std::vector; Method_B::Method_B() { - ub::matrix<double> _xCor(0,0); - ub::matrix<double> _yCor(0,0); + _xCor(0,0); + _yCor(0,0); _tIn = nullptr; _tOut = nullptr; _entrancePoint = {}; diff --git a/methods/Method_D.cpp b/methods/Method_D.cpp index c72fd7c22f00fe498786f863eaabc5f5cbac3c79..6fd827bd8c486d697ed4bde5cc9779b0f79fe364 100644 --- a/methods/Method_D.cpp +++ b/methods/Method_D.cpp @@ -198,7 +198,7 @@ bool Method_D::Process (const PedData& peddata,const fs::path& scriptsLocation, } if(_outputVoronoiCellData) { // output the Voronoi polygons of a frame - OutputVoroGraph(str_frid, polygons_id, NumPeds, XInFrame, YInFrame,VInFrame); + OutputVoroGraph(str_frid, polygons_id, NumPeds, VInFrame); } } else @@ -404,7 +404,7 @@ void Method_D::GetProfiles(const string& frameId, const vector<polygon_2d>& poly fclose(Prf_density); } -void Method_D::OutputVoroGraph(const string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons_id, int numPedsInFrame, vector<double>& XInFrame, vector<double>& YInFrame,const vector<double>& VInFrame) +void Method_D::OutputVoroGraph(const string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons_id, int numPedsInFrame,const vector<double>& VInFrame) { //string voronoiLocation=_projectRootDir+"./Output/Fundamental_Diagram/Classical_Voronoi/VoronoiCell/id_"+_measureAreaId; @@ -444,9 +444,9 @@ void Method_D::OutputVoroGraph(const string & frameId, std::vector<std::pair<po if(polys.is_open()) { //for(vector<polygon_2d> polygon_iterator=polygons.begin(); polygon_iterator!=polygons.end(); polygon_iterator++) - for(auto && p:polygons_id) + for(auto && p_it : polygons_id) { - poly = p.first; + poly = p_it.first; for(auto&& point:poly.outer()) { point.x(point.x()*CMtoM); @@ -460,7 +460,7 @@ void Method_D::OutputVoroGraph(const string & frameId, std::vector<std::pair<po point.y(point.y()*CMtoM); } } - polys << p.second << " | " << dsv(poly) << endl; + polys << p_it.second << " | " << dsv(poly) << endl; //polys <<dsv(poly)<< endl; } } @@ -530,7 +530,7 @@ void Method_D::OutputVoroGraph(const string & frameId, std::vector<std::pair<po velo.close(); } -std::string polygon_to_string(const polygon_2d & polygon) +/*std::string polygon_to_string(const polygon_2d & polygon) { string polygon_str = "(("; for(auto point: boost::geometry::exterior_ring(polygon) ) @@ -559,7 +559,7 @@ std::string polygon_to_string(const polygon_2d & polygon) polygon_str.pop_back(); polygon_str.pop_back(); //remove last komma polygon_str.append("))"); return polygon_str; -} +}*/ void Method_D::GetIndividualFD(const vector<polygon_2d>& polygon, const vector<double>& Velocity, const vector<int>& Id, const polygon_2d& measureArea, const string& frid) { diff --git a/methods/Method_D.h b/methods/Method_D.h index 49ebaa9d00614124c2f63c88bd17788e6e4d4fd1..96aa7946e16f8ce3e14e1bc47382204c5f30aa55 100644 --- a/methods/Method_D.h +++ b/methods/Method_D.h @@ -102,8 +102,7 @@ private: void OutputVoronoiResults(const std::vector<polygon_2d>& polygons, const std::string& frid, const std::vector<double>& VInFrame); std::tuple<double,double> GetVoronoiDensityVelocity(const std::vector<polygon_2d>& polygon, const std::vector<double>& Velocity, const polygon_2d & measureArea); void GetProfiles(const std::string& frameId, const std::vector<polygon_2d>& polygons, const std::vector<double>& velocity); - void OutputVoroGraph(const std::string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons, int numPedsInFrame,std::vector<double>& XInFrame, - std::vector<double>& YInFrame,const std::vector<double>& VInFrame); + void OutputVoroGraph(const std::string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons, int numPedsInFrame,const std::vector<double>& VInFrame); void GetIndividualFD(const std::vector<polygon_2d>& polygon, const std::vector<double>& Velocity, const std::vector<int>& Id, const polygon_2d& measureArea, const std::string& frid); /** * Reduce the precision of the points to two digits diff --git a/methods/Method_I.cpp b/methods/Method_I.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2a1f4a7d05a90e731ff4975eced8452c3db93d6 --- /dev/null +++ b/methods/Method_I.cpp @@ -0,0 +1,807 @@ +/** + * \file Method_I.cpp + * \date Feb 07, 2019 + * \version v0.8 + * \copyright <2009-2019> Forschungszentrum Jülich GmbH. All rights reserved. + * + * \section License + * This file is part of JuPedSim. + * + * JuPedSim 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 + * any later version. + * + * JuPedSim 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 General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JuPedSim. If not, see <http://www.gnu.org/licenses/>. + * + * \section Description + * In this file functions related to method I are defined. + * + * + **/ + +#include "Method_I.h" +#include <cmath> +#include<map> +#include<iostream> +#include<vector> +#include <tuple> +//using std::string; +//using std::vector; +//using std::ofstream; +using namespace std; + + + +Method_I::Method_I() +{ + _grid_size_X = 0.10; + _grid_size_Y = 0.10; + _fps=16; + _outputVoronoiCellData = false; + _getProfile = false; + _geoMinX = 0; + _geoMinY = 0; + _geoMaxX = 0; + _geoMaxY = 0; + _cutByCircle = false; + _cutRadius = -1; + _circleEdges = -1; + _fIndividualFD = nullptr; + _calcIndividualFD = false; + _areaForMethod_I = nullptr; + _plotVoronoiCellData=false; + _isOneDimensional=false; + _startFrame =-1; + _stopFrame = -1; +} + +Method_I::~Method_I() +{ + +} +// auto outOfRange = [&](int number, int start, int end) -> bool +// { +// return (number < start || number > end); +// }; +bool Method_I::Process(const PedData& peddata,const fs::path& scriptsLocation, const double& zPos_measureArea) +{ + bool return_value = true; + _scriptsLocation = scriptsLocation; + _outputLocation = peddata.GetOutputLocation(); + _peds_t = peddata.GetPedsFrame(); + _trajName = peddata.GetTrajName(); + _projectRootDir = peddata.GetProjectRootDir(); + _measureAreaId = boost::lexical_cast<string>(_areaForMethod_I->_id); + _fps =peddata.GetFps(); + int mycounter = 0; + int minFrame = peddata.GetMinFrame(); + Log->Write("INFO:\tMethod I: frame rate fps: <%.2f>, start: <%d>, stop: <%d> (minFrame = %d)", _fps, _startFrame, _stopFrame, minFrame); + if(_startFrame != _stopFrame) + { + if(_startFrame==-1) + { + _startFrame = minFrame; + } + if(_stopFrame==-1) + { + _stopFrame = peddata.GetNumFrames()+minFrame; + } + for(std::map<int , std::vector<int> >::iterator ite=_peds_t.begin();ite!=_peds_t.end();) + { + if((ite->first + minFrame)<_startFrame || (ite->first + minFrame) >_stopFrame) + { + mycounter++; + ite = _peds_t.erase(ite); + } + else + { + ++ite; + } + + + } + } + + if(_calcIndividualFD) + { + if (!OpenFileIndividualFD()) + { + return_value = false; + } + } + Log->Write("------------------------ Analyzing with Method I -----------------------------"); + //for(int frameNr = 0; frameNr < peddata.GetNumFrames(); frameNr++ ) + //for(std::map<int , std::vector<int> >::iterator ite=_peds_t.begin();ite!=_peds_t.end();ite++) + + for(auto ite: _peds_t) + { + int frameNr = ite.first; + int frid = frameNr + minFrame; + //padd the frameid with 0 + std::ostringstream ss; + ss << std::setw(5) << std::setfill('0') << std::internal << frid; + const std::string str_frid = ss.str(); + if(!(frid%50)) + { + Log->Write("INFO:\tframe ID = %d",frid); + } + vector<int> ids=_peds_t[frameNr]; + vector<int> IdInFrame = peddata.GetIdInFrame(frameNr, ids, zPos_measureArea); + vector<double> XInFrame = peddata.GetXInFrame(frameNr, ids, zPos_measureArea); + vector<double> YInFrame = peddata.GetYInFrame(frameNr, ids, zPos_measureArea); + vector<double> ZInFrame = peddata.GetZInFrame(frameNr, ids, zPos_measureArea); + vector<double> VInFrame = peddata.GetVInFrame(frameNr, ids, zPos_measureArea); + if(XInFrame.size() == 0) + { + Log->Write("Warning:\t no pedestrians in frame <%d>", frameNr); + continue; + } + //vector int to_remove + //------------------------------Remove peds outside geometry------------------------------------------ + for( int i=0;i<(int)IdInFrame.size();i++) + { + if(false==within(point_2d(round(XInFrame[i]), round(YInFrame[i])), _geoPoly)) + { + Log->Write("Warning:\tPedestrian at <x=%.4f, y=%.4f, , z=%.4f> is not in geometry and not considered in analysis!", XInFrame[i]*CMtoM, YInFrame[i]*CMtoM, ZInFrame[i]*CMtoM ); + IdInFrame.erase(IdInFrame.begin() + i); + XInFrame.erase(XInFrame.begin() + i); + YInFrame.erase(YInFrame.begin() + i); + ZInFrame.erase(ZInFrame.begin() + i); + VInFrame.erase(VInFrame.begin() + i); + Log->Write("Warning:\t Pedestrian removed"); + i--; + + } + } + int NumPeds = IdInFrame.size(); + // std::cout << "numpeds = " << NumPeds << "\n"; + +//--------------------------------------------------------------------------------------------------------------- + if(_isOneDimensional) + { + CalcVoronoiResults1D(XInFrame, VInFrame, IdInFrame, _areaForMethod_I->_poly,str_frid); + } + else + { + if(IsPointsOnOneLine(XInFrame, YInFrame)) + { + if(fabs(XInFrame[1]-XInFrame[0])<dmin) + { + XInFrame[1]+= offset; + } + else + { + YInFrame[1]+= offset; + } + } + std::vector<std::pair<polygon_2d, int> > polygons_id = GetPolygons(XInFrame, YInFrame, VInFrame, IdInFrame); + // std::cout << ">> polygons_id " << polygons_id.size() << "\n"; + vector<polygon_2d> polygons; + for (auto p: polygons_id) + { + polygons.push_back(p.first); + } + + if(!polygons.empty()) + { + if(_calcIndividualFD) + { + if(!_isOneDimensional) + { + // GetIndividualFD(polygons,VInFrame, IdInFrame, str_frid); // TODO polygons_id + GetIndividualFD(polygons,VInFrame, IdInFrame, str_frid, XInFrame, YInFrame, ZInFrame); // + } + } + if(_getProfile) + { // field analysis + GetProfiles(str_frid, polygons, VInFrame); // TODO polygons_id + } + if(_outputVoronoiCellData) + { // output the Voronoi polygons of a frame + OutputVoroGraph(str_frid, polygons_id, NumPeds,VInFrame); + } + } + else + { + for(int i=0;i<(int)IdInFrame.size();i++) + { + std::cout << XInFrame[i]*CMtoM << " " << YInFrame[i]*CMtoM << " " << IdInFrame[i] << "\n"; + } + Log->Write("WARNING: \tVoronoi Diagrams are not obtained!. Frame: %d (minFrame = %d)\n", frid, minFrame); + } + } + }//peds + if(_calcIndividualFD) + { + fclose(_fIndividualFD); + } + return return_value; +} + + bool Method_I::OpenFileMethodI() + { + + std::string voroLocation(VORO_LOCATION); + fs::path tmp("_id_"+_measureAreaId+".dat"); + tmp = _outputLocation / voroLocation / ("rho_v_Voronoi_" + _trajName.string() + tmp.string()); +// _outputLocation.string() + voroLocation+"rho_v_Voronoi_"+_trajName+"_id_"+_measureAreaId+".dat"; + string results_V= tmp.string(); + + + if((_fVoronoiRhoV=Analysis::CreateFile(results_V))==nullptr) + { + Log->Write("ERROR: \tcannot open the file to write Voronoi density and velocity\n"); + return false; + } + else + { + if(_isOneDimensional) + { + fprintf(_fVoronoiRhoV,"#framerate:\t%.2f\n\n#Frame \t Voronoi density(m^(-1))\t Voronoi velocity(m/s)\n",_fps); + } + else + { + fprintf(_fVoronoiRhoV,"#framerate:\t%.2f\n\n#Frame \t Voronoi density(m^(-2))\t Voronoi velocity(m/s)\n",_fps); + } + return true; + } + } + + bool Method_I::OpenFileIndividualFD() + { + fs::path trajFileName("_id_"+_measureAreaId+".dat"); + fs::path indFDPath("Fundamental_Diagram"); + indFDPath = _outputLocation / indFDPath / "IndividualFD" / (_trajName.string() + trajFileName.string()); + string Individualfundment=indFDPath.string(); + if((_fIndividualFD=Analysis::CreateFile(Individualfundment))==nullptr) + { + Log->Write("ERROR:\tcannot open the file individual\n"); + return false; + } + else + { + if(_isOneDimensional) + { + fprintf(_fIndividualFD,"#framerate (fps):\t%.2f\n\n#Frame \t PersID \t Individual density(m^(-1)) \t Individual velocity(m/s) \t Headway(m)\n",_fps); + } + else + { + fprintf(_fIndividualFD,"#framerate (fps):\t%.2f\n\n#Frame \t PersID \t x/m \t y/m \t z/m \t Individual density(m^(-2)) \t Individual velocity(m/s) \t Voronoi Polygon\n",_fps); + } + return true; + } + } + + std::vector<std::pair<polygon_2d, int> > Method_I::GetPolygons(vector<double>& XInFrame, vector<double>& YInFrame, vector<double>& VInFrame, vector<int>& IdInFrame) + { + VoronoiDiagram vd; + //int NrInFrm = ids.size(); + double boundpoint =10*max(max(fabs(_geoMinX),fabs(_geoMinY)), max(fabs(_geoMaxX), fabs(_geoMaxY))); + std::vector<std::pair<polygon_2d, int> > polygons_id; + polygons_id = vd.getVoronoiPolygons(XInFrame, YInFrame, VInFrame,IdInFrame, boundpoint); + polygon_2d poly ; + if(_cutByCircle) + { + polygons_id = vd.cutPolygonsWithCircle(polygons_id, XInFrame, YInFrame, _cutRadius,_circleEdges); + } +//todo HH + polygons_id = vd.cutPolygonsWithGeometry(polygons_id, _geoPoly, XInFrame, YInFrame); + // todo HH + // std:: cout << dsv(_geoPoly) << "\n"; + for(auto && p:polygons_id) + { + poly = p.first; + ReducePrecision(poly); + // TODO update polygon_id? + } + // std:: cout << " GetPolygons leave " << polygons_id.size() << "\n"; + return polygons_id; + } +/** + * Output the Voronoi density and velocity in the corresponding file + */ + void Method_I::OutputVoronoiResults(const vector<polygon_2d>& polygons, const string& frid, const vector<double>& VInFrame) + { + double VoronoiVelocity=1; + double VoronoiDensity=-1; + std::tie(VoronoiDensity, VoronoiVelocity) = GetVoronoiDensityVelocity(polygons,VInFrame,_areaForMethod_I->_poly); + fprintf(_fVoronoiRhoV,"%s\t%.3f\t%.3f\n",frid.c_str(),VoronoiDensity, VoronoiVelocity); + } + +/* + * calculate the voronoi density and velocity according to voronoi cell of each pedestrian and their instantaneous velocity "Velocity". + * input: voronoi cell and velocity of each pedestrian and the measurement area + * output: the voronoi density and velocity in the measurement area (tuple) + */ + std::tuple<double,double> Method_I::GetVoronoiDensityVelocity(const vector<polygon_2d>& polygon, const vector<double>& Velocity, const polygon_2d & measureArea) + { + double meanV=0; + double density=0; + int temp=0; + for (auto && polygon_iterator:polygon) + { + polygon_list v; + intersection(measureArea, polygon_iterator, v); + if(!v.empty()) + { + meanV+=Velocity[temp]*area(v[0]); + density+=area(v[0])/area(polygon_iterator); + if((area(v[0]) - area(polygon_iterator))>J_EPS) + { + std::cout<<"----------------------Now calculating density-velocity!!!-----------------\n "; + std::cout<<"measure area: \t"<<std::setprecision(16)<<dsv(measureArea)<<"\n"; + std::cout<<"Original polygon:\t"<<std::setprecision(16)<<dsv(polygon_iterator)<<"\n"; + std::cout<<"intersected polygon: \t"<<std::setprecision(16)<<dsv(v[0])<<"\n"; + std::cout<<"this is a wrong result in density calculation\t "<<area(v[0])<<'\t'<<area(polygon_iterator)<< " (diff=" << (area(v[0]) - area(polygon_iterator)) << ")" << "\n"; + } + } + temp++; + } + meanV = meanV/area(measureArea); + density = density/(area(measureArea)*CMtoM*CMtoM); + return std::make_tuple(density, meanV); + } +// and velocity is calculated for every frame + void Method_I::GetProfiles(const string& frameId, const vector<polygon_2d>& polygons, const vector<double>& velocity) + { + std::string voroLocation(VORO_LOCATION); + fs::path tmp("field"); + fs::path vtmp ("velocity"); + fs::path dtmp("density"); + tmp = _outputLocation / voroLocation / tmp; + vtmp = tmp / vtmp / ("Prf_v_"+_trajName.string()+"_id_"+_measureAreaId+"_"+frameId+".dat"); + dtmp = tmp / dtmp / ("Prf_d_"+_trajName.string()+"_id_"+_measureAreaId+"_"+frameId+".dat"); + //string voronoiLocation=_outputLocation.string() + voroLocation+"field/"; + + // string Prfvelocity=voronoiLocation+"/velocity/Prf_v_"+_trajName.string()+"_id_"+_measureAreaId+"_"+frameId+".dat"; + // string Prfdensity=voronoiLocation+"/density/Prf_d_"+_trajName.string()+"_id_"+_measureAreaId+"_"+frameId+".dat"; + string Prfvelocity = vtmp.string(); + string Prfdensity = dtmp.string(); + + FILE *Prf_velocity; + if((Prf_velocity=Analysis::CreateFile(Prfvelocity))==nullptr) { + Log->Write("cannot open the file <%s> to write the field data\n",Prfvelocity.c_str()); + exit(EXIT_FAILURE); + } + FILE *Prf_density; + if((Prf_density=Analysis::CreateFile(Prfdensity))==nullptr) { + Log->Write("cannot open the file to write the field density\n"); + exit(EXIT_FAILURE); + } + + int NRow = (int)ceil((_geoMaxY-_geoMinY)/_grid_size_Y); // the number of rows that the geometry will be discretized for field analysis + int NColumn = (int)ceil((_geoMaxX-_geoMinX)/_grid_size_X); //the number of columns that the geometry will be discretized for field analysis + for(int row_i=0; row_i<NRow; row_i++) { // + for(int colum_j=0; colum_j<NColumn; colum_j++) { + polygon_2d measurezoneXY; + { + const double coor[][2] = { + {_geoMinX+colum_j*_grid_size_X,_geoMaxY-row_i*_grid_size_Y}, {_geoMinX+colum_j*_grid_size_X+_grid_size_X,_geoMaxY-row_i*_grid_size_Y}, {_geoMinX+colum_j*_grid_size_X+_grid_size_X, _geoMaxY-row_i*_grid_size_Y-_grid_size_Y}, + {_geoMinX+colum_j*_grid_size_X, _geoMaxY-row_i*_grid_size_Y-_grid_size_Y}, + {_geoMinX+colum_j*_grid_size_X,_geoMaxY-row_i*_grid_size_Y} // closing point is opening point + }; + assign_points(measurezoneXY, coor); + } + correct(measurezoneXY); // Polygons should be closed, and directed clockwise. If you're not sure if that is the case, call this function + + double densityXY; + double velocityXY; + std::tie(densityXY, velocityXY) = GetVoronoiDensityVelocity(polygons,velocity,measurezoneXY); + fprintf(Prf_density,"%.3f\t",densityXY); + fprintf(Prf_velocity,"%.3f\t",velocityXY); + } + fprintf(Prf_density,"\n"); + fprintf(Prf_velocity,"\n"); + } + fclose(Prf_velocity); + fclose(Prf_density); + } + + void Method_I::OutputVoroGraph(const string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons_id, int numPedsInFrame,const vector<double>& VInFrame) + { + //string voronoiLocation=_projectRootDir+"./Output/Fundamental_Diagram/Classical_Voronoi/VoronoiCell/id_"+_measureAreaId; + + fs::path voroLocPath(_outputLocation); + fs::path voro_location_path (VORO_LOCATION); // TODO: convert + // this MACRO to + // path. Maybe + // remove the MACRO? + voroLocPath = voroLocPath / voro_location_path / "VoronoiCell"; + polygon_2d poly; + if(!fs::exists(voroLocPath)) + { + if(!fs::create_directories(voroLocPath)) + { + Log->Write("ERROR:\tcan not create directory <%s>", voroLocPath.string().c_str()); + std::cout << "can not create directory "<< voroLocPath.string().c_str() << "\n"; + exit(EXIT_FAILURE); + } + else + std::cout << "create directory "<< voroLocPath.string().c_str() << "\n"; + } + + fs::path polygonPath=voroLocPath / "polygon"; + if(!fs::exists(polygonPath)) + { + if(!fs::create_directory(polygonPath)) + { + Log->Write("ERROR:\tcan not create directory <%s>", polygonPath.string().c_str()); + exit(EXIT_FAILURE); + } + } + fs::path trajFileName(_trajName.string()+"_id_"+_measureAreaId+"_"+frameId+".dat"); + fs::path p = polygonPath / trajFileName; + string polygon = p.string(); + ofstream polys (polygon.c_str()); + + if(polys.is_open()) + { + //for(vector<polygon_2d> polygon_iterator=polygons.begin(); polygon_iterator!=polygons.end(); polygon_iterator++) + for(auto && polygon_id:polygons_id) + { + poly = polygon_id.first; + for(auto&& point:poly.outer()) + { + point.x(point.x()*CMtoM); + point.y(point.y()*CMtoM); + } + for(auto&& innerpoly:poly.inners()) + { + for(auto&& point:innerpoly) + { + point.x(point.x()*CMtoM); + point.y(point.y()*CMtoM); + } + } + polys << polygon_id.second << " | " << dsv(poly) << endl; + //polys <<dsv(poly)<< endl; + } + } + else + { + Log->Write("ERROR:\tcannot create the file <%s>",polygon.c_str()); + exit(EXIT_FAILURE); + } + fs::path speedPath=voroLocPath / "speed"; + if(!fs::exists(speedPath)) + if(!fs::create_directory(speedPath)) + { + Log->Write("ERROR:\tcan not create directory <%s>", speedPath.string().c_str()); + exit(EXIT_FAILURE); + } + fs::path pv = speedPath /trajFileName; + string v_individual= pv.string(); + ofstream velo (v_individual.c_str()); + if(velo.is_open()) + { + for(int pts=0; pts<numPedsInFrame; pts++) + { + velo << fabs(VInFrame[pts]) << endl; + } + } + else + { + Log->Write("ERROR:\tcannot create the file <%s>",pv.string().c_str()); + exit(EXIT_FAILURE); + } + + /*string point=voronoiLocation+"/points"+_trajName+"_id_"+_measureAreaId+"_"+frameId+".dat"; + ofstream points (point.c_str()); + if( points.is_open()) + { + for(int pts=0; pts<numPedsInFrame; pts++) + { + points << XInFrame[pts]*CMtoM << "\t" << YInFrame[pts]*CMtoM << endl; + } + } + else + { + Log->Write("ERROR:\tcannot create the file <%s>",point.c_str()); + exit(EXIT_FAILURE); + }*/ + + if(_plotVoronoiCellData) + { + //@todo: use fs::path + string parameters_rho=" " + _scriptsLocation.string()+"/_Plot_cell_rho.py -f \""+ voroLocPath.string() + "\" -n "+ _trajName.string()+"_id_"+_measureAreaId+"_"+frameId+ + " -g "+_geometryFileName.string()+" -p "+_trajectoryPath.string(); + string parameters_v=" " + _scriptsLocation.string()+"/_Plot_cell_v.py -f \""+ voroLocPath.string() + "\" -n "+ _trajName.string() + "_id_"+_measureAreaId+"_"+frameId+ + " -g "+_geometryFileName.string()+" -p "+_trajectoryPath.string(); + + if(_plotVoronoiIndex) + parameters_rho += " -i"; + + Log->Write("INFO:\t%s",parameters_rho.c_str()); + Log->Write("INFO:\tPlotting Voronoi Cell at the frame <%s>",frameId.c_str()); + parameters_rho = PYTHON + parameters_rho; + parameters_v = PYTHON + parameters_v; + system(parameters_rho.c_str()); + system(parameters_v.c_str()); + } + //points.close(); + polys.close(); + velo.close(); + } + + + void Method_I::GetIndividualFD(const vector<polygon_2d>& polygon, const vector<double>& Velocity, const vector<int>& Id, const string& frid) + { + double uniquedensity=0; + double uniquevelocity=0; + int uniqueId=0; + int temp=0; + for (const auto & polygon_iterator:polygon) + { + string polygon_str = polygon_to_string(polygon_iterator); + uniquedensity=1.0/(area(polygon_iterator)*CMtoM*CMtoM); + uniquevelocity=Velocity[temp]; + uniqueId=Id[temp]; + fprintf(_fIndividualFD,"%s\t%d\t%.3f\t%.3f\t%s\n", + frid.c_str(), + uniqueId, + uniquedensity, + uniquevelocity, + polygon_str.c_str() + ); + temp++; + } + } + +void Method_I::GetIndividualFD(const vector<polygon_2d>& polygon, const vector<double>& Velocity, const vector<int>& Id, const string& frid, vector<double>& XInFrame, vector<double>& YInFrame, vector<double>& ZInFrame) +{ + double uniquedensity=0; + double uniquevelocity=0; + double x, y, z; + int uniqueId=0; + int temp=0; + for (const auto & polygon_iterator:polygon) + { + string polygon_str = polygon_to_string(polygon_iterator); + uniquedensity=1.0/(area(polygon_iterator)*CMtoM*CMtoM); + uniquevelocity=Velocity[temp]; + uniqueId=Id[temp]; + x = XInFrame[temp]*CMtoM; + y = YInFrame[temp]*CMtoM; + z = ZInFrame[temp]*CMtoM; + fprintf(_fIndividualFD,"%s\t %d\t %.4f\t %.4f\t %.4f\t %.4f\t %.4f\t %s\n", + frid.c_str(), + uniqueId, + x, + y, + z, + uniquedensity, + uniquevelocity, + polygon_str.c_str() + ); + temp++; + } +} + + void Method_I::SetCalculateIndividualFD(bool individualFD) + { + _calcIndividualFD = individualFD; + } + + void Method_I::SetStartFrame(int startFrame) + { + _startFrame=startFrame; + } + + void Method_I::SetStopFrame(int stopFrame) + { + _stopFrame=stopFrame; + } + + void Method_I::Setcutbycircle(double radius,int edges) + { + _cutByCircle=true; + _cutRadius = radius; + _circleEdges = edges; + } + + void Method_I::SetGeometryPolygon(polygon_2d geometryPolygon) + { + _geoPoly = geometryPolygon; + } + + void Method_I::SetGeometryBoundaries(double minX, double minY, double maxX, double maxY) + { + _geoMinX = minX; + _geoMinY = minY; + _geoMaxX = maxX; + _geoMaxY = maxY; + } + + void Method_I::SetGeometryFileName(const fs::path& geometryFile) + { + _geometryFileName=geometryFile; + } + + void Method_I::SetTrajectoriesLocation(const fs::path& trajectoryPath) + { + _trajectoryPath=trajectoryPath; + } + + void Method_I::SetGridSize(double x, double y) + { + _grid_size_X = x; + _grid_size_Y = y; + } + + void Method_I::SetCalculateProfiles(bool calcProfile) + { + _getProfile =calcProfile; + } + + void Method_I::SetOutputVoronoiCellData(bool outputCellData) + { + _outputVoronoiCellData = outputCellData; + } + + void Method_I::SetPlotVoronoiGraph(bool plotVoronoiGraph) + { + _plotVoronoiCellData = plotVoronoiGraph; + } + void Method_I::SetPlotVoronoiIndex(bool plotVoronoiIndex) + { + _plotVoronoiIndex = plotVoronoiIndex; + } + + void Method_I::SetMeasurementArea (MeasurementArea_B* area) + { + _areaForMethod_I = area; + } + + void Method_I::SetDimensional (bool dimension) + { + _isOneDimensional = dimension; + } + + void Method_I::ReducePrecision(polygon_2d& polygon) + { + for(auto&& point:polygon.outer()) + { + point.x(round(point.x() * 100000000000.0) / 100000000000.0); + point.y(round(point.y() * 100000000000.0) / 100000000000.0); + } + } + + bool Method_I::IsPedInGeometry(int frames, int peds, double **Xcor, double **Ycor, int *firstFrame, int *lastFrame) + { + for(int i=0; i<peds; i++) + for(int j =0; j<frames; j++) + { + if (j>firstFrame[i] && j< lastFrame[i] && (false==within(point_2d(round(Xcor[i][j]), round(Ycor[i][j])), _geoPoly))) + { + Log->Write("Error:\tPedestrian at the position <x=%.4f, y=%.4f> is outside geometry. Please check the geometry or trajectory file!", Xcor[i][j]*CMtoM, Ycor[i][j]*CMtoM ); + return false; + } + } + return true; + } + + void Method_I::CalcVoronoiResults1D(vector<double>& XInFrame, vector<double>& VInFrame, vector<int>& IdInFrame, const polygon_2d & measureArea,const string& frid) + { + vector<double> measurearea_x; + for(unsigned int i=0;i<measureArea.outer().size();i++) + { + measurearea_x.push_back(measureArea.outer()[i].x()); + } + double left_boundary=*min_element(measurearea_x.begin(),measurearea_x.end()); + double right_boundary=*max_element(measurearea_x.begin(),measurearea_x.end()); + + vector<double> voronoi_distance; + vector<double> Xtemp=XInFrame; + vector<double> dist; + vector<double> XLeftNeighbor; + vector<double> XLeftTemp; + vector<double> XRightNeighbor; + vector<double> XRightTemp; + sort(Xtemp.begin(),Xtemp.end()); + dist.push_back(Xtemp[1]-Xtemp[0]); + XLeftTemp.push_back(2*Xtemp[0]-Xtemp[1]); + XRightTemp.push_back(Xtemp[1]); + for(unsigned int i=1;i<Xtemp.size()-1;i++) + { + dist.push_back((Xtemp[i+1]-Xtemp[i-1])/2.0); + XLeftTemp.push_back(Xtemp[i-1]); + XRightTemp.push_back(Xtemp[i+1]); + } + dist.push_back(Xtemp[Xtemp.size()-1]-Xtemp[Xtemp.size()-2]); + XLeftTemp.push_back(Xtemp[Xtemp.size()-2]); + XRightTemp.push_back(2*Xtemp[Xtemp.size()-1]-Xtemp[Xtemp.size()-2]); + for(unsigned int i=0;i<XInFrame.size();i++) + { + for(unsigned int j=0;j<Xtemp.size();j++) + { + if(fabs(XInFrame[i]-Xtemp[j])<1.0e-5) + { + voronoi_distance.push_back(dist[j]); + XLeftNeighbor.push_back(XLeftTemp[j]); + XRightNeighbor.push_back(XRightTemp[j]); + break; + } + } + } + + double VoronoiDensity=0; + double VoronoiVelocity=0; + for(unsigned int i=0; i<XInFrame.size(); i++) + { + double ratio=getOverlapRatio((XInFrame[i]+XLeftNeighbor[i])/2.0, (XRightNeighbor[i]+XInFrame[i])/2.0,left_boundary,right_boundary); + VoronoiDensity+=ratio; + VoronoiVelocity+=(VInFrame[i]*voronoi_distance[i]*ratio*CMtoM); + if(_calcIndividualFD) + { + double headway=(XRightNeighbor[i] - XInFrame[i])*CMtoM; + double individualDensity = 2.0/((XRightNeighbor[i] - XLeftNeighbor[i])*CMtoM); + fprintf(_fIndividualFD,"%s\t%d\t%.3f\t%.3f\t%.3f\n",frid.c_str(), IdInFrame[i], individualDensity,VInFrame[i], headway); + } + } + VoronoiDensity/=((right_boundary-left_boundary)*CMtoM); + VoronoiVelocity/=((right_boundary-left_boundary)*CMtoM); + fprintf(_fVoronoiRhoV,"%s\t%.3f\t%.3f\n",frid.c_str(),VoronoiDensity, VoronoiVelocity); + + } + + double Method_I::getOverlapRatio(const double& left, const double& right, const double& measurearea_left, const double& measurearea_right) + { + double OverlapRatio=0; + double PersonalSpace=right-left; + if(left > measurearea_left && right < measurearea_right) //case1 + { + OverlapRatio=1; + } + else if(right > measurearea_left && right < measurearea_right && left < measurearea_left) + { + OverlapRatio=(right-measurearea_left)/PersonalSpace; + } + else if(left < measurearea_left && right > measurearea_right) + { + OverlapRatio=(measurearea_right - measurearea_left)/PersonalSpace; + } + else if(left > measurearea_left && left < measurearea_right && right > measurearea_right) + { + OverlapRatio=(measurearea_right-left)/PersonalSpace; + } + return OverlapRatio; + } + + bool Method_I::IsPointsOnOneLine(vector<double>& XInFrame, vector<double>& YInFrame) + { + double deltaX=XInFrame[1] - XInFrame[0]; + bool isOnOneLine=true; + if(fabs(deltaX)<dmin) + { + for(unsigned int i=2; i<XInFrame.size();i++) + { + if(fabs(XInFrame[i] - XInFrame[0])> dmin) + { + isOnOneLine=false; + break; + } + } + } + else + { + double slope=(YInFrame[1] - YInFrame[0])/deltaX; + double intercept=YInFrame[0] - slope*XInFrame[0]; + for(unsigned int i=2; i<XInFrame.size();i++) + { + double dist=fabs(slope*XInFrame[i] - YInFrame[i] + intercept)/sqrt(slope*slope +1); + if(dist > dmin) + { + isOnOneLine=false; + break; + } + } + } + return isOnOneLine; + } diff --git a/methods/Method_I.h b/methods/Method_I.h new file mode 100644 index 0000000000000000000000000000000000000000..01ec100843c7d3e951eede75814b31a83eaf87a0 --- /dev/null +++ b/methods/Method_I.h @@ -0,0 +1,119 @@ +/** + * \file Method_I.h + * \date Feb 07, 201 + * \version v0.8 + * \copyright <2009-2019> Forschungszentrum Juelich GmbH. All rights reserved. + * + * \section License + * This file is part of JuPedSim. + * + * JuPedSim 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 + * any later version. + * + * JuPedSim 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 General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JuPedSim. If not, see <http://www.gnu.org/licenses/>. + * + * \section Description + * + * + **/ + +#ifndef Method_I_H_ +#define Method_I_H_ + +#include "PedData.h" +#include "../Analysis.h" +#include "VoronoiDiagram.h" + + + +//handle more than two person are in one line +#define dmin 200 +#define offset 200 + + +class Method_I +{ +public: + Method_I(); + virtual ~Method_I(); + bool Process (const PedData& peddata,const fs::path& scriptsLocation, const double& zPos_measureArea); + void SetCalculateIndividualFD(bool individualFD); + void Setcutbycircle(double radius,int edges); + void SetGeometryPolygon(polygon_2d geometryPolygon); + void SetGeometryFileName(const fs::path& geometryFile); + void SetGeometryBoundaries(double minX, double minY, double maxX, double maxY); + void SetGridSize(double x, double y); + void SetCalculateProfiles(bool calcProfile); + void SetOutputVoronoiCellData(bool outputCellData); + void SetPlotVoronoiGraph(bool plotVoronoiGraph); + void SetPlotVoronoiIndex(bool plotVoronoiIndex); + void SetMeasurementArea (MeasurementArea_B* area); + void SetDimensional (bool dimension); + void SetTrajectoriesLocation(const fs::path& trajectoryPath); + void SetStartFrame(int startFrame); + void SetStopFrame(int stopFrame); + +private: + std::map<int , std::vector<int> > _peds_t; + std::string _measureAreaId; + MeasurementArea_B* _areaForMethod_I; + fs::path _trajName; + fs::path _projectRootDir; + fs::path _outputLocation; + fs::path _scriptsLocation; + bool _calcIndividualFD; + polygon_2d _areaIndividualFD; + bool _getProfile; + bool _outputVoronoiCellData; + bool _plotVoronoiCellData; + bool _plotVoronoiIndex; + bool _isOneDimensional; + bool _cutByCircle; //Adjust whether cut each original voronoi cell by a circle + double _cutRadius; + int _circleEdges; + polygon_2d _geoPoly; + double _geoMinX; // LOWest vertex of the geometry (x coordinate) + double _geoMinY; // LOWest vertex of the geometry (y coordinate) + double _geoMaxX; // Highest vertex of the geometry + double _geoMaxY; + FILE* _fVoronoiRhoV; + FILE* _fIndividualFD; + double _grid_size_X; // the size of the grid + double _grid_size_Y; + float _fps; + bool OpenFileMethodI(); + bool OpenFileIndividualFD(); + fs::path _geometryFileName; + fs::path _trajectoryPath; + int _startFrame; + int _stopFrame; + + + std::vector<std::pair<polygon_2d, int> > GetPolygons(std::vector<double>& XInFrame, std::vector<double>& YInFrame, + std::vector<double>& VInFrame, std::vector<int>& IdInFrame); + void OutputVoronoiResults(const std::vector<polygon_2d>& polygons, const std::string& frid, const std::vector<double>& VInFrame); + std::tuple<double,double> GetVoronoiDensityVelocity(const std::vector<polygon_2d>& polygon, const std::vector<double>& Velocity, const polygon_2d & measureArea); + void GetProfiles(const std::string& frameId, const std::vector<polygon_2d>& polygons, const std::vector<double>& velocity); + void OutputVoroGraph(const std::string & frameId, std::vector<std::pair<polygon_2d, int> >& polygons, int numPedsInFrame,const std::vector<double>& VInFrame); + void GetIndividualFD(const std::vector<polygon_2d>& polygon, const std::vector<double>& Velocity, const std::vector<int>& Id, const std::string& frid); + void GetIndividualFD(const std::vector<polygon_2d>& polygon, const std::vector<double>& Velocity, const std::vector<int>& Id, const std::string& frid, std::vector<double>& XInFrame, std::vector<double>& YInFrame, std::vector<double>& ZInFrame); + /** + * Reduce the precision of the points to two digits + * @param polygon + */ + void CalcVoronoiResults1D(std::vector<double>& XInFrame, std::vector<double>& VInFrame, std::vector<int>& IdInFrame, const polygon_2d & measureArea, const std::string& frid); + void ReducePrecision(polygon_2d& polygon); + bool IsPedInGeometry(int frames, int peds, double **Xcor, double **Ycor, int *firstFrame, int *lastFrame); //check whether all the pedestrians are in the geometry + double getOverlapRatio(const double& left, const double& right, const double& measurearea_left, const double& measurearea_right); + bool IsPointsOnOneLine(std::vector<double>& XInFrame, std::vector<double>& YInFrame); +}; + +#endif /* Method_I_H_ */ diff --git a/methods/PedData.cpp b/methods/PedData.cpp index 08d4d47e88d3e19452bea3cd948fafdfe08d7b53..66b88d2ec228d2ed16837a561ca4b9976cf313b1 100644 --- a/methods/PedData.cpp +++ b/methods/PedData.cpp @@ -29,6 +29,8 @@ #include "PedData.h" #include <cmath> #include <string> +#include <set> + using std::string; using std::map; using std::vector; @@ -45,6 +47,7 @@ PedData::~PedData() bool PedData::ReadData(const fs::path& projectRootDir, const fs::path&outputLocation, const fs::path& path, const fs::path& filename, const FileFormat& trajformat, int deltaF, std::string vComponent, const bool IgnoreBackwardMovement) { _minID = INT_MAX; + _maxID = INT_MAX; _minFrame = INT_MAX; _deltaF = deltaF; _vComponent = vComponent; @@ -67,8 +70,8 @@ bool PedData::ReadData(const fs::path& projectRootDir, const fs::path&outputLoca return false; } TiXmlElement* xRootNode = docGeo.RootElement(); - fs::path filename(xRootNode->ValueStr()); - result=InitializeVariables(filename); //initialize some global variables + result=InitializeVariables(xRootNode); //initialize some global + //variables using xml format } else if(trajformat == FORMAT_PLAIN) @@ -92,7 +95,7 @@ bool PedData::InitializeVariables(const fs::path& filename) fdata.open(filename.string()); if (fdata.is_open() == false) { - Log->Write("ERROR: \t could not parse the trajectories file <%s>",filename.string().c_str()); + Log->Write("ERROR: \t could not open the trajectories file <%s>",filename.string().c_str()); return false; } else @@ -218,10 +221,13 @@ bool PedData::InitializeVariables(const fs::path& filename) Log->Write("INFO:\t Finished reading the data"); } + fdata.close(); Log->Write("INFO: Got %d lines", _IdsTXT.size()); _minID = *min_element(_IdsTXT.begin(),_IdsTXT.end()); + _maxID = *max_element(_IdsTXT.begin(),_IdsTXT.end()); Log->Write("INFO: minID: %d", _minID); + Log->Write("INFO: maxID: %d", _maxID); _minFrame = *min_element(_FramesTXT.begin(),_FramesTXT.end()); Log->Write("INFO: minFrame: %d", _minFrame); //Total number of frames @@ -230,24 +236,27 @@ bool PedData::InitializeVariables(const fs::path& filename) //Total number of agents std::vector<int> unique_ids = _IdsTXT; - // no need to + + // no need to //sort. Assume that ids are ascendant - sort(unique_ids.begin(), unique_ids.end()); - std::vector<int>::iterator it; - it = unique(unique_ids.begin(), unique_ids.end()); - unique_ids.resize(distance(unique_ids.begin(),it)); + + std::set<int> s; + for( auto a: _IdsTXT ) + { + s.insert( a ); + } + unique_ids.assign( s.begin(), s.end() ); _numPeds = unique_ids.size(); Log->Write("INFO: Total number of Agents: %d", _numPeds); CreateGlobalVariables(_numPeds, _numFrames); Log->Write("INFO: Create Global Variables done"); - - - for(int i=_minID;i<_minID+_numPeds; i++){ + for(int i = 0; i < (int)unique_ids.size(); i++){ int firstFrameIndex=INT_MAX; //The first frame index of a pedestrian int lastFrameIndex=-1; //The last frame index of a pedestrian int actual_totalframe=0; //The total data points of a pedestrian in the trajectory + int pos_i = i; //std::distance(_IdsTXT.begin(), &i); for (auto j = _IdsTXT.begin(); j != _IdsTXT.end(); ++j){ - if (*j ==i){ + if (*j == unique_ids[i]){ int pos = std::distance(_IdsTXT.begin(), j); if(pos<firstFrameIndex) { @@ -262,37 +271,34 @@ bool PedData::InitializeVariables(const fs::path& filename) } if(lastFrameIndex <=0 || lastFrameIndex == INT_MAX) { - Log->Write("Warning:\tThere is no trajectory for ped with ID <%d>!",i); + Log->Write("Warning:\tThere is no trajectory for ped with ID <%d>!", unique_ids[i]); continue; } - _firstFrame[i-_minID] = _FramesTXT[firstFrameIndex] - _minFrame; - _lastFrame[i-_minID] = _FramesTXT[lastFrameIndex] - _minFrame; + _firstFrame[pos_i] = _FramesTXT[firstFrameIndex] - _minFrame; + _lastFrame[pos_i] = _FramesTXT[lastFrameIndex] - _minFrame; - int expect_totalframe=_lastFrame[i-_minID]-_firstFrame[i-_minID]+1; + int expect_totalframe=_lastFrame[pos_i]-_firstFrame[pos_i]+1; if(actual_totalframe != expect_totalframe) { - Log->Write("Error:\tThe trajectory of ped with ID <%d> is not continuous. Please modify the trajectory file!",i); + Log->Write("Error:\tThe trajectory of ped with ID <%d> is not continuous. Please modify the trajectory file!", _IdsTXT[pos_i]); Log->Write("Error:\t actual_totalfame = <%d>, expected_totalframe = <%d> ", actual_totalframe, expect_totalframe); return false; } } Log->Write("convert x and y"); for(unsigned int i = 0; i < _IdsTXT.size(); i++) - //for(unsigned int i = 0; i < unique_ids .size(); i++) { - int ID = _IdsTXT[i] - _minID; // this asumes that idstxt - // are consecutive. 1, 2, 10, - // 11 does not work + int id_pos = 0; // position in array unique_ids //---------- get position of index in unique index vector --------------- - auto it = std::find(unique_ids.begin(), unique_ids.end(), _IdsTXT[i]); - if (it == unique_ids.end()) + auto it_uid = std::find(unique_ids.begin(), unique_ids.end(), _IdsTXT[i]); + if (it_uid == unique_ids.end()) { Log->Write("Error:\t Id %d does not exist in file", _IdsTXT[i]); return false; } else { - ID = std::distance(unique_ids.begin(), it); + id_pos = std::distance(unique_ids.begin(), it_uid); } //-------------------- int frm = _FramesTXT[i] - _minFrame; @@ -300,16 +306,22 @@ bool PedData::InitializeVariables(const fs::path& filename) double y = ys[i]*M2CM; double z = zs[i]*M2CM; - _xCor(ID,frm) = x; - _yCor(ID,frm) = y; - _zCor(ID,frm) = z; + /* structure of these matrices + * line: position id in unique_ids + * column: frame id - minFrame + */ + _xCor(id_pos,frm) = x; + _yCor(id_pos,frm) = y; + _zCor(id_pos,frm) = z; + _id(id_pos,frm) = _IdsTXT[i]; + // std::cout << "id_pos " << id_pos << " FR " << frm << ": " << _id(id_pos,frm) << ", " << _xCor(id_pos, frm) << ", " << _yCor(id_pos,frm) << ", " << _zCor(id_pos,frm) << "\n"; if(_vComponent == "F") { - _vComp(ID,frm) = vcmp[i]; + _vComp(id_pos,frm) = vcmp[i]; } else { - _vComp(ID,frm) = _vComponent; + _vComp(id_pos,frm) = _vComponent; } } Log->Write("Save the data for each frame"); @@ -317,38 +329,39 @@ bool PedData::InitializeVariables(const fs::path& filename) //save the data for each frame for (unsigned int i = 0; i < _FramesTXT.size(); i++ ) { - int id = _IdsTXT[i]-_minID; // this make the assumption that - // indexes in the trajectories - // are consecutive - auto it = std::find(unique_ids.begin(), unique_ids.end(), _IdsTXT[i]); - if (it == unique_ids.end()) + int id_pos = 0; + auto itIds = std::find(unique_ids.begin(), unique_ids.end(), _IdsTXT[i]); + if (itIds == unique_ids.end()) { Log->Write("Error2:\t Id %d does not exist in file", _IdsTXT[i]); return false; } else { - id = std::distance(unique_ids.begin(), it); + id_pos = std::distance(unique_ids.begin(), itIds); } - int t =_FramesTXT[i]- _minFrame; - _peds_t[t].push_back(id); + /* structure of peds_t + * + * index: frame id - minFrame, value: position id in unique_ids + */ + _peds_t[t].push_back(id_pos); + // std::cout << "frame: " << _FramesTXT[i] << " t: " << t << " > " << id_pos << "\n"; } return true; } - -// initialize the global variables variables +// initialize the global variables. xml format bool PedData::InitializeVariables(TiXmlElement* xRootNode) { if( ! xRootNode ) { - Log->Write("ERROR:\tRoot element does not exist"); + Log->Write("ERROR:\tPedData::InitializeVariables: Root element does not exist"); return false; } if( xRootNode->ValueStr () != "trajectories" ) { - Log->Write("ERROR:\tRoot element value is not 'trajectories'."); + Log->Write("ERROR:\tPedData::InitializeVariables. Root element value is not 'trajectories'."); return false; } @@ -417,7 +430,7 @@ bool PedData::InitializeVariables(TiXmlElement* xRootNode) for(TiXmlElement* xAgent = xFrame->FirstChildElement("agent"); xAgent; xAgent = xAgent->NextSiblingElement("agent")) { - //get agent id, x, y + //get agent id, x, y, z double x= atof(xAgent->Attribute("x")); double y= atof(xAgent->Attribute("y")); double z= atof(xAgent->Attribute("z")); @@ -433,6 +446,7 @@ bool PedData::InitializeVariables(TiXmlElement* xRootNode) _xCor(ID,frameNr) = x*M2CM; _yCor(ID,frameNr) = y*M2CM; _zCor(ID,frameNr) = z*M2CM; + _id(ID,frameNr) = ID + _minID; if(_vComponent == "F") { if(xAgent->Attribute("VD")) @@ -573,14 +587,34 @@ vector<double> PedData::GetZInFrame(int frame, const vector<int>& ids) const } return ZInFrame; } +vector<double> PedData::GetZInFrame(int frame, const vector<int>& ids, double zPos) const +{ + vector<double> ZInFrame; + for(unsigned int i=0; i<ids.size();i++) + { + int id = ids[i]; + if(zPos<1000000.0) + { + if(fabs(_zCor(id,frame)-zPos*M2CM)<J_EPS_EVENT) + { + ZInFrame.push_back(_zCor(id,frame)); + } + } + else + { + ZInFrame.push_back(_zCor(id,frame)); + } + + } + return ZInFrame; +} -vector<int> PedData::GetIdInFrame(const vector<int>& ids) const +vector<int> PedData::GetIdInFrame(int frame, const vector<int>& ids) const { vector<int> IdInFrame; for(int id:ids) { - id = id +_minID; - IdInFrame.push_back(id); + IdInFrame.push_back(_id(id,frame)); } return IdInFrame; } @@ -594,12 +628,14 @@ vector<int> PedData::GetIdInFrame(int frame, const vector<int>& ids, double zPos { if(fabs(_zCor(id,frame)-zPos*M2CM)<J_EPS_EVENT) { - IdInFrame.push_back(id +_minID); + //IdInFrame.push_back(id +_minID); + IdInFrame.push_back(_id(id,frame)); } } else { - IdInFrame.push_back(id +_minID); + // IdInFrame.push_back(id +_minID); + IdInFrame.push_back(_id(id,frame)); } } return IdInFrame; @@ -736,6 +772,8 @@ void PedData::CreateGlobalVariables(int numPeds, int numFrames) _yCor = ub::matrix<double>(numPeds, numFrames); Log->Write("INFO: allocate memory for zCor"); _zCor = ub::matrix<double>(numPeds, numFrames); + Log->Write("INFO: allocate memory for index"); + _id = ub::matrix<double>(numPeds, numFrames); Log->Write("INFO: allocate memory for vComp"); _vComp = ub::matrix<std::string>(numPeds, numFrames); Log->Write(" Finished memory allocation"); diff --git a/methods/PedData.h b/methods/PedData.h index 432b5f5786b2eeb3b2996948370d1b1787f7f735..3fa72be24da4d96cff2bbb81fc3f4c7e00026711 100644 --- a/methods/PedData.h +++ b/methods/PedData.h @@ -67,15 +67,17 @@ public: ub::matrix<double> GetXCor() const; ub::matrix<double> GetYCor() const; ub::matrix<double> GetZCor() const; + ub::matrix<double> GetId() const; int* GetFirstFrame() const; int* GetLastFrame() const; - std::vector<int> GetIdInFrame(const std::vector<int>& ids) const; + std::vector<int> GetIdInFrame(int frame, const std::vector<int>& ids) const; std::vector<int> GetIdInFrame(int frame, const std::vector<int>& ids, double zPos) const; std::vector<double> GetXInFrame(int frame, const std::vector<int>& ids, double zPos) const; std::vector<double> GetYInFrame(int frame, const std::vector<int>& ids, double zPos) const; std::vector<double> GetXInFrame(int frame, const std::vector<int>& ids) const; std::vector<double> GetYInFrame(int frame, const std::vector<int>& ids) const; std::vector<double> GetZInFrame(int frame, const std::vector<int>& ids) const; + std::vector<double> GetZInFrame(int frame, const std::vector<int>& ids, double zPos) const; std::vector<double> GetVInFrame(int frame, const std::vector<int>& ids, double zPos) const; bool ReadData(const fs::path& projectRootDir,const fs::path& outputDir, const fs::path& path, const fs::path& filename, const FileFormat& _trajformat, int deltaF, std::string vComponent, const bool IgnoreBackwardMovement); fs::path GetOutputLocation() const; @@ -94,6 +96,7 @@ private: fs::path _outputLocation=""; int _minFrame=0; int _minID=1; + int _maxID=0; int _numFrames=0; // total number of frames int _numPeds=0; // total number of pedestrians float _fps=16; @@ -108,6 +111,7 @@ private: ub::matrix<double> _xCor; ub::matrix<double> _yCor; ub::matrix<double> _zCor; + ub::matrix<double> _id; ub::matrix<std::string> _vComp; }; diff --git a/methods/VoronoiDiagram.cpp b/methods/VoronoiDiagram.cpp index a31985b6710a86d2311dd0dc432e6b8ca9ef1834..791375f3793e2e9dbdef693968892a26e1dcf09a 100644 --- a/methods/VoronoiDiagram.cpp +++ b/methods/VoronoiDiagram.cpp @@ -49,11 +49,44 @@ VoronoiDiagram::~VoronoiDiagram() std::vector<std::pair<polygon_2d, int> > VoronoiDiagram::getVoronoiPolygons(vector<double>& XInFrame, vector<double>& YInFrame, vector<double>& VInFrame, vector<int>& IdInFrame, const double Bound_Max) { - const int numPedsInFrame = IdInFrame.size(); + double M2CM = 10000; + int numPedsInFrame = IdInFrame.size(); vector<int> XInFrame_temp; vector<int> YInFrame_temp; vector<double> VInFrame_temp; vector<int> IdInFrame_temp; + // in case 1 or 2 pedestrians are in the geometry + // add dummy pedestrians around to enable voronoi calculations + // @todo: maybe use negative ids for these dummy pedestrians to exclude + // them from any analysis. + if(numPedsInFrame == 1 || numPedsInFrame == 2) + { + numPedsInFrame += 4; + // up right + XInFrame.push_back(XInFrame[0]+10*M2CM); + YInFrame.push_back(YInFrame[0]+10*M2CM); + VInFrame.push_back(VInFrame[0]); + //IdInFrame.push_back(IdInFrame[0]+1); + IdInFrame.push_back(-1); + // up left + XInFrame.push_back(XInFrame[0]-10*M2CM); + YInFrame.push_back(YInFrame[0]+10*M2CM); + VInFrame.push_back(VInFrame[0]); + //IdInFrame.push_back(IdInFrame[0]+2); + IdInFrame.push_back(-2); + // down right + XInFrame.push_back(XInFrame[0]+10*M2CM); + YInFrame.push_back(YInFrame[0]-10*M2CM); + VInFrame.push_back(VInFrame[0]); + //IdInFrame.push_back(IdInFrame[0]+3); + IdInFrame.push_back(-3); + // down left + XInFrame.push_back(XInFrame[0]-10*M2CM); + YInFrame.push_back(YInFrame[0]-10*M2CM); + VInFrame.push_back(VInFrame[0]); + // IdInFrame.push_back(IdInFrame[0]+4); + IdInFrame.push_back(-4); + } for (int i = 0; i < numPedsInFrame; i++) { @@ -62,8 +95,12 @@ std::vector<std::pair<polygon_2d, int> > VoronoiDiagram::getVoronoiPolygons(vect YInFrame_temp.push_back(round(YInFrame[i])); VInFrame_temp.push_back(VInFrame[i]); IdInFrame_temp.push_back(IdInFrame[i]); + // std::cout << "i: " << i << " Id " << IdInFrame[i] << " pos = " << XInFrame[i] << ", " << YInFrame[i] << "\n"; + } + + VD voronoidiagram; construct_voronoi(points.begin(), points.end(), &voronoidiagram); int Ncell = 0; @@ -100,6 +137,7 @@ std::vector<std::pair<polygon_2d, int> > VoronoiDiagram::getVoronoiPolygons(vect break; } } + XInFrame[Ncell] = thispoint.x(); YInFrame[Ncell] = thispoint.y(); int NumVertex = 0; @@ -193,9 +231,13 @@ std::vector<std::pair<polygon_2d, int> > VoronoiDiagram::getVoronoiPolygons(vect //cout << "poly is: " << typeid(poly).name() << '\n' int id_ped = IdInFrame[Ncell]; std::pair<polygon_2d, int> poly_id = std::make_pair(poly, id_ped); + if (id_ped < 0 ) + { + continue; + } polygons_id.push_back(poly_id); Ncell++; - } + }// for voronoi cells return polygons_id; } @@ -418,10 +460,10 @@ point_type2 VoronoiDiagram::getIntersectionPoint(const point_2d& pt0, const poin { vector<point_2d> pt; segment edge0(pt0, pt1); - vector<point_2d> const& points = square.outer(); - for (vector<point_2d>::size_type i = 1; i < points.size(); ++i) + vector<point_2d> const& opoints = square.outer(); + for (vector<point_2d>::size_type i = 1; i < opoints.size(); ++i) { - segment edge1(points[i], points[i-1]); + segment edge1(opoints[i], opoints[i-1]); if(intersects(edge0, edge1)) { intersection(edge0, edge1, pt); @@ -430,7 +472,7 @@ point_type2 VoronoiDiagram::getIntersectionPoint(const point_2d& pt0, const poin } if(pt.empty()) { - segment edge1(points[3], points[0]); + segment edge1(opoints[3], opoints[0]); intersection(edge0, edge1, pt); } point_type2 interpts(pt[0].x(), pt[0].y()); diff --git a/methods/VoronoiDiagram.h b/methods/VoronoiDiagram.h index 88ec2091e796b1ac6d9f5eb07fe6a90ce2521869..6a4211a0114257edfd377329d0ccf216caeb379d 100644 --- a/methods/VoronoiDiagram.h +++ b/methods/VoronoiDiagram.h @@ -36,32 +36,32 @@ #define PI 3.14159265 -#include <boost/polygon/voronoi.hpp> -using boost::polygon::voronoi_builder; -using boost::polygon::voronoi_diagram; +//#include <boost/polygon/voronoi.hpp> +//using boost::polygon::voronoi_builder; +//using boost::polygon::voronoi_diagram; -#include <boost/geometry.hpp> -#include <boost/geometry/geometry.hpp> -#include <boost/geometry/geometries/point_xy.hpp> -#include <boost/geometry/geometries/polygon.hpp> -#include <boost/geometry/geometries/adapted/c_array.hpp> -#include <boost/geometry/geometries/ring.hpp> -#include <boost/geometry/algorithms/intersection.hpp> -#include <boost/geometry/algorithms/within.hpp> -#include <boost/foreach.hpp> +//#include <boost/geometry.hpp> +//#include <boost/geometry/geometry.hpp> +//#include <boost/geometry/geometries/point_xy.hpp> +//#include <boost/geometry/geometries/polygon.hpp> +//#include <boost/geometry/geometries/adapted/c_array.hpp> +//#include <boost/geometry/geometries/ring.hpp> +//#include <boost/geometry/algorithms/intersection.hpp> +//#include <boost/geometry/algorithms/within.hpp> +//#include <boost/foreach.hpp> #include "../general/Macros.h" - -typedef boost::geometry::model::d2::point_xy<double, boost::geometry::cs::cartesian> point_2d; -typedef boost::geometry::model::polygon<point_2d> polygon_2d; -typedef std::vector<polygon_2d > polygon_list; -typedef boost::geometry::model::segment<boost::geometry::model::d2::point_xy<double> > segment; - -typedef boost::polygon::point_data<double> point_type2; -typedef double coordinate_type; -typedef boost::polygon::voronoi_diagram<double> VD; -typedef VD::edge_type edge_type; -typedef VD::cell_type cell_type; -typedef VD::cell_type::source_index_type source_index_type; +// +//typedef boost::geometry::model::d2::point_xy<double, boost::geometry::cs::cartesian> point_2d; +//typedef boost::geometry::model::polygon<point_2d> polygon_2d; +//typedef std::vector<polygon_2d > polygon_list; +//typedef boost::geometry::model::segment<boost::geometry::model::d2::point_xy<double> > segment; +// +//typedef boost::polygon::point_data<double> point_type2; +//typedef double coordinate_type; +//typedef boost::polygon::voronoi_diagram<double> VD; +//typedef VD::edge_type edge_type; +//typedef VD::cell_type cell_type; +//typedef VD::cell_type::source_index_type source_index_type; class VoronoiDiagram { diff --git a/tinyxml/tinyxml.cpp b/tinyxml/tinyxml.cpp index 9c161dfcb934e855ff679998c34669bfdd66aa21..54dcef1ff0bf0df6caf4972416b922c3b207ab12 100644 --- a/tinyxml/tinyxml.cpp +++ b/tinyxml/tinyxml.cpp @@ -38,670 +38,670 @@ bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - FILE* fp = 0; - errno_t err = fopen_s( &fp, filename, mode ); - if ( !err && fp ) - return fp; - return 0; - #else - return fopen( filename, mode ); - #endif + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filename, mode ); + if ( !err && fp ) + return fp; + return 0; + #else + return fopen( filename, mode ); + #endif } void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) { - int i=0; - - while( i<(int)str.length() ) - { - unsigned char c = (unsigned char) str[i]; - - if ( c == '&' - && i < ( (int)str.length() - 2 ) - && str[i+1] == '#' - && str[i+2] == 'x' ) - { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while ( i<(int)str.length()-1 ) - { - outString->append( str.c_str() + i, 1 ); - ++i; - if ( str[i] == ';' ) - break; - } - } - else if ( c == '&' ) - { - outString->append( entity[0].str, entity[0].strLength ); - ++i; - } - else if ( c == '<' ) - { - outString->append( entity[1].str, entity[1].strLength ); - ++i; - } - else if ( c == '>' ) - { - outString->append( entity[2].str, entity[2].strLength ); - ++i; - } - else if ( c == '\"' ) - { - outString->append( entity[3].str, entity[3].strLength ); - ++i; - } - else if ( c == '\'' ) - { - outString->append( entity[4].str, entity[4].strLength ); - ++i; - } - else if ( c < 32 ) - { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[ 32 ]; - - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); - #else - sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); - #endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append( buf, (int)strlen( buf ) ); - ++i; - } - else - { - //char realc = (char) c; - //outString->append( &realc, 1 ); - *outString += (char) c; // somewhat more efficient function call. - ++i; - } - } + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } } TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() { - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; } TiXmlNode::~TiXmlNode() { - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } } void TiXmlNode::CopyTo( TiXmlNode* target ) const { - target->SetValue (value.c_str() ); - target->userData = userData; - target->location = location; + target->SetValue (value.c_str() ); + target->userData = userData; + target->location = location; } void TiXmlNode::Clear() { - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } - firstChild = 0; - lastChild = 0; + firstChild = 0; + lastChild = 0; } TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) { - assert( node->parent == 0 || node->parent == this ); - assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - delete node; - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } + if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + delete node; + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } - node->parent = this; + node->parent = this; - node->prev = lastChild; - node->next = 0; + node->prev = lastChild; + node->next = 0; - if ( lastChild ) - lastChild->next = node; - else - firstChild = node; // it was an empty list. + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. - lastChild = node; - return node; + lastChild = node; + return node; } TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; - return LinkEndChild( node ); + return LinkEndChild( node ); } TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) -{ - if ( !beforeThis || beforeThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if ( beforeThis->prev ) - { - beforeThis->prev->next = node; - } - else - { - assert( firstChild == beforeThis ); - firstChild = node; - } - beforeThis->prev = node; - return node; +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; } TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) { - if ( !afterThis || afterThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if ( afterThis->next ) - { - afterThis->next->prev = node; - } - else - { - assert( lastChild == afterThis ); - lastChild = node; - } - afterThis->next = node; - return node; + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; } TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { - if ( !replaceThis ) - return 0; + if ( !replaceThis ) + return 0; - if ( replaceThis->parent != this ) - return 0; + if ( replaceThis->parent != this ) + return 0; - if ( withThis.ToDocument() ) { - // A document can never be a child. Thanks to Noam. - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } + if ( withThis.ToDocument() ) { + // A document can never be a child. Thanks to Noam. + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } - TiXmlNode* node = withThis.Clone(); - if ( !node ) - return 0; + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; - node->next = replaceThis->next; - node->prev = replaceThis->prev; + node->next = replaceThis->next; + node->prev = replaceThis->prev; - if ( replaceThis->next ) - replaceThis->next->prev = node; - else - lastChild = node; + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; - if ( replaceThis->prev ) - replaceThis->prev->next = node; - else - firstChild = node; + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; - delete replaceThis; - node->parent = this; - return node; + delete replaceThis; + node->parent = this; + return node; } bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { - if ( !removeThis ) { - return false; - } + if ( !removeThis ) { + return false; + } - if ( removeThis->parent != this ) - { - assert( 0 ); - return false; - } + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } - if ( removeThis->next ) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; - if ( removeThis->prev ) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; - delete removeThis; - return true; + delete removeThis; + return true; } const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const { - const TiXmlNode* node; - for ( node = firstChild; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; } const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const { - const TiXmlNode* node; - for ( node = lastChild; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; } const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const { - if ( !previous ) - { - return FirstChild(); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling(); - } + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } } const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const { - if ( !previous ) - { - return FirstChild( val ); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling( val ); - } + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } } -const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const { - const TiXmlNode* node; - for ( node = next; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; } const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const { - const TiXmlNode* node; - for ( node = prev; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; } void TiXmlElement::RemoveAttribute( const char * name ) { #ifdef TIXML_USE_STL - TIXML_STRING str( name ); - TiXmlAttribute* node = attributeSet.Find( str ); - #else - TiXmlAttribute* node = attributeSet.Find( name ); - #endif - if ( node ) - { - attributeSet.Remove( node ); - delete node; - } + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } } const TiXmlElement* TiXmlNode::FirstChildElement() const { - const TiXmlNode* node; + const TiXmlNode* node; - for ( node = FirstChild(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; } const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const { - const TiXmlNode* node; + const TiXmlNode* node; - for ( node = FirstChild( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement() const { - const TiXmlNode* node; + const TiXmlNode* node; - for ( node = NextSibling(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const { - const TiXmlNode* node; + const TiXmlNode* node; - for ( node = NextSibling( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; } const TiXmlDocument* TiXmlNode::GetDocument() const { - const TiXmlNode* node; + const TiXmlNode* node; - for( node = this; node; node = node->parent ) - { - if ( node->ToDocument() ) - return node->ToDocument(); - } - return 0; + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; } TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { - firstChild = lastChild = 0; - value = _value; + firstChild = lastChild = 0; + value = _value; } #ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { - firstChild = lastChild = 0; - value = _value; + firstChild = lastChild = 0; + value = _value; } #endif TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { - firstChild = lastChild = 0; - copy.CopyTo( this ); + firstChild = lastChild = 0; + copy.CopyTo( this ); } TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { - ClearThis(); - base.CopyTo( this ); - return *this; + ClearThis(); + base.CopyTo( this ); + return *this; } TiXmlElement::~TiXmlElement() { - ClearThis(); + ClearThis(); } void TiXmlElement::ClearThis() { - Clear(); - while( attributeSet.First() ) - { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove( node ); - delete node; - } + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } } const char* TiXmlElement::Attribute( const char* name ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return node->Value(); - return 0; + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( attrib ) - return &attrib->ValueStr(); - return 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( attrib ) + return &attrib->ValueStr(); + return 0; } #endif const char* TiXmlElement::Attribute( const char* name, int* i ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; - if ( attrib ) { - result = attrib->Value(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; + if ( attrib ) { + result = attrib->Value(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; - if ( attrib ) { - result = &attrib->ValueStr(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; + if ( attrib ) { + result = &attrib->ValueStr(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; - if ( attrib ) { - result = attrib->Value(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; + if ( attrib ) { + result = attrib->Value(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; - if ( attrib ) { - result = &attrib->ValueStr(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; + if ( attrib ) { + result = &attrib->ValueStr(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); } -int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const +int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* Value ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; - int ival = 0; - int result = node->QueryIntValue( &ival ); - *value = (unsigned)ival; - return result; + int ival = 0; + int result = node->QueryIntValue( &ival ); + *Value = (unsigned)ival; + return result; } int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - int result = TIXML_WRONG_TYPE; - if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = true; - result = TIXML_SUCCESS; - } - else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = false; - result = TIXML_SUCCESS; - } - return result; + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + int result = TIXML_WRONG_TYPE; + if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = true; + result = TIXML_SUCCESS; + } + else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = false; + result = TIXML_SUCCESS; + } + return result; } @@ -709,1178 +709,1177 @@ int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const #ifdef TIXML_USE_STL int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } } #ifdef TIXML_USE_STL void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } } -#endif +#endif void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); - if ( attrib ) { - attrib->SetValue( cvalue ); - } + TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); + if ( attrib ) { + attrib->SetValue( cvalue ); + } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); - if ( attrib ) { - attrib->SetValue( _value ); - } + TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); + if ( attrib ) { + attrib->SetValue( _value ); + } } #endif void TiXmlElement::Print( FILE* cfile, int depth ) const { - int i; - assert( cfile ); - for ( i=0; i<depth; i++ ) { - fprintf( cfile, " " ); - } - - fprintf( cfile, "<%s", value.c_str() ); - - const TiXmlAttribute* attrib; - for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) - { - fprintf( cfile, " " ); - attrib->Print( cfile, depth ); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a <foo /> node - // 2) An element with only a text child is printed as <foo> text </foo> - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if ( !firstChild ) - { - fprintf( cfile, " />" ); - } - else if ( firstChild == lastChild && firstChild->ToText() ) - { - fprintf( cfile, ">" ); - firstChild->Print( cfile, depth + 1 ); - fprintf( cfile, "</%s>", value.c_str() ); - } - else - { - fprintf( cfile, ">" ); - - for ( node = firstChild; node; node=node->NextSibling() ) - { - if ( !node->ToText() ) - { - fprintf( cfile, "\n" ); - } - node->Print( cfile, depth+1 ); - } - fprintf( cfile, "\n" ); - for( i=0; i<depth; ++i ) { - fprintf( cfile, " " ); - } - fprintf( cfile, "</%s>", value.c_str() ); - } + int i; + assert( cfile ); + for ( i=0; i<depth; i++ ) { + fprintf( cfile, " " ); + } + + fprintf( cfile, "<%s", value.c_str() ); + + const TiXmlAttribute* attrib; + for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a <foo /> node + // 2) An element with only a text child is printed as <foo> text </foo> + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "</%s>", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i<depth; ++i ) { + fprintf( cfile, " " ); + } + fprintf( cfile, "</%s>", value.c_str() ); + } } void TiXmlElement::CopyTo( TiXmlElement* target ) const { - // superclass: - TiXmlNode::CopyTo( target ); + // superclass: + TiXmlNode::CopyTo( target ); - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for( attribute = attributeSet.First(); - attribute; - attribute = attribute->Next() ) - { - target->SetAttribute( attribute->Name(), attribute->Value() ); - } + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } } bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const { - if ( visitor->VisitEnter( *this, attributeSet.First() ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); } TiXmlNode* TiXmlElement::Clone() const { - TiXmlElement* clone = new TiXmlElement( Value() ); - if ( !clone ) - return 0; + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } const char* TiXmlElement::GetText() const { - const TiXmlNode* child = this->FirstChild(); - if ( child ) { - const TiXmlText* childText = child->ToText(); - if ( childText ) { - return childText->Value(); - } - } - return 0; + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; } TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); } TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); } #ifdef TIXML_USE_STL TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { - tabsize = 4; - useMicrosoftBOM = false; + tabsize = 4; + useMicrosoftBOM = false; value = documentName; - ClearError(); + ClearError(); } #endif TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { - copy.CopyTo( this ); + copy.CopyTo( this ); } TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { - Clear(); - copy.CopyTo( this ); - return *this; + Clear(); + copy.CopyTo( this ); + return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { - return LoadFile( Value(), encoding ); + return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { - return SaveFile( Value() ); + return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { - TIXML_STRING filename( _filename ); - value = filename; + TIXML_STRING filename( _filename ); + value = filename; - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = TiXmlFOpen( value.c_str (), "rb" ); + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = TiXmlFOpen( value.c_str (), "rb" ); - if ( file ) - { - bool result = LoadFile( file, encoding ); - fclose( file ); - return result; - } - else - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } } bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) { - if ( !file ) - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek( file, 0, SEEK_END ); - length = ftell( file ); - fseek( file, 0, SEEK_SET ); - - // Strange case, but good to handle up front. - if ( length <= 0 ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // <snip> - // <quote> - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // </quote> - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[ length+1 ]; - buf[0] = 0; - - if ( fread( buf, length, 1, file ) != 1 ) { - delete [] buf; - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Process the buffer in place to normalize new lines. (See comment above.) - // Copies from the 'p' to 'q' pointer, where p can advance faster if - // a newline-carriage return is hit. - // - // Wikipedia: - // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or - // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... - // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length <= 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // <snip> + // <quote> + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // </quote> + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Process the buffer in place to normalize new lines. (See comment above.) + // Copies from the 'p' to 'q' pointer, where p can advance faster if + // a newline-carriage return is hit. + // + // Wikipedia: + // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or + // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... + // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 - const char* p = buf; // the read head - char* q = buf; // the write head - const char CR = 0x0d; - const char LF = 0x0a; + const char* p = buf; // the read head + char* q = buf; // the write head + const char CR = 0x0d; + const char LF = 0x0a; - buf[length] = 0; - while( *p ) { - assert( p < (buf+length) ); - assert( q <= (buf+length) ); - assert( q <= p ); + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + assert( q <= (buf+length) ); + assert( q <= p ); - if ( *p == CR ) { - *q++ = LF; - p++; - if ( *p == LF ) { // check for CR+LF (and skip LF) - p++; - } - } - else { - *q++ = *p++; - } - } - assert( q <= (buf+length) ); - *q = 0; + if ( *p == CR ) { + *q++ = LF; + p++; + if ( *p == LF ) { // check for CR+LF (and skip LF) + p++; + } + } + else { + *q++ = *p++; + } + } + assert( q <= (buf+length) ); + *q = 0; - Parse( buf, 0, encoding ); + Parse( buf, 0, encoding ); - delete [] buf; - return !Error(); + delete [] buf; + return !Error(); } bool TiXmlDocument::SaveFile( const char * filename ) const { - // The old c stuff lives on... - FILE* fp = TiXmlFOpen( filename, "w" ); - if ( fp ) - { - bool result = SaveFile( fp ); - fclose( fp ); - return result; - } - return false; + // The old c stuff lives on... + FILE* fp = TiXmlFOpen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; } bool TiXmlDocument::SaveFile( FILE* fp ) const { - if ( useMicrosoftBOM ) - { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - fputc( TIXML_UTF_LEAD_0, fp ); - fputc( TIXML_UTF_LEAD_1, fp ); - fputc( TIXML_UTF_LEAD_2, fp ); - } - Print( fp, 0 ); - return (ferror(fp) == 0); + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); } void TiXmlDocument::CopyTo( TiXmlDocument* target ) const { - TiXmlNode::CopyTo( target ); + TiXmlNode::CopyTo( target ); - target->error = error; - target->errorId = errorId; - target->errorDesc = errorDesc; - target->tabsize = tabsize; - target->errorLocation = errorLocation; - target->useMicrosoftBOM = useMicrosoftBOM; + target->error = error; + target->errorId = errorId; + target->errorDesc = errorDesc; + target->tabsize = tabsize; + target->errorLocation = errorLocation; + target->useMicrosoftBOM = useMicrosoftBOM; - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } } TiXmlNode* TiXmlDocument::Clone() const { - TiXmlDocument* clone = new TiXmlDocument(); - if ( !clone ) - return 0; + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } void TiXmlDocument::Print( FILE* cfile, int depth ) const { - assert( cfile ); - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - node->Print( cfile, depth ); - fprintf( cfile, "\n" ); - } + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } } bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const { - if ( visitor->VisitEnter( *this ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); } const TiXmlAttribute* TiXmlAttribute::Next() const { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; } /* TiXmlAttribute* TiXmlAttribute::Next() { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; } */ const TiXmlAttribute* TiXmlAttribute::Previous() const { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; } /* TiXmlAttribute* TiXmlAttribute::Previous() { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; } */ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { - TIXML_STRING n, v; + TIXML_STRING n, v; - EncodeString( name, &n ); - EncodeString( value, &v ); + EncodeString( name, &n ); + EncodeString( value, &v ); - if (value.find ('\"') == TIXML_STRING::npos) { - if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; - } - } - else { - if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; - } - } + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } } int TiXmlAttribute::QueryIntValue( int* ival ) const { - if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; + if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; } int TiXmlAttribute::QueryDoubleValue( double* dval ) const { - if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; + if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; } void TiXmlAttribute::SetIntValue( int _value ) { - char buf [64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); - #else - sprintf (buf, "%d", _value); - #endif - SetValue (buf); + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); } void TiXmlAttribute::SetDoubleValue( double _value ) { - char buf [256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); - #else - sprintf (buf, "%g", _value); - #endif - SetValue (buf); + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); + #else + sprintf (buf, "%g", _value); + #endif + SetValue (buf); } int TiXmlAttribute::IntValue() const { - return atoi (value.c_str ()); + return atoi (value.c_str ()); } double TiXmlAttribute::DoubleValue() const { - return atof (value.c_str ()); + return atof (value.c_str ()); } TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { - copy.CopyTo( this ); + copy.CopyTo( this ); } TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { - Clear(); - base.CopyTo( this ); - return *this; + Clear(); + base.CopyTo( this ); + return *this; } void TiXmlComment::Print( FILE* cfile, int depth ) const { - assert( cfile ); - for ( int i=0; i<depth; i++ ) - { - fprintf( cfile, " " ); - } - fprintf( cfile, "<!--%s-->", value.c_str() ); + assert( cfile ); + for ( int i=0; i<depth; i++ ) + { + fprintf( cfile, " " ); + } + fprintf( cfile, "<!--%s-->", value.c_str() ); } void TiXmlComment::CopyTo( TiXmlComment* target ) const { - TiXmlNode::CopyTo( target ); + TiXmlNode::CopyTo( target ); } bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const { - return visitor->Visit( *this ); + return visitor->Visit( *this ); } TiXmlNode* TiXmlComment::Clone() const { - TiXmlComment* clone = new TiXmlComment(); + TiXmlComment* clone = new TiXmlComment(); - if ( !clone ) - return 0; + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } void TiXmlText::Print( FILE* cfile, int depth ) const { - assert( cfile ); - if ( cdata ) - { - int i; - fprintf( cfile, "\n" ); - for ( i=0; i<depth; i++ ) { - fprintf( cfile, " " ); - } - fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output - } - else - { - TIXML_STRING buffer; - EncodeString( value, &buffer ); - fprintf( cfile, "%s", buffer.c_str() ); - } + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i<depth; i++ ) { + fprintf( cfile, " " ); + } + fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + EncodeString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } } void TiXmlText::CopyTo( TiXmlText* target ) const { - TiXmlNode::CopyTo( target ); - target->cdata = cdata; + TiXmlNode::CopyTo( target ); + target->cdata = cdata; } bool TiXmlText::Accept( TiXmlVisitor* visitor ) const { - return visitor->Visit( *this ); + return visitor->Visit( *this ); } TiXmlNode* TiXmlText::Clone() const -{ - TiXmlText* clone = 0; - clone = new TiXmlText( "" ); +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); - if ( !clone ) - return 0; + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } TiXmlDeclaration::TiXmlDeclaration( const char * _version, - const char * _encoding, - const char * _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { - version = _version; - encoding = _encoding; - standalone = _standalone; + version = _version; + encoding = _encoding; + standalone = _standalone; } #ifdef TIXML_USE_STL TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { - version = _version; - encoding = _encoding; - standalone = _standalone; + version = _version; + encoding = _encoding; + standalone = _standalone; } #endif TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { - copy.CopyTo( this ); + copy.CopyTo( this ); } TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { - Clear(); - copy.CopyTo( this ); - return *this; + Clear(); + copy.CopyTo( this ); + return *this; } void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { - if ( cfile ) fprintf( cfile, "<?xml " ); - if ( str ) (*str) += "<?xml "; + if ( cfile ) fprintf( cfile, "<?xml " ); + if ( str ) (*str) += "<?xml "; - if ( !version.empty() ) { - if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ()); - if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; } - } - if ( !encoding.empty() ) { - if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); - if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; } - } - if ( !standalone.empty() ) { - if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); - if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; } - } - if ( cfile ) fprintf( cfile, "?>" ); - if ( str ) (*str) += "?>"; + if ( !version.empty() ) { + if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ()); + if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; } + } + if ( !encoding.empty() ) { + if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); + if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; } + } + if ( !standalone.empty() ) { + if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); + if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; } + } + if ( cfile ) fprintf( cfile, "?>" ); + if ( str ) (*str) += "?>"; } void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const { - TiXmlNode::CopyTo( target ); + TiXmlNode::CopyTo( target ); - target->version = version; - target->encoding = encoding; - target->standalone = standalone; + target->version = version; + target->encoding = encoding; + target->standalone = standalone; } bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const { - return visitor->Visit( *this ); + return visitor->Visit( *this ); } TiXmlNode* TiXmlDeclaration::Clone() const -{ - TiXmlDeclaration* clone = new TiXmlDeclaration(); +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); - if ( !clone ) - return 0; + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } void TiXmlUnknown::Print( FILE* cfile, int depth ) const { - for ( int i=0; i<depth; i++ ) - fprintf( cfile, " " ); - fprintf( cfile, "<%s>", value.c_str() ); + for ( int i=0; i<depth; i++ ) + fprintf( cfile, " " ); + fprintf( cfile, "<%s>", value.c_str() ); } void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const { - TiXmlNode::CopyTo( target ); + TiXmlNode::CopyTo( target ); } bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const { - return visitor->Visit( *this ); + return visitor->Visit( *this ); } TiXmlNode* TiXmlUnknown::Clone() const { - TiXmlUnknown* clone = new TiXmlUnknown(); + TiXmlUnknown* clone = new TiXmlUnknown(); - if ( !clone ) - return 0; + if ( !clone ) + return 0; - CopyTo( clone ); - return clone; + CopyTo( clone ); + return clone; } TiXmlAttributeSet::TiXmlAttributeSet() { - sentinel.next = &sentinel; - sentinel.prev = &sentinel; + sentinel.next = &sentinel; + sentinel.prev = &sentinel; } TiXmlAttributeSet::~TiXmlAttributeSet() { - assert( sentinel.next == &sentinel ); - assert( sentinel.prev == &sentinel ); + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); } void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) { #ifdef TIXML_USE_STL - assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. - #else - assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. - #endif + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif - addMe->next = &sentinel; - addMe->prev = sentinel.prev; + addMe->next = &sentinel; + addMe->prev = sentinel.prev; - sentinel.prev->next = addMe; - sentinel.prev = addMe; + sentinel.prev->next = addMe; + sentinel.prev = addMe; } void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) { - TiXmlAttribute* node; + TiXmlAttribute* node; - for( node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node == removeMe ) - { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert( 0 ); // we tried to remove a non-linked attribute. + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. } #ifdef TIXML_USE_STL TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; } #endif TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; } -#ifdef TIXML_USE_STL +#ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) { - TIXML_STRING tag; - tag.reserve( 8 * 1000 ); - base.StreamIn( &in, &tag ); + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); - base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); - return in; + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; } #endif -#ifdef TIXML_USE_STL +#ifdef TIXML_USE_STL std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) { - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out << printer.Str(); + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); - return out; + return out; } std::string& operator<< (std::string& out, const TiXmlNode& base ) { - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out.append( printer.Str() ); + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); - return out; + return out; } #endif TiXmlHandle TiXmlHandle::FirstChild() const { - if ( node ) - { - TiXmlNode* child = node->FirstChild(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const { - if ( node ) - { - TiXmlNode* child = node->FirstChild( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement() const { - if ( node ) - { - TiXmlElement* child = node->FirstChildElement(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const { - if ( node ) - { - TiXmlElement* child = node->FirstChildElement( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( int count ) const { - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild(); - for ( i=0; - child && i<count; - child = child->NextSibling(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && i<count; + child = child->NextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const { - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild( value ); - for ( i=0; - child && i<count; - child = child->NextSibling( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && i<count; + child = child->NextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( int count ) const { - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement(); - for ( i=0; - child && i<count; - child = child->NextSiblingElement(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && i<count; + child = child->NextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const { - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement( value ); - for ( i=0; - child && i<count; - child = child->NextSiblingElement( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && i<count; + child = child->NextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); } bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) { - return true; + return true; } bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) { - return true; + return true; } bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) - { - buffer += " "; - attrib->Print( 0, 0, &buffer ); - } - - if ( !element.FirstChild() ) - { - buffer += " />"; - DoLineBreak(); - } - else - { - buffer += ">"; - if ( element.FirstChild()->ToText() - && element.LastChild() == element.FirstChild() - && element.FirstChild()->ToText()->CDATA() == false ) - { - simpleTextPrint = true; - // no DoLineBreak()! - } - else - { - DoLineBreak(); - } - } - ++depth; - return true; + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; } bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) { - --depth; - if ( !element.FirstChild() ) - { - // nothing. - } - else - { - if ( simpleTextPrint ) - { - simpleTextPrint = false; - } - else - { - DoIndent(); - } - buffer += "</"; - buffer += element.Value(); - buffer += ">"; - DoLineBreak(); - } - return true; + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += "</"; + buffer += element.Value(); + buffer += ">"; + DoLineBreak(); + } + return true; } bool TiXmlPrinter::Visit( const TiXmlText& text ) { - if ( text.CDATA() ) - { - DoIndent(); - buffer += "<![CDATA["; - buffer += text.Value(); - buffer += "]]>"; - DoLineBreak(); - } - else if ( simpleTextPrint ) - { - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - } - else - { - DoIndent(); - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - DoLineBreak(); - } - return true; + if ( text.CDATA() ) + { + DoIndent(); + buffer += "<![CDATA["; + buffer += text.Value(); + buffer += "]]>"; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + } + else + { + DoIndent(); + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + DoLineBreak(); + } + return true; } bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) { - DoIndent(); - declaration.Print( 0, 0, &buffer ); - DoLineBreak(); - return true; + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; } bool TiXmlPrinter::Visit( const TiXmlComment& comment ) { - DoIndent(); - buffer += "<!--"; - buffer += comment.Value(); - buffer += "-->"; - DoLineBreak(); - return true; + DoIndent(); + buffer += "<!--"; + buffer += comment.Value(); + buffer += "-->"; + DoLineBreak(); + return true; } bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) { - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; } - diff --git a/tinyxml/tinyxmlparser.cpp b/tinyxml/tinyxmlparser.cpp index a7e0137264ed4da6c19a6e75f34477c9761e8f3d..fda2f129b1a19b941b68c517be21a82bb0219953 100644 --- a/tinyxml/tinyxmlparser.cpp +++ b/tinyxml/tinyxmlparser.cpp @@ -2,23 +2,23 @@ www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source +3. This notice may not be removed or altered from any source distribution. */ @@ -40,14 +40,14 @@ distribution. // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } }; // Bunch of unicode info at: @@ -55,91 +55,94 @@ TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: +// Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be -// ef bf bf +// ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; -const int TiXmlBase::utf8ByteTable[256] = +const int TiXmlBase::utf8ByteTable[256] = { - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte - 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid }; void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if ( input < 0x800 ) - *length = 2; - else if ( input < 0x10000 ) - *length = 3; - else if ( input < 0x200000 ) - *length = 4; - else - { *length = 0; return; } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) - { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - } + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + [[fallthrough]]; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + [[fallthrough]]; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + [[fallthrough]]; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } } /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { - if ( anyByte < 127 ) - return isalpha( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { @@ -150,17 +153,17 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { - if ( anyByte < 127 ) - return isalnum( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { @@ -171,228 +174,228 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng class TiXmlParsingData { - friend class TiXmlDocument; + friend class TiXmlDocument; public: - void Stamp( const char* now, TiXmlEncoding encoding ); + void Stamp( const char* now, TiXmlEncoding encoding ); - const TiXmlCursor& Cursor() const { return cursor; } + const TiXmlCursor& Cursor() const { return cursor; } private: - // Only used by the document! - TiXmlParsingData( const char* start, int _tabsize, int row, int col ) - { - assert( start ); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; }; void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) { - assert( now ); - - // Do nothing if the tabsize is 0. - if ( tabsize < 1 ) - { - return; - } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert( p ); - - while ( p < now ) - { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { - ++p; - } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { - ++p; - } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( *(p+1) && *(p+2) ) - { - // In these cases, don't advance the column. These are - // 0-width spaces. - if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; - else - { p +=3; ++col; } // A normal character. - } - } - else - { - ++p; - ++col; - } - break; - - default: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if ( step == 0 ) - step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } - else - { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert( cursor.row >= -1 ); - assert( cursor.col >= -1 ); - stamp = p; - assert( stamp ); + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); } const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) { - if ( !p || !*p ) - { - return 0; - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - while ( *p ) - { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 - && *(pU+2)==TIXML_UTF_LEAD_2 ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbeU ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbfU ) - { - p += 3; - continue; - } - - if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. - ++p; - else - break; - } - } - else - { - while ( *p && IsWhiteSpace( *p ) ) - ++p; - } - - return p; + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) ) + ++p; + } + + return p; } #ifdef TIXML_USE_STL /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) { - for( ;; ) - { - if ( !in->good() ) return false; + for( ;; ) + { + if ( !in->good() ) return false; - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if ( !IsWhiteSpace( c ) || c <= 0 ) - return true; + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; - *tag += (char) in->get(); - } + *tag += (char) in->get(); + } } /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) { - //assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while ( in->good() ) - { - int c = in->peek(); - if ( c == character ) - return true; - if ( c <= 0 ) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char) c; - } - return false; + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; } #endif @@ -401,1239 +404,1238 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) // const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) { - // Oddly, not supported on some comilers, - //name->clear(); - // So use this: - *name = ""; - assert( p ); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if ( p && *p - && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) - { - const char* start = p; - while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) - { - //(*name) += *p; // expensive - ++p; - } - if ( p-start > 0 ) { - name->assign( start, p-start ); - } - return p; - } - return 0; + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; } const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) { - // Presume an entity, and pull it out. + // Presume an entity, and pull it out. TIXML_STRING ent; - int i; - *length = 0; - - if ( *(p+1) && *(p+1) == '#' && *(p+2) ) - { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if ( *(p+2) == 'x' ) - { - // Hexadecimal. - if ( !*(p+3) ) return 0; - - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != 'x' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else if ( *q >= 'a' && *q <= 'f' ) - ucs += mult * (*q - 'a' + 10); - else if ( *q >= 'A' && *q <= 'F' ) - ucs += mult * (*q - 'A' + 10 ); - else - return 0; - mult *= 16; - --q; - } - } - else - { - // Decimal. - if ( !*(p+2) ) return 0; - - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != '#' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - } - else - { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for( i=0; i<NUM_ENTITY; ++i ) - { - if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) - { - assert( strlen( entity[i].str ) == entity[i].strLength ); - *value = entity[i].chr; - *length = 1; - return ( p + entity[i].strLength ); - } - } - - // So it wasn't an entity, its unrecognized, or something like that. - *value = *p; // Don't put back the last one, since we return it! - //*length = 1; // Leave unrecognized entities - this doesn't really work. - // Just writes strange XML. - return p+1; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; i<NUM_ENTITY; ++i ) + { + if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) + { + assert( strlen( entity[i].str ) == entity[i].strLength ); + *value = entity[i].chr; + *length = 1; + return ( p + entity[i].strLength ); + } + } + + // So it wasn't an entity, its unrecognized, or something like that. + *value = *p; // Don't put back the last one, since we return it! + //*length = 1; // Leave unrecognized entities - this doesn't really work. + // Just writes strange XML. + return p+1; } bool TiXmlBase::StringEqual( const char* p, - const char* tag, - bool ignoreCase, - TiXmlEncoding encoding ) + const char* tag, + bool ignoreCase, + TiXmlEncoding encoding ) { - assert( p ); - assert( tag ); - if ( !p || !*p ) - { - assert( 0 ); - return false; - } - - const char* q = p; - - if ( ignoreCase ) - { - while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) - { - ++q; - ++tag; - } - - if ( *tag == 0 ) - return true; - } - else - { - while ( *q && *tag && *q == *tag ) - { - ++q; - ++tag; - } - - if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? - return true; - } - return false; + assert( p ); + assert( tag ); + if ( !p || !*p ) + { + assert( 0 ); + return false; + } + + const char* q = p; + + if ( ignoreCase ) + { + while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) + { + ++q; + ++tag; + } + + if ( *tag == 0 ) + return true; + } + else + { + while ( *q && *tag && *q == *tag ) + { + ++q; + ++tag; + } + + if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? + return true; + } + return false; } -const char* TiXmlBase::ReadText( const char* p, - TIXML_STRING * text, - bool trimWhiteSpace, - const char* endTag, - bool caseInsensitive, - TiXmlEncoding encoding ) +const char* TiXmlBase::ReadText( const char* p, + TIXML_STRING * text, + bool trimWhiteSpace, + const char* endTag, + bool caseInsensitive, + TiXmlEncoding encoding ) { *text = ""; - if ( !trimWhiteSpace // certain tags always keep whitespace - || !condenseWhiteSpace ) // if true, whitespace is always kept - { - // Keep all the white space. - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) - ) - { - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - text->append( cArr, len ); - } - } - else - { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace( p, encoding ); - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) ) - { - if ( *p == '\r' || *p == '\n' ) - { - whitespace = true; - ++p; - } - else if ( IsWhiteSpace( *p ) ) - { - whitespace = true; - ++p; - } - else - { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if ( whitespace ) - { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - if ( len == 1 ) - (*text) += cArr[0]; // more efficient - else - text->append( cArr, len ); - } - } - } - if ( p && *p ) - p += strlen( endTag ); - return ( p && *p ) ? p : 0; + if ( !trimWhiteSpace // certain tags always keep whitespace + || !condenseWhiteSpace ) // if true, whitespace is always kept + { + // Keep all the white space. + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) + ) + { + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + text->append( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p && *p ) + p += strlen( endTag ); + return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) { - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if ( !StreamTo( in, '<', tag ) ) - { - SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - while ( in->good() ) - { - int tagIndex = (int) tag->length(); - while ( in->good() && in->peek() != '>' ) - { - int c = in->get(); - if ( c <= 0 ) - { - SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - break; - } - (*tag) += (char) c; - } - - if ( in->good() ) - { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); - - if ( node ) - { - node->StreamIn( in, tag ); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if ( isElement ) - { - return; - } - } - else - { - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - } - } - // We should have returned sooner. - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); } #endif const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) { - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if ( !p || !*p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if ( prevData ) - { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } - else - { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data( p, TabSize(), location.row, location.col ); - location = data.Cursor(); - - if ( encoding == TIXML_ENCODING_UNKNOWN ) - { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 - && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 - && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) - { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } p = SkipWhiteSpace( p, encoding ); - if ( !p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - while ( p && *p ) - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, &data, encoding ); - LinkEndChild( node ); - } - else - { - break; - } - - // Did we get encoding info? - if ( encoding == TIXML_ENCODING_UNKNOWN - && node->ToDeclaration() ) - { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert( enc ); - - if ( *enc == 0 ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace( p, encoding ); - } - - // Was this empty? - if ( !firstChild ) { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); - return 0; - } - - // All is well. - return p; + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - // The first error in a chain is more accurate - don't set again! - if ( error ) - return; - - assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); - error = true; - errorId = err; - errorDesc = errorString[ errorId ]; - - errorLocation.Clear(); - if ( pError && data ) - { - data->Stamp( pError, encoding ); - errorLocation = data->Cursor(); - } +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } } TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) { - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace( p, encoding ); - if( !p || !*p || *p != '<' ) - { - return 0; - } - - p = SkipWhiteSpace( p, encoding ); - - if ( !p || !*p ) - { - return 0; - } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: <!-- - // - Decleration: <?xml - // - Everthing else is unknown to tinyxml. - // - - const char* xmlHeader = { "<?xml" }; - const char* commentHeader = { "<!--" }; - const char* dtdHeader = { "<!" }; - const char* cdataHeader = { "<![CDATA[" }; - - if ( StringEqual( p, xmlHeader, true, encoding ) ) - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing Declaration\n" ); - #endif - returnNode = new TiXmlDeclaration(); - } - else if ( StringEqual( p, commentHeader, false, encoding ) ) - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing Comment\n" ); - #endif - returnNode = new TiXmlComment(); - } - else if ( StringEqual( p, cdataHeader, false, encoding ) ) - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing CDATA\n" ); - #endif - TiXmlText* text = new TiXmlText( "" ); - text->SetCDATA( true ); - returnNode = text; - } - else if ( StringEqual( p, dtdHeader, false, encoding ) ) - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing Unknown(1)\n" ); - #endif - returnNode = new TiXmlUnknown(); - } - else if ( IsAlpha( *(p+1), encoding ) - || *(p+1) == '_' ) - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing Element\n" ); - #endif - returnNode = new TiXmlElement( "" ); - } - else - { - #ifdef DEBUG_PARSER - TIXML_LOG( "XML parsing Unknown(2)\n" ); - #endif - returnNode = new TiXmlUnknown(); - } - - if ( returnNode ) - { - // Set the parent, so it can report errors - returnNode->parent = this; - } - return returnNode; + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: <!-- + // - Decleration: <?xml + // - Everthing else is unknown to tinyxml. + // + + const char* xmlHeader = { "<?xml" }; + const char* commentHeader = { "<!--" }; + const char* dtdHeader = { "<!" }; + const char* cdataHeader = { "<![CDATA[" }; + + if ( StringEqual( p, xmlHeader, true, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Declaration\n" ); + #endif + returnNode = new TiXmlDeclaration(); + } + else if ( StringEqual( p, commentHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Comment\n" ); + #endif + returnNode = new TiXmlComment(); + } + else if ( StringEqual( p, cdataHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing CDATA\n" ); + #endif + TiXmlText* text = new TiXmlText( "" ); + text->SetCDATA( true ); + returnNode = text; + } + else if ( StringEqual( p, dtdHeader, false, encoding ) ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Unknown(1)\n" ); + #endif + returnNode = new TiXmlUnknown(); + } + else if ( IsAlpha( *(p+1), encoding ) + || *(p+1) == '_' ) + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Element\n" ); + #endif + returnNode = new TiXmlElement( "" ); + } + else + { + #ifdef DEBUG_PARSER + TIXML_LOG( "XML parsing Unknown(2)\n" ); + #endif + returnNode = new TiXmlUnknown(); + } + + if ( returnNode ) + { + // Set the parent, so it can report errors + returnNode->parent = this; + } + return returnNode; } #ifdef TIXML_USE_STL void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag) { - // We're called with some amount of pre-parsing. That is, some of "this" - // element is in "tag". Go ahead and stream to the closing ">" - while( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c ; - - if ( c == '>' ) - break; - } - - if ( tag->length() < 3 ) return; - - // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. - // If not, identify and stream. - - if ( tag->at( tag->length() - 1 ) == '>' - && tag->at( tag->length() - 2 ) == '/' ) - { - // All good! - return; - } - else if ( tag->at( tag->length() - 1 ) == '>' ) - { - // There is more. Could be: - // text - // cdata text (which looks like another node) - // closing tag - // another node. - for ( ;; ) - { - StreamWhiteSpace( in, tag ); - - // Do we have text? - if ( in->good() && in->peek() != '<' ) - { - // Yep, text. - TiXmlText text( "" ); - text.StreamIn( in, tag ); - - // What follows text is a closing tag or another node. - // Go around again and figure it out. - continue; - } - - // We now have either a closing tag...or another node. - // We should be at a "<", regardless. - if ( !in->good() ) return; - assert( in->peek() == '<' ); - int tagIndex = (int) tag->length(); - - bool closingTag = false; - bool firstCharFound = false; - - for( ;; ) - { - if ( !in->good() ) - return; - - int c = in->peek(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - if ( c == '>' ) - break; - - *tag += (char) c; - in->get(); - - // Early out if we find the CDATA id. - if ( c == '[' && tag->size() >= 9 ) - { - size_t len = tag->size(); - const char* start = tag->c_str() + len - 9; - if ( strcmp( start, "<![CDATA[" ) == 0 ) { - assert( !closingTag ); - break; - } - } - - if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) - { - firstCharFound = true; - if ( c == '/' ) - closingTag = true; - } - } - // If it was a closing tag, then read in the closing '>' to clean up the input stream. - // If it was not, the streaming will be done by the tag. - if ( closingTag ) - { - if ( !in->good() ) - return; - - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - assert( c == '>' ); - *tag += (char) c; - - // We are done, once we've found our closing tag. - return; - } - else - { - // If not a closing tag, id it, and stream. - const char* tagloc = tag->c_str() + tagIndex; - TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); - if ( !node ) - return; - node->StreamIn( in, tag ); - delete node; - node = 0; - - // No return: go around from the beginning: text, closing tag, or node. - } - } - } + // We're called with some amount of pre-parsing. That is, some of "this" + // element is in "tag". Go ahead and stream to the closing ">" + while( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c ; + + if ( c == '>' ) + break; + } + + if ( tag->length() < 3 ) return; + + // Okay...if we are a "/>" tag, then we're done. We've read a complete tag. + // If not, identify and stream. + + if ( tag->at( tag->length() - 1 ) == '>' + && tag->at( tag->length() - 2 ) == '/' ) + { + // All good! + return; + } + else if ( tag->at( tag->length() - 1 ) == '>' ) + { + // There is more. Could be: + // text + // cdata text (which looks like another node) + // closing tag + // another node. + for ( ;; ) + { + StreamWhiteSpace( in, tag ); + + // Do we have text? + if ( in->good() && in->peek() != '<' ) + { + // Yep, text. + TiXmlText text( "" ); + text.StreamIn( in, tag ); + + // What follows text is a closing tag or another node. + // Go around again and figure it out. + continue; + } + + // We now have either a closing tag...or another node. + // We should be at a "<", regardless. + if ( !in->good() ) return; + assert( in->peek() == '<' ); + int tagIndex = (int) tag->length(); + + bool closingTag = false; + bool firstCharFound = false; + + for( ;; ) + { + if ( !in->good() ) + return; + + int c = in->peek(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + if ( c == '>' ) + break; + + *tag += (char) c; + in->get(); + + // Early out if we find the CDATA id. + if ( c == '[' && tag->size() >= 9 ) + { + size_t len = tag->size(); + const char* start = tag->c_str() + len - 9; + if ( strcmp( start, "<![CDATA[" ) == 0 ) { + assert( !closingTag ); + break; + } + } + + if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) + { + firstCharFound = true; + if ( c == '/' ) + closingTag = true; + } + } + // If it was a closing tag, then read in the closing '>' to clean up the input stream. + // If it was not, the streaming will be done by the tag. + if ( closingTag ) + { + if ( !in->good() ) + return; + + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + assert( c == '>' ); + *tag += (char) c; + + // We are done, once we've found our closing tag. + return; + } + else + { + // If not a closing tag, id it, and stream. + const char* tagloc = tag->c_str() + tagIndex; + TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); + if ( !node ) + return; + node->StreamIn( in, tag ); + delete node; + node = 0; + + // No return: go around from the beginning: text, closing tag, or node. + } + } + } } #endif const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - p = SkipWhiteSpace( p, encoding ); - TiXmlDocument* document = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + TiXmlDocument* document = GetDocument(); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); - return 0; - } + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); + return 0; + } - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } - if ( *p != '<' ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); - return 0; - } + if ( *p != '<' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); + return 0; + } - p = SkipWhiteSpace( p+1, encoding ); + p = SkipWhiteSpace( p+1, encoding ); - // Read the name. - const char* pErr = p; + // Read the name. + const char* pErr = p; p = ReadName( p, &value, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); - return 0; - } + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); + return 0; + } TIXML_STRING endTag ("</"); - endTag += value; - - // Check for and read attributes. Also look for an empty - // tag or an end tag. - while ( p && *p ) - { - pErr = p; - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - if ( *p == '/' ) - { - ++p; - // Empty tag. - if ( *p != '>' ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); - return 0; - } - return (p+1); - } - else if ( *p == '>' ) - { - // Done with attributes (if there were any.) - // Read the value -- which can include other - // elements -- read the end tag, and return. - ++p; - p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. - if ( !p || !*p ) { - // We were looking for the end tag, but found nothing. - // Fix for [ 1663758 ] Failure to report error on bad XML - if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); - return 0; - } - - // We should find the end tag now - // note that: - // </foo > and - // </foo> - // are both valid end tags. - if ( StringEqual( p, endTag.c_str(), false, encoding ) ) - { - p += endTag.length(); - p = SkipWhiteSpace( p, encoding ); - if ( p && *p && *p == '>' ) { - ++p; - return p; - } - if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); - return 0; - } - else - { - if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); - return 0; - } - } - else - { - // Try to read an attribute: - TiXmlAttribute* attrib = new TiXmlAttribute(); - if ( !attrib ) - { - return 0; - } - - attrib->SetDocument( document ); - pErr = p; - p = attrib->Parse( p, data, encoding ); - - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); - delete attrib; - return 0; - } - - // Handle the strange case of double attributes: - #ifdef TIXML_USE_STL - TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() ); - #else - TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); - #endif - if ( node ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); - delete attrib; - return 0; - } - - attributeSet.Add( attrib ); - } - } - return p; + endTag += value; + + // Check for and read attributes. Also look for an empty + // tag or an end tag. + while ( p && *p ) + { + pErr = p; + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + if ( *p == '/' ) + { + ++p; + // Empty tag. + if ( *p != '>' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); + return 0; + } + return (p+1); + } + else if ( *p == '>' ) + { + // Done with attributes (if there were any.) + // Read the value -- which can include other + // elements -- read the end tag, and return. + ++p; + p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. + if ( !p || !*p ) { + // We were looking for the end tag, but found nothing. + // Fix for [ 1663758 ] Failure to report error on bad XML + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + + // We should find the end tag now + // note that: + // </foo > and + // </foo> + // are both valid end tags. + if ( StringEqual( p, endTag.c_str(), false, encoding ) ) + { + p += endTag.length(); + p = SkipWhiteSpace( p, encoding ); + if ( p && *p && *p == '>' ) { + ++p; + return p; + } + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + else + { + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; + } + } + else + { + // Try to read an attribute: + TiXmlAttribute* attrib = new TiXmlAttribute(); + if ( !attrib ) + { + return 0; + } + + attrib->SetDocument( document ); + pErr = p; + p = attrib->Parse( p, data, encoding ); + + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); + delete attrib; + return 0; + } + + // Handle the strange case of double attributes: + #ifdef TIXML_USE_STL + TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() ); + #else + TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); + #endif + if ( node ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); + delete attrib; + return 0; + } + + attributeSet.Add( attrib ); + } + } + return p; } const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - TiXmlDocument* document = GetDocument(); - - // Read in text and elements in any order. - const char* pWithWhiteSpace = p; - p = SkipWhiteSpace( p, encoding ); - - while ( p && *p ) - { - if ( *p != '<' ) - { - // Take what we have, make a text element. - TiXmlText* textNode = new TiXmlText( "" ); - - if ( !textNode ) - { - return 0; - } - - if ( TiXmlBase::IsWhiteSpaceCondensed() ) - { - p = textNode->Parse( p, data, encoding ); - } - else - { - // Special case: we want to keep the white space - // so that leading spaces aren't removed. - p = textNode->Parse( pWithWhiteSpace, data, encoding ); - } - - if ( !textNode->Blank() ) - LinkEndChild( textNode ); - else - delete textNode; - } - else - { - // We hit a '<' - // Have we hit a new element or an end tag? This could also be - // a TiXmlText in the "CDATA" style. - if ( StringEqual( p, "</", false, encoding ) ) - { - return p; - } - else - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, data, encoding ); - LinkEndChild( node ); - } - else - { - return 0; - } - } - } - pWithWhiteSpace = p; - p = SkipWhiteSpace( p, encoding ); - } - - if ( !p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); - } - return p; + TiXmlDocument* document = GetDocument(); + + // Read in text and elements in any order. + const char* pWithWhiteSpace = p; + p = SkipWhiteSpace( p, encoding ); + + while ( p && *p ) + { + if ( *p != '<' ) + { + // Take what we have, make a text element. + TiXmlText* textNode = new TiXmlText( "" ); + + if ( !textNode ) + { + return 0; + } + + if ( TiXmlBase::IsWhiteSpaceCondensed() ) + { + p = textNode->Parse( p, data, encoding ); + } + else + { + // Special case: we want to keep the white space + // so that leading spaces aren't removed. + p = textNode->Parse( pWithWhiteSpace, data, encoding ); + } + + if ( !textNode->Blank() ) + LinkEndChild( textNode ); + else + delete textNode; + } + else + { + // We hit a '<' + // Have we hit a new element or an end tag? This could also be + // a TiXmlText in the "CDATA" style. + if ( StringEqual( p, "</", false, encoding ) ) + { + return p; + } + else + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, data, encoding ); + LinkEndChild( node ); + } + else + { + return 0; + } + } + } + pWithWhiteSpace = p; + p = SkipWhiteSpace( p, encoding ); + } + + if ( !p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); + } + return p; } #ifdef TIXML_USE_STL void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag ) { - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } } #endif const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - TiXmlDocument* document = GetDocument(); - p = SkipWhiteSpace( p, encoding ); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - if ( !p || !*p || *p != '<' ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); - return 0; - } - ++p; + TiXmlDocument* document = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + if ( !p || !*p || *p != '<' ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); + return 0; + } + ++p; value = ""; - while ( p && *p && *p != '>' ) - { - value += *p; - ++p; - } - - if ( !p ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); - } - if ( p && *p == '>' ) - return p+1; - return p; + while ( p && *p && *p != '>' ) + { + value += *p; + ++p; + } + + if ( !p ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); + } + if ( p && *p == '>' ) + return p+1; + return p; } #ifdef TIXML_USE_STL void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag ) { - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - - if ( c == '>' - && tag->at( tag->length() - 2 ) == '-' - && tag->at( tag->length() - 3 ) == '-' ) - { - // All is well. - return; - } - } + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + + if ( c == '>' + && tag->at( tag->length() - 2 ) == '-' + && tag->at( tag->length() - 3 ) == '-' ) + { + // All is well. + return; + } + } } #endif const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - TiXmlDocument* document = GetDocument(); - value = ""; - - p = SkipWhiteSpace( p, encoding ); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - const char* startTag = "<!--"; - const char* endTag = "-->"; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // [ 1475201 ] TinyXML parses entities in comments - // Oops - ReadText doesn't work, because we don't want to parse the entities. - // p = ReadText( p, &value, false, endTag, false, encoding ); - // - // from the XML spec: - /* - [Definition: Comments may appear anywhere in a document outside other markup; in addition, - they may appear within the document type declaration at places allowed by the grammar. - They are not part of the document's character data; an XML processor MAY, but need not, - make it possible for an application to retrieve the text of comments. For compatibility, - the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity - references MUST NOT be recognized within comments. - - An example of a comment: - - <!-- declarations for <head> & <body> --> - */ + TiXmlDocument* document = GetDocument(); + value = ""; + + p = SkipWhiteSpace( p, encoding ); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + const char* startTag = "<!--"; + const char* endTag = "-->"; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // [ 1475201 ] TinyXML parses entities in comments + // Oops - ReadText doesn't work, because we don't want to parse the entities. + // p = ReadText( p, &value, false, endTag, false, encoding ); + // + // from the XML spec: + /* + [Definition: Comments may appear anywhere in a document outside other markup; in addition, + they may appear within the document type declaration at places allowed by the grammar. + They are not part of the document's character data; an XML processor MAY, but need not, + make it possible for an application to retrieve the text of comments. For compatibility, + the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity + references MUST NOT be recognized within comments. + + An example of a comment: + + <!-- declarations for <head> & <body> --> + */ value = ""; - // Keep all the white space. - while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) - { - value.append( p, 1 ); - ++p; - } - if ( p && *p ) - p += strlen( endTag ); - - return p; + // Keep all the white space. + while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) + { + value.append( p, 1 ); + ++p; + } + if ( p && *p ) + p += strlen( endTag ); + + return p; } const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) return 0; - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName( p, &name, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p || *p != '=' ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if ( *p == SINGLE_QUOTE ) - { - ++p; - end = "\'"; // single quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else if ( *p == DOUBLE_QUOTE ) - { - ++p; - end = "\""; // double quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else - { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while ( p && *p // existence - && !IsWhiteSpace( *p ) // whitespace - && *p != '/' && *p != '>' ) // tag end - { - if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - value += *p; - ++p; - } - } - return p; + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; } #ifdef TIXML_USE_STL void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { - while ( in->good() ) - { - int c = in->peek(); - if ( !cdata && (c == '<' ) ) - { - return; - } - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - in->get(); // "commits" the peek made above - - if ( cdata && c == '>' && tag->size() >= 3 ) { - size_t len = tag->size(); - if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { - // terminator of cdata. - return; - } - } - } + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } } #endif const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { - value = ""; - TiXmlDocument* document = GetDocument(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - - const char* const startTag = "<![CDATA["; - const char* const endTag = "]]>"; - - if ( cdata || StringEqual( p, startTag, false, encoding ) ) - { - cdata = true; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // Keep all the white space, ignore the encoding, etc. - while ( p && *p - && !StringEqual( p, endTag, false, encoding ) - ) - { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText( p, &dummy, false, endTag, false, encoding ); - return p; - } - else - { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p && *p ) - return p-1; // don't truncate the '<' - return 0; - } + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = "<![CDATA["; + const char* const endTag = "]]>"; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p && *p ) + return p-1; // don't truncate the '<' + return 0; + } } #ifdef TIXML_USE_STL void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) { - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } } #endif const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) { - p = SkipWhiteSpace( p, _encoding ); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) - { - if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); - return 0; - } - if ( data ) - { - data->Stamp( p, _encoding ); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while ( p && *p ) - { - if ( *p == '>' ) - { - ++p; - return p; - } - - p = SkipWhiteSpace( p, _encoding ); - if ( StringEqual( p, "version", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - version = attrib.Value(); - } - else if ( StringEqual( p, "encoding", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - encoding = attrib.Value(); - } - else if ( StringEqual( p, "standalone", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - standalone = attrib.Value(); - } - else - { - // Read over whatever it is. - while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) - ++p; - } - } - return 0; + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) + { + if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; } bool TiXmlText::Blank() const { - for ( unsigned i=0; i<value.length(); i++ ) - if ( !IsWhiteSpace( value[i] ) ) - return false; - return true; + for ( unsigned i=0; i<value.length(); i++ ) + if ( !IsWhiteSpace( value[i] ) ) + return false; + return true; } -