summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorComment <tim@gray.(none)>2013-07-26 22:46:00 +0100
committerComment <tim@gray.(none)>2013-07-26 22:46:00 +0100
commit3d7eea02aa7a155b84c8c74ecbfd55a1941a9297 (patch)
treed49d6ac97a0df08f5ea7e6c6c291acca0f65cd12
parent7092eaaae3e844a68804b8a6b6825381e9a81443 (diff)
tidy files
-rw-r--r--rotord/Makefile9
-rw-r--r--rotord/Pixels.cpp90
-rw-r--r--rotord/Pixels.h28
-rw-r--r--rotord/cvimage.cpp156
-rw-r--r--rotord/cvimage.h191
-rw-r--r--rotord/graph.cpp150
-rw-r--r--rotord/image.h211
-rwxr-xr-xrotord/libavwrapper.cpp1657
-rwxr-xr-xrotord/libavwrapper.h279
-rw-r--r--rotord/nodes_audio_analysis.h47
-rw-r--r--rotord/nodes_drawing.h43
-rwxr-xr-xrotord/ofUtils.cpp745
-rwxr-xr-xrotord/ofUtils.h223
-rw-r--r--rotord/params.h0
-rw-r--r--rotord/rendercontext.cpp386
-rwxr-xr-xrotord/rotor.cpp361
-rwxr-xr-xrotord/rotor.h1391
-rwxr-xr-xrotord/rotord.cpp230
-rwxr-xr-xrotord/rotord.h136
-rw-r--r--rotord/system.h75
-rwxr-xr-xrotord/tinyxml.cpp1888
-rwxr-xr-xrotord/tinyxml.h1807
-rwxr-xr-xrotord/tinyxmlerror.cpp53
-rwxr-xr-xrotord/tinyxmlparser.cpp1719
-rw-r--r--rotord/utils.cpp29
-rw-r--r--rotord/utils.h10
-rw-r--r--rotord/vampHost.cpp815
-rw-r--r--rotord/vampHost.h92
-rwxr-xr-xrotord/xmlIO.cpp673
-rwxr-xr-xrotord/xmlIO.h169
30 files changed, 6 insertions, 13657 deletions
diff --git a/rotord/Makefile b/rotord/Makefile
index 41ededb..d7bd454 100644
--- a/rotord/Makefile
+++ b/rotord/Makefile
@@ -23,11 +23,13 @@ LDFLAGS =
# The directories in which source files reside.
# If not specified, only the current directory will be serached.
-SRCDIRS =
+SRCDIRS = src
# The executable file name.
# If not specified, current directory name or `a.out' will be used.
-PROGRAM =
+PROGRAM = bin/rotord
+
+OBJ_OUTPUT = obj/
## Implicit Section: change the following only when necessary.
##==========================================================================
@@ -78,6 +80,7 @@ endif
ifeq ($(SRCDIRS),)
SRCDIRS = .
endif
+##mkdir -p $(OBJ_OUTPUT)
SOURCES = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(SRCEXTS))))
HEADERS = $(foreach d,$(SRCDIRS),$(wildcard $(addprefix $(d)/*,$(HDREXTS))))
SRC_CXX = $(filter-out %.c,$(SOURCES))
@@ -210,7 +213,7 @@ endif
clean:
- $(RM) $(OBJS) $(PROGRAM) $(PROGRAM).exe
+ $(RM) $(OBJS) $(PROGRAM) $(DEPS)
distclean: clean
$(RM) $(DEPS) TAGS
diff --git a/rotord/Pixels.cpp b/rotord/Pixels.cpp
deleted file mode 100644
index 78f4bbb..0000000
--- a/rotord/Pixels.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "Pixels.h"
-Pixels::Pixels(){
- pixels=nullptr;
- pixelsOwner=false;
-}
-Pixels::~Pixels(){
- clear();
-}
-void Pixels::allocate(int w, int h, int _channels){
- if (w < 0 || h < 0) {
- return;
- }
-
- //we check if we are already allocated at the right size
- if(bAllocated && w == width && h == height && channels ==_channels){
- return; //we don't need to allocate
- }
-
- //we do need to allocate, clear the data
- clear();
-
- channels = _channels;
- width= w;
- height = h;
-
- pixels = new uint8_t[w * h * channels];
- bAllocated = true;
- pixelsOwner = true;
-}
-void Pixels::clear(){
- if(pixels){
- if(pixelsOwner) delete[] pixels;
- pixels = nullptr;
- }
-
- width = 0;
- height = 0;
- channels = 0;
- bAllocated = false;
-}
-bool Pixels::isAllocated() const{
- return bAllocated;
-}
-
-void Pixels::setFromExternalPixels(uint8_t * newPixels,int w, int h, int _channels){
- clear();
- channels = _channels;
- width= w;
- height = h;
-
- pixels = newPixels;
- pixelsOwner = false;
- bAllocated = true;
-}
-
-uint8_t * Pixels::getPixels(){
- return &pixels[0];
-}
-
-int Pixels::getWidth() const{
- return width;
-}
-
-int Pixels::getHeight() const{
- return height;
-}
-
-int Pixels::getBytesPerPixel() const{
- return channels;
-}
-
-int Pixels::getNumChannels() const{
- return channels;
-}
-
-void Pixels::swap(Pixels & pix){
- std::swap(pixels,pix.pixels);
- std::swap(width, pix.width);
- std::swap(height,pix.height);
- std::swap(channels,pix.channels);
- std::swap(pixelsOwner, pix.pixelsOwner);
- std::swap(bAllocated, pix.bAllocated);
-}
-
-void Pixels::set(uint8_t val){
- int size = width * height * channels;
- for(int i = 0; i < size; i++){
- pixels[i] = val;
- }
-} \ No newline at end of file
diff --git a/rotord/Pixels.h b/rotord/Pixels.h
deleted file mode 100644
index b6f5865..0000000
--- a/rotord/Pixels.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdint.h>
-#include <algorithm>
-//for now always uint8_t* rather than templated
-
-class Pixels{
- public:
- Pixels();
- ~Pixels();
- void allocate(int w, int h, int channels);
- bool isAllocated() const;
- void setFromExternalPixels(uint8_t * newPixels,int w, int h, int channels);
- uint8_t * getPixels();
- int getWidth() const;
- int getHeight() const;
- void clear();
- void swap(Pixels & pix);
- int getBytesPerPixel() const;
- int getNumChannels() const;
- void set(uint8_t val);
- private:
- uint8_t * pixels;
- int width;
- int height;
- int channels;
- bool bAllocated;
- bool pixelsOwner; // if set from external data don't delete it
-};
-
diff --git a/rotord/cvimage.cpp b/rotord/cvimage.cpp
deleted file mode 100644
index c18c585..0000000
--- a/rotord/cvimage.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-#include "cvimage.h"
-
-using namespace std;
-
-namespace Rotor {
- Image & Image::operator+=(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- rgb+=other.rgb;
- }
- return *this;
- }
- Image & Image::operator*=(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- //rgb/=other.rgb; //does funny glitchy stuff
- //could use cv::Mat.mul() here
- for (int i=0;i<w*h*3;i++){
- //calculate with tables
- rgb.data[i]=pixels.multiply[rgb.data[i]][other.rgb.data[i]];
- }
- }
- return *this;
- }
- Image & Image::operator^=(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- rgb^=other.rgb;
- }
- return *this;
- }
- Image & Image::add_wrap(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- for (int i=0;i<w*h*3;i++){
- //creates rainbow overload, openCV doesn't do this
- rgb.data[i]=(unsigned char)(((int)other.rgb.data[i]+(int)rgb.data[i]));
- }
- }
- return *this;
- }
- Image & Image::divide_wrap(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- for (int i=0;i<w*h*3;i++){
- //creates rainbow overload, openCV doesn't do this
- rgb/=other.rgb; //does funny glitchy stuff
- }
- }
- return *this;
- }
- //THIS OPENCV VERSION IS SLOWER THAN THE OLDSKOOL VERSION BELOW
- Image & Image::alpha_blend_cv(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- //why not??
- }
- else if (!other.alpha.data){
- //default to full on alpha
- rgb=other.rgb.clone();
- }
- else {
- //overlay the other image based on its alpha values
- //https://gist.github.com/Brick85/5009046 - this is a dumb way to do it?
- //how to invert a matrix?
- //'invert' is matrix invert - different
- //subtract from a scalar (1) ?
- vector<cv::Mat> ichans,ochans;
- vector<cv::Mat> compchans;
- cv::split(rgb,ichans);
- cv::split(other.rgb,ochans);
- uint8_t b=0xFF;
- cv::Mat iA=b-other.alpha;
- for (int i=0;i<3;i++) {
- compchans.push_back(ichans[i].mul(iA,1.0/255.0)+ochans[i].mul(other.alpha,1.0/255.0));
- }
- merge(compchans,rgb);
- //rgb+=other.rgb;
- //for (int i=0;i<w*h*3;i++) {
- // rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
- //}
- }
-
- return *this;
- }
- Image & Image::alpha_blend(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- //why not??
- }
- else if (!other.alpha.data){
- //default to full on alpha
- rgb=other.rgb.clone();
- }
- else {
- for (int i=0;i<w*h*3;i++) {
- rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
- }
- }
- return *this;
- }
- Image & Image::alpha_merge(const Image &other) {
- //converts the incoming image to monochrome and inserts it into the alpha channel of this image
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- cv::cvtColor(other.rgb,alpha,CV_RGB2GRAY);
- }
- return *this;
- }
- //channel rearrangement
- //RGBAZ - these are channels 0-4
- //HSB - can also have these virtual channels 5-7
- //convert channels- int outChannel[5] - {0,1,2,-5,4} - this mapping sends inverted brightness to alpha
-
- //scalar operations allocate a new image.
- //maybe this could not be the case if the data is owned by this image?
- //need to look into auto_ptr
- Image & Image::operator*=(const float &amount) {
- rgb*=amount;
- return *this;
- }
- Image * Image::operator*(const float &amount) {
- Image *other=new Image(w,h);
- other->rgb=rgb*amount;
- return other;
- }
- Image * Image::operator+(const float &amount) {
- uint8_t amt=(uint8_t)(amount*255.0f);
- Image *other=new Image(w,h);
- other->rgb=rgb+amt;
- return other;
- }
- Image * Image::operator-(const float &amount) {
- uint8_t amt=(uint8_t)(amount*255.0f);
- Image *other=new Image(w,h);
- other->rgb=rgb-amt;
- return other;
- }
- Image * Image::operator/(const float &amount) {
- Image *other=new Image(w,h);
- other->rgb=rgb/amount;
- return other;
- }
-}
diff --git a/rotord/cvimage.h b/rotord/cvimage.h
deleted file mode 100644
index 2f9ed3b..0000000
--- a/rotord/cvimage.h
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef ROTOR_CVIMAGE
-#define ROTOR_CVIMAGE
-
-#include <math.h>
-#include <cv.h>
-
-//converting to use a cv image...
-//cv::Mat supports most of what we want here
-//need to think
-//http://answers.opencv.org/question/8202/using-external-image-data-in-a-cvmat/
-
-//all access to the image is presently through a pointer to the data
-//cv::Mat supports this
-
-//how will copying work?
-//Rotor::Image will contain a cv::Mat object which may own its data or inherit it
-//cv::Mat should take care of reference counting
-
-//can cv::Mat
-
-namespace Rotor {
- class pixeltables{
- //handy pixel arithmetic lookup tables as nested arrays
- //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation
- // pixels.mono_weights[0][0x100]; will give the red component to convert to mono
- public:
- pixeltables(){
- add=new uint8_t*[256];
- multiply=new uint8_t*[256];
- for (int i=0;i<256;i++){
- add[i]=new uint8_t[256];
- multiply[i]=new uint8_t[256];
- for (int j=0;j<256;j++){
- add[i][j]=(uint8_t)std::min(i+j,0xFF);
- multiply[i][j]=(uint8_t)((((float)i)/255.0f)*(((float)j)/255.0f)*255.0f);
- }
- }
- mono_weights=new uint8_t*[3];
- float weights[3]={0.2989, 0.5870, 0.1140};
- for (int i=0;i<3;i++) {
- mono_weights[i]=new uint8_t[256];
- for (int j=0;j<256;j++){
- mono_weights[i][j]=(uint8_t)(((float)j)*weights[i]);
- }
- }
- }
- virtual ~pixeltables(){
- for (int i=0;i<256;i++){
- delete[] add[i];
- delete[] multiply[i];
- }
- delete[] add;
- delete[] multiply;
- for (int i=0;i<3;i++) {
- delete[] mono_weights[i];
- }
- delete[] mono_weights;
- }
- uint8_t **add;
- uint8_t **multiply;
- uint8_t **mono_weights;
- };
- static pixeltables pixels;
- class Image{
- public:
- Image(){
- zero();
- };
- Image(int _w,int _h){
- zero();
- setup(_w,_h);
- };
- ~Image() {
- free();
- };
- void free(){
- if (RGBdata&&ownsRGBdata) delete[] RGBdata;
- if (Adata&&ownsAdata) delete[] Adata;
- if (Zdata&&ownsZdata) delete[] Zdata;
- zero();
- }
- void zero(){
- RGBdata=nullptr;
- Adata=nullptr;
- Zdata=nullptr;
- w=0;
- h=0;
- ownsRGBdata=ownsAdata=ownsZdata=false;
- }
- int getStride(){
- return w*3;
- }
- bool setup(int _w,int _h){ //set up with internal data
- rgb.create(_h,_w,CV_8UC3);
- RGBdata=rgb.data; //can move to use the bare pointer eventually
- ownsRGBdata=false; //will not be necessary
- w=_w;
- h=_h;
- return true;
- /*
- if (w!=_w||h!=_h||!ownsRGBdata||!ownsAdata||!ownsZdata){
- free();
- w=_w;
- h=_h;
- RGBdata=new uint8_t[w*h*3];
- Adata=new uint8_t[w*h];
- Zdata=new uint16_t[w*h];
- ownsRGBdata=ownsAdata=ownsZdata=true;
- return true;
- }
- else return false;
- */
- }
- bool setup_fromRGB(int _w,int _h,uint8_t *pRGBdata,int linepadding=0){
- //here the data belongs to libavcodec or other
- //could move to using cv::Mat there also and just passing cv:Mat over
-
- //linepadding causes crash, but it doesn't seem to be necessary
- // Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
- rgb=cv::Mat(_h,_w,CV_8UC3,pRGBdata,(_w*3)+linepadding);
- //std::cerr<<"created cv::Mat with step= "<<rgb.step<<",should be "<<((_w*3)+linepadding)<<std::endl;
-
- RGBdata=rgb.data; //can move to use the bare pointer eventually
- ownsRGBdata=false; //will not be necessary
- w=_w;
- h=_h;
- return true;
- /*
- if (w!=_w||h!=_h||ownsRGBdata||!ownsAdata||!ownsZdata){
- free();
- w=_w;
- h=_h;
- RGBdata=pRGBdata;
- Adata=new uint8_t[w*h];
- Zdata=new uint16_t[w*h];
- ownsRGBdata=false;
- ownsAdata=ownsZdata=true;
- return true;
- }
- return false;
- */
- }
- bool setup_fromMat(cv::Mat& othermat){
- //here the mat belongs to another Image object
- rgb=cv::Mat(othermat);
- RGBdata=rgb.data; //can move to use the bare pointer eventually
- ownsRGBdata=false; //will not be necessary
- w=rgb.rows;
- h=rgb.cols;
- return true;
- }
- Image* clone(){
- Image *t=new Image();
- t->rgb=rgb.clone();
- t->w=w;
- t->h=h;
- t->RGBdata=t->rgb.data; //can move to use the bare pointer eventually
- t->ownsRGBdata=false; //will not be necessary
- /*
- for (int i=0;i<w*h*3;i++) {
- t->RGBdata[i]=RGBdata[i];
- }
- */
- return t;
- }
- //believe these still work, don't know if these optimisations are better than opencvs..
- Image & operator+=(const Image &other);
- Image & operator*=(const Image &other);
- Image & operator^=(const Image &other);
- Image & alpha_blend(const Image &other);
- Image & alpha_blend_cv(const Image &other);
- Image & alpha_merge(const Image &other);
- Image & add_wrap(const Image &other);
- Image & divide_wrap(const Image &other);
- Image & operator*=(const float &amount);
- Image * operator*(const float &amount);
- Image * operator+(const float &amount);
- Image * operator-(const float &amount);
- Image * operator/(const float &amount);
- uint8_t *RGBdata;
- uint8_t *Adata;
- uint16_t *Zdata;
- int h,w;
- bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr?
-
- cv::Mat rgb;
- cv::Mat alpha;
- };
-}
-
-#endif \ No newline at end of file
diff --git a/rotord/graph.cpp b/rotord/graph.cpp
deleted file mode 100644
index 59f7361..0000000
--- a/rotord/graph.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#include "rotor.h"
-
-using namespace Rotor;
-const string Graph::toString(){
- string xmlgraph;
- if (loaded) {
- xml.copyXmlToString(xmlgraph);
- return xmlgraph;
- }
- else return "";
-}
-vector<Node*> Graph::find_nodes(const string &type){
- vector<Node*> found;
- for (std::unordered_map<string,Node*>::iterator it=nodes.begin();it!=nodes.end();++it) {
- if (it->second->type==type) found.push_back(it->second);
- }
- return found;
-};
-Node* Graph::find_node(const string &type){
- for (std::unordered_map<string,Node*>::iterator it=nodes.begin();it!=nodes.end();++it) {
- if (it->second->type==type) return it->second;
- }
- return nullptr; //can be tested against
-};
-bool Graph::signal_render(string &signal_xml,const float framerate) {
- if (find_node("signal_output")) {
- Signal_output *signal_output=dynamic_cast<Signal_output*>(find_node("signal_output"));
- return signal_output->render(duration,framerate,signal_xml);
- }
- cerr<<"Rotor: signal output node not found"<<endl;
-
- return false;
-}
-bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress) {
- vector<Node*> loaders=find_nodes("video_loader");
- for (auto i:loaders){
- if (!dynamic_cast<Video_loader*>(i)->isLoaded) {
- cerr<<"Rotor: all loaders must be populated before rendering"<<endl;
- return false;
- }
- }
- if (find_node("video_output")) {
- Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output"));
- return video_output->render(duration,framerate,output_filename,audio_filename,progress,outW,outH);
- }
-
- cerr<<"Rotor: video output node not found"<<endl;
- return false;
-}
-bool Graph::set_resolution(int w,int h){
- if (w>64&&h>48){
- outW=w;
- outH=h;
- return true;
- }
- else return false;
-}
-bool Graph::load(string data){
- if (xml.loadFromBuffer(data)){
- return parseXml();
- }
- return false;
-}
-bool Graph::loadFile(string &filename){
- loaded=false;
- printf("loading graph: %s\n",filename.c_str());
- if(xml.loadFile(filename) ){
- return parseXml();
- }
- else return false;
-}
-bool Graph::parseXml(){
- init(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0));
- if(xml.pushTag("patchbay")) {
- int n1=xml.getNumTags("node");
- for (int i1=0;i1<n1;i1++){
- map<string,string> settings;
- vector<string> attrs;
- xml.getAttributeNames("node",attrs,i1);
- for (auto& attr: attrs) {
- settings[attr]=xml.getAttribute("node",attr,"",i1);
- //cerr << "Got attribute: " << attr << ":" << xml.getAttribute("node",attr,"",i1) << endl;
- }
- settings["description"]=xml.getValue("node","",i1);
- Node* node=factory.create(settings);
- if (node) {
- string nodeID=xml.getAttribute("node","ID","",i1);
- cerr << "Rotor: created node '"<<nodeID<<"': '"<< xml.getAttribute("node","type","",i1) << "'" << endl;
- nodes[nodeID]=node;
- if(xml.pushTag("node",i1)) {
- int n2=xml.getNumTags("signal_input");
- for (int i2=0;i2<n2;i2++){
- nodes[nodeID]->create_signal_input(xml.getValue("signal_input","",i2));
- string fromID=xml.getAttribute("signal_input","from","",i2);
- if (nodes.find(fromID)!=nodes.end()) {
- if (!nodes[nodeID]->inputs[i2]->connect((Signal_node*)nodes[fromID])){
- cerr << "Rotor: graph loader cannot connect input " << i2 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- return false;
- }
- else cerr << "Rotor: linked input " << i2 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- }
- else cerr << "Rotor: linking input " << i2 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
- }
- int n3=xml.getNumTags("image_input");
- for (int i3=0;i3<n3;i3++){
- ((Image_node*)nodes[nodeID])->create_image_input(xml.getValue("image_input","",i3));
- string fromID=xml.getAttribute("image_input","from","",i3);
- if (nodes.find(fromID)!=nodes.end()) {
- if (!(((Image_node*)nodes[nodeID])->image_inputs[i3]->connect((Image_node*)nodes[fromID]))){
- cerr << "Rotor: graph loader cannot connect image input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- return false;
- }
- else cerr << "Rotor: linked image input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- }
- else cerr << "Rotor: linking image input " << i3 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
- }
- int n4=xml.getNumTags("parameter_input");
- for (int i4=0;i4<n4;i4++){
- nodes[nodeID]->create_parameter_input(xml.getAttribute("parameter_input","parameter","",i4),xml.getValue("parameter_input","",i4));
- string fromID=xml.getAttribute("parameter_input","from","",i4);
- if (nodes.find(fromID)!=nodes.end()) {
- if (!nodes[nodeID]->parameter_inputs[i4]->connect(nodes[fromID])){
- cerr << "Rotor: graph loader cannot connect parameter input " << i4 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- return false;
- }
- else cerr << "Rotor: linked parameter input " << i4 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl;
- }
- else cerr << "Rotor: linking parameter input " << i4 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl;
- }
- nodes[nodeID]->link_params();
- //extra key/value pairs that can be specific to sub-settings
- int n5=xml.getNumTags("parameter");
- for (int i5=0;i5<n5;i5++){
- nodes[nodeID]->set_parameter(xml.getAttribute("parameter","name","",i5),xml.getAttribute("parameter","value","",i5));
- }
- if (n5>0) cerr << "Rotor: found " << n5 << " extra parameters for node '" << nodeID << "'" << endl;
-
- xml.popTag();
- }
- }
- else {
- cerr << "Rotor: graph loader cannot find node '" << xml.getAttribute("node","type","",i1) << "'" << endl;
- return false;
- }
- }
- xml.popTag();
- }
- loaded=true;
- return true;
-} \ No newline at end of file
diff --git a/rotord/image.h b/rotord/image.h
deleted file mode 100644
index 5e39b18..0000000
--- a/rotord/image.h
+++ /dev/null
@@ -1,211 +0,0 @@
-namespace Rotor {
- class pixeltables{
- //handy pixel arithmetic lookup tables as nested arrays
- //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation
- // pixels.mono_weights[0][0x100]; will give the red component to convert to mono
- public:
- pixeltables(){
- add=new uint8_t*[256];
- multiply=new uint8_t*[256];
- for (int i=0;i<256;i++){
- add[i]=new uint8_t[256];
- multiply[i]=new uint8_t[256];
- for (int j=0;j<256;j++){
- add[i][j]=(uint8_t)min(i+j,0xFF);
- multiply[i][j]=(uint8_t)((((float)i)/255.0f)*(((float)j)/255.0f)*255.0f);
- }
- }
- mono_weights=new uint8_t*[3];
- float weights[3]={0.2989, 0.5870, 0.1140};
- for (int i=0;i<3;i++) {
- mono_weights[i]=new uint8_t[256];
- for (int j=0;j<256;j++){
- mono_weights[i][j]=(uint8_t)(((float)j)*weights[i]);
- }
- }
- }
- virtual ~pixeltables(){
- for (int i=0;i<256;i++){
- delete[] add[i];
- delete[] multiply[i];
- }
- delete[] add;
- delete[] multiply;
- for (int i=0;i<3;i++) {
- delete[] mono_weights[i];
- }
- delete[] mono_weights;
- }
- uint8_t **add;
- uint8_t **multiply;
- uint8_t **mono_weights;
- };
- static pixeltables pixels;
- class Image{
- public:
- Image(){
- zero();
- };
- Image(int _w,int _h){
- zero();
- setup(_w,_h);
- };
- ~Image() {
- free();
- };
- void free(){
- if (RGBdata&&ownsRGBdata) delete[] RGBdata;
- if (Adata&&ownsAdata) delete[] Adata;
- if (Zdata&&ownsZdata) delete[] Zdata;
- zero();
- }
- void zero(){
- RGBdata=nullptr;
- Adata=nullptr;
- Zdata=nullptr;
- w=0;
- h=0;
- ownsRGBdata=ownsAdata=ownsZdata=false;
- }
- bool setup(int _w,int _h){ //set up with internal data
- if (w!=_w||h!=_h||!ownsRGBdata||!ownsAdata||!ownsZdata){
- free();
- w=_w;
- h=_h;
- RGBdata=new uint8_t[w*h*3];
- Adata=new uint8_t[w*h];
- Zdata=new uint16_t[w*h];
- ownsRGBdata=ownsAdata=ownsZdata=true;
- return true;
- }
- else return false;
- }
- bool setup_fromRGB(int _w,int _h,uint8_t *pRGBdata){ //possibility of just resetting pointer?
- if (w!=_w||h!=_h||ownsRGBdata||!ownsAdata||!ownsZdata){
- free();
- w=_w;
- h=_h;
- RGBdata=pRGBdata;
- Adata=new uint8_t[w*h];
- Zdata=new uint16_t[w*h];
- ownsRGBdata=false;
- ownsAdata=ownsZdata=true;
- return true;
- }
- return false;
- }
- Image* clone(){
- Image *t=new Image(w,h);
- for (int i=0;i<w*h*3;i++) {
- t->RGBdata[i]=RGBdata[i];
- }
- return t;
- }
- Image & operator+=(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- for (int i=0;i<w*h*3;i++){
- //calculate with tables
- RGBdata[i]=pixels.add[RGBdata[i]][other.RGBdata[i]];
- }
- }
- return *this;
- }
- Image & operator*=(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- for (int i=0;i<w*h*3;i++){
- //calculate with tables
- uint8_t p1=RGBdata[i];
- uint8_t p2=other.RGBdata[i];
- RGBdata[i]=pixels.multiply[RGBdata[i]][other.RGBdata[i]];
- }
- }
- return *this;
- }
- Image & add_wrap(const Image &other) {
- if (other.w!=w||other.h!=h) {
- cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
- }
- else {
- for (int i=0;i<w*h*3;i++){
- //creates rainbow overload
- RGBdata[i]=(unsigned char)(((int)other.RGBdata[i]+(int)RGBdata[i]));
- }
- }
- return *this;
- }
- //scalar operations allocate a new image.
- //maybe this could not be the case if the data is owned by this image?
- //need to look into auto_ptr
- Image & operator*=(const float &amount) {
- uint8_t *LUT=new uint8_t[256];
- for (int i=0;i<256;i++) {
- LUT[i]=(uint8_t)min(0xFF,max(0,(int)(i*amount)));
- }
- for (int i=0;i<w*h*3;i++){
- //calculate with table
- RGBdata[i]=LUT[RGBdata[i]];
- }
- delete[] LUT;
- return *this;
- }
- Image * operator*(const float &amount) {
- Image *other=new Image(w,h);
- uint8_t *LUT=new uint8_t[256];
- for (int i=0;i<256;i++) {
- LUT[i]=(uint8_t)min(0xFF,max(0,(int)(i*amount)));
- }
- for (int i=0;i<w*h*3;i++){
- other->RGBdata[i]=LUT[RGBdata[i]];
- }
- delete[] LUT;
- return other;
- }
- Image * operator+(const float &amount) {
- Image *other=new Image(w,h);
- uint8_t *LUT=new uint8_t[256];
- for (int i=0;i<256;i++) {
- LUT[i]=(uint8_t)min(0xFF,max(0,(int)(i+(amount*255.0f))));
- }
- for (int i=0;i<w*h*3;i++){
- other->RGBdata[i]=LUT[RGBdata[i]];
- }
- delete[] LUT;
- return other;
- }
- Image * operator-(const float &amount) {
- Image *other=new Image(w,h);
- uint8_t *LUT=new uint8_t[256];
- for (int i=0;i<256;i++) {
- LUT[i]=(uint8_t)min(0xFF,max(0,(int)(i-(amount*255.0f))));
- }
- for (int i=0;i<w*h*3;i++){
- other->RGBdata[i]=LUT[RGBdata[i]];
- }
- delete[] LUT;
- return other;
- }
- Image * operator/(const float &amount) {
- Image *other=new Image(w,h);
- uint8_t *LUT=new uint8_t[256];
- for (int i=0;i<256;i++) {
- LUT[i]=(uint8_t)min(0xFF,max(0,(int)(i/amount)));
- }
- for (int i=0;i<w*h*3;i++){
- other->RGBdata[i]=LUT[RGBdata[i]];
- }
- delete[] LUT;
- return other;
- }
- uint8_t *RGBdata;
- uint8_t *Adata;
- uint16_t *Zdata;
- int h,w;
- bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr?
- };
-} \ No newline at end of file
diff --git a/rotord/libavwrapper.cpp b/rotord/libavwrapper.cpp
deleted file mode 100755
index a19e01a..0000000
--- a/rotord/libavwrapper.cpp
+++ /dev/null
@@ -1,1657 +0,0 @@
-#include "libavwrapper.h"
-
-extern Poco::Mutex mutex; //application wide mutex
-static Poco::Mutex mutex;
-
-
-extern "C"
-{
-#include <libswscale/swscale.h>
-}
-
-
-#include <stdexcept>
-#include <iostream>
-#include <cassert>
-
-using namespace std;
-
-// Translated to C++ by Christopher Bruns May 2012
-// from ffmeg_adapt.c in whisk package by Nathan Clack, Mark Bolstadt, Michael Meeuwisse
-
-
-// Avoid link error on some macs
-#ifdef __APPLE__
-extern "C" {
-#include <stdlib.h>
-#include <errno.h>
-
-}
-#endif
-
-// Custom read function so FFMPEG does not need to read from a local file by name.
-// But rather from a stream derived from a URL or whatever.
-extern "C" {
-
-int readFunction(void* opaque, uint8_t* buf, int buf_size)
-{
- //QIODevice* stream = (QIODevice*)opaque;
- ifstream* stream = (ifstream*)opaque;
- //int numBytes =
- stream->read((char*)buf, (streamsize)buf_size);
- return stream->gcount(); //?? is this right
- //numBytes; //TODO work out
-}
-
-// http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/
-int64_t seekFunction(void* opaque, int64_t offset, int whence)
-{
- //QIODevice* stream = (QIODevice*)opaque;
- ifstream* stream = (ifstream*)opaque;
- if (stream == NULL)
- return -1;
- else if (whence == AVSEEK_SIZE)
- return -1; // "size of my handle in bytes"
- //else if (stream->isSequential())
- // return -1; // cannot seek a sequential stream //presume this would be certain kind of network stream
- else if (whence == SEEK_CUR) { // relative to start of file
- if (! stream->seekg(offset,ios_base::cur)) //stream->pos() + offset) )
- return -1;
- }
- else if (whence == SEEK_END) { // relative to end of file
- assert(offset < 0);
- if (! stream->seekg(offset,ios_base::end)) //stream->size() + offset) )
- return -1;
- }
- else if (whence == SEEK_SET) { // relative to start of file
- if (! stream->seekg(offset) )
- return -1;
- }
- else {
- assert(false);
- }
- return stream->tellg();
-}
-
-}
-
-
-/////////////////////////////
-// AVPacketWrapper methods //
-/////////////////////////////
-
-
-class AVPacketWrapper
-{
-public:
- AVPacketWrapper();
- virtual ~AVPacketWrapper();
- void free();
-
- AVPacket packet;
-};
-
-
-AVPacketWrapper::AVPacketWrapper()
-{
- packet.destruct = NULL;
-}
-
-/* virtual */
-AVPacketWrapper::~AVPacketWrapper()
-{
- free();
-}
-
-void AVPacketWrapper::free()
-{
- av_free_packet(&packet);
-}
-
-
-//bool libav::b_is_one_time_inited = false;
-
-/////////////////////////
-// decoder methods //
-/////////////////////////
-
-libav::decoder::decoder(PixelFormat pixelFormat)
- : isOpen(false)
-{
- mutex.lock();
- initialize();
- format = pixelFormat;
- mutex.unlock();
-}
-
-
-
-void libav::decoder::cleanup(){
-
- mutex.lock();
- if (NULL != Sctx) {
- sws_freeContext(Sctx);
- Sctx = NULL;
- }
- if (NULL != pRaw) {
- av_free(pRaw);
- pRaw = NULL;
- }
- if (NULL != pFrameRGB) {
- av_free(pFrameRGB);
- pFrameRGB = NULL;
- }
- if (NULL != pCtx) {
- avcodec_close(pCtx);
- pCtx = NULL;
- }
- if (NULL != container) {
- avformat_close_input(&container);
- container = NULL;
- }
- if (NULL != buffer) {
- av_free(buffer);
- buffer = NULL;
- }
- if (NULL != blank) {
- av_free(blank);
- blank = NULL;
- }
- mutex.unlock();
- /*
- if (NULL != avioContext) {
- av_free(avioContext);
- avioContext = NULL;
- }
- */
- // Don't need to free pCodec?
-
-}
-
-/* virtual */
-libav::decoder::~decoder()
-{
- cleanup();
-}
-
-
-// file name based method for historical continuity
-bool libav::decoder::open(char* fileName, enum PixelFormat formatParam){
-
- if (!avtry( avformat_open_input(&container, fileName, NULL, NULL), string(fileName) ))
- return false;
- return openUsingInitializedContainer(formatParam);
-}
-bool libav::decoder::open(string& fileName, enum PixelFormat formatParam)
-{
- // Open file, check usability
-
- if (!avtry( avformat_open_input(&container, fileName.c_str(), NULL, NULL), fileName ))
- return false;
- return openUsingInitializedContainer(formatParam);
-}
-
-
-bool libav::decoder::openUsingInitializedContainer(enum PixelFormat formatParam)
-{
- format = formatParam;
- sc = getNumberOfChannels();
-
- if (!avtry( avformat_find_stream_info(container, NULL), "Cannot find stream information." ))
- return false;
- if (!avtry( videoStream=av_find_best_stream(container, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0), "Cannot find a video stream." ))
- return false;
- pCtx=container->streams[videoStream]->codec;
- width = pCtx->width;
- height = pCtx->height;
- if (!avtry( avcodec_open2(pCtx, pCodec, NULL), "Cannot open video decoder." ))
- return false;
-
- /* Frame rate fix for some codecs */
- if( pCtx->time_base.num > 1000 && pCtx->time_base.den == 1 )
- pCtx->time_base.den = 1000;
-
- //cerr<<"stream frame rate:"<<container->streams[videoStream]->r_frame_rate.num<<"/"<<container->streams[videoStream]->r_frame_rate.den<<endl;
-
- //cerr<<"video duration: "<<container->duration<<endl;
- //cerr<<"video time base: "<<pCtx->time_base.num<<"/"<<pCtx->time_base.den<<endl;
- //cerr<<"AV time base: "<<AV_TIME_BASE<<endl;
-
- /* Compute the total number of frames in the file */
- /* duration is in microsecs */
- //numFrames = (int)(( container->duration / (double)AV_TIME_BASE ) * pCtx->time_base.den + 0.5);
- //this approach just seems wrong!
-
-
-
- numFrames=container->streams[videoStream]->nb_frames-1;
-
- if (numFrames<1){
- //some codecs don't keep this info in the header
- float fr=((float)container->streams[videoStream]->r_frame_rate.num)/container->streams[videoStream]->r_frame_rate.den;
- numFrames = (int)(( container->duration / (double)AV_TIME_BASE ) * fr );
- //this approach still doesn't seem to give quite the right answer- comes out a little too big
- //could alternatively just redefine the length if the reader fails
- }
-
-
-
- init_buffers_and_scaler();
-
- /* Give some info on stderr about the file & stream */
- //dump_format(container, 0, fname, 0);
-
- previousFrameIndex = -1;
- return true;
-}
-bool libav::decoder::reinit_buffers_and_scaler(){
- mutex.lock();
- if (NULL != Sctx) {
- sws_freeContext(Sctx);
- Sctx = NULL;
- }
- if (NULL != pRaw) {
- av_free(pRaw);
- pRaw = NULL;
- }
- if (NULL != pFrameRGB) {
- av_free(pFrameRGB);
- pFrameRGB = NULL;
- }
- mutex.unlock();
- init_buffers_and_scaler();
-}
-
-bool libav::decoder::init_buffers_and_scaler(){
- /* Get framebuffers */
- if (! (pRaw = avcodec_alloc_frame()) )
- throw std::runtime_error("");
- if (! (pFrameRGB = avcodec_alloc_frame()) )
- throw std::runtime_error("");
-
- /* Create data buffer */
- if (format == PIX_FMT_NONE) {
- numBytes = 0;
- buffer = NULL;
- blank = NULL;
- pFrameRGB = NULL;
- Sctx = NULL;
- }
- else {
- numBytes = avpicture_get_size( format, width, height ); // RGB24 format
- if (! (buffer = (uint8_t*)av_malloc(numBytes + FF_INPUT_BUFFER_PADDING_SIZE)) ) // RGB24 format
- throw std::runtime_error("");
- if (! (blank = (uint8_t*)av_mallocz(avpicture_get_size(pCtx->pix_fmt,width,height))) ) // native codec format
- throw std::runtime_error("");
-
- /* Init buffers */
- avpicture_fill( (AVPicture * ) pFrameRGB, buffer, format,
- width, height );
-
- /* Init scale & convert */
- if (! (Sctx=sws_getContext(
- pCtx->width,
- pCtx->height,
- pCtx->pix_fmt,
- width,
- height,
- format,
- SWS_POINT, // fastest?
- NULL,NULL,NULL)) )
- throw std::runtime_error("");
- }
-}
-
-bool libav::decoder::fetchFrame(int w, int h,int targetFrameIndex)
-{
- if (w!=width||h!=height){
- width=w;
- height=h;
- cerr<<"libav::decoder reiniting to "<<width<<"x"<<height<<endl; //does not seem to be aware of wrong frame
- reinit_buffers_and_scaler();
- }
-
- //seems to crash out on the last frame, if it can be caught should maybe decrement number of frames
-
- return fetchFrame(targetFrameIndex);
-}
-
-bool libav::decoder::fetchFrame(int targetFrameIndex)
-{
- if ((targetFrameIndex < 0) || (targetFrameIndex > numFrames))
- return false;
- if (targetFrameIndex == (previousFrameIndex + 1)) {
- if (! readNextFrame(targetFrameIndex+1)) //frame indexing starts at 1
- return false;
- }
- else {
- int64_t response=seekToFrame(targetFrameIndex+1); //frame indexing starts at 1
- if (response < 0)
- return false;
- if (response!=targetFrameIndex+1) {
- cerr<<"libav::decoder asked for "<<targetFrameIndex<<", got "<<(response-1)<<endl; //does not seem to be aware of wrong frame
- }
- }
- previousFrameIndex = targetFrameIndex;
- return true;
-}
-
-// \returns current frame on success, otherwise -1
-int libav::decoder::seekToFrame(int targetFrameIndex)
-{
- int64_t duration = container->streams[videoStream]->duration;
- int64_t ts = av_rescale(duration,targetFrameIndex,numFrames);
- int64_t tol = av_rescale(duration,1,2*numFrames);
- if ( (targetFrameIndex < 0) || (targetFrameIndex >= numFrames) ) {
- return -1;
- }
- int result = avformat_seek_file( container, //format context
- videoStream,//stream id
- 0, //min timestamp 0?
- ts, //target timestamp
- ts, //max timestamp
- 0);//flags AVSEEK_FLAG_ANY //doesn't seem to work great
- if (result < 0)
- return -1;
-
- avcodec_flush_buffers(pCtx);
- if (! readNextFrame(targetFrameIndex))
- return -1;
-
- return targetFrameIndex;
-}
-
-bool libav::decoder::readNextFrame(int targetFrameIndex)
-{
- AVPacket packet = {0};
- av_init_packet(&packet);
- bool result = readNextFrameWithPacket(targetFrameIndex, packet, pRaw);
- av_free_packet(&packet);
- return result;
-}
-
-// WARNING this method can raise an exception
-bool libav::decoder::readNextFrameWithPacket(int targetFrameIndex, AVPacket& packet, AVFrame* pYuv)
-{
- int finished = 0;
- do {
- finished = 0;
- av_free_packet(&packet);
- int result;
- //if (!avtry(av_read_frame( container, &packet ), "Failed to read frame"))
- if (!avtry(av_read_packet( container, &packet ), "Failed to read packet"))
- return false; // !!NOTE: see docs on packet.convergence_duration for proper seeking
- if( packet.stream_index != videoStream ) /* Is it what we're trying to parse? */
- continue;
- if (!avtry(avcodec_decode_video2( pCtx, pYuv, &finished, &packet ), "Failed to decode video"))
- return false;
- // handle odd cases and debug
- if((pCtx->codec_id==CODEC_ID_RAWVIDEO) && !finished)
- {
- avpicture_fill( (AVPicture * ) pYuv, blank, pCtx->pix_fmt,width, height ); // set to blank frame
- finished = 1;
- }
-#if 0 // very useful for debugging, very
- cout << "Packet - pts:" << (int)packet.pts;
- cout << " dts:" << (int)packet.dts;
- cout << " - flag: " << packet.flags;
- cout << " - finished: " << finished;
- cout << " - Frame pts:" << (int)pYuv->pts;
- cout << " " << (int)pYuv->best_effort_timestamp;
- cout << endl;
- /* printf("Packet - pts:%5d dts:%5d (%5d) - flag: %1d - finished: %3d - Frame pts:%5d %5d\n",
- (int)packet.pts,(int)packet.dts,
- packet.flags,finished,
- (int)pYuv->pts,(int)pYuv->best_effort_timestamp); */
-#endif
- if(!finished) {
- if (packet.pts == AV_NOPTS_VALUE)
- packet.pts = 0;
- //throw std::runtime_error("");
- //why does it want to throw an error here, isn't the frame succesfully decoded?
- //
- //when we allow these packets through we get
- //[swscaler @ 0x9ef0c80] bad src image pointers
- //trying to ignore timestamp below
- if (packet.size == 0) // packet.size==0 usually means EOF
- break;
- }
- } while ( (!finished) || (pYuv->best_effort_timestamp < targetFrameIndex));
- // } while (!finished);
-
- av_free_packet(&packet);
-
- if (format != PIX_FMT_NONE) {
- sws_scale(Sctx, // sws context
- pYuv->data, // src slice
- pYuv->linesize, // src stride
- 0, // src slice origin y
- pCtx->height, // src slice height
- pFrameRGB->data, // dst
- pFrameRGB->linesize ); // dst stride
- }
-
- previousFrameIndex = targetFrameIndex;
- return true;
-}
-
-uint8_t libav::decoder::getPixelIntensity(int x, int y, Channel c) const
-{
- return *(pFrameRGB->data[0] + y * pFrameRGB->linesize[0] + x * sc + c);
-}
-
-int libav::decoder::getNumberOfFrames() const { return numFrames; }
-
-int libav::decoder::getWidth() const { return width; }
-
-int libav::decoder::getHeight() const { return height; }
-
-int libav::decoder::getNumberOfChannels() const
-{
- switch(format)
- {
- case PIX_FMT_BGRA:
- return 4;
- break;
- case PIX_FMT_RGB24:
- return 3;
- break;
- case PIX_FMT_GRAY8:
- return 1;
- break;
- default:
- return 0;
- break;
- }
- return 0;
-}
-
-void libav::decoder::initialize()
-{
- Sctx = NULL;
- pRaw = NULL;
- pFrameRGB = NULL;
- pCtx = NULL;
- container = NULL;
- buffer = NULL;
- blank = NULL;
- pCodec = NULL;
- format = PIX_FMT_NONE;
- //network stuff
- //reply = NULL;
- //ioBuffer = NULL;
- //avioContext = NULL;
- maybeInitFFMpegLib();
-}
-
-void libav::maybeInitFFMpegLib()
-{
- if (b_is_one_time_inited)
- return;
- av_register_all();
- avcodec_register_all();
- avformat_network_init();
- b_is_one_time_inited = true;
-}
-
-bool libav::decoder::avtry(int result, const std::string& msg) {
- if ((result < 0) && (result != AVERROR_EOF)) {
- char buf[1024];
- av_strerror(result, buf, sizeof(buf));
- std::string message = std::string("libav::Error: ") + msg + " "+ buf;
- //qDebug() << QString(message.c_str());
- cerr<<message<<endl;
- return false;
- }
- return true;
-}
-
-
-
-
-///////////////////////////
-// encoder methods //
-///////////////////////////
-
-
-libav::encoder::encoder(const char * file_name, int width, int height, float _framerate,enum AVCodecID codec_id)
- : picture_yuv(NULL)
- , picture_rgb(NULL)
- , container(NULL)
-{
- //multiply float seconds by this to get pts
- timebase=((float)AV_TIME_BASE_Q.den)/(AV_TIME_BASE_Q.num*_framerate*3.125f); //no idea where the 3.125 comes from
-
- if (0 != (width % 2))
- cerr << "WARNING: Video width is not a multiple of 2" << endl;
- if (0 != (height % 2))
- cerr << "WARNING: Video height is not a multiple of 2" << endl;
-
- maybeInitFFMpegLib();
-
- container = avformat_alloc_context();
- if (NULL == container)
- throw std::runtime_error("Unable to allocate format context");
-
- AVOutputFormat * fmt = av_guess_format(NULL, file_name, NULL);
- if (!fmt)
- fmt = av_guess_format("mpeg", NULL, NULL);
- if (!fmt)
- throw std::runtime_error("Unable to deduce video format");
- container->oformat = fmt;
-
- fmt->video_codec = codec_id;
- // fmt->video_codec = CODEC_ID_H264; // fails to write
-
- video_st = avformat_new_stream(container, NULL);
-
- pCtx = video_st->codec;
- pCtx->codec_id = fmt->video_codec;
- pCtx->codec_type = AVMEDIA_TYPE_VIDEO;
- // resolution must be a multiple of two
- pCtx->width = width;
- pCtx->height = height;
-
- // bit_rate determines image quality
- pCtx->bit_rate = width * height * 4; // ?
- // pCtx->qmax = 50; // no effect?
-
- // "high quality" parameters from http://www.cs.ait.ac.th/~on/mplayer/pl/menc-feat-enc-libavcodec.html
- // vcodec=mpeg4:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:predia=2:dia=2:vmax_b_frames=2:vb_strategy=1:precmp=2:cmp=2:subcmp=2:preme=2:vme=5:naq:qns=2
- if (false) // does not help
- // if (pCtx->codec_id == CODEC_ID_MPEG4)
- {
- pCtx->mb_decision = 2;
- pCtx->last_predictor_count = 3;
- pCtx->pre_dia_size = 2;
- pCtx->dia_size = 2;
- pCtx->max_b_frames = 2;
- pCtx->b_frame_strategy = 2;
- pCtx->trellis = 2;
- pCtx->compression_level = 2;
- pCtx->global_quality = 300;
- pCtx->pre_me = 2;
- pCtx->mv0_threshold = 1;
- // pCtx->quantizer_noise_shaping = 2; // deprecated
- // TODO
- }
-
- pCtx->time_base = (AVRational){1, 25}; /////TODO FIX TO SUPPORT OTHER RATES
- // pCtx->time_base = (AVRational){1, 10};
- pCtx->gop_size = 12; // emit one intra frame every twelve frames
- // pCtx->max_b_frames = 0;
- pCtx->pix_fmt = PIX_FMT_YUV420P;
- if (fmt->flags & AVFMT_GLOBALHEADER)
- pCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- if (pCtx->codec_id == CODEC_ID_H264)
- {
- // http://stackoverflow.com/questions/3553003/encoding-h-264-with-libavcodec-x264
- pCtx->coder_type = 1; // coder = 1
- pCtx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
- pCtx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
- // pCtx->partitions|=X264_PART_I8X8+X264_PART_I4X4+X264_PART_P8X8+X264_PART_B8X8; // partitions=+parti8x8+parti4x4+partp8x8+partb8x8
- pCtx->me_method=ME_HEX; // me_method=hex
- pCtx->me_subpel_quality = 7; // subq=7
- pCtx->me_range = 16; // me_range=16
- pCtx->gop_size = 250; // g=250
- pCtx->keyint_min = 25; // keyint_min=25
- pCtx->scenechange_threshold = 40; // sc_threshold=40
- pCtx->i_quant_factor = 0.71; // i_qfactor=0.71
- pCtx->b_frame_strategy = 1; // b_strategy=1
- pCtx->qcompress = 0.6; // qcomp=0.6
- pCtx->qmin = 10; // qmin=10
- pCtx->qmax = 51; // qmax=51
- pCtx->max_qdiff = 4; // qdiff=4
- pCtx->max_b_frames = 3; // bf=3
- pCtx->refs = 3; // refs=3
- // pCtx->directpred = 1; // directpred=1
- pCtx->trellis = 1; // trellis=1
- // pCtx->flags2|=CODEC_FLAG2_BPYRAMID+CODEC_FLAG2_MIXED_REFS+CODEC_FLAG2_WPRED+CODEC_FLAG2_8X8DCT+CODEC_FLAG2_FASTPSKIP; // flags2=+bpyramid+mixed_refs+wpred+dct8x8+fastpskip
- // pCtx->weighted_p_pred = 2; // wpredp=2
- // libx264-main.ffpreset preset
- // pCtx->flags2|=CODEC_FLAG2_8X8DCT;
- // pCtx->flags2^=CODEC_FLAG2_8X8DCT; // flags2=-dct8x8
- }
-
- AVCodec * codec = avcodec_find_encoder(pCtx->codec_id);
- if (NULL == codec)
- throw std::runtime_error("Unable to find Mpeg4 codec");
- if (codec->pix_fmts)
- pCtx->pix_fmt = codec->pix_fmts[0];
- {
- //QMutexLocker lock(&decoder::mutex);
- mutex.lock();
- if (avcodec_open2(pCtx, codec, NULL) < 0)
- throw std::runtime_error("Error opening codec");
- mutex.unlock();
- }
-
- /* Get framebuffers */
- if (! (picture_yuv = avcodec_alloc_frame()) ) // final frame format
- throw std::runtime_error("");
- if (! (picture_rgb = avcodec_alloc_frame()) ) // rgb version I can understand easily
- throw std::runtime_error("");
- /* the image can be allocated by any means and av_image_alloc() is
- * just the most convenient way if av_malloc() is to be used */
- if ( av_image_alloc(picture_yuv->data, picture_yuv->linesize,
- pCtx->width, pCtx->height, pCtx->pix_fmt, 1) < 0 )
- throw std::runtime_error("Error allocating YUV frame buffer");
- if ( av_image_alloc(picture_rgb->data, picture_rgb->linesize,
- pCtx->width, pCtx->height, PIX_FMT_RGB24, 1) < 0 )
- throw std::runtime_error("Error allocating RGB frame buffer");
-
- /* Init scale & convert */
- if (! (Sctx=sws_getContext(
- width,
- height,
- PIX_FMT_RGB24,
- pCtx->width,
- pCtx->height,
- pCtx->pix_fmt,
- SWS_BICUBIC,NULL,NULL,NULL)) )
- throw std::runtime_error("");
-
-//
-//
-// added audio init
- fmt->audio_codec = AV_CODEC_ID_MP3;
- // fmt->video_codec = CODEC_ID_H264; // fails to write
-
- audio_st = avformat_new_stream(container, NULL);
-
- aCtx = audio_st->codec;
- aCtx->codec_id = fmt->audio_codec;
- aCtx->codec_type = AVMEDIA_TYPE_AUDIO;
-
- aCtx->sample_fmt=AV_SAMPLE_FMT_S16P; //s16p is invalid or not supported by aac: S16 not by mp3
- aCtx->channels=2;
- aCtx->sample_rate=44100;
- aCtx->channel_layout=AV_CH_LAYOUT_STEREO;
- aCtx->bit_rate = 64000;
-
-
-
- AVCodec * acodec = avcodec_find_encoder(aCtx->codec_id);
- mutex.lock();
- int ret = avcodec_open2(aCtx, acodec, NULL);
- mutex.unlock();
- if (ret < 0) {
- throw std::runtime_error("Could not open audio codec:");
-
- }
-
- if (aCtx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
- audio_input_frame_size = 10000;
- else
- audio_input_frame_size = aCtx->frame_size;
-
-
- if (container->oformat->flags & AVFMT_GLOBALHEADER)
- aCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-
- audiostep=((float)audio_input_frame_size)/(aCtx->sample_rate);
-
-
-
-
-// are we supposed to use the same codeccontext?
-//
-
- /* open the output file */
- if (!(fmt->flags & AVFMT_NOFILE))
- {
- //QMutexLocker lock(&decoder::mutex);
- mutex.lock();
- if (avio_open(&container->pb, file_name, AVIO_FLAG_WRITE) < 0)
- throw std::runtime_error("Error opening output video file");
- mutex.unlock();
- }
- avformat_write_header(container, NULL);
-}
-
-void libav::encoder::setPixelIntensity(int x, int y, int c, uint8_t value)
-{
- uint8_t * ptr = picture_rgb->data[0] + y * picture_rgb->linesize[0] + x * 3 + c;
- *ptr = value;
-}
-
-void libav::encoder::write_frame(float seconds,uint8_t *rgbdata)
-{
- picture_rgb->data[0]=rgbdata;
-
- // convert from RGB24 to YUV
- sws_scale(Sctx, // sws context
- picture_rgb->data, // src slice
- picture_rgb->linesize, // src stride
- 0, // src slice origin y
- pCtx->height, // src slice height
- picture_yuv->data, // dst
- picture_yuv->linesize ); // dst stride
-
- /* encode the image */
- // use non-deprecated avcodec_encode_video2(...)
- AVPacket packet={0};
- av_init_packet(&packet);
- packet.data = NULL;
- packet.size = 0;
-
- //no time stamps as is
- //http://dranger.com/ffmpeg/tutorial07.html
-
- picture_yuv->pts=(uint64_t)(seconds*timebase); //
-
- int got_packet;
- int ret = avcodec_encode_video2(pCtx,
- &packet,
- picture_yuv,
- &got_packet);
-
- //packet.pts=(uint64_t)(seconds*timebase); //added 0606
- packet.stream_index = video_st->index;; //added 0606
-
- if (ret < 0)
- throw std::runtime_error("Video encoding failed");
- if (got_packet)
- {
- // std::cout << "encoding frame" << std::endl;
- int result = av_write_frame(container, &packet);
- av_destruct_packet(&packet);
- }
-}
-void libav::encoder::write_frame(float seconds,uint16_t *audiodata){
- audio_frame = avcodec_alloc_frame();
- AVPacket pkt = { 0 }; // data and size must be 0;
- int got_packet, ret;
- av_init_packet(&pkt);
- audio_frame->nb_samples = audio_input_frame_size;
- uint8_t *sampleptr;
- int bufsize=audio_input_frame_size * av_get_bytes_per_sample(aCtx->sample_fmt) *aCtx->channels;
- if (audiodata) {
- sampleptr=(uint8_t*)audiodata;
- }
- else {
- sampleptr=new uint8_t[bufsize];
- memset(sampleptr,0,bufsize);
- }
-
- audio_frame->pts=(uint64_t)(seconds*timebase); //
-
- avcodec_fill_audio_frame(audio_frame, aCtx->channels, aCtx->sample_fmt,
- sampleptr,
- audio_input_frame_size *
- av_get_bytes_per_sample(aCtx->sample_fmt) *
- aCtx->channels, 0); //;
-
-
-
- ret = avcodec_encode_audio2(aCtx, &pkt, audio_frame, &got_packet);
-
- pkt.stream_index = audio_st->index; //hardcoded stream index added 0606
- //pkt.pts=(uint64_t)(seconds*timebase); //added 060613
-
- if (!audiodata) {
- delete[] sampleptr;
- }
- if (ret < 0) {
- throw std::runtime_error("Audio encoding failed");
- }
-
- if (!got_packet)
- return;
-
- // ? pkt.stream_index = st->index;
-
- ret = av_interleaved_write_frame(container, &pkt);
- avcodec_free_frame(&audio_frame);
-}
-
-/* virtual */
-libav::encoder::~encoder()
-{
-
- //avcodec_flush_buffers(pCtx); ???? from exporter version
-
-
- int result = av_write_frame(container, NULL); // flush
- result = av_write_trailer(container);
- //QMutexLocker lock(&decoder::mutex);
- mutex.lock();
- avio_close(container->pb);
- mutex.unlock();
-
- //added 0706
- video_st=nullptr;
- audio_st=nullptr;
- //
-
- for (int i = 0; i < container->nb_streams; ++i) {
- av_freep(container->streams[i]); //CRASHING HERE ON STREAM 1, OUTPUT IS VALID BUT AUDIO INAUDIBLE - 060613
- }
- av_free(container);
- container = nullptr;
- //QMutexLocker lock(&decoder::mutex);
- mutex.lock();
- avcodec_close(aCtx);
- avcodec_close(pCtx);
- mutex.unlock();
- av_free(pCtx);
- pCtx = NULL;
- av_free(aCtx);
- aCtx=nullptr;
- av_free(picture_yuv->data[0]);
- av_free(picture_yuv);
- picture_yuv = NULL;
- av_free(picture_rgb->data[0]);
- av_free(picture_rgb);
- picture_rgb = NULL;
-
-}
-
-bool libav::exporter::setup(int w,int h, int bitRate, int frameRate, std::string container){
-
- maybeInitFFMpegLib();
-
- this->w=w;
- this->h=h;
- this->bitRate=bitRate;
- this->frameRate=frameRate;
- this->container=container;
-
- return true;
-}
-
-bool libav::exporter::record(std::string filename){
-
- // allocate the output media context //
- avformat_alloc_output_context2(&oc, NULL, NULL, filename.c_str());
- if (!oc) {
- printf("Could not deduce output format from file extension: using MPEG.\n");
- avformat_alloc_output_context2(&oc, NULL, "mpeg", filename.c_str());
- }
- if (!oc) {
- return false;
- }
- fmt = oc->oformat;
-
- // Add the audio and video streams using the default format codecs
- // * and initialize the codecs. //
- video_st = NULL;
- audio_st = NULL;
-
- fmt->video_codec=AV_CODEC_ID_MPEG4;
-
- if (fmt->video_codec != AV_CODEC_ID_NONE) {
- video_st = add_stream(oc, &video_codec, fmt->video_codec);
- }
- if (fmt->audio_codec != AV_CODEC_ID_NONE) {
- audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);
- }
-
- //set initial video params
- video_st->codec->width=w;
- video_st->codec->height=h;
- video_st->codec->time_base.num = 1;//codecCtx->ticks_per_frame;
- video_st->codec->time_base.den = frameRate;
- video_st->time_base = video_st->codec->time_base;
- //audioStream->time_base = codecCtx->time_base; //???has the capability of crashing
-
- video_st->codec->gop_size = 10; /* emit one intra frame every ten frames */
- video_st->codec->pix_fmt = PIX_FMT_YUV420P;
-
- // Now that all the parameters are set, we can open the audio and
- // * video codecs and allocate the necessary encode buffers. //
- if (video_st)
- open_video(oc, video_codec, video_st);
- if (audio_st) {
- audioframesize=open_audio(oc, audio_codec, audio_st);
- audiostep=((float)audioframesize)/(audio_st->codec->sample_rate);
- std::cerr << "opened audio codec with "<<audioframesize<<" frame size and "<<audiostep<<" seconds per frame"<<std::endl;
- }
-
-
- av_dump_format(oc, 0, filename.c_str(), 1);
-
- // open the output file, if needed //
- if (!(fmt->flags & AVFMT_NOFILE)) {
- mutex.lock();
- int ret = avio_open(&oc->pb, filename.c_str(), AVIO_FLAG_WRITE);
- mutex.unlock();
- if (ret < 0) {
- std::cerr <<"Could not open " << filename.c_str() << std::endl;
- return false;
- }
- }
-
- // Write the stream header, if any. //
- int ret = avformat_write_header(oc, NULL);
- if (ret < 0) {
- //std::cerr <<"Error occurred when opening output file:" << av_err2str(ret) << std::endl;
- return false;
- }
-
- if (frame)
- frame->pts = 0;
-
- outputframe=0;
-
- return true;
-}
-bool libav::exporter::encodeFrame(unsigned char *pixels,uint16_t *samples){
- // Compute current audio and video time. //
- if (audio_st)
- audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
- else
- audio_pts = 0.0;
-
- if (video_st)
- video_pts = (double)video_st->pts.val * video_st->time_base.num /
- video_st->time_base.den;
- else
- video_pts = 0.0;
-
- // write interleaved audio and video frames //
- if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
- write_audio_frame(oc, audio_st, samples);
- } else {
- write_video_frame(oc, video_st, pixels);
-
- frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
- }
-
- //std::cerr << "encoded frame " << outputframe << std::endl;
- outputframe++;
-
- return true;
-}
-bool libav::exporter::encodeFrame(unsigned char *pixels,AVPacket *audio){
- // Compute current audio and video time. //
- if (audio_st)
- audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
- else
- audio_pts = 0.0;
-
- if (video_st)
- video_pts = (double)video_st->pts.val * video_st->time_base.num /
- video_st->time_base.den;
- else
- video_pts = 0.0;
-
- // write interleaved audio and video frames //
- if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
- write_audio_frame(oc, audio_st, audio);
- } else {
- write_video_frame(oc, video_st, pixels);
-
- frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
- }
-
- //std::cerr << "encoded frame " << outputframe << std::endl;
- outputframe++;
-
- return true;
-}
-bool libav::exporter::encodeFrame(unsigned char *pixels){
- video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
- write_video_frame(oc, video_st, pixels);
- frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
- outputframe++;
- return true;
-}
-bool libav::exporter::encodeFrame(uint16_t *samples){
- audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
- write_audio_frame(oc, audio_st, samples);
- return true;
-}
-void libav::exporter::finishRecord(){
-
- av_write_trailer(oc);
- // Close each codec. //
- if (video_st)
- close_video(oc, video_st);
- if (audio_st)
- close_audio(oc, audio_st);
-
- if (!(fmt->flags & AVFMT_NOFILE)) {
- // Close the output file. //
- mutex.lock();
- avio_close(oc->pb);
- mutex.unlock();
- }
-
- // free the stream //
- avformat_free_context(oc);
-}
-
-AVStream* libav::exporter::add_stream(AVFormatContext *oc, AVCodec **codec,enum AVCodecID codec_id)
- {
- AVCodecContext *c;
- AVStream *st;
-
- // find the encoder //
- *codec = avcodec_find_encoder(codec_id);
- if (!(*codec)) {
- //fprintf(stderr, "Could not find encoder for '%s'\n",
- // avcodec_get_name(codec_id));
- exit(1);
- }
-
- st = avformat_new_stream(oc, *codec);
- if (!st) {
- //fprintf(stderr, "Could not allocate stream\n");
- exit(1);
- }
- st->id = oc->nb_streams-1;
- c = st->codec;
-
- switch ((*codec)->type) {
- case AVMEDIA_TYPE_AUDIO:
- st->id = 1;
- c->sample_fmt = AV_SAMPLE_FMT_S16;
- c->bit_rate = 64000;
- c->sample_rate = 44100;
- c->channels = 2;
- c->channel_layout=AV_CH_LAYOUT_STEREO;
- break;
-
- case AVMEDIA_TYPE_VIDEO:
- c->codec_id = codec_id;
-
- c->bit_rate = 400000;
- // Resolution must be a multiple of two. //
- c->width = 352;
- c->height = 288;
- // timebase: This is the fundamental unit of time (in seconds) in terms
- // * of which frame timestamps are represented. For fixed-fps content,
- // * timebase should be 1/framerate and timestamp increments should be
- // * identical to 1. //
- c->time_base.den = frameRate;
- c->time_base.num = 1;
- c->gop_size = 12; // emit one intra frame every twelve frames at most //
- c->pix_fmt = AV_PIX_FMT_YUV420P; //ADDED HARDCODED TJR 280513
- if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
- // just for testing, we also add B frames //
- c->max_b_frames = 2;
- }
- if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
- // Needed to avoid using macroblocks in which some coeffs overflow.
- // * This does not happen with normal video, it just happens here as
- // * the motion of the chroma plane does not match the luma plane. //
- c->mb_decision = 2;
- }
- break;
-
- default:
- break;
- }
-
- // Some formats want stream headers to be separate. //
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- return st;
- }
-
-void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
- {
- int ret;
- AVCodecContext *c = st->codec;
-
- // open the codec //
- mutex.lock();
- ret = avcodec_open2(c, codec, NULL);
- mutex.unlock();
- if (ret < 0) {
- //fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
- exit(1);
- }
-
- // allocate and init a re-usable frame //
- frame = avcodec_alloc_frame();
- // moved to constructor and freeing in destructor -- stills crashes the same
- if (!frame) {
- //fprintf(stderr, "Could not allocate video frame\n");
- exit(1);
- }
-
- // Allocate the encoded raw picture. //
- ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
- if (ret < 0) {
- //fprintf(stderr, "Could not allocate picture: %s\n", av_err2str(ret));
- exit(1);
- }
-
- // If the output format is not YUV420P, then a temporary YUV420P
- // * picture is needed too. It is then converted to the required
- // * output format. //
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- ret = avpicture_alloc(&src_picture, AV_PIX_FMT_RGB24, c->width, c->height);
- if (ret < 0) {
- //fprintf(stderr, "Could not allocate temporary picture: %s\n",
- // av_err2str(ret));
- exit(1);
- }
- }
-
- // copy data and linesize picture pointers to frame //
- *((AVPicture *)frame) = dst_picture;
-
- outPixels = (uint8_t*)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, st->codec->width,st->codec->height));
- }
-
- int libav::exporter::open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)
- {
- AVCodecContext *c;
- int ret;
-
- c = st->codec;
-
- // open it //
- mutex.lock();
- ret = avcodec_open2(c, codec, NULL);
- mutex.unlock();
- if (ret < 0) {
- //fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
- exit(1);
- }
-
- // init signal generator //
- t = 0;
- tincr = 2 * M_PI * 110.0 / c->sample_rate;
- // increment frequency by 110 Hz per second //
- tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
-
- if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
- audio_input_frame_size = 10000;
- else
- audio_input_frame_size = c->frame_size;
-
- /*
- samples = av_malloc(audio_input_frame_size *
- av_get_bytes_per_sample(c->sample_fmt) *
- c->channels);
- if (!samples) {
- //fprintf(stderr, "Could not allocate audio samples buffer\n");
- exit(1);
- }
- */
- return audio_input_frame_size;
- }
-
- void libav::exporter::write_audio_frame(AVFormatContext *oc, AVStream *st,uint16_t *samples)
- {
- AVCodecContext *c;
- AVPacket pkt = { 0 }; // data and size must be 0;
- AVFrame *frame = avcodec_alloc_frame();
- int got_packet, ret;
-
- av_init_packet(&pkt);
- c = st->codec;
-
- //get_audio_frame(samples, audio_input_frame_size, c->channels);
- frame->nb_samples = audio_input_frame_size;
- uint8_t *sampleptr;
- int bufsize=audio_input_frame_size * av_get_bytes_per_sample(c->sample_fmt) *c->channels;
- if (samples) {
- sampleptr=(uint8_t*)samples;
- }
- else {
- sampleptr=new uint8_t[bufsize];
- memset(sampleptr,0,bufsize);
- }
-
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
- sampleptr,
- audio_input_frame_size *
- av_get_bytes_per_sample(c->sample_fmt) *
- c->channels, 0); //;
- //frame->sample_rate=44100; //hard coded input rate- nope, this doesn't help
- //frame->format=AV_SAMPLE_FMT_S16P;
- //?? why is ffmpeg reporting fltp as the sample format??? doesn't seem to have an effect to change this though
- ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);
- if (!samples) {
- delete[] sampleptr;
- }
- if (ret < 0) {
- //fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
- exit(1);
- }
-
- if (!got_packet)
- return;
-
- pkt.stream_index = st->index;
-
- // Write the compressed frame to the media file. //
- ret = av_interleaved_write_frame(oc, &pkt);
- if (ret != 0) {
- //fprintf(stderr, "Error while writing audio frame: %s\n",
- // av_err2str(ret));
- exit(1);
- }
- avcodec_free_frame(&frame);
- }
-
- void libav::exporter::write_audio_frame(AVFormatContext *oc, AVStream *st,AVPacket *pkt)
- {
- /*
- AVCodecContext *c;
- AVPacket pkt = { 0 }; // data and size must be 0;
- AVFrame *frame = avcodec_alloc_frame();
- int got_packet, ret;
-
- av_init_packet(&pkt);
- c = st->codec;
-
- //get_audio_frame(samples, audio_input_frame_size, c->channels);
- frame->nb_samples = audio_input_frame_size;
- uint8_t *sampleptr;
- int bufsize=audio_input_frame_size * av_get_bytes_per_sample(c->sample_fmt) *c->channels;
- if (samples) {
- sampleptr=(uint8_t*)samples;
- }
- else {
- sampleptr=new uint8_t[bufsize];
- memset(sampleptr,0,bufsize);
- }
- avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
- sampleptr,
- audio_input_frame_size *
- av_get_bytes_per_sample(c->sample_fmt) *
- c->channels, 1);
-
- ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);
- if (!samples) {
- free(sampleptr);
- }
- if (ret < 0) {
- //fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
- exit(1);
- }
-
- if (!got_packet)
- return;
- */
-
- pkt->stream_index = st->index;
-
- // Write the compressed frame to the media file. //
- int ret = av_interleaved_write_frame(oc, pkt);
- if (ret != 0) {
- //fprintf(stderr, "Error while writing audio frame: %s\n",
- // av_err2str(ret));
- exit(1);
- }
- //avcodec_free_frame(&frame);
- av_free_packet(pkt);
- }
-
- void libav::exporter::close_audio(AVFormatContext *oc, AVStream *st)
- {
- mutex.lock();
- avcodec_close(st->codec);
- mutex.unlock();
-
- }
-
- void libav::exporter::write_video_frame(AVFormatContext *oc, AVStream *st, uint8_t *pixels)
- {
- int ret;
-
- AVCodecContext *c = st->codec;
-
-/*
- if (frame_count >= STREAM_NB_FRAMES) {
- // No more frames to compress. The codec has a latency of a few
- // * frames if using B-frames, so we get the last frames by
- // * passing the same picture again. //
- } else {
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- // as we only generate a YUV420P picture, we must convert it
- // * to the codec pixel format if needed //
- if (!sws_ctx) {
- sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_YUV420P,
- c->width, c->height, c->pix_fmt,
- sws_flags, NULL, NULL, NULL);
- if (!sws_ctx) {
- //fprintf(stderr,
- // "Could not initialize the conversion context\n");
- exit(1);
- }
- }
- fill_yuv_image(&src_picture, frame_count, c->width, c->height);
- sws_scale(sws_ctx,
- (const uint8_t * const *)src_picture.data, src_picture.linesize,
- 0, c->height, dst_picture.data, dst_picture.linesize);
- } else {
- fill_yuv_image(&dst_picture, frame_count, c->width, c->height);
- }
- }
-*/
- //always convert RGB to YUV
- //should be context allocated once per render instead of per frame??
- //
- //
- sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_RGB24,
- c->width, c->height, AV_PIX_FMT_YUV420P,
- sws_flags, NULL, NULL, NULL);
-
- avpicture_fill(&src_picture, pixels, PIX_FMT_RGB24, c->width,c->height);
- //avpicture_fill(&dst_picture, outPixels, PIX_FMT_YUV420P, c->width,c->height);
-
- sws_scale(sws_ctx, src_picture.data, src_picture.linesize, 0, c->height, dst_picture.data, dst_picture.linesize);
- //fill_yuv_image(&dst_picture, frame_count, c->width, c->height);
- if (oc->oformat->flags & AVFMT_RAWPICTURE) {
- // Raw video case - directly store the picture in the packet //
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.stream_index = st->index;
- pkt.data = dst_picture.data[0];
- pkt.size = sizeof(AVPicture);
-
- ret = av_interleaved_write_frame(oc, &pkt);
- } else {
- AVPacket pkt = { 0 };
- int got_packet;
- av_init_packet(&pkt);
-
- // encode the image //
-
- // 2nd time you render it crashes right after here
-
- // where the hell is frame being allocated? is the problem caused by it being freed? (see removeal of avframe_free in cleanup)
- ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
- if (ret < 0) {
- //fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
- exit(1);
- }
- // If size is zero, it means the image was buffered. //
-
- if (!ret && got_packet && pkt.size) {
- pkt.stream_index = st->index;
-
- // Write the compressed frame to the media file. //
- ret = av_interleaved_write_frame(oc, &pkt);
- } else {
- ret = 0;
- }
- }
-
- //
- // added 22 may in memory leak run
- //
- sws_freeContext(sws_ctx); //should be done once per render instead of per frame??
-
- if (ret != 0) {
- //fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
- exit(1);
- }
- frame_count++;
-
- //avcodec_free_frame(&frame);
- }
-
- void libav::exporter::close_video(AVFormatContext *oc, AVStream *st)
- {
- mutex.lock();
- //avcodec_close(st->codec); //change 0706 to trace 2nd render issue
- avcodec_close(audio_st->codec);
- avcodec_close(video_st->codec);
- //
- //
-
-
- //av_free(src_picture.data[0]); //removed to explore weird 2nd render crash.. seems to WORK -- seems that the picture data is owned elsewhere
- av_free(dst_picture.data[0]);
- av_free(frame); //removed to explore crash 2nd time render
- //gives *** Error in `./rotord': corrupted double-linked list: 0x00007fd8b005bd60 ***
- //where is frame initialised???
- //moved to destructor
-
-
- av_free(outPixels); //SIGSEV here???
- mutex.unlock();
- }
-
-bool libav::audioloader::setup(const std::string &filename){
-
- maybeInitFFMpegLib();
-
- frame = avcodec_alloc_frame();
- if (!frame)
- {
- std::cout << "Error allocating the frame" << std::endl;
- return false;
- }
-
- formatContext = NULL;
- mutex.lock();
- if (avformat_open_input(&formatContext, filename.c_str(), NULL, NULL) != 0)
- {
- av_free(frame);
- std::cout << "Error opening the file" << std::endl;
- mutex.unlock();
- return false;
- }
- mutex.unlock();
-
- if (avformat_find_stream_info(formatContext, NULL) < 0)
- {
- mutex.lock();
- av_free(frame);
- avformat_close_input(&formatContext);
- mutex.unlock();
- std::cout << "Error finding the stream info" << std::endl;
- return false;
- }
-
- //use the first audio stream found
-
- audioStream = NULL;
- for (unsigned int i = 0; i < formatContext->nb_streams; ++i)
- {
- if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- {
- audioStream = formatContext->streams[i];
- break;
- }
- }
-
- if (audioStream == NULL)
- {
- mutex.lock();
- av_free(frame);
- avformat_close_input(&formatContext);
- mutex.unlock();
- std::cout << "Could not find any audio stream in the file" << std::endl;
- return false;
- }
-
- codecContext = audioStream->codec;
-
- codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
- mutex.lock();
- if (codecContext->codec == NULL)
- {
-
- av_free(frame);
- avformat_close_input(&formatContext);
- mutex.unlock();
- std::cout << "Couldn't find a proper decoder" << std::endl;
- return false;
- }
- else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
- {
- av_free(frame);
- avformat_close_input(&formatContext);
- mutex.unlock();
- std::cout << "Couldn't open the context with the decoder" << std::endl;
- return false;
- }
- mutex.unlock();
-
- av_dump_format(formatContext, 0, 0, false); //avformat.h line 1256
- int samples = ((formatContext->duration + 5000)*codecContext->sample_rate)/AV_TIME_BASE;
-
- std::cout << "This stream has " << codecContext->channels << " channels, a sample rate of " << codecContext->sample_rate << "Hz and "<<samples <<" samples" << std::endl;
- std::cout << "The data is in format " <<codecContext->sample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<<std::endl;
-
- isPlanar=(av_sample_fmt_is_planar(codecContext->sample_fmt)==1);
-
- if(isPlanar) { cerr<<"found planar audio"<<endl; }
-
-
- av_init_packet(&packet);
- //sample_processed=0;
- ready=true;
- return true;
- }
-
- AVFrame* libav::audioloader::get_frame() {
-
- if (!ready) return nullptr;
-
- int frameFinished = 0;
- while (!frameFinished) {
- int ret=av_read_frame(formatContext, &packet);
- if (ret<0) {
- std::cerr << "finished with code "<<ret <<(ret==AVERROR_EOF?" ,EOF":"")<<std::endl;
- ready=false;
- return nullptr;
- }
- if (packet.stream_index == audioStream->index)
- {
- //int bytes =
- avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);
-
- // Some frames rely on multiple packets, so we have to make sure the frame is finished before
- // we can use it
- }
- // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory
- av_free_packet(&packet);
- }
- return frame;
-
- }
- AVPacket* libav::audioloader::get_packet() {
-
- if (!ready) return nullptr;
-
- int ret=av_read_frame(formatContext, &packet);
- if (ret<0) {
- std::cerr << "finished with code "<<ret <<(ret==AVERROR_EOF?" ,EOF":"")<<std::endl;
- ready=false;
- return nullptr;
- }
- //if (packet.stream_index == audioStream->index)
- //{
- //int bytes =
- // avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);
-
- // Some frames rely on multiple packets, so we have to make sure the frame is finished before
- // we can use it
- //}
- // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory
- //av_free_packet(&packet);?????
- //}
- return &packet;
-
- }
- uint16_t* libav::audioloader::get_samples(int num){ //presumes 16bpc here
- //std::cerr << "request "<<num<<" samples: "<<(ready?"ready":"not ready")<<std::endl;
- //if(!ready) return nullptr;
- //shuffle down samples
-
- if (sample_start>0){
- for (int i=0;i<sample_end-sample_start;i++){
- for (int j=0;j<channels;j++) {
- buffer[(i*channels)+j]=buffer[((sample_start+i)*channels)+j];
- }
- }
- sample_start=sample_end-sample_start;
- }
-
- sample_end=sample_start;
- while (sample_end<num) {
- frame=get_frame();
- if (frame) {
- channels=av_frame_get_channels(frame); //will always reach here 1st
- if (((sample_end+std::max(num,frame->nb_samples))*channels)>buffer.size()){
- int m=buffer.size();
- int s=((sample_end+std::max(num,frame->nb_samples))*channels);
- buffer.reserve(s);
- std::cerr << "audioloader reserved buffer to " << s << std::endl;
- for (int i=m;i<s;i++) buffer.push_back(0);
- }
- for (int i=0;i<frame->nb_samples;i++) {
- for (int j=0;j<channels;j++) {
- //int frame->format
- //format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames, enum AVSampleFormat for audio)
- //int ff=frame->format;
- //uint64_t frame->channel_layout
- //Channel layout of the audio data.
- //uint64_t fcl=frame->channel_layout;
- //int frame->nb_extended_buf
- //Number of elements in extended_buf.
- //int fnb=frame->nb_extended_buf;
- //int frame->decode_error_flags
- //decode error flags of the frame, set to a combination of FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there were errors during the decoding.
- //int fde=frame->decode_error_flags;
-
-
- //uint16_t s=((uint16_t*) frame->buf[j]->data)[i];
- uint16_t s;
- if (isPlanar) {
- s=((uint16_t*) frame->buf[j]->data)[i];
- }else {
- s=((uint16_t*) frame->buf[0]->data)[j*channels+i];
- }
-
- //where is audio grunge coming from? signed/ unsigned? doesn't seem to be byte order..
- // add +1 to data subscript with no effect
-
-
- //which? must be determined by format or layout of the channels
- //ALSO some kind of HEINOUS memory leak??
- buffer[((sample_end+i)*frame->channels)+j]=s;
- //buffer[(j*frame->channels)+(sample_end+i)]= ((uint16_t*) frame->buf[j]->data)[i]; ??planar?? nope
- }
- }
- sample_end+=frame->nb_samples;
- }
- else {
- for (int i=sample_end;i<num;i++){
- for (int j=0;j<channels;j++) {
- buffer[(channels*i)+j]=0;
- }
- }
- sample_end=num;
- }
- //std::cerr<<"filling buffer to "<<((sample_end+frame->nb_samples)*frame->channels)<<std::endl;
-
-
- //avcodec_free_frame(&frame);
- }
- if (sample_end>num) {
- sample_start=num;
- }
- else {
- sample_start=0;
- }
- return (uint16_t*)(&buffer[0]);
-}
-
-bool libav::audioloader::close() {
- mutex.lock();
- av_free(frame);
- avcodec_close(codecContext);
- avformat_close_input(&formatContext);
- mutex.unlock();
- ready=false;
- sample_start=0;
- sample_end=0;
- return true;
-}
diff --git a/rotord/libavwrapper.h b/rotord/libavwrapper.h
deleted file mode 100755
index 656f885..0000000
--- a/rotord/libavwrapper.h
+++ /dev/null
@@ -1,279 +0,0 @@
-#ifndef libavwrapper_H
-#define libavwrapper_H
-
-/*
- * libavwrapper.h
- * May 2012 Christopher Bruns
- * The libavwrapper class is a C++ wrapper around the poorly documented
- * libavcodec movie API used by ffmpeg. I made extensive use of Nathan
- * Clack's implemention in the whisk project.
- *
- * The libavwrapper.h and libavwrapper.cpp files depend only on the libavcodec
- * and allied sets of libraries. To compartmentalize and reduce dependencies
- * I placed the Vaa3d specific use of this class into a separate set of
- * source files: loadV3dFFMpeg.h/cpp
- */
-
-////////////////////////
-//now that we have guards
-//instead of crashing instantly when the 2nd thread tries to encode a frame, we get an error
-
- //*** Error in `./rotord': corrupted double-linked list: 0x00007f3c31b1b630 ***
-
- //or
-
- //*** Error in `./rotord': double free or corruption (out): 0x00007f3bf8210080 ***
- ///////////////////////
-
-
-//http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/
-//great to use c++11 features
-
-#ifndef UINT64_C
-#define UINT64_C(c) (c ## ULL)
-#endif
-
-#include "Poco/Mutex.h"
-
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavutil/pixfmt.h>
-#include <libavutil/opt.h>
-#include <libavutil/imgutils.h>
-#include <libavutil/samplefmt.h>
-
-#include <libswscale/swscale.h> //?
-}
-
-/*
-#include <QFile>
-#include <QNetworkAccessManager>
-#include <QMutex>
-#include <QUrl>
-#include <QBuffer>
-*/
-
-
-#include <string>
-#include <stdexcept>
-#include <iostream>
-#include <fstream>
-#include <math.h>
-#include <vector>
-
-
-
-namespace libav {
-
-
-
- static bool b_is_one_time_inited=false;
- // Some libavcodec calls are not reentrant
-
- void maybeInitFFMpegLib();
-
- static int sws_flags = SWS_BICUBIC;
-
-// Translated to C++ by Christopher Bruns May 2012
-// from ffmeg_adapt.c in whisk package by Nathan Clack, Mark Bolstadt, Michael Meeuwisse
- class decoder
- {
- public:
- enum Channel {
- RED = 0,
- GRAY = 0,
- GREEN = 1,
- BLUE = 2,
- ALPHA = 3
- };
-
-
- decoder(PixelFormat pixelFormat=PIX_FMT_RGB24);
- //decoder(QUrl url, PixelFormat pixelFormat=PIX_FMT_RGB24);
- void cleanup();
- virtual ~decoder();
- //bool open(QUrl url, enum PixelFormat formatParam = PIX_FMT_RGB24);
- //bool open(QIODevice& fileStream, QString& fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);
- bool reinit_buffers_and_scaler();
- bool init_buffers_and_scaler();
- uint8_t getPixelIntensity(int x, int y, Channel c = GRAY) const;
- bool fetchFrame(int targetFrameIndex = 0);
- bool fetchFrame(int w,int h,int targetFrameIndex = 0);
- int getNumberOfFrames() const;
- int getWidth() const;
- int getHeight() const;
- int getNumberOfChannels() const;
- bool readNextFrame(int targetFrameIndex = 0);
- bool readNextFrameWithPacket(int targetFrameIndex, AVPacket& packet, AVFrame* pYuv);
- int seekToFrame(int targetFrameIndex = 0);
-
- // make certain members public, for use by Fast3DTexture class
- AVFrame *pFrameRGB;
- AVFrame *pRaw;
- AVFormatContext *container;
- AVCodecContext *pCtx;
- int videoStream;
- int previousFrameIndex;
- bool isOpen;
-
- bool open(std::string& fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);
- bool open(char* fileName, enum PixelFormat formatParam = PIX_FMT_RGB24);
-
- protected:
-
-
- void initialize();
-
- bool openUsingInitializedContainer(enum PixelFormat formatParam = PIX_FMT_RGB24 );
- static bool avtry(int result, const std::string& msg);
-
- AVCodec *pCodec;
- uint8_t *buffer,
- *blank;
- //struct
- SwsContext *Sctx;
- int width, height;
- PixelFormat format;
- size_t numBytes;
- int numFrames;
- int sc; // number of color channels
-
- // For loading from URL
- /*
- static const int ioBufferSize = 32768;
- unsigned char * ioBuffer;
- QNetworkAccessManager networkManager;
- AVIOContext* avioContext;
- QFile fileStream;
- QNetworkReply* reply;
- QBuffer fileBuffer;
- QByteArray byteArray;
- */
- };
-
-
- // TODO - finish refactoring based on
- // http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/output_example.c
- class encoder
- {
- public:
- //typedef encoder::Channel Channel;
-
- encoder(const char * file_name, int width, int height, float _framerate=25.0f, enum AVCodecID codec_id = CODEC_ID_H264);
- virtual ~encoder();
- void setPixelIntensity(int x, int y, int c, uint8_t value);
- void write_frame(float seconds,uint8_t *rgbdata);
- void write_frame(float seconds,uint16_t *audiodata);
- int get_audio_framesize(){ return audio_input_frame_size; }
- float get_audio_step(){return audiostep;};
-
- protected:
- AVFormatContext *container;
- AVCodecContext *pCtx;
- AVFrame *picture_yuv;
- AVFrame *picture_rgb;
- AVFrame *audio_frame;
- float timebase;
- struct SwsContext *Sctx;
-
- AVStream *audio_st;
- AVStream *video_st;
-
- AVCodecContext *aCtx;
- int audio_input_frame_size;
- float audiostep;
- };
-
-
- class exporter {
- public:
- virtual ~exporter(){};
- bool setup(int w,int h, int bitRate, int frameRate, std::string container);
- bool record(std::string filename);
- bool encodeFrame(unsigned char *pixels, uint16_t *samples);
- bool encodeFrame(unsigned char *pixels,AVPacket *audiopkt); //is possible to just copy the packets?
- bool encodeFrame(unsigned char *pixels);
- bool encodeFrame(uint16_t *samples);
- void finishRecord();
- int get_audio_framesize(){return audioframesize;};
- float get_audio_step(){return audiostep;};
-
- AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,enum AVCodecID codec_id);
- void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st);
- int open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st);
-
- void write_audio_frame(AVFormatContext *oc, AVStream *st,uint16_t *samples);
- void write_audio_frame(AVFormatContext *oc, AVStream *st,AVPacket *pkt);
- void close_audio(AVFormatContext *oc, AVStream *st);
-
- void write_video_frame(AVFormatContext *oc, AVStream *st, uint8_t *pixels);
- void close_video(AVFormatContext *oc, AVStream *st);
-
- private:
- AVOutputFormat *fmt;
- AVFormatContext *oc;
- AVStream *audio_st, *video_st;
- AVCodec *audio_codec, *video_codec;
- double audio_pts, video_pts;
-
- struct SwsContext *sws_ctx;
-
- int audioframesize;
- float audiostep;
- int w;
- int h;
- int bitRate;
- int frameRate;
- std::string container;
-
- int outputframe;
-
- // video output //
-
- AVFrame *frame;
- AVPicture src_picture, dst_picture;
- int frame_count;
- uint8_t *outPixels;
-
-
- //************************************************************//
- // audio output //
-
- float t, tincr, tincr2;
- int audio_input_frame_size;
-
-
- };
-
- class audioloader{
- public:
- audioloader(){ready=false;sample_start=0;sample_end=0;};
- bool setup(const std::string &filename);
- AVFrame* get_frame();
- uint16_t* get_samples(int num);
- AVPacket* get_packet();
- bool close();
- bool ready;
-
- AVCodecContext* codecContext;
- AVFormatContext* formatContext;
- int channels; //necessary to handle final packet -- unititialised after load/ problem?
- private:
- std::vector<uint16_t> buffer;
- AVFrame* frame;
-
- AVStream* audioStream;
-
- AVPacket packet;
- int sample_end;
- int sample_start;
- bool isPlanar;
-
- };
-
-}
-
-
-
-#endif // libavwrapper_H
diff --git a/rotord/nodes_audio_analysis.h b/rotord/nodes_audio_analysis.h
deleted file mode 100644
index e6c1e65..0000000
--- a/rotord/nodes_audio_analysis.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef ROTOR_NODES_AUDIO_ANALYSIS
-#define ROTOR_NODES_AUDIO_ANALYSIS
-
-#include "rotor.h"
-#include "vampHost.h"
-
-namespace Rotor {
- class Audio_analysis: public Base_audio_processor {
- public:
- Audio_analysis(){};
- Audio_analysis(map<string,string> &settings) {
- base_settings(settings);
- soname=find_setting(settings,"soname");
- id=find_setting(settings,"id");
- outputNo=find_setting(settings,"outputNo",0);
- };
- Audio_analysis* clone(map<string,string> &_settings) { return new Audio_analysis(_settings);};
- bool init(int _channels,int _bits,int _samples,int _rate);
- void cleanup();
- void set_parameter(const std::string &key,const std::string &value){params[key]=ofToFloat(value);};
- int process_frame(uint8_t *data,int samples_in_frame);
- const float output(const Time_spec &time) {
- if (analyser.features.size()) {
- auto i=analyser.features.upper_bound(time.time); //the first element in the container whose key is considered to go after k
- if (i!=analyser.features.end()){
- float uk=i->first;
- i--;
- float lk=i->first;
- int ln=i->second;
- return (((time.time-lk)/(uk-lk))+ln);
- }
- }
- return 0.0f;
- }
- void print_features();
- void print_summary(){
- cerr<<"vamp plugin "<<id<<" of library "<<soname<<" found "<<analyser.features.size()<<" features "<<endl;
- };
- private:
- string soname,id;
- int outputNo;
- vampHost::Analyser analyser;
- map <string,float> params;
- };
-}
-
-#endif \ No newline at end of file
diff --git a/rotord/nodes_drawing.h b/rotord/nodes_drawing.h
deleted file mode 100644
index 11df2d6..0000000
--- a/rotord/nodes_drawing.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ROTOR_NODES_DRAWING
-#define ROTOR_NODES_DRAWING
-
-#include "rotor.h"
-#include <cairo.h>
-
-namespace Rotor {
- class Draw: public Image_node {
- public:
- Draw(){image=nullptr;};
- Draw(map<string,string> &settings) {
- base_settings(settings);
- };
- ~Draw(){ if (image) delete image;};
- Draw* clone(map<string,string> &_settings) { return new Draw(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- //copy incoming image **writable
- if (image) delete image;
- image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
- }
- else image->setup(frame.w,frame.h);
- }
- else image->setup(frame.w,frame.h); //do this twice or use a goto
- //draw onto new or input image
- cairo_surface_t * cs = cairo_image_surface_create_for_data (image->RGBdata,
- CAIRO_FORMAT_RGB24,
- image->w,
- image->h,
- image->getStride());
- cairo_t *c=cairo_create(cs);
- cairo_rectangle(c, image->w/2, image->h/2, image->w, image->h);
- cairo_set_source_rgb(c, 1.0, 0.0, 0.0);
- cairo_fill(c);
- return image;
- }
- private:
- Image *image; //is an image generator
- };
-}
-
-#endif \ No newline at end of file
diff --git a/rotord/ofUtils.cpp b/rotord/ofUtils.cpp
deleted file mode 100755
index 7d7d9cc..0000000
--- a/rotord/ofUtils.cpp
+++ /dev/null
@@ -1,745 +0,0 @@
-#include "ofUtils.h"
-//#include "ofImage.h"
-//#include "ofTypes.h"
-//#include "ofGraphics.h"
-//#include "ofAppRunner.h"
-
-#include "Poco/String.h"
-#include "Poco/LocalDateTime.h"
-#include "Poco/DateTimeFormatter.h"
-
-#include <cctype> // for toupper
-
-
-
-/*
-#ifdef TARGET_WIN32
- #ifndef _MSC_VER
- #include <unistd.h> // this if for MINGW / _getcwd
- #include <sys/param.h> // for MAXPATHLEN
- #endif
-#endif
-
-
-#if defined(TARGET_OF_IPHONE) || defined(TARGET_OSX ) || defined(TARGET_LINUX)
- #include <sys/time.h>
-#endif
-
-#ifdef TARGET_OSX
- #ifndef TARGET_OF_IPHONE
- #include <mach-o/dyld.h>
- #include <sys/param.h> // for MAXPATHLEN
- #endif
-#endif
-
-#ifdef TARGET_WIN32
- #include <mmsystem.h>
- #ifdef _MSC_VER
- #include <direct.h>
- #endif
-
-#endif
-*/
-
-#ifndef MAXPATHLEN
- #define MAXPATHLEN 1024
-#endif
-
-
-static bool enableDataPath = true;
-//static unsigned long startTime = ofGetSystemTime(); // better at the first frame ?? (currently, there is some delay from static init, to running.
-//static unsigned long startTimeMicros = ofGetSystemTimeMicros();
-
-/*
-//--------------------------------------
-unsigned long ofGetElapsedTimeMillis(){
- return ofGetSystemTime() - startTime;
-}
-
-//--------------------------------------
-unsigned long ofGetElapsedTimeMicros(){
- return ofGetSystemTimeMicros() - startTimeMicros;
-}
-
-//--------------------------------------
-float ofGetElapsedTimef(){
- return ofGetElapsedTimeMicros() / 1000000.0f;
-}
-
-//--------------------------------------
-void ofResetElapsedTimeCounter(){
- startTime = ofGetSystemTime();
- startTimeMicros = ofGetSystemTimeMicros();
-}
-*/
-//=======================================
-// this is from freeglut, and used internally:
-/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer.
- * This value wraps every 49.7 days, but integer overflows cancel
- * when subtracting an initial start time, unless the total time exceeds
- * 32-bit, where the GLUT API return value is also overflowed.
- */
-/*
-unsigned long ofGetSystemTime( ) {
- #ifndef TARGET_WIN32
- struct timeval now;
- gettimeofday( &now, NULL );
- return now.tv_usec/1000 + now.tv_sec*1000;
- #else
- #if defined(_WIN32_WCE)
- return GetTickCount();
- #else
- return timeGetTime();
- #endif
- #endif
-}
-*/
-
-/*
-unsigned long ofGetSystemTimeMicros( ) {
- #ifndef TARGET_WIN32
- struct timeval now;
- gettimeofday( &now, NULL );
- return now.tv_usec + now.tv_sec*1000000;
- #else
- #if defined(_WIN32_WCE)
- return GetTickCount()*1000;
- #else
- return timeGetTime()*1000;
- #endif
- #endif
-}
-*/
-//--------------------------------------------------
-unsigned int ofGetUnixTime(){
- return (unsigned int)time(NULL);
-}
-
-//default ofGetTimestampString returns in this format: 2011-01-15-18-29-35-299
-//--------------------------------------------------
-string ofGetTimestampString(){
- string timeFormat = "%Y-%m-%d-%H-%M-%S-%i";
- Poco::LocalDateTime now;
- return Poco::DateTimeFormatter::format(now, timeFormat);
-}
-
-//specify the string format - eg: %Y-%m-%d-%H-%M-%S-%i ( 2011-01-15-18-29-35-299 )
-//--------------------------------------------------
-string ofGetTimestampString(string timestampFormat){
- Poco::LocalDateTime now;
- return Poco::DateTimeFormatter::format(now, timestampFormat);
-}
-
-//--------------------------------------------------
-int ofGetSeconds(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- return local.tm_sec;
-}
-
-//--------------------------------------------------
-int ofGetMinutes(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- return local.tm_min;
-}
-
-//--------------------------------------------------
-int ofGetHours(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- return local.tm_hour;
-}
-
-//--------------------------------------------------
-int ofGetYear(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- int year = local.tm_year + 1900;
- return year;
-}
-
-//--------------------------------------------------
-int ofGetMonth(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- int month = local.tm_mon + 1;
- return month;
-}
-
-//--------------------------------------------------
-int ofGetDay(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- return local.tm_mday;
-}
-
-//--------------------------------------------------
-int ofGetWeekday(){
- time_t curr;
- tm local;
- time(&curr);
- local =*(localtime(&curr));
- return local.tm_wday;
-}
-
-//--------------------------------------------------
-void ofEnableDataPath(){
- enableDataPath = true;
-}
-
-//--------------------------------------------------
-void ofDisableDataPath(){
- enableDataPath = false;
-}
-
-//--------------------------------------------------
-//use ofSetDataPathRoot() to override this
-static string & dataPathRoot(){
-#if defined TARGET_OSX
- static string * dataPathRoot = new string("../../../data/");
-#elif defined TARGET_ANDROID
- static string * dataPathRoot = new string("sdcard/");
-#elif defined(TARGET_LINUX)
- static string * dataPathRoot = new string(ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/"));
-#else
- static string * dataPathRoot = new string("data/");
-#endif
- return *dataPathRoot;
-}
-
-static bool & isDataPathSet(){
- static bool * dataPathSet = new bool(false);
- return * dataPathSet;
-}
-
-//--------------------------------------------------
-void ofSetDataPathRoot(string newRoot){
- string newPath = "";
-
- #ifdef TARGET_OSX
- #ifndef TARGET_OF_IPHONE
- char path[MAXPATHLEN];
- uint32_t size = sizeof(path);
-
- if (_NSGetExecutablePath(path, &size) == 0){
- //printf("executable path is %s\n", path);
- string pathStr = string(path);
-
- //theo: check this with having '/' as a character in a folder name - OSX treats the '/' as a ':'
- //checked with spaces too!
-
- vector < string> pathBrokenUp = ofSplitString( pathStr, "/");
-
- newPath = "";
-
- for(int i = 0; i < pathBrokenUp.size()-1; i++){
- newPath += pathBrokenUp[i];
- newPath += "/";
- }
-
- //cout << newPath << endl; // some sanity checks here
- //system( "pwd" );
-
- chdir ( newPath.c_str() );
- //system("pwd");
- }else{
- ofLog(OF_LOG_FATAL_ERROR, "buffer too small; need size %u\n", size);
- }
- #endif
- #endif
-
- dataPathRoot() = newRoot;
- isDataPathSet() = true;
-}
-
-//--------------------------------------------------
-string ofToDataPath(string path, bool makeAbsolute){
-
- if (!isDataPathSet())
- ofSetDataPathRoot(dataPathRoot());
-
- if( enableDataPath ){
-
- //check if absolute path has been passed or if data path has already been applied
- //do we want to check for C: D: etc ?? like substr(1, 2) == ':' ??
- if( path.length()==0 || (path.substr(0,1) != "/" && path.substr(1,1) != ":" && path.substr(0,dataPathRoot().length()) != dataPathRoot())){
- path = dataPathRoot()+path;
- }
-
- if(makeAbsolute && (path.length()==0 || path.substr(0,1) != "/")){
- /*
- #if !defined( TARGET_OF_IPHONE) & !defined(TARGET_ANDROID)
-
- #ifndef TARGET_WIN32
- char currDir[1024];
- path = "/"+path;
- path = getcwd(currDir, 1024)+path;
-
- #else
-
- char currDir[1024];
- path = "\\"+path;
- path = _getcwd(currDir, 1024)+path;
- std::replace( path.begin(), path.end(), '/', '\\' ); // fix any unixy paths...
-
-
- #endif
-
-
- #else
- //do we need iphone specific code here?
- #endif
- */
- }
-
- }
- return path;
-}
-
-//----------------------------------------
-template <>
-string ofToHex(const string& value) {
- ostringstream out;
- // how many bytes are in the string
- int numBytes = value.size();
- for(int i = 0; i < numBytes; i++) {
- // print each byte as a 2-character wide hex value
- out << setfill('0') << setw(2) << hex << (unsigned int) ((unsigned char)value[i]);
- }
- return out.str();
-}
-
-//----------------------------------------
-string ofToHex(const char* value) {
- // this function is necessary if you want to print a string
- // using a syntax like ofToHex("test")
- return ofToHex((string) value);
-}
-
-//----------------------------------------
-int ofToInt(const string& intString) {
- int x = 0;
- istringstream cur(intString);
- cur >> x;
- return x;
-}
-
-//----------------------------------------
-int ofHexToInt(const string& intHexString) {
- int x = 0;
- istringstream cur(intHexString);
- cur >> hex >> x;
- return x;
-}
-
-//----------------------------------------
-char ofHexToChar(const string& charHexString) {
- int x = 0;
- istringstream cur(charHexString);
- cur >> hex >> x;
- return (char) x;
-}
-
-//----------------------------------------
-float ofHexToFloat(const string& floatHexString) {
- union intFloatUnion {
- int x;
- float f;
- } myUnion;
- myUnion.x = 0;
- istringstream cur(floatHexString);
- cur >> hex >> myUnion.x;
- return myUnion.f;
-}
-
-//----------------------------------------
-string ofHexToString(const string& stringHexString) {
- stringstream out;
- stringstream stream(stringHexString);
- // a hex string has two characters per byte
- int numBytes = stringHexString.size() / 2;
- for(int i = 0; i < numBytes; i++) {
- string curByte;
- // grab two characters from the hex string
- stream >> setw(2) >> curByte;
- // prepare to parse the two characters
- stringstream curByteStream(curByte);
- int cur = 0;
- // parse the two characters as a hex-encoded int
- curByteStream >> hex >> cur;
- // add the int as a char to our output stream
- out << (char) cur;
- }
- return out.str();
-}
-
-//----------------------------------------
-float ofToFloat(const string& floatString) {
- float x = 0;
- istringstream cur(floatString);
- cur >> x;
- return x;
-}
-
-//----------------------------------------
-bool ofToBool(const string& boolString) {
- static const string trueString = "true";
- static const string falseString = "false";
- string lower = Poco::toLower(boolString);
- if(lower == trueString) {
- return true;
- }
- if(lower == falseString) {
- return false;
- }
- bool x = false;
- istringstream cur(lower);
- cur >> x;
- return x;
-}
-
-//----------------------------------------
-char ofToChar(const string& charString) {
- char x = '\0';
- istringstream cur(charString);
- cur >> x;
- return x;
-}
-
-//----------------------------------------
-template <> string ofToBinary(const string& value) {
- stringstream out;
- int numBytes = value.size();
- for(int i = 0; i < numBytes; i++) {
- bitset<8> bitBuffer(value[i]);
- out << bitBuffer;
- }
- return out.str();
-}
-
-//----------------------------------------
-string ofToBinary(const char* value) {
- // this function is necessary if you want to print a string
- // using a syntax like ofToBinary("test")
- return ofToBinary((string) value);
-}
-
-//----------------------------------------
-int ofBinaryToInt(const string& value) {
- const int intSize = sizeof(int) * 8;
- bitset<intSize> binaryString(value);
- return (int) binaryString.to_ulong();
-}
-
-//----------------------------------------
-char ofBinaryToChar(const string& value) {
- const int charSize = sizeof(char) * 8;
- bitset<charSize> binaryString(value);
- return (char) binaryString.to_ulong();
-}
-
-//----------------------------------------
-float ofBinaryToFloat(const string& value) {
- const int floatSize = sizeof(float) * 8;
- bitset<floatSize> binaryString(value);
- union ulongFloatUnion {
- unsigned long result;
- float f;
- } myUFUnion;
- myUFUnion.result = binaryString.to_ulong();
- return myUFUnion.f;
-}
-//----------------------------------------
-string ofBinaryToString(const string& value) {
- ostringstream out;
- stringstream stream(value);
- bitset<8> byteString;
- int numBytes = value.size() / 8;
- for(int i = 0; i < numBytes; i++) {
- stream >> byteString;
- out << (char) byteString.to_ulong();
- }
- return out.str();
-}
-
-//--------------------------------------------------
-vector <string> ofSplitString(const string & source, const string & delimiter, bool ignoreEmpty, bool trim) {
- vector<string> result;
- if (delimiter.empty()) {
- result.push_back(source);
- return result;
- }
- string::const_iterator substart = source.begin(), subend;
- while (true) {
- subend = search(substart, source.end(), delimiter.begin(), delimiter.end());
- string sub(substart, subend);
- if(trim) {
- Poco::trimInPlace(sub);
- }
- if (!ignoreEmpty || !sub.empty()) {
- result.push_back(sub);
- }
- if (subend == source.end()) {
- break;
- }
- substart = subend + delimiter.size();
- }
- return result;
-}
-
-//--------------------------------------------------
-string ofJoinString(vector <string> stringElements, const string & delimiter){
- string resultString = "";
- int numElements = stringElements.size();
-
- for(int k = 0; k < numElements; k++){
- if( k < numElements-1 ){
- resultString += stringElements[k] + delimiter;
- } else {
- resultString += stringElements[k];
- }
- }
-
- return resultString;
-}
-
-//--------------------------------------------------
-void ofStringReplace(string& input, string searchStr, string replaceStr){
- size_t uPos = 0;
- size_t uFindLen = searchStr.length();
- size_t uReplaceLen = replaceStr.length();
-
- if( uFindLen == 0 ){
- return;
- }
-
- for( ;(uPos = input.find( searchStr, uPos )) != std::string::npos; ){
- input.replace( uPos, uFindLen, replaceStr );
- uPos += uReplaceLen;
- }
-}
-
-//--------------------------------------------------
-bool ofIsStringInString(string haystack, string needle){
- return ( strstr(haystack.c_str(), needle.c_str() ) != NULL );
-}
-
-//--------------------------------------------------
-string ofToLower(const string & src){
- string dst(src);
- transform(src.begin(),src.end(),dst.begin(),::tolower);
- return dst;
-}
-
-//--------------------------------------------------
-string ofToUpper(const string & src){
- string dst(src);
- transform(src.begin(),src.end(),dst.begin(),::toupper);
- return dst;
-}
-
-//--------------------------------------------------
-string ofVAArgsToString(const char * format, ...){
- // variadic args to string:
- // http://www.codeproject.com/KB/string/string_format.aspx
- static char aux_buffer[10000];
- string retStr("");
- if (NULL != format){
-
- va_list marker;
-
- // initialize variable arguments
- va_start(marker, format);
-
- // Get formatted string length adding one for NULL
- size_t len = vsprintf(aux_buffer, format, marker) + 1;
-
- // Reset variable arguments
- va_end(marker);
-
- if (len > 0)
- {
- va_list args;
-
- // initialize variable arguments
- va_start(args, format);
-
- // Create a char vector to hold the formatted string.
- vector<char> buffer(len, '\0');
- vsprintf(&buffer[0], format, args);
- retStr = &buffer[0];
- va_end(args);
- }
-
- }
- return retStr;
-}
-
-string ofVAArgsToString(const char * format, va_list args){
- // variadic args to string:
- // http://www.codeproject.com/KB/string/string_format.aspx
- char aux_buffer[10000];
- string retStr("");
- if (NULL != format){
-
- // Get formatted string length adding one for NULL
- vsprintf(aux_buffer, format, args);
- retStr = aux_buffer;
-
- }
- return retStr;
-}
-
-/*
-//--------------------------------------------------
-void ofLaunchBrowser(string url){
-
- // http://support.microsoft.com/kb/224816
-
- //make sure it is a properly formatted url
- if(Poco::icompare(url.substr(0,7), "http://") != 0 &&
- Poco::icompare(url.substr(0,8), "https://") != 0) {
- ofLog(OF_LOG_WARNING, "ofLaunchBrowser: url must begin http:// or https://");
- return;
- }
-
- //----------------------------
- #ifdef TARGET_WIN32
- //----------------------------
-
- #if (_MSC_VER)
- // microsoft visual studio yaks about strings, wide chars, unicode, etc
- ShellExecuteA(NULL, "open", url.c_str(),
- NULL, NULL, SW_SHOWNORMAL);
- #else
- ShellExecute(NULL, "open", url.c_str(),
- NULL, NULL, SW_SHOWNORMAL);
- #endif
-
- //----------------------------
- #endif
- //----------------------------
-
- //--------------------------------------
- #ifdef TARGET_OSX
- //--------------------------------------
- // ok gotta be a better way then this,
- // this is what I found...
- string commandStr = "open "+url;
- system(commandStr.c_str());
- //----------------------------
- #endif
- //----------------------------
-
- //--------------------------------------
- #ifdef TARGET_LINUX
- //--------------------------------------
- string commandStr = "xdg-open "+url;
- int ret = system(commandStr.c_str());
- if(ret!=0) ofLog(OF_LOG_ERROR,"ofLaunchBrowser: couldn't open browser");
- //----------------------------
- #endif
- //----------------------------
-}
-
-//--------------------------------------------------
-string ofGetVersionInfo(){
- string version;
- stringstream sstr;
- sstr << "of version: " << OF_VERSION << endl;
- return sstr.str();
-}
-*/
-//---- new to 006
-//from the forums http://www.openframeworks.cc/forum/viewtopic.php?t=1413
-/*
-//--------------------------------------------------
-void ofSaveScreen(string filename) {
- ofImage screen;
- screen.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR);
- screen.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
- screen.saveImage(filename);
-}
-
-//--------------------------------------------------
-void ofSaveViewport(string filename) {
- // because ofSaveScreen doesn't related to viewports
- ofImage screen;
- ofRectangle view = ofGetCurrentViewport();
- screen.allocate(view.width, view.height, OF_IMAGE_COLOR);
- screen.grabScreen(0, 0, view.width, view.height);
- screen.saveImage(filename);
-}
-
-//--------------------------------------------------
-int saveImageCounter = 0;
-void ofSaveFrame(bool bUseViewport){
- string fileName = ofToString(saveImageCounter) + ".png";
- if (bUseViewport){
- ofSaveViewport(fileName);
- } else {
- ofSaveScreen(fileName);
- }
- saveImageCounter++;
-}
-
-//--------------------------------------------------
-string ofSystem(string command){
- FILE * ret = NULL;
-#ifdef TARGET_WIN32
- ret = _popen(command.c_str(),"r");
-#else
- ret = popen(command.c_str(),"r");
-#endif
-
- string strret;
- char c;
-
- if (ret == NULL){
- ofLogError() << "ofSystem: error opening return file";
- }else{
- do {
- c = fgetc (ret);
- strret += c;
- } while (c != EOF);
- fclose (ret);
- }
-
- return strret;
-}
-
-//--------------------------------------------------
-ofTargetPlatform ofGetTargetPlatform(){
-#ifdef TARGET_LINUX
- if(ofSystem("uname -m").find("x86_64")==0)
- return OF_TARGET_LINUX64;
- else
- return OF_TARGET_LINUX;
-#elif defined(TARGET_OSX)
- return OF_TARGET_OSX;
-#elif defined(TARGET_WIN32)
- #if (_MSC_VER)
- return OF_TARGET_WINVS;
- #else
- return OF_TARGET_WINGCC;
- #endif
-#elif defined(TARGET_ANDROID)
- return OF_TARGET_ANDROID;
-#elif defined(TARGET_OF_IPHONE)
- return OF_TARGET_IPHONE;
-#endif
-}
-*/ \ No newline at end of file
diff --git a/rotord/ofUtils.h b/rotord/ofUtils.h
deleted file mode 100755
index 0567e22..0000000
--- a/rotord/ofUtils.h
+++ /dev/null
@@ -1,223 +0,0 @@
-#pragma once
-
-//#include "ofConstants.h"
-
-
-// core: ---------------------------
-#include <cstdio>
-#include <cstdarg>
-#include <cmath>
-#include <ctime>
-#include <cstdlib>
-#include <string>
-#include <iostream>
-#include <vector>
-#include <cstring>
-#include <sstream> //for ostringsream
-#include <iomanip> //for setprecision
-#include <fstream>
-#include <algorithm>
-
-#include <bitset> // for ofToBinary
-
-
-
-
-//#include "ofLog.h"
-
-/*#ifdef TARGET_WIN32 // for ofLaunchBrowser
- #include <shellapi.h>
-#endif
-*/
-
-
-using namespace std;
-
-int ofNextPow2(int input);
-
-void ofResetElapsedTimeCounter(); // this happens on the first frame
-float ofGetElapsedTimef();
-unsigned long ofGetElapsedTimeMillis();
-unsigned long ofGetElapsedTimeMicros();
-int ofGetFrameNum();
-
-int ofGetSeconds();
-int ofGetMinutes();
-int ofGetHours();
-
-//number of seconds since 1970
-unsigned int ofGetUnixTime();
-
-
-/*
-unsigned long ofGetSystemTime( ); // system time in milliseconds;
-unsigned long ofGetSystemTimeMicros( ); // system time in microseconds;
-
- //returns
-string ofGetTimestampString();
-string ofGetTimestampString(string timestampFormat);
-
-
-int ofGetYear();
-int ofGetMonth();
-int ofGetDay();
-int ofGetWeekday();
-
-void ofLaunchBrowser(string url);
-*/
-void ofEnableDataPath();
-void ofDisableDataPath();
-string ofToDataPath(string path, bool absolute=false);
-
-template<class T>
-void ofRandomize(vector<T>& values) {
- random_shuffle(values.begin(), values.end());
-}
-
-template<class T, class BoolFunction>
-void ofRemove(vector<T>& values, BoolFunction shouldErase) {
- values.erase(remove_if(values.begin(), values.end(), shouldErase), values.end());
-}
-
-template<class T>
-void ofSort(vector<T>& values) {
- sort(values.begin(), values.end());
-}
-template<class T, class BoolFunction>
-void ofSort(vector<T>& values, BoolFunction compare) {
- sort(values.begin(), values.end(), compare);
-}
-
-template <class T>
-unsigned int ofFind(const vector<T>& values, const T& target) {
- return distance(values.begin(), find(values.begin(), values.end(), target));
-}
-
-template <class T>
-bool ofContains(const vector<T>& values, const T& target) {
- return ofFind(values, target) != values.size();
-}
-
-//set the root path that ofToDataPath will use to search for files relative to the app
-//the path must have a trailing slash (/) !!!!
-void ofSetDataPathRoot( string root );
-
-template <class T>
-string ofToString(const T& value){
- ostringstream out;
- out << value;
- return out.str();
-}
-
-/// like sprintf "%4f" format, in this example precision=4
-template <class T>
-string ofToString(const T& value, int precision){
- ostringstream out;
- out << fixed << setprecision(precision) << value;
- return out.str();
-}
-
-/// like sprintf "% 4d" or "% 4f" format, in this example width=4, fill=' '
-template <class T>
-string ofToString(const T& value, int width, char fill ){
- ostringstream out;
- out << fixed << setfill(fill) << setw(width) << value;
- return out.str();
-}
-
-/// like sprintf "%04.2d" or "%04.2f" format, in this example precision=2, width=4, fill='0'
-template <class T>
-string ofToString(const T& value, int precision, int width, char fill ){
- ostringstream out;
- out << fixed << setfill(fill) << setw(width) << setprecision(precision) << value;
- return out.str();
-}
-
-template<class T>
-string ofToString(const vector<T>& values) {
- stringstream out;
- int n = values.size();
- out << "{";
- if(n > 0) {
- for(int i = 0; i < n - 1; i++) {
- out << values[i] << ", ";
- }
- out << values[n - 1];
- }
- out << "}";
- return out.str();
-}
-
-template <class T>
-string ofToHex(const T& value) {
- ostringstream out;
- // pretend that the value is a bunch of bytes
- unsigned char* valuePtr = (unsigned char*) &value;
- // the number of bytes is determined by the datatype
- int numBytes = sizeof(T);
- // the bytes are stored backwards (least significant first)
- for(int i = numBytes - 1; i >= 0; i--) {
- // print each byte out as a 2-character wide hex value
- out << setfill('0') << setw(2) << hex << (int) valuePtr[i];
- }
- return out.str();
-}
-template <>
-string ofToHex(const string& value);
-string ofToHex(const char* value);
-
-int ofHexToInt(const string& intHexString);
-char ofHexToChar(const string& charHexString);
-float ofHexToFloat(const string& floatHexString);
-string ofHexToString(const string& stringHexString);
-
-int ofToInt(const string& intString);
-char ofToChar(const string& charString);
-float ofToFloat(const string& floatString);
-bool ofToBool(const string& boolString);
-
-template <class T>
-string ofToBinary(const T& value) {
- ostringstream out;
- const char* data = (const char*) &value;
- // the number of bytes is determined by the datatype
- int numBytes = sizeof(T);
- // the bytes are stored backwards (least significant first)
- for(int i = numBytes - 1; i >= 0; i--) {
- bitset<8> cur(data[i]);
- out << cur;
- }
- return out.str();
-}
-template <>
-string ofToBinary(const string& value);
-string ofToBinary(const char* value);
-
-int ofBinaryToInt(const string& value);
-char ofBinaryToChar(const string& value);
-float ofBinaryToFloat(const string& value);
-string ofBinaryToString(const string& value);
-
-string ofGetVersionInfo();
-
-void ofSaveScreen(string filename);
-void ofSaveFrame(bool bUseViewport = false);
-void ofSaveViewport(string filename);
-
-//--------------------------------------------------
-vector <string> ofSplitString(const string & source, const string & delimiter, bool ignoreEmpty = false, bool trim = false);
-string ofJoinString(vector <string> stringElements, const string & delimiter);
-void ofStringReplace(string& input, string searchStr, string replaceStr);
-bool ofIsStringInString(string haystack, string needle);
-
-string ofToLower(const string & src);
-string ofToUpper(const string & src);
-
-string ofVAArgsToString(const char * format, ...);
-string ofVAArgsToString(const char * format, va_list args);
-
-string ofSystem(string command);
-
-//ofTargetPlatform ofGetTargetPlatform();
-
-
diff --git a/rotord/params.h b/rotord/params.h
deleted file mode 100644
index e69de29..0000000
--- a/rotord/params.h
+++ /dev/null
diff --git a/rotord/rendercontext.cpp b/rotord/rendercontext.cpp
deleted file mode 100644
index 7362d64..0000000
--- a/rotord/rendercontext.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-#include "rotor.h"
-
-
-using namespace Rotor;
-void Render_context::runTask() {
- while (!isCancelled()) {
- int cmd=0;
- mutex.lock();
- if (work_queue.size()){
- cmd=work_queue[0];
- work_queue.pop_front();
- }
- mutex.unlock();
- if(cmd==ANALYSE_AUDIO) {
- state=ANALYSING_AUDIO;
- vector<Base_audio_processor*> processors;
- processors.push_back(audio_thumb);
- vector<Node*> analysers=graph.find_nodes("audio_analysis");
- for (auto a: analysers) {
- processors.push_back(dynamic_cast<Base_audio_processor*>(a));
- }
- if (load_audio(audio_filename,processors)) {
- audio_loaded=true;
- state=IDLE;
- }
- else {
- //an error occurred: TODO have to clean up allocated data. autoptr?
- audio_loaded=false;
- state=IDLE;
- }
- }
- if(cmd==RENDER) {
- state=RENDERING;
- if(graph.video_render(output_filename,audio_filename,output_framerate,progress)){
- state=IDLE;
- }
- else {
- //an error occurred: TODO have to clean up allocated data. autoptr?
- cerr<<"Rotor: render failed"<<endl;
- state=IDLE;
- }
- }
- sleep(100);
- }
- printf("Rotor: stopping thread\n");
-}
-void Render_context::add_queue(int item) {
- mutex.lock();
- work_queue.push_back(item);
- mutex.unlock();
-}
-void Render_context::session_command(const std::vector<std::string>& command,xmlIO& XML,HTTPResponse::HTTPStatus& status){
- Logger& logger = Logger::get("Rotor");
- status=HTTPResponse::HTTP_BAD_REQUEST; //error by default
- if (command[2]=="resolution") {
- if (command[0]=="PUT") {
- if (command.size()>2) {
- if (state==IDLE) {
- Poco::StringTokenizer t1(command[3],",");
- if (t1.count()>1){
- int w=ofToInt(t1[0]);
- int h=ofToInt(t1[1]);
- if (graph.set_resolution(w,h)){
- logger.information("resolution set to "+t1[0]+"x"+t1[1]);
- XML.addValue("status","resolution set to "+t1[0]+"x"+t1[1]);
- status=HTTPResponse::HTTP_OK;
- }
- else {
- logger.error("ERROR: invalid resolution request: "+t1[0]+"x"+t1[1]);
- XML.addValue("error","invalid resolution request: "+t1[0]+"x"+t1[1]);
- }
- }
- }
- else {
- XML.addValue("error","session busy");
- }
- }
- }
- }
- if (command[2]=="audio") {
- if (command[0]=="PUT") { //get audio file location and initiate analysis
- if (command.size()>2) {
- if (state==IDLE) {
- audio_filename=media_dir+command[3]; //for now, store session variables in memory //check file exists
- Poco::File f=Poco::File(audio_filename);
- if (f.exists()) {
- //pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read??
- add_queue(ANALYSE_AUDIO);
- status=HTTPResponse::HTTP_OK;
- logger.information("Starting audio analysis: "+command[3]);
- XML.addValue("status","Starting audio analysis: "+command[3]);
- }
- else {
- status=HTTPResponse::HTTP_NOT_FOUND;
- logger.error("ERROR: audio file "+command[3]+" not found");
- XML.addValue("error",command[3]+" not found");
- }
-
- }
- else {
- logger.error("ERROR: Session busy");
- XML.addValue("error","Session busy");
- }
- }
- }
- if (command[0]=="GET") {
- if (state==ANALYSING_AUDIO) {
- status=HTTPResponse::HTTP_OK;
- XML.addValue("status","Analysing audio");
- char c[20];
- sprintf(c,"%02f",progress);
- XML.addValue("progress",string(c));
- }
- else if (audio_loaded) {
- //not sure about this-- should this state be retained?
- //can the data only be read once?
- //for now
- status=HTTPResponse::HTTP_OK;
- XML.addValue("status","Audio ready");
- XML.addValue("audio",audio_thumb->print());
- }
- else {
- logger.error("ERROR: audio thumbnail requested but no audio loaded");
- XML.addValue("error","No audio loaded");
- }
- }
- if (command[0]=="DELETE") {
- if (state==IDLE) {
- audio_filename="";
- logger.information("Audio deleted");
- XML.addValue("status","Audio deleted");
- status=HTTPResponse::HTTP_OK;
- }
- else {
- logger.error("ERROR: Session busy");
- XML.addValue("error","Session busy");
- }
- }
- }
- if (command[2]=="graph") {
- if (command[0]=="GET") {
- if (graph.loaded) {
- status=HTTPResponse::HTTP_OK;
- //XML.addValue("patchbay",graph.toString());
- logger.information("Requested graph");
- XML.loadFromBuffer(graph.toString());
- }
- else {
- logger.error("ERROR: graph not loaded: check XML");
- XML.addValue("error","graph not loaded: check XML");
- }
- }
- if (command[0]=="PUT") { //get new graph from file
- if (command.size()>2) {
- //should interrupt whatever is happening?
- //before begining to load from xml
- if (state==IDLE) { //eventually not like this
- if (graph.load(command[3])) {
- status=HTTPResponse::HTTP_OK;
- logger.information("Loaded graph from http PUT body");
- XML.addValue("status","Loaded graph from PUT body");
- if (audio_loaded) {
- add_queue(ANALYSE_AUDIO);
- status=HTTPResponse::HTTP_OK;
- logger.information("Starting audio analysis for graph: "+command[3]);
- XML.addValue("status","Starting audio analysis for graph: "+command[3]);
- }
- }
- else {
- string graph_filename=graph_dir+command[3];
- Poco::File f=Poco::File(graph_filename);
- if (f.exists()) {
- if (graph.loadFile(graph_filename)) {
- status=HTTPResponse::HTTP_OK;
- //XML.addValue("patchbay",graph.toString());
- //XML.loadFromBuffer(graph.toString());
- XML=graph.xml;
- //the graph could actually contain an xml object and we could just print it here?
- //or could our nodes even be subclassed from xml nodes?
- //the graph or the audio could load first- have to analyse the audio with vamp after the graph is loaded
- //for now the graph must load 1st
- if (audio_loaded) {
- add_queue(ANALYSE_AUDIO);
- status=HTTPResponse::HTTP_OK;
- logger.information("Starting audio analysis for graph: "+command[3]);
- XML.addValue("status","Starting audio analysis for graph: "+command[3]);
- }
- }
- else {
- status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; //~/sources/poco-1.4.6-all/Net/include/Poco/Net/HTTPResponse.h
- logger.error("ERROR: graph not loaded: check XML");
- XML.addValue("error","graph not loaded: check XML");
- }
- }
- else {
- status=HTTPResponse::HTTP_NOT_FOUND;
- logger.error("ERROR: "+command[3]+" not found");
- XML.addValue("error",command[3]+" not found");
- }
- }
- }
- }
- }
- if (command[0]=="DELETE") {
- //for now
- graph=Graph();
- logger.information("graph deleted");
- XML.addValue("status","graph deleted");
- status=HTTPResponse::HTTP_OK;
- }
- }
- if (command[2]=="signal") {
- if (command[0]=="GET") { //generate xml from 1st signal output
- if (state==IDLE) {
- //direct call for testing
- float framerate=25.0f;
- //if (command.size()>2) {
- // framerate=ofToFloat(command[3]);
- //}
- string signal_xml;
- if (graph.signal_render(signal_xml,framerate)){
- status=HTTPResponse::HTTP_OK;
- logger.information("rendering signal to xml");
- XML.addValue("signal",signal_xml); //this doesn't work >> pseudo xml
- }
- else {
- status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR;
- logger.error("ERROR: could not render output signal");
- XML.addValue("error","could not render output signal");
- }
- //else {
- // status=HTTPResponse::HTTP_NOT_FOUND;
- // XML.addValue("error","Signal output not found in graph");
- //}
- }
- else {
- status=HTTPResponse::HTTP_SERVICE_UNAVAILABLE;
- logger.error("ERROR: context busy");
- XML.addValue("error","Context busy");
- }
- }
- }
- if (command[2]=="video") {
- if (command[0]=="PUT") { //get vide file location and initiate analysis
- if (command.size()>4) { //there should be a filename + a destination node
- if (state==IDLE) {
- string video_filename=media_dir+command[4];
- //check file exists
- Poco::File f=Poco::File(video_filename);
- if (f.exists()) {
- if (load_video(command[3],video_filename)) {
- //pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read??
- //DUMMY RESPONSE
- status=HTTPResponse::HTTP_OK;
- logger.information("Succesfully loaded "+command[4]+" into video node "+command[3]);
- XML.addValue("status","Succesfully loaded "+command[4]+" into video node "+command[3]);
- }
- else {
- status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR;
- logger.error("ERROR: could not load "+command[4]+" into video node "+command[3]);
- XML.addValue("error","could not load "+command[4]+" into video node "+command[3]);
- }
- }
- else {
- status=HTTPResponse::HTTP_NOT_FOUND;
- logger.error("ERROR: "+command[4]+" not found");
- XML.addValue("error",command[4]+" not found");
- }
- }
- else {
- status=HTTPResponse::HTTP_BAD_REQUEST;
- logger.error("ERROR: Session busy");
- XML.addValue("error","Session busy");
- }
- }
- else {
- status=HTTPResponse::HTTP_BAD_REQUEST;
- logger.error("ERROR: Bad request");
- XML.addValue("error","Bad request");
- }
- }
- }
- if (command[2]=="render") {
- if (command[0]=="GET") {
- if(state==RENDERING){
- status=HTTPResponse::HTTP_OK;
- XML.addValue("status","Rendering video");
- XML.addValue("progress",ofToString(progress));
- }
- else {
- logger.error("ERROR: Render progress requested but not rendering");
- XML.addValue("error","Not rendering");
- }
- }
- if (command[0]=="PUT") {
- if (command.size()>2) {
- if (state==IDLE) {
- output_filename=output_dir+command[3];
- if (command.size()>3) {
-// output_framerate=ofToFloat(command[4]);
- }
- add_queue(RENDER);
- status=HTTPResponse::HTTP_OK;
- logger.information("Starting render: "+command[3]);
- XML.addValue("status","Starting render: "+command[3]);
- }
- else {
- status=HTTPResponse::HTTP_BAD_REQUEST;
- logger.error("ERROR: Session busy");
- XML.addValue("error","Session busy");
- }
- }
- else {
- status=HTTPResponse::HTTP_BAD_REQUEST;
- logger.error("ERROR: No output file specified");
- XML.addValue("error","No output file specified");
- }
- }
- if (command[0]=="DELETE") {
- status=HTTPResponse::HTTP_OK;
- logger.error("ERROR: Not implemented");
- XML.addValue("status","DUMMY RESPONSE: cancelling render");
- }
- }
-}
-
-bool Render_context::load_audio(const string &filename,vector<Base_audio_processor*> processors){
- Logger& logger = Logger::get("Rotor");
- logger.information("Starting audio analysis");
-
- libav::audioloader loader;
- loader.setup(filename);
-
- graph.duration=((float)loader.formatContext->duration)/AV_TIME_BASE;
-
- int rate = loader.codecContext->sample_rate;
- int samples = ((loader.formatContext->duration + 5000)*rate)/AV_TIME_BASE; //why 5000 more?
- int channels= loader.codecContext->channels;
- int bits = loader.codecContext->bits_per_raw_sample;
-
- for (auto p: processors) {
- if(!p->init(channels,bits,samples,rate) ){
- logger.error("ERROR: Audio plugin failed to initialse");
- return false;
- }
- }
-
- AVFrame* frame=loader.get_frame();
- int sample_processed=0;
-
- while (frame)
- {
- //now we can pass the data to the processor(s)
- for (auto p: processors) {
- p->process_frame(frame->data[0],frame->nb_samples);
- }
- sample_processed+=frame->nb_samples;
- //mutex.lock();
- progress=((float)sample_processed)/samples; //atomic on 64 bit?
- //mutex.unlock();
-
- frame=loader.get_frame();
- }
-
- loader.close();
-
- for (auto p: processors) {
- p->cleanup();
- p->print_summary();
- }
-
- logger.information("Finished audio analysis");
- return true;
-}
-bool Render_context::load_video(const string &nodeID,const string &filename){
- //this is a good standard example of how to find
- //a node of a specific type by ID and do something
- if (graph.nodes.find(nodeID)!=graph.nodes.end()){
- if (graph.nodes[nodeID]->type=="video_loader") {
- if (((Video_loader*)graph.nodes[nodeID])->load(filename)) {
- return true;
- }
- }
- }
- return false;
-}
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
deleted file mode 100755
index 8b72c50..0000000
--- a/rotord/rotor.cpp
+++ /dev/null
@@ -1,361 +0,0 @@
-#include "rotor.h"
-#include "nodes_audio_analysis.h"
-#include "nodes_drawing.h"
-
-using namespace Rotor;
-Node_factory::Node_factory(){
- //for now, statically load prototype map in constructor
- add_type("audio_analysis",new Audio_analysis());
- add_type("divide",new Signal_divide());
- add_type("bang",new Is_new_integer());
- add_type("signal_output",new Signal_output());
- add_type("testcard",new Testcard());
- add_type("video_output",new Video_output());
- add_type("video_loader",new Video_loader());
- add_type("on_off",new On_off());
- add_type("invert",new Invert());
- add_type("video_cycler",new Video_cycler());
- add_type("luma_levels",new Luma_levels());
- add_type("echo_trails",new Echo_trails());
- add_type("time",new Time());
- add_type("track_time",new Track_time());
- add_type("comparison",new Comparison()); //TODO: alias to symbols
- add_type("arithmetic",new Arithmetic()); //TODO: alias to symbols
- add_type("signal_colour",new Signal_colour());
- add_type("signal_greyscale",new Signal_greyscale());
- add_type("image_arithmetic",new Image_arithmetic());
- add_type("random",new Random());
- add_type("blend",new Blend());
- add_type("mirror",new Mirror());
- add_type("monochrome",new Monochrome());
- add_type("transform",new Transform());
- add_type("alpha_merge",new Alpha_merge());
- add_type("draw",new Draw());
-}
-
-bool Signal_input::connect(Signal_node* source) {
- if (source->output_type=="signal") {
- connection=(Node*)source;
- return true;
- }
- else return false;
-}
-void Parameter_input::update(const Time_spec& time){ //gets input and updates variable
- if (receiver){
- *receiver=((Signal_node*)connection)->get_output(time);
- }
-}
-bool Image_input::connect(Image_node* source) {
- if (source->output_type=="image") {
- connection=(Node*)source;
- return true;
- }
- else return false;
-}
-void Node::update_params(const Time_spec& time){ //compute connected parameters
- for (auto p:parameter_inputs){
- p->update(time);
- }
-}
-bool Signal_output::render(const float duration, const float framerate,string &xml_out){
- //testing signal routes
- cerr << "Rotor: Signal_output rendering " << duration << " seconds at " << framerate << " frames per second" << endl;
- float step=1.0f/framerate;
- float v=0.0f;
- float min=10000000.0f;
- float max=-10000000.0f;
- for (float f=0.0f;f<duration;f+=step) {
- float u=get_output(Time_spec(f,framerate,duration));
- if (!fequal(u,v)) {
- xml_out+=("<signal time='"+ofToString(f)+"'>"+ofToString(u)+"</signal>\n");
- v=u;
- if (v>max) max=v;
- if (v<min) min=v;
- }
- }
- xml_out+=("<signal_finished min='"+ofToString(min)+"' max='"+ofToString(max)+"'/>\n");
- return true;
-}
-
-bool Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) {
- //base_audio_processor::init(_channels,_bits,_samples);
- channels=_channels;
- bits=_bits;
- samples=_samples;
- samples_per_column=samples/width;
- column=0; //point thumbnail bitmap
- out_sample=0; //sample in whole track
- offset=0x1<<(bits-1); //signed audio
- scale=1.0/offset;
- sample=0;
- samples=0;
- accum=0.0;
- return true;
-}
-int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){
- //begin by processing remaining samples
- //samples per column could be larger than a frame! (probably is)
- //but all we are doing is averaging
- int bytes=(bits>>3);
- int stride=channels*bytes;
- int in_sample=0;
- while (in_sample<samples_in_frame&&column<width) {
- //continue the column
- while (sample<samples_per_column&&in_sample<samples_in_frame) {
- //accumulate samples for this column until we run out of samples
- for (int i=0;i<channels;i++) {
- unsigned int this_val=0;
- for (int j=0;j<bytes;j++) {
- this_val+=_data[(in_sample*stride)+(i*bytes)+j]<<(j*8);
- }
- //convert from integer data format - i.e s16p - to audio signal in -1..1 range
- //presume 16 bits for now...
- double val=((double)((int16_t)this_val))*scale;
- accum+=val*val;
- samples++;
- }
- in_sample++;
- sample++;
- out_sample++;
- }
- if (sample==samples_per_column) { //finished a column
- //get root-mean
- double mean=pow(accum/samples,0.5);
- //if (column==0) {
- // cerr << "first column total: "<< accum << " in " << samples << " samples, average " << (accum/samples)<<endl;
- //}
- int colheight=height*mean*0.5;
- int hh=height>>1;
- for (int i=0;i<height;i++) {
- data[i*width+column]=abs(i-hh)<colheight?0xff:0x00;
- }
- column++;
- sample=0;
- samples=0;
- accum=0.0;
- }
- }
- return out_sample;
-}
-string Audio_thumbnailer::print(){
- //base64 encode the image data output it
-
- stringstream output;
- Poco::Base64Encoder *enc=new Poco::Base64Encoder(output);
-
- enc->write((char*)data,width*height);
- //tring output;
- /*
- for (int j=0;j<height;j++) {
- for (int i=0;i<width;i++) {
- output+=data[j*width+i]<0x7f?"0":"1";
- }
- output +="\n";
- }
- */
- enc->close();
- delete enc;
- return output.str();
-}
-bool Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) {
- //need these to make sense of data
- channels=_channels;
- bits=_bits;
- samples=_samples;
-
- return analyser.init(soname,id,_channels,_bits,_samples,_rate,outputNo,params);
-
-
- //attempt to load vamp plugin and prepare to receive frames of data
- //should the audio analysis contain a vamphost or should it inherit?
- //maybe neater to contain it in terms of headers etc
-
-}
-int Audio_analysis::process_frame(uint8_t *data,int samples_in_frame) {
- analyser.process_frame(data,samples_in_frame);
- return 1;
-}
-void Audio_analysis::cleanup() {
- analyser.cleanup();
- //print_features();
-}
-void Audio_analysis::print_features(){
- for (auto i: analyser.features) {
- cerr<<" ["<<i.second<<":"<<i.first<<"]";
- }
- cerr<<endl;
-}
-
-bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress,int outW,int outH){
-
- //
- //setup defaults
- int bitRate=5000000;
- AVCodecID codecId=AV_CODEC_ID_H264; //MPEG4;
- std::string container ="mp4";
-
-
- //at the moment it crashes if you render before audio is loaded and also on 2nd render
- libav::exporter exporter;
-
- float spct=100.0f/duration;
-
- if (exporter.setup(outW,outH,bitRate,framerate,container)) { //codecId,
- if (exporter.record(output_filename)) {
-
- libav::audioloader audioloader;
-
- bool usingaudio=audioloader.setup(audio_filename);
-
- cerr << "Rotor: Video_output rendering " << duration << " seconds at " << framerate << " fps, audio frame size: " << exporter.get_audio_framesize()<<endl;
- //25fps video and 43.06640625fps audio? hmm
- //how to get the timecodes correct for the interleaved files
-
- struct timeval start, end;
-
- gettimeofday(&start, NULL);
-
-
- float vstep=1.0f/framerate;
- float v=0.0f;
- float vf=0.0f;
- float af=0.0f;
- while (vf<duration){ //-vstep) {
- if (usingaudio) {
- while (!fless(af,vf)) {
- //insert audio frames until we are ahead of the video
- exporter.encodeFrame(audioloader.get_samples(exporter.get_audio_framesize()));
- af+=exporter.get_audio_step();
-
- }
- }
-
-
- //[mp3 @ 0x7fffe40330e0] max_analyze_duration 5000000 reached at 5015510 microseconds
- //[mp3 @ 0x7fffe4033ec0] Insufficient thread locking around avcodec_open/close()
- //[mp3 @ 0x7fffe40330e0] Estimating duration from bitrate, this may be inaccurate
- //[libx264 @ 0x7fffe8003940] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2
- //[libx264 @ 0x7fffe8003940] profile High, level 3.0
- //[libx264 @ 0x7fffe8003940] 264 - core 123 r2189 35cf912 - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=10 keyint_min=1 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=abr mbtree=1 bitrate=400 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
- //Assertion ff_avcodec_locked failed at libavcodec/utils.c:2967
-
- //cerr<<"videoloader: "<<vf<<" seconds, vstep "<<vstep<<" ,asking for frame "<<((int)((vf*framerate)+0.5))<<endl;
-
- Image* i=get_output(Frame_spec(vf,framerate,duration,outW,outH));
- if (i) {
- exporter.encodeFrame(i->RGBdata);
-
- }
- vf+=vstep;
- progress=vf/duration;
- }
-
- exporter.finishRecord();
-
- gettimeofday(&end, NULL);
-
- float mtime = ((end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)/1000000.0) + 0.5;
-
- printf("Rotor Video_output: rendered in %02f seconds\n", mtime);
-
- if (usingaudio) audioloader.close();
-
- return true;
- }
- }
-
- return false;
-}
-
-bool Video_loader::load(const string &filename){
- /*
- //gstreamer needs absolute paths ALWAYS
- //string uri="file:///home/tim/workspace/rotor/rotord/"+filename;
- Poco::Path path;
- string uri="file://"+path.current()+filename;
- //cerr << "video input: loading "<<uri<<endl;
- if (player->loadMovie(uri)){
- player->play();
- player->setPaused(true);
- player->setFrameByFrame(true);
- player->update();
- cerr<<"Rotor::Video_loader: "<<filename<<", "<<player->getDuration()<<" seconds "<<", "<<player->getWidth()<<"x"<<player->getHeight()<<endl;
- image->setup_fromRGB(player->getWidth(),player->getHeight(),(uint8_t*) player->getPixels());
- return true;
- }
- */
- if (isLoaded) {
- player.cleanup(); ///should be in decoder class?
- isLoaded=false;
- }
- Poco::Path path;
- string uri="file://"+filename;
- isLoaded=player.open(uri);
- if (isLoaded){
- cerr<<"Rotor::Video_loader: "<<filename<<", "<<player.getNumberOfFrames()<<" frames "<<", "<<player.getWidth()<<"x"<<player.getHeight()<<endl;
- return true;
- }
- cerr<<"Rotor::Video_loader: failed to load "<<filename<<endl;
- return false;
-}
-Image* Video_loader::output(const Frame_spec &frame){
- //wonder about the actual mechanism used by gstreamer
- //have to implment callback when seek is ready?
- //presume gstreamer caches a loaded frame?
-
-
- //deal with reolution: swscale from avcodec or put scaler in pipeline?
- //can image node point to buffer in gst rather than copying the pixels?
-
- //to test using fp time to seek: need a short movie with synced audio
-
- //fix actual duration and audio file
- //trace frame that is being read
- /*
- if (player->isLoaded()){
- //player->setPosition(frame.time);
- int wanted=((int) (frame.time*frame.framerate))%(player->getTotalNumFrames()-2); //-2??
- player->setFrame(wanted);
- //while (player->getCurrentFrame()!=wanted){
- // cerr << "seeking to "<<wanted<<" :"<<player->getCurrentFrame()<<endl;
- //player->setFrame(wanted);
- //player->update();
- // sleep(.001);
- //}
- player->update();
- image->RGBdata=player->getPixels(); //don't really know why this is needed every frame
- //cerr<<"Video_loader: retrieving frame "<<((int) (frame.time*frame.framerate))<<endl;
- return image;
- }
- */
-
- if (isLoaded){
- int wanted=(((int) ((frame.time*frame.framerate)+0.5))%(player.getNumberOfFrames())); //+1 is necessary because 1st frame in a video is number 1?
-
-
- //if (wanted==99){
- // cerr<<"videoloader: near the end"<<endl;
- //}
-
- //cerr<<"videoloader: requesting frame "<<wanted<<endl;
- //if (wanted==68) {
- // int nothing=0;
- //}
-
- if (!player.fetchFrame(frame.w,frame.h,wanted)) { //seek fail
- cerr<<"Rotor: failed to seek frame"<<endl;
- if (image.w>0) return &image; //just return the previous frame if possible
- else return nullptr;
- };
- //cerr<<"Video_loader: setting up frame: lineoffset="<<(player.pFrameRGB->linesize[0]-(frame.w*3))<<endl;
- image.setup_fromRGB(frame.w,frame.h,player.pFrameRGB->data[0],player.pFrameRGB->linesize[0]-(frame.w*3));
- return &image;
- }
-
- //confusingly, crashes with files not made with short files?
- //seems to be on last frame? - returns nullptr - still tries to clone?
- //can't really return 1st frame instead, should get # of frames right 1st?
- //think about what echo trails does on the last frame
-
- return nullptr;
-};
diff --git a/rotord/rotor.h b/rotord/rotor.h
deleted file mode 100755
index f922fcf..0000000
--- a/rotord/rotor.h
+++ /dev/null
@@ -1,1391 +0,0 @@
-#ifndef ROTOR_H
-#define ROTOR_H
-
-/*
-nodes can have many inputs but only 1 output
-
-image nodes that use an image as input can pass on the incoming image only if its unchanged.
-
-TODO - parameter class that automatically links variable to correctly named inputs
-TODO - use try.. catch and dynamic_cast to verify node connections rather than checking 'type' tag
-
-TODO - put the boilerplate code for checking inputs into the base class, finally call checked_output
-
-http://stackoverflow.com/questions/5261658/how-to-seek-in-ffmpeg-c-c
-*/
-
-#include <unordered_map>
-#include <deque>
-#include <math.h>
-#include <memory>
-#include <sys/time.h>
-#include <iostream>
-
-#include "Poco/Net/HTTPServer.h"
-#include "Poco/Net/HTTPResponse.h"
-#include "Poco/UUID.h"
-#include "Poco/UUIDGenerator.h"
-#include "Poco/Notification.h"
-#include "Poco/NotificationCenter.h"
-#include "Poco/Observer.h"
-#include "Poco/ThreadPool.h"
-#include "Poco/Thread.h"
-#include "Poco/Task.h"
-#include "Poco/Runnable.h"
-#include "Poco/Mutex.h"
-#include "Poco/Random.h"
-#include "Poco/AutoPtr.h"
-#include "Poco/File.h"
-#include "Poco/Base64Encoder.h"
-#include "Poco/Path.h"
-#include "Poco/StringTokenizer.h"
-#include "Poco/Logger.h"
-
-
-using Poco::UUID;
-using Poco::UUIDGenerator;
-using Poco::Net::HTTPResponse;
-using Poco::Logger;
-
-/*
-extern "C" {
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #include <libavutil/opt.h>
- #include <libavutil/channel_layout.h>
- #include <libavutil/common.h>
- #include <libavutil/imgutils.h>
- #include <libavutil/mathematics.h>
- #include <libavutil/samplefmt.h>
-
- #include <libavutil/dict.h>
- //#include <libavutil/dict.c> stops the compiler error but causes a linker error. does libavcodec need to be statically linked?
- #include <libavutil/imgutils.h>
- #include <libavutil/samplefmt.h>
- //#include <libavutil/timestamp.h>
-}
-*/
-
-
-#define AUDIO_INBUF_SIZE 20480
-#define AUDIO_REFILL_THRESH 4096
-
-#include "xmlIO.h"
-#include "utils.h" //fequal
-#include "libavwrapper.h"
-#include "cvimage.h"
-
-namespace Rotor {
- #define IDLE 0
- #define ANALYSING_AUDIO 1
- #define AUDIO_READY 2
- #define CREATING_PREVIEW 3
- #define PREVIEW_READY 4
- #define RENDERING 5
- #define RENDER_READY 6
-
- #define ANALYSE_AUDIO 1
- #define PREVIEW 2
- #define RENDER 3
-
- //forward declaration
- class Node;
- class Signal_node;
- class Image_node;
- class Parameter_input;
-
- //http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/
- /* struct Packet {
- explicit Packet(AVFormatContext* ctxt = nullptr) {
- av_init_packet(&packet);
- packet.data = nullptr;
- packet.size=0;
- if (ctxt) reset(ctxt);
- }
-
- Packet(Packet&& other) : packet(std::move(other.packet)) {
- other.packet.data = nullptr;
- }
-
- ~Packet() {
- if (packet.data)
- av_free_packet(&packet);
- }
-
- void reset(AVFormatContext* ctxt) {
- if (packet.data)
- av_free_packet(&packet);
- if (av_read_frame(ctxt, &packet) < 0)
- packet.data = nullptr;
- }
-
- AVPacket packet;
- };
- */
- class Time_spec{
- public:
- Time_spec(){};
- Time_spec(float _time,float _framerate,float _duration){ time=_time; framerate=_framerate; duration=_duration;};
- float time;
- float framerate;
- float duration;
- Time_spec lastframe() const{
- return Time_spec(time-(1.0f/framerate),framerate,duration);
- }
- };
- class Frame_spec: public Time_spec{
- public:
- Frame_spec(float _time,float _framerate,float _duration,int _w,int _h){ time=_time; framerate=_framerate; duration=_duration; w=_w; h=_h;};
- Frame_spec(int _frame,float _framerate,float _duration,int _w,int _h){ time=((float)_frame)/_framerate; framerate=_framerate; duration=_duration; w=_w; h=_h;};
- //Frame_spec(time,_framerate,_duration,_w,_h);};
-
- //float time; //this hould probably be implemented with a num/denom scheme eventually for accuracy
- //float framerate;
- int h,w;
- //Frame_spec lastframe(){
- // return Frame_spec(time-(1.0f/framerate),framerate,w,h);
- //}
- int frame(){
- return (int)((time*framerate)+0.5); //rounded to the nearest frame
- }
- };
- class Colour{
- public:
- Colour(){
- r=g=b=0;
- }
- Colour(int c){
- r=c&0xFF;
- g=(c&0xFF00)>>8;
- b=(c&0xFF0000)>>16;
- }
- Colour(std::string s){
- r=(uint8_t)ofHexToChar(s.substr(0,2));
- g=(uint8_t)ofHexToChar(s.substr(2,2));
- b=(uint8_t)ofHexToChar(s.substr(4,2));
- }
- uint8_t r,g,b;
- };
-
- class Render_status{
- public:
- int id;
- float progress;
- };
- class Render_requirements{
- public:
- int num_performances;
- int num_clips;
- };
- class Command_response{
- public:
- Command_response() { status=Poco::Net::HTTPResponse::HTTP_OK; }
- std::string description;
- Poco::Net::HTTPResponse::HTTPStatus status;
- };
- class Input{
- public:
- Input(const string &_desc): connection(nullptr),description(_desc){};
- Node* connection;
- string description;
- };
- class Image_input: public Input{
- public:
- bool connect(Image_node *source);
- Image_input(const string &_desc): Input(_desc){};
- };
- class Signal_input: public Input{
- public:
- bool connect(Signal_node *source);
- Signal_input(const string &_desc): Input(_desc){};
- };
- class Parameter_input: public Signal_input{
- public:
- Parameter_input(const string &_param,const string &_desc): Signal_input(_desc),receiver(nullptr),parameter(_param){};
- float *receiver;
- void update(const Time_spec& time);
- string parameter;
- };
- class Node{
- public:
- virtual Node* clone(map<string,string> &_settings)=0;
- virtual ~Node(){};
- UUID uid; //every usable node has a UUID
- int id;
- vector<Signal_input*> inputs; //simple node can have signal inputs, output depends on node type
- vector<Parameter_input*> parameter_inputs; //linked parameters can convert from settings to inputs
- void create_signal_input(const string &description) {inputs.push_back(new Signal_input(description));};
- void create_parameter_input(const string &parameter,const string &description) {parameter_inputs.push_back(new Parameter_input(parameter,description));};
- string description;
- string type;
- string output_type;
- string ID;
- string find_setting(map<string,string> &settings,string key,string def=""){ if (settings.find(key)!=settings.end()) return settings[key]; else return def;};
- float find_setting(map<string,string> &settings,string key,float def){ if (settings.find(key)!=settings.end()) return ofToFloat(settings[key]); else return def;};
- int find_setting(map<string,string> &settings,string key,int def){ if (settings.find(key)!=settings.end()) return ofToInt(settings[key]); else return def;};
- void base_settings(map<string,string> &settings) {
- description=find_setting(settings,"description");
- type=find_setting(settings,"type");
- output_type=find_setting(settings,"output");
- ID=find_setting(settings,"ID");
- }
- virtual void set_parameter(const std::string &key,const std::string &value){};
- virtual void link_params(){}; //TODO make param classes that link automatically
- void update_params(const Time_spec& time);
- };
- class Signal_node: public Node{
- public:
- virtual ~Signal_node(){};
- const float get_output(const Time_spec &time) { update_params(time); return output(time); };
- virtual const float output(const Time_spec &time) { return 0.0f; };
- };
- class Image_node: public Node{
- public:
- virtual ~Image_node(){};
- vector<Image_input*> image_inputs; //image node also has image inputs and outputs
- void create_image_input(const string &description) {image_inputs.push_back(new Image_input(description));};
- Image *get_output(const Frame_spec &frame) { update_params((Time_spec)frame); return output(frame); };
- virtual const Image *output(const Frame_spec &frame)=0;
- Image *get_preview(const Frame_spec &frame);
- Image *image; //this can be privately allocated or just passed on as the node see fit
- private:
- float image_time;
- };
- class Base_audio_processor: public Signal_node {
- public:
- virtual ~Base_audio_processor(){};
- virtual int process_frame(uint8_t *data,int samples)=0;
- virtual bool init(int _channels,int _bits,int _samples,int _rate)=0;
- virtual void cleanup()=0;
- virtual void print_summary(){};
- int channels,bits,samples,rate;
- };
- //actual nodes-------------------------------------------------
- class Time: public Signal_node {
- public:
- Time(){};
- Time(map<string,string> &settings) {
- base_settings(settings);
- };
- Time* clone(map<string,string> &_settings) { return new Time(_settings);};
- const float output(const Time_spec &time) {
- return time.time;
- }
- };
- class Track_time: public Signal_node {
- public:
- Track_time(){};
- Track_time(map<string,string> &settings) {
- base_settings(settings);
- };
- Track_time* clone(map<string,string> &_settings) { return new Track_time(_settings);};
- const float output(const Time_spec &time) {
- return time.time/time.duration;
- }
- };
-#define COMPARISON_Equal 1
-#define COMPARISON_Not_equal 2
-#define COMPARISON_Greater 3
-#define COMPARISON_Less 4
-#define COMPARISON_Greater_or_equal 5
-#define COMPARISON_Less_or_equal 6
- class Comparison: public Signal_node {
- public:
- Comparison(){};
- Comparison(map<string,string> &settings) {
- base_settings(settings);
- value=find_setting(settings,"value",0.0f);
- string _op=find_setting(settings,"operator","==");
- if (_op=="==") op=COMPARISON_Equal;
- if (_op=="!=") op=COMPARISON_Not_equal;
- if (_op==">") op=COMPARISON_Greater;
- if (_op=="<") op=COMPARISON_Less;
- if (_op==">=") op=COMPARISON_Greater_or_equal;
- if (_op=="<=") op=COMPARISON_Less_or_equal;
- }
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="value") p->receiver=&value;
- }
- };
- Comparison* clone(map<string,string> &_settings) { return new Comparison(_settings);};
- const float output(const Time_spec &time) {
- if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
- if (inputs[0]->connection) {
- float in= (((Signal_node*)inputs[0]->connection)->get_output(time));
- switch (op) {
- case COMPARISON_Equal:
- return fequal(value,in)?1.0f:0.0f;
- break;
- case COMPARISON_Not_equal:
- return fequal(value,in)?0.0f:1.0f;
- break;
- case COMPARISON_Greater:
- return fgreater(value,in)?1.0f:0.0f;
- break;
- case COMPARISON_Less:
- return fless(value,in)?1.0f:0.0f;
- break;
- case COMPARISON_Greater_or_equal:
- return fgreater_or_equal(value,in)?1.0f:0.0f;
- break;
- case COMPARISON_Less_or_equal:
- return fless_or_equal(value,in)?1.0f:0.0f;
- break;
- }
- }
- }
- return 0.0f;
- }
- int op;
- float value;
- };
-#define ARITHMETIC_plus 1
-#define ARITHMETIC_minus 2
-#define ARITHMETIC_multiply 3
-#define ARITHMETIC_divide 4
-#define ARITHMETIC_modulo 5
- class Arithmetic: public Signal_node {
- public:
- Arithmetic(){};
- Arithmetic(map<string,string> &settings) {
- base_settings(settings);
- value=find_setting(settings,"value",0.0f);
- string _op=find_setting(settings,"operator","+");
- if (_op=="+") op=ARITHMETIC_plus;
- if (_op=="-") op=ARITHMETIC_minus;
- if (_op=="*") op=ARITHMETIC_multiply;
- if (_op=="/") op=ARITHMETIC_divide;
- if (_op=="%") op=ARITHMETIC_modulo;
- }
- void link_params() {
- for (auto p:parameter_inputs){
- p->receiver=nullptr;
- if (p->parameter=="value") p->receiver=&value;
- }
- };
- Arithmetic* clone(map<string,string> &_settings) { return new Arithmetic(_settings);};
- const float output(const Time_spec &time) {
- if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
- if (inputs[0]->connection) {
- float in= (((Signal_node*)inputs[0]->connection)->get_output(time));
- switch (op) {
- case ARITHMETIC_plus:
- return in+value;
- break;
- case ARITHMETIC_minus:
- return in-value;
- break;
- case ARITHMETIC_multiply:
- return in*value;
- break;
- case ARITHMETIC_divide:
- return in/value;
- break;
- case ARITHMETIC_modulo:
- return fmod(in,value);
- break;
- }
- }
- }
- return 0.0f;
- }
- int op;
- float value;
- };
- class Signal_divide: public Signal_node {
- public:
- Signal_divide(){};
- Signal_divide(map<string,string> &settings) {
- base_settings(settings);
- divide_amount=ofToFloat(find_setting(settings,"amount"));
- for (auto p:parameter_inputs){
- if (p->parameter=="amount") p->receiver=&divide_amount;
- }
- };
- Signal_divide* clone(map<string,string> &_settings) { return new Signal_divide(_settings);};
- const float output(const Time_spec &time) {
- if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
- if (inputs[0]->connection) {
- return (((Signal_node*)inputs[0]->connection)->get_output(time))/divide_amount;
- }
- }
- return 0.0f;
- }
- float divide_amount;
- };
- class Is_new_integer: public Signal_node {
- public:
- Is_new_integer(){};
- Is_new_integer(map<string,string> &settings) {
- base_settings(settings);
- };
- Is_new_integer* clone(map<string,string> &_settings) { return new Is_new_integer(_settings);};
- const float output(const Time_spec &time) {
- if (inputs[0]->connection) {
- float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time));
- float s2=(((Signal_node*)(inputs[0]->connection))->get_output(time.lastframe()));
- if (((int)s1)>((int)s2)) {
- return 1.0f;
- }
- }
- return 0.0f;
- }
- };
- class On_off: public Signal_node {
- public:
- On_off(){};
- On_off(map<string,string> &settings) {
- base_settings(settings);
- };
- On_off* clone(map<string,string> &_settings) { return new On_off(_settings);};
- const float output(const Time_spec &time) {
- if (inputs[0]->connection) {
- float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time));
- if ((int)s1%2) return 1.0f;
- }
- return 0.0f;
- }
- };
- //pseudo random repeatable hash function
- //http://create.stephan-brumme.com/fnv-hash/
- const uint32_t Prime = 0x01000193; // 16777619
- const uint32_t Seed = 0x811C9DC5; // 2166136261
- /// hash a byte
- inline uint32_t fnv1a(unsigned char oneByte, uint32_t hash = Seed)
- {
- return (oneByte ^ hash) * Prime;
- }
- /// hash a short (two bytes)
- inline uint32_t fnv1a(unsigned short twoBytes, uint32_t hash = Seed)
- {
- const unsigned char* ptr = (const unsigned char*) &twoBytes;
- hash = fnv1a(*ptr++, hash);
- return fnv1a(*ptr , hash);
- }
- /// hash a 32 bit integer (four bytes)
- inline uint32_t fnv1a(uint32_t fourBytes, uint32_t hash = Seed)
- {
- const unsigned char* ptr = (const unsigned char*) &fourBytes;
- hash = fnv1a(*ptr++, hash);
- hash = fnv1a(*ptr++, hash);
- hash = fnv1a(*ptr++, hash);
- return fnv1a(*ptr , hash);
- }
- class Random: public Signal_node {
- public:
- Random(){};
- Random(map<string,string> &settings) {
- base_settings(settings);
- seed=(Seed+find_setting(settings,"seed",0));
- cerr<<"random:: seed "<<seed<<" ("<<Seed<<")"<<endl;
- };
- Random* clone(map<string,string> &_settings) { return new Random(_settings);};
- const float output(const Time_spec &time) {
- if (inputs.size()) {
- if (inputs[0]->connection) {
-
- //hash the integer part and add the fractional part back on
- float o=(((Signal_node*)inputs[0]->connection)->get_output(time));
- uint32_t m=(int)o;
- return ((float)(fnv1a(m,seed)%((uint32_t)time.duration)))+(o-m);
- }
- }
- return 0.0f;
- }
- uint32_t seed;
- private:
- };
- class Signal_output: public Signal_node {
- public:
- Signal_output(){};
- Signal_output(map<string,string> &settings) {
- base_settings(settings);
- };
- Signal_output* clone(map<string,string> &_settings) { return new Signal_output(_settings);};
- bool render(const float duration, const float framerate,string &xml_out);
- const float output(const Time_spec &time) {
- if (inputs[0]->connection) {
- return ((Signal_node*)(inputs[0]->connection))->get_output(time);
- }
- else return 0.0f;
- }
- };
- class Testcard: public Image_node {
- public:
- Testcard(){image=nullptr;};
- Testcard(map<string,string> &settings) {
- base_settings(settings);
- image=new Image();
- };
- ~Testcard(){ if (image) delete image;};
- Testcard* clone(map<string,string> &_settings) { return new Testcard(_settings);};
- Image *output(const Frame_spec &frame){
- if (image->setup(frame.w,frame.h)) {
-
- }
- //always create testcard
- //float ws=(255.0f/frame.w);
- float hs=(255.0f/frame.h);
- for (int i=0;i<frame.h;i++){
- for (int j=0;j<frame.w;j++){
- image->RGBdata[(i*frame.w+j)*3]=(uint8_t)((int)((i+(frame.time*25.0f)*hs))%255);
- image->RGBdata[((i*frame.w+j)*3)+1]=(uint8_t)((int)((j+(frame.time*100.0f)*hs))%255);
- image->RGBdata[((i*frame.w+j)*3)+2]=(uint8_t)(0);
- //image->Adata[i*frame.w+j]=(uint8_t)255;
- //image->Zdata[i*frame.w+j]=(uint16_t)512; //1.0 in fixed point 8.8 bits
- }
- }
- return image;
- }
- private:
- Image *image; //is an image generator
- };
- class Invert: public Image_node {
- public:
- Invert(){image=nullptr;};
- Invert(map<string,string> &settings) {
- base_settings(settings);
- image=new Image();
- };
- ~Invert(){ if (image) delete image;};
- Invert* clone(map<string,string> &_settings) { return new Invert(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- if (inputs[0]->connection) {
- if (fgreater_or_equal(1.0f,(((Signal_node*)inputs[0]->connection)->get_output((Time_spec)frame)))) {
- Image *in=(((Image_node*)image_inputs[0]->connection)->get_output(frame));
- if (in){
- image->setup(frame.w,frame.h);
- for (int i=0;i<in->w*in->h*3;i++) {
- image->RGBdata[i]=255-in->RGBdata[i];
- }
- return image;
- }
- }
- }
- return (((Image_node*)image_inputs[0]->connection)->get_output(frame));
- }
-
- }
- if (image_inputs[0]->connection) {
- return image;
- }
- return nullptr;
- }
- private:
- Image *image; //is an image generator
- //bool invert;
- };
- class Video_output: public Image_node {
- public:
- Video_output(){};
- Video_output(map<string,string> &settings) {
- base_settings(settings);
- };
- ~Video_output(){ };
- Image *output(const Frame_spec &frame){
- if (image_inputs[0]->connection) {
- return ((Image_node*)(image_inputs[0]->connection))->get_output(frame);
- }
- else return nullptr;
- };
- Video_output* clone(map<string,string> &_settings) { return new Video_output(_settings);};
- bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress,int w,int h);
-
- private:
-
- };
- class Video_loader: public Image_node {
- public:
- Video_loader(){};
- Video_loader(map<string,string> &settings) {
- base_settings(settings);
- isLoaded=false;
- };
- ~Video_loader(){};
- bool load(const string &filename);
- Image *output(const Frame_spec &frame);
- Video_loader* clone(map<string,string> &_settings) { return new Video_loader(_settings);};
- bool isLoaded;
- private:
- libav::decoder player;
- Image image;
- };
- class Video_cycler: public Image_node {
- //cycles through video inputs in order
- public:
- Video_cycler(){};
- Video_cycler(map<string,string> &settings) {
- base_settings(settings);
- };
- ~Video_cycler(){};
- bool load(const string &filename);
- Image *output(const Frame_spec &frame){
- int which_input=0;
- if (inputs[0]->connection) {
- which_input=((int)((Signal_node*)inputs[0]->connection)->get_output((Time_spec)frame))%image_inputs.size();
- }
- if (image_inputs.size()) {
- if (image_inputs[which_input]->connection){
- return (((Image_node*)image_inputs[which_input]->connection)->get_output(frame));
- }
- }
- return nullptr;
- }
- Video_cycler* clone(map<string,string> &_settings) { return new Video_cycler(_settings);};
- private:
- };
- class Signal_colour: public Image_node {
- //cycles through video inputs in order
- public:
- Signal_colour(){};
- Signal_colour(map<string,string> &settings) {
- base_settings(settings);
- string colours=find_setting(settings,"palette","");
- for (int i=0;i<colours.size()/6;i++){
- palette.push_back(Colour(colours.substr(i*6,6)));
- }
- for (auto i: palette) {
- cerr << "Signal_colour found palette colour: "<<(int)i.r<<" "<<(int)i.g<<" "<<(int)i.b<<endl;
- }
- prevcol=-1;
- };
- ~Signal_colour(){};
- Image *output(const Frame_spec &frame){
- if (palette.size()) {
- if (inputs.size()) {
- if (inputs[0]->connection){
- int col= ((int)(((Signal_node*)inputs[0]->connection)->get_output(frame)))%palette.size();
- if (col!=prevcol||image.w!=frame.w||image.h!=frame.h){
- image.setup(frame.w,frame.h);
- for (int i=0;i<image.w*image.h;i++){
- image.RGBdata[i*3]=palette[col].r;
- image.RGBdata[i*3+1]=palette[col].g;
- image.RGBdata[i*3+2]=palette[col].b;
- }
- prevcol=col;
- }
- return &image;
- }
- }
- }
- return nullptr;
- }
- Signal_colour* clone(map<string,string> &_settings) { return new Signal_colour(_settings);};
- private:
- vector<Rotor::Colour> palette;
- Image image;
- int prevcol;
- };
- class Signal_greyscale: public Image_node {
- //Draws signal bars in greyscale
- public:
- Signal_greyscale(){};
- Signal_greyscale(map<string,string> &settings) {
- base_settings(settings);
- prevcol=-1;
- };
- ~Signal_greyscale(){};
- Image *output(const Frame_spec &frame){
- if (inputs.size()) {
- if (inputs[0]->connection){
- float sig= ((((Signal_node*)inputs[0]->connection)->get_output(frame)));
- uint8_t col=255-((uint8_t)(sig*255.0f));
- if (col!=prevcol||image.w!=frame.w||image.h!=frame.h){
- image.setup(frame.w,frame.h);
- for (int i=0;i<image.w*image.h*3;i++){
- image.RGBdata[i]=col;
- }
- prevcol=col;
- }
- return &image;
- }
- }
- return nullptr;
- }
- Signal_greyscale* clone(map<string,string> &_settings) { return new Signal_greyscale(_settings);};
- private:
- Image image;
- uint8_t prevcol;
- };
- class Image_arithmetic: public Image_node {
- //Draws signal bars in greyscale
- public:
- Image_arithmetic(){image=nullptr;};
- Image_arithmetic(map<string,string> &settings) {
- base_settings(settings);
- value=find_setting(settings,"value",0.0f);
- string _op=find_setting(settings,"operator","+");
- if (_op=="+") op=ARITHMETIC_plus;
- if (_op=="-") op=ARITHMETIC_minus;
- if (_op=="*") op=ARITHMETIC_multiply;
- if (_op=="/") op=ARITHMETIC_divide;
- //if (_op=="%") op=ARITHMETIC_modulo; ??what would this even mean?
- image=nullptr;
- cerr<<"image_arithmetic: mode "<<op<<", value "<<value<<endl;
- }
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="value") {
- p->receiver=&value;
- }
- }
-
- };
- ~Image_arithmetic(){if (image) delete image;};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- if (image) delete image; //from the previous frame- this may not be ideal
- //because operator* made a new image it should be deleted
- Image *in=(((Image_node*)image_inputs[0]->connection)->get_output(frame));
- switch (op) {
- case ARITHMETIC_plus:
- image=(*in)+value;
- break;
- case ARITHMETIC_minus:
- image=(*in)-value;
- break;
- case ARITHMETIC_multiply:
- image=(*in)*value;
- break;
- case ARITHMETIC_divide:
- image=(*in)/value;
- break;
- }
- return image;
- }
- }
- return nullptr;
- }
- Image_arithmetic* clone(map<string,string> &_settings) { return new Image_arithmetic(_settings);};
- private:
- Image *image;
- float value;
- int op;
- };
-
- class Luma_levels: public Image_node {
- //applies LUT To RGB channels equally
- public:
- Luma_levels(){LUT=nullptr;image=nullptr;};
- Luma_levels(map<string,string> &settings) {
- base_settings(settings);
- levels_settings(settings);
- image=new Image();
- }
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="black_in") p->receiver=&black_in;
- if (p->parameter=="white_in") p->receiver=&white_in;
- if (p->parameter=="gamma") p->receiver=&gamma;
- if (p->parameter=="black_out") p->receiver=&black_out;
- if (p->parameter=="white_out") p->receiver=&white_out;
- }
- };
- ~Luma_levels(){if (LUT) {delete[] LUT;} if (image) delete image; };
- void levels_settings(map<string,string> &settings){
- black_in=find_setting(settings,"black_in",0.0f);
- white_in=find_setting(settings,"white_in",1.0f);
- gamma=find_setting(settings,"gamma",1.0f);
- black_out=find_setting(settings,"black_out",0.0f);
- white_out=find_setting(settings,"white_out",1.0f);
- LUT=nullptr;
- generate_LUT();
- }
- void generate_LUT(){ //check this
- if (LUT) delete[] LUT;
- LUT=new unsigned char[256];
- float fltmax=(255.0f/256.0f);
- for (int i=0;i<256;i++){
- LUT[i]=(unsigned char)(((pow(min(fltmax,max(0.0f,(((((float)i)/256.0f)-black_in)/(white_in-black_in)))),(1.0/gamma))*(white_out-black_out))+black_out)*256.0f);
- }
- }
- void apply_LUT(const Image& in){
- apply_LUT(in,*image);
- }
- void apply_LUT(const Image& in,Image &out){ //facility to apply to other images for inherited classes
- out.setup(in.w,in.h);
- for (int i=0;i<out.w*out.h*3;i++){
- out.RGBdata[i]=LUT[in.RGBdata[i]];
- }
- }
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- if (LUT) {
- apply_LUT(*(((Image_node*)image_inputs[0]->connection)->get_output(frame)));
- return image;
- }
- }
- }
- return nullptr;
- }
- Luma_levels* clone(map<string,string> &_settings) { return new Luma_levels(_settings);};
- protected:
- unsigned char *LUT;
- Image *image;
- float black_in,white_in,gamma,black_out,white_out;
- };
- class Echo_trails: public Luma_levels {
- //draw trail frames additively that fade off over time
- //the hard thing here is how to cache frames, if its done cleverly it could have no impact when
- //used linearly
- //Image needs to overload operator+
- //need a clever data structure to cache frames - maybe a map of Image pointers
-
- //we know the frames we want to overlay as offsets ie -25,-20,-15,-10,-5
- //do we keep 25 frames loaded in order to benefit? 25 PAL frames is 60MB so probably so
- //OK so:
- //make a new set of pointers
- //identify if any of the new pointers can inherit old frames
- //delete unneeded old frames
- //load new frames
- //do the calculations
-
- //new set of pointers? or track frames by absolute frame number?
- //with relative pointers and switching frames, could use auto_ptr?
-
- //this cache mechanism should maybe be inheritable too?
-
- //it could be hugely beneficial to only do the LUT once?
- //although maybe the way to do the fading is to have a LUT for each frame?
-
- //or is it actually best to use alpha keying after all!
- public:
- Echo_trails(){image=nullptr;};
- Echo_trails(map<string,string> &settings) {
- base_settings(settings);
- //duration=find_setting(settings,"duration",1.0f);
- number=find_setting(settings,"number",1);
- fadeto=find_setting(settings,"fadeto",1.0f);
- levels_settings(settings);
- image=nullptr;
- lastframe=-1;
- mode=find_setting(settings,"mode",0.0f);
- }
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="black_in") p->receiver=&black_in;
- if (p->parameter=="white_in") p->receiver=&white_in;
- if (p->parameter=="gamma") p->receiver=&gamma;
- if (p->parameter=="black_out") p->receiver=&black_out;
- if (p->parameter=="white_out") p->receiver=&white_out;
-
- //TODO: control an integer
- if (p->parameter=="mode") p->receiver=&mode;
- }
- };
- //~Echo_trails(){if (image) {delete image;} };
- ~Echo_trails(){
- if (image) delete image;
- for (auto i:images) {if (image) delete i.second;}
- };
- Image *output(const Frame_spec &frame){
- //check if cache is valid
- if (images.size()){
- if (frame.w!=image->w||frame.h!=image->h){ //or framerate changed?
- //clear cache and start over
- images.clear();
- lastframe=-1;
- //calculate frame interval
- //interval=(int)(((duration/number)*frame.framerate)+0.5);
- //total=interval*number;
- }
- }
- int thisframe=frame.frame();
- //iterate cache and throw out any obsolete frames
- auto i = std::begin(images);
- while (i != std::end(images)) {
- // check if the image is in the range we need
- if (thisframe-(*i).first>number||thisframe-(*i).first<0) {
- delete (*i).second;
- i = images.erase(i);
- }
- else
- ++i;
- }
- //if frame has already been calculated just return it
- if (thisframe==lastframe) {
- return image;
- }
- else {
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- if (LUT) {
- //need a better strategy here, should be able to get each image once
- //copy incoming image **writable
- if (image) image->free();
- image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
- images[thisframe]=new Image(frame.w,frame.h);
- apply_LUT(*(image),*(images[thisframe]));
- for (int i=1;i<number;i++){
- //check echo frame isn't at negative time
- int absframe=thisframe-i;
- if (absframe>-1){
- //check if image is in the cache
- if (images.find(absframe)==images.end()){
- images[absframe]=new Image(frame.w,frame.h);
- Frame_spec wanted=Frame_spec(absframe,frame.framerate,frame.duration,frame.w,frame.h);
- apply_LUT(*(((Image_node*)image_inputs[0]->connection)->get_output(wanted)),*(images[absframe]));
- }
- //cerr<<"Rotor: about to apply image ("<<images[absframe].w<<"x"<<images[absframe].h<<")"<<endl;
- if (fless(1.0f,fadeto)){
- float amount=((((float)number-i)/number)*(1.0f-fadeto))+(1.0f-fadeto);
- Image *temp=*images[absframe]*amount;
- if (mode<0.5) {
- (*image)+=*temp;
- }
- else {
- image->add_wrap(*temp);
- }
- delete temp;
- }
- else {
- if (mode<0.5) (*image)+=*(images[absframe]);
- else (*image)=image->add_wrap(*(images[absframe]));
- }
- }
- }
- //for (int i=0;i<frame.w*frame.h*3;i++){
- // image->RGBdata[i]=LUT[in->RGBdata[i]];
- //}
- lastframe=thisframe;
- return image;
- }
- }
- }
- }
- return nullptr;
- }
- Echo_trails* clone(map<string,string> &_settings) { return new Echo_trails(_settings);};
- protected:
- float duration,fadeto;
- int number;
- int interval,total,lastframe; //number of frames between displayed echoes
- unordered_map<int,Image*> images;
- float mode; //TODO make int, enum string parameter types
- };
- #define BLEND_screen 1
- #define BLEND_multiply 2
- #define BLEND_blend 3
- #define BLEND_alpha 4
- #define BLEND_screen_wrap 5
- #define BLEND_multiply_wrap 6
- #define BLEND_xor 7
- class Blend: public Image_node {
- public:
- Blend(){image=nullptr;};
- Blend(map<string,string> &settings) {
- base_settings(settings);
- image=nullptr;
- amount=find_setting(settings,"amount",1.0f);
- string _mode=find_setting(settings,"mode","screen");
- if (_mode=="screen") mode=BLEND_screen;
- if (_mode=="multiply") mode=BLEND_multiply;
- if (_mode=="blend") mode=BLEND_blend;
- if (_mode=="alpha") mode=BLEND_alpha;
- if (_mode=="screen_wrap") mode=BLEND_screen_wrap;
- if (_mode=="multiply_wrap") mode=BLEND_multiply_wrap;
- if (_mode=="xor") mode=BLEND_xor;
- };
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="amount") p->receiver=&amount;
- }
- };
- ~Blend(){ if (image) delete image;};
- Blend* clone(map<string,string> &_settings) { return new Blend(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- if (image_inputs.size()>1) {
- if (image_inputs[1]->connection) {
- //copy incoming image **writable
- if (image) delete image;
- image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
- switch(mode){
- case BLEND_screen:
- (*image)+=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_multiply:
- (*image)*=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_xor:
- (*image)^=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_alpha:
- (*image)=(*image).alpha_blend(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_screen_wrap:
- (*image)=(*image).add_wrap(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_multiply_wrap:
- (*image)=(*image).divide_wrap(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
- break;
- case BLEND_blend: //has to be last because of initialser of *in? go figure
- (*image)*=(1.0f-amount);
- Image *in=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)))*amount;
- (*image)+=(*in);
- delete in;
- break;
-
- }
- return image;
- }
- }
- //if there aren't 2 image inputs connected just return the first
- return (((Image_node*)image_inputs[0]->connection)->get_output(frame));
- }
- }
- return nullptr;
- }
- private:
- Image *image; //is an image generator
- int mode;
- float amount; //for blend
- };
- #define MIRROR_horiz 1
- #define MIRROR_vert 2
- #define MIRROR_horizR 3
- #define MIRROR_vertR 4
- class Mirror: public Image_node {
- public:
- Mirror(){image=nullptr;};
- Mirror(map<string,string> &settings) {
- base_settings(settings);
- image=nullptr;
- string _mode=find_setting(settings,"mode","horiz");
- if (_mode=="horiz") mode=MIRROR_horiz;
- if (_mode=="vert") mode=MIRROR_vert;
- if (_mode=="horizR") mode=MIRROR_horizR;
- if (_mode=="vertR") mode=MIRROR_vertR;
- };
- ~Mirror(){ if (image) delete image;};
- Mirror* clone(map<string,string> &_settings) { return new Mirror(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- //copy incoming image **writable
- if (image) delete image;
- image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
- switch (mode) {
- case MIRROR_horiz:
- for (int i=0;i<image->w/2;i++){
- for (int j=0;j<image->h;j++){
- for (int k=0;k<3;k++){
- image->RGBdata[(((j*image->w)+((image->w/2)+i))*3)+k]=image->RGBdata[(((j*image->w)+((image->w/2)-i))*3)+k];
- }
- }
- }
- break;
- case MIRROR_vert:
- for (int i=0;i<image->w;i++){
- for (int j=0;j<image->h/2;j++){
- for (int k=0;k<3;k++){
- image->RGBdata[((((image->h/2+j)*image->w)+i)*3)+k]=image->RGBdata[((((image->h/2-j)*image->w)+i)*3)+k];
- }
- }
- }
- break;
- case MIRROR_horizR:
- for (int i=0;i<image->w/2;i++){
- for (int j=0;j<image->h;j++){
- for (int k=0;k<3;k++){
- image->RGBdata[(((j*image->w)+((image->w/2)-i))*3)+k]=image->RGBdata[(((j*image->w)+((image->w/2)+i))*3)+k];
- }
- }
- }
- break;
- case MIRROR_vertR:
- for (int i=0;i<image->w;i++){
- for (int j=0;j<image->h/2;j++){
- for (int k=0;k<3;k++){
- image->RGBdata[((((image->h/2-j)*image->w)+i)*3)+k]=image->RGBdata[((((image->h/2+j)*image->w)+i)*3)+k];
- }
- }
- }
- break;
- }
- return image;
- }
- }
- return nullptr;
- }
- private:
- Image *image; //is an image generator
- int mode;
- };
- class Monochrome: public Image_node {
- public:
- Monochrome(){};
- Monochrome(map<string,string> &settings) {
- base_settings(settings);
- };
- ~Monochrome(){
- };
- Monochrome* clone(map<string,string> &_settings) { return new Monochrome(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- Image *other=(((Image_node*)image_inputs[0]->connection)->get_output(frame));
- image.setup(other->w,other->h);
- for (int i=0;i<image.w;i++){
- for (int j=0;j<image.h;j++){
- uint8_t luma=0;
- for (int l=0;l<3;l++) luma+=pixels.mono_weights[l][other->RGBdata[(((j*image.w)+i)*3)+l]];
- for (int k=0;k<3;k++) image.RGBdata[(((j*image.w)+i)*3)+k]=luma;
- }
- }
- return &image;
- }
- }
- return nullptr;
- }
- private:
- Image image;
- };
- class Transform: public Image_node {
- //what is the best coordinate system to use?
- //origin: corner or centre
- //units: pixel or fractional
- //aspect: scaled or homogenous
- public:
- Transform(){};
- Transform(map<string,string> &settings) {
- base_settings(settings);
- tX=find_setting(settings,"transformX",0.0f);
- tY=find_setting(settings,"transformY",0.0f);
- oX=find_setting(settings,"originX",0.5f);
- oY=find_setting(settings,"originX",0.5f);
- r=find_setting(settings,"rotation",0.0f);
- s=find_setting(settings,"scale",1.0f);
- };
- ~Transform(){
- };
- void link_params() {
- for (auto p:parameter_inputs){
- if (p->parameter=="scale") p->receiver=&s;
- if (p->parameter=="rotation") p->receiver=&r;
- if (p->parameter=="transformX") p->receiver=&tX;
- if (p->parameter=="transformY") p->receiver=&tY;
- if (p->parameter=="originX") p->receiver=&oX;
- if (p->parameter=="originY") p->receiver=&oY;
- }
- };
- Transform* clone(map<string,string> &_settings) { return new Transform(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- Image *other=(((Image_node*)image_inputs[0]->connection)->get_output(frame));
- if (other) {
- image.setup(other->w,other->h);
- //do opencv transform
- cv::Point2f srcTri[3], dstTri[3];
- cv::Mat rot_mat(2,3,CV_32FC1);
- cv::Mat trans_mat(2,3,CV_32FC1);
-
-
- Image inter;
- inter.setup(other->w,other->h);
- // Compute matrix by creating triangle and transforming
- //is there a better way - combine the 2? Just a bit of geometry
- srcTri[0].x=0;
- srcTri[0].y=0;
- srcTri[1].x=other->w-1;
- srcTri[1].y=0;
- srcTri[2].x=0;
- srcTri[2].y=other->h-1;
- for (int i=0;i<3;i++){
- dstTri[i].x=srcTri[i].x+(tX*other->w);
- dstTri[i].y=srcTri[i].y+(tY*other->h);
- }
- trans_mat=getAffineTransform( srcTri, dstTri );
- warpAffine( other->rgb, inter.rgb, trans_mat, inter.rgb.size(), cv::INTER_LINEAR, cv::BORDER_WRAP);
-
-
- // Compute rotation matrix
- //
- cv::Point centre = cv::Point( oX*other->w, oY*other->h );
-
- rot_mat = getRotationMatrix2D( centre, r, s );
- // Do the transformation
- //
- warpAffine( inter.rgb, image.rgb, rot_mat, image.rgb.size(), cv::INTER_LINEAR, cv::BORDER_WRAP);
- //BORDER_WRAP
-
- //INTER_NEAREST - a nearest-neighbor interpolation
- //INTER_LINEAR - a bilinear interpolation (used by default)
- //INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
- //INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood
- //INTER_LANCZOS4 - a Lanczos interpolation over 8x8 pixel neighborhood
-
- return &image;
- }
- }
- }
- return nullptr;
- }
- private:
- Image image;
- float tX,tY,oX,oY,r,s;
- //todo - quality settings
- };
- class Alpha_merge: public Image_node {
- public:
- Alpha_merge(){image=nullptr;};
- Alpha_merge(map<string,string> &settings) {
- base_settings(settings);
- };
- ~Alpha_merge(){ if (image) delete image;};
- Alpha_merge* clone(map<string,string> &_settings) { return new Alpha_merge(_settings);};
- Image *output(const Frame_spec &frame){
- if (image_inputs.size()) {
- if (image_inputs[0]->connection){
- //copy incoming image **writable
- if (image) delete image;
- image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
- if (image_inputs.size()>1) {
- if (image_inputs[1]->connection) {
- image->alpha_merge(*((Image_node*)image_inputs[1]->connection)->get_output(frame));
- }
- }
- //if there aren't 2 image inputs connected just return the first
- return image;
- }
- }
- return nullptr;
- }
- private:
- Image *image; //is an image generator
- };
- //-------------------------------------------------------------------
- class Node_factory{
- public:
- Node_factory();
- ~Node_factory(){
- for (auto t:type_map) delete t.second;
- }
- void add_type(string type,Node* proto){
- type_map[type]=proto;
- };
- Node *create(map<string,string> &settings){
- if (settings.find("type")!=settings.end()) {
- if (type_map.find(settings["type"])!=type_map.end()) {
- return type_map[settings["type"]]->clone(settings);
- }
- }
- return NULL;
- };
- private:
- unordered_map<string,Node*> type_map;
- };
- class Graph{
- public:
- Graph(){duration=20.0f;loaded = false;outW=640;outH=360;};
- Graph(const string& _uid,const string& _desc){init(_uid,_desc);};
- void init(const string& _uid,const string& _desc){ uid=_uid;description=_desc;duration=20.0f;};
- string uid; //every version of a graph has a UUID, no particular need to actually read its data(?)
- //?? is it faster than using strings??
- string description;
- std::unordered_map<string,Node*> nodes;
- vector<Node*> find_nodes(const string &type); //could be a way of finding a set based on capabilities?
- Node* find_node(const string &type);
- bool signal_render(string &signal_xml,const float framerate);
- bool video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress);
- int load(Poco::UUID uid);
- bool load(string data);
- bool loadFile(string &filename);
- bool parseXml();
- bool set_resolution(int w,int h);
- UUID save(); //save to DB, returns UUID of saved graph
- bool loaded;
- float duration;
- const string toString();
- xmlIO xml;
- private:
- Node_factory factory;
- int outW,outH;
- };
- class Audio_thumbnailer: public Base_audio_processor {
- public:
- Audio_thumbnailer(){
- height=128;
- width=512; //fit
- data=new uint8_t[height*width];
- memset(data,0,height*width);
- };
- ~Audio_thumbnailer(){
- delete[] data;
- };
- Audio_thumbnailer* clone(map<string,string> &_settings) { return new Audio_thumbnailer();};
- bool init(int _channels,int _bits,int _samples,int _rate);
- void cleanup(){};
- int process_frame(uint8_t *data,int samples_in_frame);
- string print();
- uint8_t *data;
- int height,width,samples_per_column;
- int column,out_sample,sample,samples;
- int offset;
- double scale,accum;
- };
- class Render_context: public Poco::Task { //Poco task object
- //manages a 'patchbay'
- //high level interfaces for the wizard
- //and low level interface onto the graph
- public:
- Render_context(const std::string& name): Task(name) {
- audio_thumb=new Audio_thumbnailer();
- state=IDLE;
- output_framerate=25.0f;
- audio_loaded=false;
-
- xmlIO xml;
- if(xml.loadFile("settings.xml") ){
- graph_dir=xml.getAttribute("Rotor","graph_dir","",0);
- media_dir=xml.getAttribute("Rotor","media_dir","",0);
- output_dir=xml.getAttribute("Rotor","output_dir","",0);
- }
- else cerr<<"Rotor: settings.xml not found, using defaults"<<endl;
- };
- ~Render_context(){delete audio_thumb;};
- void runTask();
- void add_queue(int item);
- Command_response session_command(const std::vector<std::string>& command);
- void session_command(const std::vector<std::string>& command,xmlIO& XML,HTTPResponse::HTTPStatus& status);
- Render_status get_status();
- void cancel(); //interrupt locking process
- int make_preview(int nodeID, float time); //starts a frame preview - returns status code - how to retrieve?
- bool load_audio(const string &filename,vector<Base_audio_processor*> processors);
- bool _load_audio(const string &filename,vector<Base_audio_processor*> processors);
- Render_requirements get_requirements();
- bool load_video(const string &nodeID,const string &filename);//can be performance or clip
- private:
- int state;
- float progress; //for a locking process: audio analysis or rendering
- //thread only does one thing at once
- std::deque<int> work_queue;
- Poco::Mutex mutex; //lock for access from parent thread
- std::string audio_filename;
- std::string output_filename;
- std::string graph_dir;
- std::string media_dir;
- std::string output_dir;
-
- Audio_thumbnailer *audio_thumb;
- Graph graph;
- Node_factory factory;
- float output_framerate;
- bool audio_loaded;
-
- };
-}
-
-/*
-coding style
-Types begin with capitals 'New_type'
-variables/ instances use lower case with underscore as a seperator
-*/
-#endif \ No newline at end of file
diff --git a/rotord/rotord.cpp b/rotord/rotord.cpp
deleted file mode 100755
index 6f2d765..0000000
--- a/rotord/rotord.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-#include "rotord.h"
-
-RenderContextHandler::RenderContextHandler(const std::string _content,const HTTPServerResponse::HTTPStatus _status){
- content=_content;
- status=_status;
-}
-
-
-void RenderContextHandler::handleRequest(HTTPServerRequest& request,HTTPServerResponse& response) {
-
- response.setChunkedTransferEncoding(true);
- response.setContentType("text/html");
- response.setStatus(status);
-
- std::ostream& ostr = response.send();
-
- ostr << "<?xml version='1.0' encoding='ISO-8859-1'?>\n"; //this is the mysterious extra header
- ostr << content;
-
-}
-
-
-HTTPRequestHandler* RotorRequestHandlerFactory::createRequestHandler(const HTTPServerRequest& request){
-
-
- Poco::URI theuri=Poco::URI(request.getURI());
- std::vector <std::string> command;
- theuri.getPathSegments(command);
-
- Logger& logger = Logger::get("Rotor");
- logger.information(request.clientAddress().toString()+" "+request.getMethod());
-
- HTTPResponse::HTTPStatus status=HTTPResponse::HTTP_BAD_REQUEST; //by default
-
- std::string body;
- std::ostringstream os;
- os<<request.stream().rdbuf();
- body=os.str();
-
- xmlIO XML; //xml object handles the servers responses
- XML.addTag("rotor");
-
- //can we create a tinyxml object here and pass a pointer to it to the render context?
- //can tinyxml output to a string? is there any reason to use poco instead?
-
- if (command.size()) {
- if (command[0]=="new") {
- XML.pushTag("rotor");
- if (request.getMethod()=="GET") {
- string sID=idGen.createOne().toString(); //create() seems to cause problems
- //Creates a new time-based UUID, using the MAC address of one of the system's ethernet adapters.
- //Throws a SystemException if no MAC address can be obtained.
- //
- //seems to hang, to me
- logger.information("starting thread "+sID);
- manager.start(new Rotor::Render_context(sID));
- //XML.addTag("sID");
- XML.addValue("sID",sID);
- status=HTTPResponse::HTTP_OK;
- }
- if (request.getMethod()=="PUT") { //unofficial manual thread name
- if (body.size()) {
- string sID=body;
- bool found=false;
- for (auto& task: manager.taskList()) {
- if(task->name()==sID) {
- logger.error("ERROR: tried to create thread with existing name "+sID);
- XML.addValue("error","Render context /"+sID+"/ exists already");
- found=true;
- }
- }
- if (!found){
- logger.information("starting thread "+sID);
- manager.start(new Rotor::Render_context(sID));
- XML.addValue("sID",sID);
- status=HTTPResponse::HTTP_OK;
- }
- }
- }
- }
- else if (command[0]=="list") {
- XML.pushTag("rotor");
- if (request.getMethod()=="GET") {
- logger.information("sending tasklist");
- //std::list < Poco::AutoPtr < Poco::Task > >::iterator it;
- //it=manager.taskList().begin();
- //for (it=manager.taskList().begin();it !=manager.taskList().end();++it) {
- //content+="<sID>"+(*it)->name()+"</sID>\n";
- //}
-
- //massive problems making an iterator for the tasklist, the above crashes
- //solution: auto type range-based for-loop
- //this is c++11 specific but works
-
- for (auto& task: manager.taskList()) { //c++11
- XML.addValue("sID",task->name());
- }
- status=HTTPResponse::HTTP_OK;
- }
- }
- else if (command[0]=="exit") {
- logger.information("exiting");
- exit(0);
- }
- else {
- bool found=false;
- for (auto& task: manager.taskList()) { //c++11
- if(task->name()==command[0]) {
- //valid session command
- found=true;
- XML.addAttribute("rotor","context",task->name(),0);
- XML.pushTag("rotor");
- if (command.size()==1) {
- //just invoking sID
- if (request.getMethod()=="DELETE") {
- task->cancel();
- status=HTTPResponse::HTTP_OK;
- logger.information("deleted context "+command[0]);
- XML.addValue("status","context deleted successfully");
- }
- else {
- logger.error("ERROR: Render context invoked with no command: "+command[0]);
- XML.addValue("error","Render context invoked with no command");
- }
- }
- else { //session modifier command- to be passed to render context
- //some commands need to return error codes
- //ie where the audio file isn't found
- //on the other hand, some commands need to know state of the renderer?
-
-
- vector<string> sc; //method,id,command1,{command2,}{body}
- sc.push_back(request.getMethod());
- for (auto& i: command){
- sc.push_back(i);
- }
- sc.push_back(body);
-
- ((Poco::AutoPtr<Rotor::Render_context>)task)->session_command(sc,XML,status);
-
- }
- }
- }
- if (!found) {
- status=HTTPResponse::HTTP_NOT_FOUND;
- logger.error("ERROR: context not found: "+command[0]);
- XML.pushTag("rotor");
- XML.addValue("error","Render context not found");
- }
- }
- }
- else {
- logger.error("ERROR: Empty request");
- XML.addValue("error","Empty request");
- }
- string content;
- XML.copyXmlToString(content);
- return new RenderContextHandler(content, status);
-}
-
-
-RotorServer::RotorServer(): _helpRequested(false)
-{
-}
-
-RotorServer::~RotorServer()
-{
-}
-
-void RotorServer::initialize(Application& self){
- loadConfiguration();
- ServerApplication::initialize(self);
-}
-
-void RotorServer::uninitialize(){
- ServerApplication::uninitialize();
-}
-
-void RotorServer::defineOptions(OptionSet& options) {
- ServerApplication::defineOptions(options);
- options.addOption(
- Option("help", "h", "display argument help information")
- .required(false)
- .repeatable(false)
- .callback(OptionCallback<RotorServer>(this, &RotorServer::handleHelp)
- )
- );
-}
-
-void RotorServer::handleHelp(const std::string& name, const std::string& value){
- HelpFormatter helpFormatter(options());
- helpFormatter.setCommand(commandName());
- helpFormatter.setUsage("OPTIONS");
- helpFormatter.setHeader(
- "Rotor");
- helpFormatter.format(std::cout);
- stopOptionsProcessing();
- _helpRequested = true;
-}
-
-int RotorServer::main(const std::vector<std::string>& args){
- if (!_helpRequested) {
-
- unsigned short port;
-
- Logger& logger = Logger::get("Rotor");
-
- xmlIO xml;
- if(xml.loadFile("settings.xml") ){
- port=xml.getAttribute("Rotor","port",9000,0);
- }
- else logger.information("settings.xml not found, using defaults");
-
- logger.information("rotord running on port "+ofToString(port));
-
- port = (unsigned short) config().getInt("port", port); //override from command line
-
- std::string format(config().getString("format", DateTimeFormat::SORTABLE_FORMAT));
-
-
-
- ServerSocket svs(port);
- HTTPServer srv(new RotorRequestHandlerFactory(),svs, new HTTPServerParams);
- srv.start();
- waitForTerminationRequest();
- srv.stop();
- }
- return Application::EXIT_OK;
-}
- \ No newline at end of file
diff --git a/rotord/rotord.h b/rotord/rotord.h
deleted file mode 100755
index 7656c28..0000000
--- a/rotord/rotord.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "Poco/Net/HTTPServer.h"
-#include "Poco/Net/HTTPRequestHandler.h"
-#include "Poco/Net/HTTPRequestHandlerFactory.h"
-#include "Poco/Net/HTTPServerParams.h"
-#include "Poco/Net/HTTPServerRequest.h"
-#include "Poco/Net/HTTPServerResponse.h"
-#include "Poco/Net/HTTPServerParams.h"
-#include "Poco/Net/ServerSocket.h"
-#include "Poco/Timestamp.h"
-#include "Poco/DateTimeFormatter.h"
-#include "Poco/DateTimeFormat.h"
-#include "Poco/Exception.h"
-#include "Poco/ThreadPool.h"
-#include "Poco/Task.h"
-#include "Poco/NotificationCenter.h"
-#include "Poco/TaskManager.h"
-#include "Poco/Util/ServerApplication.h"
-#include "Poco/Util/Option.h"
-#include "Poco/Util/OptionSet.h"
-#include "Poco/Util/HelpFormatter.h"
-#include "Poco/FileStream.h"
-#include "Poco/StreamCopier.h"
-#include "Poco/Net/HTTPStreamFactory.h"
-#include <iostream>
-
-#include <sstream>
-#include "Poco/URI.h"
-#include "Poco/Channel.h"
-#include "Poco/SplitterChannel.h"
-#include "Poco/ConsoleChannel.h"
-#include "Poco/FormattingChannel.h"
-#include "Poco/FileChannel.h"
-#include "Poco/Message.h"
-#include "Poco/Formatter.h"
-#include "Poco/PatternFormatter.h"
-#include "Poco/AutoPtr.h"
-
-using Poco::Net::ServerSocket;
-using Poco::Net::HTTPResponse;
-using Poco::Net::HTTPRequestHandler;
-using Poco::Net::HTTPRequestHandlerFactory;
-using Poco::Net::HTTPServer;
-using Poco::Net::HTTPServerRequest;
-using Poco::Net::HTTPServerResponse;
-using Poco::Net::HTTPServerParams;
-using Poco::Timestamp;
-using Poco::DateTimeFormatter;
-using Poco::DateTimeFormat;
-using Poco::ThreadPool;
-using Poco::TaskManager;
-using Poco::Util::ServerApplication;
-using Poco::Util::Application;
-using Poco::Util::Option;
-using Poco::Util::OptionSet;
-using Poco::Util::OptionCallback;
-using Poco::Util::HelpFormatter;
-using Poco::Net::HTTPStreamFactory;
-using Poco::Logger;
-using Poco::Channel;
-using Poco::SplitterChannel;
-using Poco::ConsoleChannel;
-using Poco::FormattingChannel;
-using Poco::Formatter;
-using Poco::PatternFormatter;
-using Poco::FileChannel;
-using Poco::Message;
-using Poco::AutoPtr;
-
-
-#include "rotor.h"
-
-
-class RenderContextHandler: public HTTPRequestHandler
-{
- public:
- RenderContextHandler(string _content,HTTPServerResponse::HTTPStatus _status);
- void handleRequest(HTTPServerRequest& request,HTTPServerResponse& response);
- private:
- std::string content;
- HTTPServerResponse::HTTPStatus status;
-};
-
-class RotorRequestHandlerFactory: public HTTPRequestHandlerFactory
-{
- public:
- HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request);
- private:
-
- std::unordered_map<std::string,Rotor::Render_context> context;
- Poco::UUIDGenerator idGen;
- Poco::TaskManager manager;
-};
-
-class RotorServer: public Poco::Util::ServerApplication
-{
- public:
- RotorServer();
- ~RotorServer();
- protected:
- void initialize(Application& self);
- void uninitialize();
- void defineOptions(OptionSet& options);
- void handleHelp(const std::string& name, const std::string& value);
- int main(const std::vector<std::string>& args);
- private:
- bool _helpRequested;
-};
-
-RotorServer app; //needs to be global for logger
-
-int main(int argc, char** argv)
-{
- AutoPtr<SplitterChannel> splitterChannel(new SplitterChannel());
- AutoPtr<Channel> consoleChannel(new ConsoleChannel());
- AutoPtr<Channel> fileChannel(new FileChannel("Rotord.log"));
- AutoPtr<FileChannel> rotatedFileChannel(new FileChannel("Rotord_R.log"));
-
- rotatedFileChannel->setProperty("rotation", "100");
- rotatedFileChannel->setProperty("archive", "timestamp");
-
- splitterChannel->addChannel(consoleChannel);
- splitterChannel->addChannel(fileChannel);
- splitterChannel->addChannel(rotatedFileChannel);
-
- AutoPtr<Formatter> formatter(new PatternFormatter("%d-%m-%Y %H:%M:%S %s: %t"));
- AutoPtr<Channel> formattingChannel(new FormattingChannel(formatter, splitterChannel));
-
- Logger& sLog = Logger::create("Rotor", formattingChannel, Message::PRIO_TRACE);
-
- Logger& logger = Logger::get("Rotor");
- logger.information("starting rendering daemon");
-
- HTTPStreamFactory::registerFactory();
-
- return app.run(argc, argv);
-}
diff --git a/rotord/system.h b/rotord/system.h
deleted file mode 100644
index 15aa8c1..0000000
--- a/rotord/system.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
-
-/*
- Vamp
-
- An API for audio analysis and feature extraction plugins.
-
- Centre for Digital Music, Queen Mary, University of London.
- Copyright 2006 Chris Cannam.
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use, copy,
- modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
- ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Except as contained in this notice, the names of the Centre for
- Digital Music; Queen Mary, University of London; and Chris Cannam
- shall not be used in advertising or otherwise to promote the sale,
- use or other dealings in this Software without prior written
- authorization.
-*/
-
-#ifndef _SYSTEM_H_
-#define _SYSTEM_H_
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#define DLOPEN(a,b) LoadLibrary((a).c_str())
-#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b))
-#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a))
-#define DLERROR() ""
-
-#define PLUGIN_SUFFIX "dll"
-
-#else
-
-#include <dlfcn.h>
-
-#define DLOPEN(a,b) dlopen((a).c_str(),(b))
-#define DLSYM(a,b) dlsym((a),(b))
-#define DLCLOSE(a) dlclose((a))
-#define DLERROR() dlerror()
-
-#ifdef __APPLE__
-
-#define PLUGIN_SUFFIX "dylib"
-#define HAVE_OPENDIR 1
-
-#else
-
-#define PLUGIN_SUFFIX "so"
-#define HAVE_OPENDIR 1
-
-#endif /* __APPLE__ */
-
-#endif /* ! _WIN32 */
-
-#endif
-
diff --git a/rotord/tinyxml.cpp b/rotord/tinyxml.cpp
deleted file mode 100755
index 5de21f6..0000000
--- a/rotord/tinyxml.cpp
+++ /dev/null
@@ -1,1888 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2006 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
-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
-redistribute it freely, subject to the following restrictions:
-
-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
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include <ctype.h>
-
-#ifdef TIXML_USE_STL
-#include <sstream>
-#include <iostream>
-#endif
-
-#include "tinyxml.h"
-
-
-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
-}
-
-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.
- // &#xA9; -- 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;
-}
-
-
-TiXmlNode::~TiXmlNode()
-{
- TiXmlNode* node = firstChild;
- TiXmlNode* temp = 0;
-
- while ( node )
- {
- temp = node;
- node = node->next;
- delete temp;
- }
-}
-
-
-void TiXmlNode::CopyTo( TiXmlNode* target ) const
-{
- target->SetValue (value.c_str() );
- target->userData = userData;
-}
-
-
-void TiXmlNode::Clear()
-{
- TiXmlNode* node = firstChild;
- TiXmlNode* temp = 0;
-
- while ( node )
- {
- temp = node;
- node = node->next;
- delete temp;
- }
-
- firstChild = 0;
- lastChild = 0;
-}
-
-
-TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
-{
- assert( node->parent == 0 || node->parent == this );
- assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
-
- if ( node->Type() == TiXmlNode::DOCUMENT )
- {
- delete node;
- if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
- return 0;
- }
-
- node->parent = this;
-
- node->prev = lastChild;
- node->next = 0;
-
- if ( lastChild )
- lastChild->next = node;
- else
- firstChild = node; // it was an empty list.
-
- lastChild = node;
- return node;
-}
-
-
-TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
-{
- if ( addThis.Type() == TiXmlNode::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 );
-}
-
-
-TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
-{
- if ( !beforeThis || beforeThis->parent != this ) {
- return 0;
- }
- if ( addThis.Type() == TiXmlNode::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::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->parent != this )
- return 0;
-
- TiXmlNode* node = withThis.Clone();
- if ( !node )
- return 0;
-
- node->next = replaceThis->next;
- node->prev = replaceThis->prev;
-
- if ( replaceThis->next )
- replaceThis->next->prev = node;
- else
- lastChild = node;
-
- if ( replaceThis->prev )
- replaceThis->prev->next = node;
- else
- firstChild = node;
-
- delete replaceThis;
- node->parent = this;
- return node;
-}
-
-
-bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
-{
- if ( removeThis->parent != this )
- {
- assert( 0 );
- return false;
- }
-
- if ( removeThis->next )
- removeThis->next->prev = removeThis->prev;
- else
- lastChild = removeThis->prev;
-
- if ( removeThis->prev )
- removeThis->prev->next = removeThis->next;
- else
- firstChild = removeThis->next;
-
- 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* 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* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
-{
- 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 );
- }
-}
-
-
-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* 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;
-}
-
-
-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;
- }
-}
-
-const TiXmlElement* TiXmlNode::FirstChildElement() const
-{
- const TiXmlNode* node;
-
- 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;
-
- 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;
-
- 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;
-
- 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;
-
- for( node = this; node; node = node->parent )
- {
- if ( node->ToDocument() )
- return node->ToDocument();
- }
- return 0;
-}
-
-
-TiXmlElement::TiXmlElement (const char * _value)
- : TiXmlNode( TiXmlNode::ELEMENT )
-{
- firstChild = lastChild = 0;
- value = _value;
-}
-
-
-#ifdef TIXML_USE_STL
-TiXmlElement::TiXmlElement( const std::string& _value )
- : TiXmlNode( TiXmlNode::ELEMENT )
-{
- firstChild = lastChild = 0;
- value = _value;
-}
-#endif
-
-
-TiXmlElement::TiXmlElement( const TiXmlElement& copy)
- : TiXmlNode( TiXmlNode::ELEMENT )
-{
- firstChild = lastChild = 0;
- copy.CopyTo( this );
-}
-
-
-void TiXmlElement::operator=( const TiXmlElement& base )
-{
- ClearThis();
- base.CopyTo( this );
-}
-
-
-TiXmlElement::~TiXmlElement()
-{
- ClearThis();
-}
-
-
-void TiXmlElement::ClearThis()
-{
- 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;
-}
-
-
-#ifdef TIXML_USE_STL
-const std::string* TiXmlElement::Attribute( const std::string& name ) const
-{
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( node )
- return &node->ValueStr();
- return 0;
-}
-#endif
-
-
-const char* TiXmlElement::Attribute( const char* name, int* i ) const
-{
- const char* s = Attribute( name );
- if ( i )
- {
- if ( s ) {
- *i = atoi( s );
- }
- else {
- *i = 0;
- }
- }
- return s;
-}
-
-
-#ifdef TIXML_USE_STL
-const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
-{
- const std::string* s = Attribute( name );
- if ( i )
- {
- if ( s ) {
- *i = atoi( s->c_str() );
- }
- else {
- *i = 0;
- }
- }
- return s;
-}
-#endif
-
-
-const char* TiXmlElement::Attribute( const char* name, double* d ) const
-{
- const char* s = Attribute( name );
- if ( d )
- {
- if ( s ) {
- *d = atof( s );
- }
- else {
- *d = 0;
- }
- }
- return s;
-}
-
-
-#ifdef TIXML_USE_STL
-const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
-{
- const std::string* s = Attribute( name );
- if ( d )
- {
- if ( s ) {
- *d = atof( s->c_str() );
- }
- else {
- *d = 0;
- }
- }
- return s;
-}
-#endif
-
-
-int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
-{
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
- return node->QueryIntValue( ival );
-}
-
-
-#ifdef TIXML_USE_STL
-int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
-{
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
- return node->QueryIntValue( ival );
-}
-#endif
-
-
-int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
-{
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
- return node->QueryDoubleValue( dval );
-}
-
-
-#ifdef TIXML_USE_STL
-int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
-{
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
- return node->QueryDoubleValue( dval );
-}
-#endif
-
-
-void TiXmlElement::SetAttribute( const char * name, int val )
-{
- char buf[64];
- #if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
- #else
- sprintf( buf, "%d", val );
- #endif
- SetAttribute( name, buf );
-}
-
-
-#ifdef TIXML_USE_STL
-void TiXmlElement::SetAttribute( const std::string& name, int val )
-{
- std::ostringstream oss;
- oss << val;
- SetAttribute( name, oss.str() );
-}
-#endif
-
-
-void TiXmlElement::SetDoubleAttribute( const char * name, double val )
-{
- char buf[256];
- #if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
- #else
- sprintf( buf, "%f", val );
- #endif
- SetAttribute( name, buf );
-}
-
-
-void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
-{
- #ifdef TIXML_USE_STL
- TIXML_STRING _name( cname );
- TIXML_STRING _value( cvalue );
- #else
- const char* _name = cname;
- const char* _value = cvalue;
- #endif
-
- TiXmlAttribute* node = attributeSet.Find( _name );
- if ( node )
- {
- node->SetValue( _value );
- return;
- }
-
- TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
- if ( attrib )
- {
- attributeSet.Add( attrib );
- }
- else
- {
- TiXmlDocument* document = GetDocument();
- if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
- }
-}
-
-
-#ifdef TIXML_USE_STL
-void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
-{
- TiXmlAttribute* node = attributeSet.Find( name );
- if ( node )
- {
- node->SetValue( _value );
- return;
- }
-
- TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
- if ( attrib )
- {
- attributeSet.Add( attrib );
- }
- else
- {
- TiXmlDocument* document = GetDocument();
- if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
- }
-}
-#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() );
- }
-}
-
-
-void TiXmlElement::CopyTo( TiXmlElement* target ) const
-{
- // 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() );
- }
-
- 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 );
-}
-
-
-TiXmlNode* TiXmlElement::Clone() const
-{
- TiXmlElement* clone = new TiXmlElement( Value() );
- if ( !clone )
- return 0;
-
- 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;
-}
-
-
-TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
-{
- tabsize = 4;
- useMicrosoftBOM = false;
- ClearError();
-}
-
-TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
-{
- tabsize = 4;
- useMicrosoftBOM = false;
- value = documentName;
- ClearError();
-}
-
-
-#ifdef TIXML_USE_STL
-TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
-{
- tabsize = 4;
- useMicrosoftBOM = false;
- value = documentName;
- ClearError();
-}
-#endif
-
-
-TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
-{
- copy.CopyTo( this );
-}
-
-
-void TiXmlDocument::operator=( const TiXmlDocument& copy )
-{
- Clear();
- copy.CopyTo( this );
-}
-
-
-bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
-{
- // See STL_STRING_BUG below.
- //StringToBuffer buf( value );
-
- return LoadFile( Value(), encoding );
-}
-
-
-bool TiXmlDocument::SaveFile() const
-{
- // See STL_STRING_BUG below.
-// StringToBuffer buf( value );
-//
-// if ( buf.buffer && SaveFile( buf.buffer ) )
-// return true;
-//
-// return false;
- return SaveFile( Value() );
-}
-
-bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
-{
- // There was a really terrifying little bug here. The code:
- // value = filename
- // in the STL case, cause the assignment method of the std::string to
- // be called. What is strange, is that the std::string had the same
- // address as it's c_str() method, and so bad things happen. Looks
- // like a bug in the Microsoft STL implementation.
- // Add an extra string to avoid the crash.
- TIXML_STRING filename( _filename );
- value = filename;
-
- // 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;
- }
-}
-
-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;
- }
-
- // If we have a file, assume it is all one big XML file, and read it in.
- // The document parser may decide the document ends sooner than the entire file, however.
- TIXML_STRING data;
- data.reserve( length );
-
- // 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;
- }
-
- const char* lastPos = buf;
- const char* p = buf;
-
- buf[length] = 0;
- while( *p ) {
- assert( p < (buf+length) );
- if ( *p == 0xa ) {
- // Newline character. No special rules for this. Append all the characters
- // since the last string, and include the newline.
- data.append( lastPos, (p-lastPos+1) ); // append, include the newline
- ++p; // move past the newline
- lastPos = p; // and point to the new buffer (may be 0)
- assert( p <= (buf+length) );
- }
- else if ( *p == 0xd ) {
- // Carriage return. Append what we have so far, then
- // handle moving forward in the buffer.
- if ( (p-lastPos) > 0 ) {
- data.append( lastPos, p-lastPos ); // do not add the CR
- }
- data += (char)0xa; // a proper newline
-
- if ( *(p+1) == 0xa ) {
- // Carriage return - new line sequence
- p += 2;
- lastPos = p;
- assert( p <= (buf+length) );
- }
- else {
- // it was followed by something else...that is presumably characters again.
- ++p;
- lastPos = p;
- assert( p <= (buf+length) );
- }
- }
- else {
- ++p;
- }
- }
- // Handle any left over characters.
- if ( p-lastPos ) {
- data.append( lastPos, p-lastPos );
- }
- delete [] buf;
- buf = 0;
-
- Parse( data.c_str(), 0, encoding );
-
- if ( Error() )
- return false;
- else
- return true;
-}
-
-
-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;
-}
-
-
-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;
-
- 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 );
-
- 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* TiXmlDocument::Clone() const
-{
- TiXmlDocument* clone = new TiXmlDocument();
- if ( !clone )
- return 0;
-
- 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" );
- }
-}
-
-
-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 );
-}
-
-
-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;
-}
-
-/*
-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;
-}
-*/
-
-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;
-}
-
-/*
-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;
-}
-*/
-
-void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
-{
- TIXML_STRING n, 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) += "'";
- }
- }
-}
-
-
-int TiXmlAttribute::QueryIntValue( int* ival ) const
-{
- 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;
-}
-
-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);
-}
-
-void TiXmlAttribute::SetDoubleValue( double _value )
-{
- char buf [256];
- #if defined(TIXML_SNPRINTF)
- TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
- #else
- sprintf (buf, "%lf", _value);
- #endif
- SetValue (buf);
-}
-
-int TiXmlAttribute::IntValue() const
-{
- return atoi (value.c_str ());
-}
-
-double TiXmlAttribute::DoubleValue() const
-{
- return atof (value.c_str ());
-}
-
-
-TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
-{
- copy.CopyTo( this );
-}
-
-
-void TiXmlComment::operator=( const TiXmlComment& base )
-{
- Clear();
- base.CopyTo( 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() );
-}
-
-
-void TiXmlComment::CopyTo( TiXmlComment* target ) const
-{
- TiXmlNode::CopyTo( target );
-}
-
-
-bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
-{
- return visitor->Visit( *this );
-}
-
-
-TiXmlNode* TiXmlComment::Clone() const
-{
- TiXmlComment* clone = new TiXmlComment();
-
- if ( !clone )
- return 0;
-
- 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() );
- }
-}
-
-
-void TiXmlText::CopyTo( TiXmlText* target ) const
-{
- TiXmlNode::CopyTo( target );
- target->cdata = cdata;
-}
-
-
-bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
-{
- return visitor->Visit( *this );
-}
-
-
-TiXmlNode* TiXmlText::Clone() const
-{
- TiXmlText* clone = 0;
- clone = new TiXmlText( "" );
-
- if ( !clone )
- return 0;
-
- CopyTo( clone );
- return clone;
-}
-
-
-TiXmlDeclaration::TiXmlDeclaration( const char * _version,
- const char * _encoding,
- const char * _standalone )
- : TiXmlNode( TiXmlNode::DECLARATION )
-{
- 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::DECLARATION )
-{
- version = _version;
- encoding = _encoding;
- standalone = _standalone;
-}
-#endif
-
-
-TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
- : TiXmlNode( TiXmlNode::DECLARATION )
-{
- copy.CopyTo( this );
-}
-
-
-void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
-{
- Clear();
- copy.CopyTo( this );
-}
-
-
-void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
-{
- 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) += "?>";
-}
-
-
-void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
-{
- TiXmlNode::CopyTo( target );
-
- target->version = version;
- target->encoding = encoding;
- target->standalone = standalone;
-}
-
-
-bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
-{
- return visitor->Visit( *this );
-}
-
-
-TiXmlNode* TiXmlDeclaration::Clone() const
-{
- TiXmlDeclaration* clone = new TiXmlDeclaration();
-
- if ( !clone )
- return 0;
-
- 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() );
-}
-
-
-void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
-{
- TiXmlNode::CopyTo( target );
-}
-
-
-bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
-{
- return visitor->Visit( *this );
-}
-
-
-TiXmlNode* TiXmlUnknown::Clone() const
-{
- TiXmlUnknown* clone = new TiXmlUnknown();
-
- if ( !clone )
- return 0;
-
- CopyTo( clone );
- return clone;
-}
-
-
-TiXmlAttributeSet::TiXmlAttributeSet()
-{
- sentinel.next = &sentinel;
- sentinel.prev = &sentinel;
-}
-
-
-TiXmlAttributeSet::~TiXmlAttributeSet()
-{
- 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
-
- addMe->next = &sentinel;
- addMe->prev = sentinel.prev;
-
- sentinel.prev->next = addMe;
- sentinel.prev = addMe;
-}
-
-void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
-{
- 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.
-}
-
-
-#ifdef TIXML_USE_STL
-const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
-{
- for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
- {
- if ( node->name == name )
- return node;
- }
- return 0;
-}
-
-/*
-TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
-{
- for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
- {
- if ( node->name == name )
- return node;
- }
- return 0;
-}
-*/
-#endif
-
-
-const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
-{
- for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
- {
- if ( strcmp( node->name.c_str(), name ) == 0 )
- return node;
- }
- return 0;
-}
-
-/*
-TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
-{
- for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
- {
- if ( strcmp( node->name.c_str(), name ) == 0 )
- return node;
- }
- return 0;
-}
-*/
-
-#ifdef TIXML_USE_STL
-std::istream& operator>> (std::istream & in, TiXmlNode & base)
-{
- TIXML_STRING tag;
- tag.reserve( 8 * 1000 );
- base.StreamIn( &in, &tag );
-
- base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
- return in;
-}
-#endif
-
-
-#ifdef TIXML_USE_STL
-std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
-{
- TiXmlPrinter printer;
- printer.SetStreamPrinting();
- base.Accept( &printer );
- out << printer.Str();
-
- return out;
-}
-
-
-std::string& operator<< (std::string& out, const TiXmlNode& base )
-{
- TiXmlPrinter printer;
- printer.SetStreamPrinting();
- base.Accept( &printer );
- out.append( printer.Str() );
-
- return out;
-}
-#endif
-
-
-TiXmlHandle TiXmlHandle::FirstChild() const
-{
- 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 );
-}
-
-
-TiXmlHandle TiXmlHandle::FirstChildElement() const
-{
- 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 );
-}
-
-
-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 );
-}
-
-
-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 );
-}
-
-
-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 );
-}
-
-
-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 );
-}
-
-
-bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
-{
- return true;
-}
-
-bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
-{
- 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;
-}
-
-
-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;
-}
-
-
-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;
-}
-
-
-bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
-{
- DoIndent();
- declaration.Print( 0, 0, &buffer );
- DoLineBreak();
- return true;
-}
-
-
-bool TiXmlPrinter::Visit( const TiXmlComment& comment )
-{
- DoIndent();
- buffer += "<!--";
- buffer += comment.Value();
- buffer += "-->";
- DoLineBreak();
- return true;
-}
-
-
-bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
-{
- DoIndent();
- buffer += "<";
- buffer += unknown.Value();
- buffer += ">";
- DoLineBreak();
- return true;
-}
-
diff --git a/rotord/tinyxml.h b/rotord/tinyxml.h
deleted file mode 100755
index 7958de5..0000000
--- a/rotord/tinyxml.h
+++ /dev/null
@@ -1,1807 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2006 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
-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
-redistribute it freely, subject to the following restrictions:
-
-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
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-
-#ifndef TINYXML_INCLUDED
-#define TINYXML_INCLUDED
-
-#ifdef _MSC_VER
-#pragma warning( push )
-#pragma warning( disable : 4530 )
-#pragma warning( disable : 4786 )
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-// Help out windows:
-#if defined( _DEBUG ) && !defined( DEBUG )
-#define DEBUG
-#endif
-
-#define TIXML_USE_STL // for now, OFXML will use STL for string stuff
-
-#ifdef TIXML_USE_STL
- #include <string>
- #include <iostream>
- #include <sstream>
- #define TIXML_STRING std::string
-#else
- #include "tinystr.h"
- #define TIXML_STRING TiXmlString
-#endif
-
-// Deprecated library function hell. Compilers want to use the
-// new safe versions. This probably doesn't fully address the problem,
-// but it gets closer. There are too many compilers for me to fully
-// test. If you get compilation troubles, undefine TIXML_SAFE
-#define TIXML_SAFE
-
-#ifdef TIXML_SAFE
- #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
- // Microsoft visual studio, version 2005 and higher.
- #define TIXML_SNPRINTF _snprintf_s
- #define TIXML_SNSCANF _snscanf_s
- #define TIXML_SSCANF sscanf_s
- #elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
- // Microsoft visual studio, version 6 and higher.
- //#pragma message( "Using _sn* functions." )
- #define TIXML_SNPRINTF _snprintf
- #define TIXML_SNSCANF _snscanf
- #define TIXML_SSCANF sscanf
- #elif defined(__GNUC__) && (__GNUC__ >= 3 )
- // GCC version 3 and higher.s
- //#warning( "Using sn* functions." )
- #define TIXML_SNPRINTF snprintf
- #define TIXML_SNSCANF snscanf
- #define TIXML_SSCANF sscanf
- #else
- #define TIXML_SSCANF sscanf
- #endif
-#endif
-
-class TiXmlDocument;
-class TiXmlElement;
-class TiXmlComment;
-class TiXmlUnknown;
-class TiXmlAttribute;
-class TiXmlText;
-class TiXmlDeclaration;
-class TiXmlParsingData;
-
-const int TIXML_MAJOR_VERSION = 2;
-const int TIXML_MINOR_VERSION = 5;
-const int TIXML_PATCH_VERSION = 3;
-
-/* Internal structure for tracking location of items
- in the XML file.
-*/
-struct TiXmlCursor
-{
- TiXmlCursor() { Clear(); }
- void Clear() { row = col = -1; }
-
- int row; // 0 based.
- int col; // 0 based.
-};
-
-
-/**
- If you call the Accept() method, it requires being passed a TiXmlVisitor
- class to handle callbacks. For nodes that contain other nodes (Document, Element)
- you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
- are simple called with Visit().
-
- If you return 'true' from a Visit method, recursive parsing will continue. If you return
- false, <b>no children of this node or its sibilings</b> will be Visited.
-
- All flavors of Visit methods have a default implementation that returns 'true' (continue
- visiting). You need to only override methods that are interesting to you.
-
- Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
-
- You should never change the document from a callback.
-
- @sa TiXmlNode::Accept()
-*/
-class TiXmlVisitor
-{
-public:
- virtual ~TiXmlVisitor() {}
-
- /// Visit a document.
- virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; }
- /// Visit a document.
- virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; }
-
- /// Visit an element.
- virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; }
- /// Visit an element.
- virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; }
-
- /// Visit a declaration
- virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; }
- /// Visit a text node
- virtual bool Visit( const TiXmlText& /*text*/ ) { return true; }
- /// Visit a comment node
- virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; }
- /// Visit an unknow node
- virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; }
-};
-
-// Only used by Attribute::Query functions
-enum
-{
- TIXML_SUCCESS,
- TIXML_NO_ATTRIBUTE,
- TIXML_WRONG_TYPE
-};
-
-
-// Used by the parsing routines.
-enum TiXmlEncoding
-{
- TIXML_ENCODING_UNKNOWN,
- TIXML_ENCODING_UTF8,
- TIXML_ENCODING_LEGACY
-};
-
-const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
-
-/** TiXmlBase is a base class for every class in TinyXml.
- It does little except to establish that TinyXml classes
- can be printed and provide some utility functions.
-
- In XML, the document and elements can contain
- other elements and other types of nodes.
-
- @verbatim
- A Document can contain: Element (container or leaf)
- Comment (leaf)
- Unknown (leaf)
- Declaration( leaf )
-
- An Element can contain: Element (container or leaf)
- Text (leaf)
- Attributes (not on tree)
- Comment (leaf)
- Unknown (leaf)
-
- A Decleration contains: Attributes (not on tree)
- @endverbatim
-*/
-class TiXmlBase
-{
- friend class TiXmlNode;
- friend class TiXmlElement;
- friend class TiXmlDocument;
-
-public:
- TiXmlBase() : userData(0) {}
- virtual ~TiXmlBase() {}
-
- /** All TinyXml classes can print themselves to a filestream
- or the string class (TiXmlString in non-STL mode, std::string
- in STL mode.) Either or both cfile and str can be null.
-
- This is a formatted print, and will insert
- tabs and newlines.
-
- (For an unformatted stream, use the << operator.)
- */
- virtual void Print( FILE* cfile, int depth ) const = 0;
-
- /** The world does not agree on whether white space should be kept or
- not. In order to make everyone happy, these global, static functions
- are provided to set whether or not TinyXml will condense all white space
- into a single space or not. The default is to condense. Note changing this
- value is not thread safe.
- */
- static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; }
-
- /// Return the current white space setting.
- static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
-
- /** Return the position, in the original source file, of this node or attribute.
- The row and column are 1-based. (That is the first row and first column is
- 1,1). If the returns values are 0 or less, then the parser does not have
- a row and column value.
-
- Generally, the row and column value will be set when the TiXmlDocument::Load(),
- TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
- when the DOM was created from operator>>.
-
- The values reflect the initial load. Once the DOM is modified programmatically
- (by adding or changing nodes and attributes) the new values will NOT update to
- reflect changes in the document.
-
- There is a minor performance cost to computing the row and column. Computation
- can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
-
- @sa TiXmlDocument::SetTabSize()
- */
- int Row() const { return location.row + 1; }
- int Column() const { return location.col + 1; } ///< See Row()
-
- void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data.
- void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data.
- const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data.
-
- // Table that returs, for a given lead byte, the total number of bytes
- // in the UTF-8 sequence.
- static const int utf8ByteTable[256];
-
- virtual const char* Parse( const char* p,
- TiXmlParsingData* data,
- TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
-
- /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc,
- or they will be transformed into entities!
- */
- static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
-
- enum
- {
- TIXML_NO_ERROR = 0,
- TIXML_ERROR,
- TIXML_ERROR_OPENING_FILE,
- TIXML_ERROR_OUT_OF_MEMORY,
- TIXML_ERROR_PARSING_ELEMENT,
- TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
- TIXML_ERROR_READING_ELEMENT_VALUE,
- TIXML_ERROR_READING_ATTRIBUTES,
- TIXML_ERROR_PARSING_EMPTY,
- TIXML_ERROR_READING_END_TAG,
- TIXML_ERROR_PARSING_UNKNOWN,
- TIXML_ERROR_PARSING_COMMENT,
- TIXML_ERROR_PARSING_DECLARATION,
- TIXML_ERROR_DOCUMENT_EMPTY,
- TIXML_ERROR_EMBEDDED_NULL,
- TIXML_ERROR_PARSING_CDATA,
- TIXML_ERROR_DOCUMENT_TOP_ONLY,
-
- TIXML_ERROR_STRING_COUNT
- };
-
-protected:
-
- static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
- inline static bool IsWhiteSpace( char c )
- {
- return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' );
- }
- inline static bool IsWhiteSpace( int c )
- {
- if ( c < 256 )
- return IsWhiteSpace( (char) c );
- return false; // Again, only truly correct for English/Latin...but usually works.
- }
-
- #ifdef TIXML_USE_STL
- static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
- static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
- #endif
-
- /* Reads an XML name into the string provided. Returns
- a pointer just past the last character of the name,
- or 0 if the function has an error.
- */
- static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
-
- /* Reads text. Returns a pointer past the given end tag.
- Wickedly complex options, but it keeps the (sensitive) code in one place.
- */
- static const char* ReadText( const char* in, // where to start
- TIXML_STRING* text, // the string read
- bool ignoreWhiteSpace, // whether to keep the white space
- const char* endTag, // what ends this text
- bool ignoreCase, // whether to ignore case in the end tag
- TiXmlEncoding encoding ); // the current encoding
-
- // If an entity has been found, transform it into a character.
- static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
-
- // Get a character, while interpreting entities.
- // The length can be from 0 to 4 bytes.
- inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
- {
- assert( p );
- if ( encoding == TIXML_ENCODING_UTF8 )
- {
- *length = utf8ByteTable[ *((const unsigned char*)p) ];
- assert( *length >= 0 && *length < 5 );
- }
- else
- {
- *length = 1;
- }
-
- if ( *length == 1 )
- {
- if ( *p == '&' )
- return GetEntity( p, _value, length, encoding );
- *_value = *p;
- return p+1;
- }
- else if ( *length )
- {
- //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe),
- // and the null terminator isn't needed
- for( int i=0; p[i] && i<*length; ++i ) {
- _value[i] = p[i];
- }
- return p + (*length);
- }
- else
- {
- // Not valid text.
- return 0;
- }
- }
-
- // Return true if the next characters in the stream are any of the endTag sequences.
- // Ignore case only works for english, and should only be relied on when comparing
- // to English words: StringEqual( p, "version", true ) is fine.
- static bool StringEqual( const char* p,
- const char* endTag,
- bool ignoreCase,
- TiXmlEncoding encoding );
-
- static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
-
- TiXmlCursor location;
-
- /// Field containing a generic user pointer
- void* userData;
-
- // None of these methods are reliable for any language except English.
- // Good for approximation, not great for accuracy.
- static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
- static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
- inline static int ToLower( int v, TiXmlEncoding encoding )
- {
- if ( encoding == TIXML_ENCODING_UTF8 )
- {
- if ( v < 128 ) return tolower( v );
- return v;
- }
- else
- {
- return tolower( v );
- }
- }
- static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
-
-private:
- TiXmlBase( const TiXmlBase& ); // not implemented.
- void operator=( const TiXmlBase& base ); // not allowed.
-
- struct Entity
- {
- const char* str;
- unsigned int strLength;
- char chr;
- };
- enum
- {
- NUM_ENTITY = 5,
- MAX_ENTITY_LENGTH = 6
-
- };
- static Entity entity[ NUM_ENTITY ];
- static bool condenseWhiteSpace;
-};
-
-
-/** The parent class for everything in the Document Object Model.
- (Except for attributes).
- Nodes have siblings, a parent, and children. A node can be
- in a document, or stand on its own. The type of a TiXmlNode
- can be queried, and it can be cast to its more defined type.
-*/
-class TiXmlNode : public TiXmlBase
-{
- friend class TiXmlDocument;
- friend class TiXmlElement;
-
-public:
- #ifdef TIXML_USE_STL
-
- /** An input stream operator, for every class. Tolerant of newlines and
- formatting, but doesn't expect them.
- */
- friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
-
- /** An output stream operator, for every class. Note that this outputs
- without any newlines or formatting, as opposed to Print(), which
- includes tabs and new lines.
-
- The operator<< and operator>> are not completely symmetric. Writing
- a node to a stream is very well defined. You'll get a nice stream
- of output, without any extra whitespace or newlines.
-
- But reading is not as well defined. (As it always is.) If you create
- a TiXmlElement (for example) and read that from an input stream,
- the text needs to define an element or junk will result. This is
- true of all input streams, but it's worth keeping in mind.
-
- A TiXmlDocument will read nodes until it reads a root element, and
- all the children of that root element.
- */
- friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
-
- /// Appends the XML node or attribute to a std::string.
- friend std::string& operator<< (std::string& out, const TiXmlNode& base );
-
- #endif
-
- /** The types of XML nodes supported by TinyXml. (All the
- unsupported types are picked up by UNKNOWN.)
- */
- enum NodeType
- {
- DOCUMENT,
- ELEMENT,
- COMMENT,
- UNKNOWN,
- TEXT,
- DECLARATION,
- TYPECOUNT
- };
-
- virtual ~TiXmlNode();
-
- /** The meaning of 'value' changes for the specific type of
- TiXmlNode.
- @verbatim
- Document: filename of the xml file
- Element: name of the element
- Comment: the comment text
- Unknown: the tag contents
- Text: the text string
- @endverbatim
-
- The subclasses will wrap this function.
- */
- const char *Value() const { return value.c_str (); }
-
- #ifdef TIXML_USE_STL
- /** Return Value() as a std::string. If you only use STL,
- this is more efficient than calling Value().
- Only available in STL mode.
- */
- const std::string& ValueStr() const { return value; }
- #endif
-
- const TIXML_STRING& ValueTStr() const { return value; }
-
- /** Changes the value of the node. Defined as:
- @verbatim
- Document: filename of the xml file
- Element: name of the element
- Comment: the comment text
- Unknown: the tag contents
- Text: the text string
- @endverbatim
- */
- void SetValue(const char * _value) { value = _value;}
-
- #ifdef TIXML_USE_STL
- /// STL std::string form.
- void SetValue( const std::string& _value ) { value = _value; }
- #endif
-
- /// Delete all the children of this node. Does not affect 'this'.
- void Clear();
-
- /// One step up the DOM.
- TiXmlNode* Parent() { return parent; }
- const TiXmlNode* Parent() const { return parent; }
-
- const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children.
- TiXmlNode* FirstChild() { return firstChild; }
- const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found.
- /// The first child of this node with the matching 'value'. Will be null if none found.
- TiXmlNode* FirstChild( const char * _value ) {
- // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
- // call the method, cast the return back to non-const.
- return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
- }
- const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children.
- TiXmlNode* LastChild() { return lastChild; }
-
- const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children.
- TiXmlNode* LastChild( const char * _value ) {
- return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
- }
-
- #ifdef TIXML_USE_STL
- const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form.
- TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form.
- const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form.
- TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form.
- #endif
-
- /** An alternate way to walk the children of a node.
- One way to iterate over nodes is:
- @verbatim
- for( child = parent->FirstChild(); child; child = child->NextSibling() )
- @endverbatim
-
- IterateChildren does the same thing with the syntax:
- @verbatim
- child = 0;
- while( child = parent->IterateChildren( child ) )
- @endverbatim
-
- IterateChildren takes the previous child as input and finds
- the next one. If the previous child is null, it returns the
- first. IterateChildren will return null when done.
- */
- const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
- TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
- return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
- }
-
- /// This flavor of IterateChildren searches for children with a particular 'value'
- const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
- TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
- return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
- }
-
- #ifdef TIXML_USE_STL
- const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
- TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
- #endif
-
- /** Add a new node related to this. Adds a child past the LastChild.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
-
-
- /** Add a new node related to this. Adds a child past the LastChild.
-
- NOTE: the node to be added is passed by pointer, and will be
- henceforth owned (and deleted) by tinyXml. This method is efficient
- and avoids an extra copy, but should be used with care as it
- uses a different memory model than the other insert functions.
-
- @sa InsertEndChild
- */
- TiXmlNode* LinkEndChild( TiXmlNode* addThis );
-
- /** Add a new node related to this. Adds a child before the specified child.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
-
- /** Add a new node related to this. Adds a child after the specified child.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
-
- /** Replace a child of this node.
- Returns a pointer to the new object or NULL if an error occured.
- */
- TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
-
- /// Delete a child of this node.
- bool RemoveChild( TiXmlNode* removeThis );
-
- /// Navigate to a sibling node.
- const TiXmlNode* PreviousSibling() const { return prev; }
- TiXmlNode* PreviousSibling() { return prev; }
-
- /// Navigate to a sibling node.
- const TiXmlNode* PreviousSibling( const char * ) const;
- TiXmlNode* PreviousSibling( const char *_prev ) {
- return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
- }
-
- #ifdef TIXML_USE_STL
- const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
- TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
- const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form.
- TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form.
- #endif
-
- /// Navigate to a sibling node.
- const TiXmlNode* NextSibling() const { return next; }
- TiXmlNode* NextSibling() { return next; }
-
- /// Navigate to a sibling node with the given 'value'.
- const TiXmlNode* NextSibling( const char * ) const;
- TiXmlNode* NextSibling( const char* _next ) {
- return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
- }
-
- /** Convenience function to get through elements.
- Calls NextSibling and ToElement. Will skip all non-Element
- nodes. Returns 0 if there is not another element.
- */
- const TiXmlElement* NextSiblingElement() const;
- TiXmlElement* NextSiblingElement() {
- return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
- }
-
- /** Convenience function to get through elements.
- Calls NextSibling and ToElement. Will skip all non-Element
- nodes. Returns 0 if there is not another element.
- */
- const TiXmlElement* NextSiblingElement( const char * ) const;
- TiXmlElement* NextSiblingElement( const char *_next ) {
- return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
- }
-
- #ifdef TIXML_USE_STL
- const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
- TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
- #endif
-
- /// Convenience function to get through elements.
- const TiXmlElement* FirstChildElement() const;
- TiXmlElement* FirstChildElement() {
- return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
- }
-
- /// Convenience function to get through elements.
- const TiXmlElement* FirstChildElement( const char * _value ) const;
- TiXmlElement* FirstChildElement( const char * _value ) {
- return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
- }
-
- #ifdef TIXML_USE_STL
- const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
- TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
- #endif
-
- /** Query the type (as an enumerated value, above) of this node.
- The possible types are: DOCUMENT, ELEMENT, COMMENT,
- UNKNOWN, TEXT, and DECLARATION.
- */
- int Type() const { return type; }
-
- /** Return a pointer to the Document this node lives in.
- Returns null if not in a document.
- */
- const TiXmlDocument* GetDocument() const;
- TiXmlDocument* GetDocument() {
- return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
- }
-
- /// Returns true if this node has no children.
- bool NoChildren() const { return !firstChild; }
-
- virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
-
- virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
- virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
-
- /** Create an exact duplicate of this node and return it. The memory must be deleted
- by the caller.
- */
- virtual TiXmlNode* Clone() const = 0;
-
- /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
- XML tree will be conditionally visited and the host will be called back
- via the TiXmlVisitor interface.
-
- This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
- the XML for the callbacks, so the performance of TinyXML is unchanged by using this
- interface versus any other.)
-
- The interface has been based on ideas from:
-
- - http://www.saxproject.org/
- - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
-
- Which are both good references for "visiting".
-
- An example of using Accept():
- @verbatim
- TiXmlPrinter printer;
- tinyxmlDoc.Accept( &printer );
- const char* xmlcstr = printer.CStr();
- @endverbatim
- */
- virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
-
-protected:
- TiXmlNode( NodeType _type );
-
- // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
- // and the assignment operator.
- void CopyTo( TiXmlNode* target ) const;
-
- #ifdef TIXML_USE_STL
- // The real work of the input operator.
- virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
- #endif
-
- // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
- TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
-
- TiXmlNode* parent;
- NodeType type;
-
- TiXmlNode* firstChild;
- TiXmlNode* lastChild;
-
- TIXML_STRING value;
-
- TiXmlNode* prev;
- TiXmlNode* next;
-
-private:
- TiXmlNode( const TiXmlNode& ); // not implemented.
- void operator=( const TiXmlNode& base ); // not allowed.
-};
-
-
-/** An attribute is a name-value pair. Elements have an arbitrary
- number of attributes, each with a unique name.
-
- @note The attributes are not TiXmlNodes, since they are not
- part of the tinyXML document object model. There are other
- suggested ways to look at this problem.
-*/
-class TiXmlAttribute : public TiXmlBase
-{
- friend class TiXmlAttributeSet;
-
-public:
- /// Construct an empty attribute.
- TiXmlAttribute() : TiXmlBase()
- {
- document = 0;
- prev = next = 0;
- }
-
- #ifdef TIXML_USE_STL
- /// std::string constructor.
- TiXmlAttribute( const std::string& _name, const std::string& _value )
- {
- name = _name;
- value = _value;
- document = 0;
- prev = next = 0;
- }
- #endif
-
- /// Construct an attribute with a name and value.
- TiXmlAttribute( const char * _name, const char * _value )
- {
- name = _name;
- value = _value;
- document = 0;
- prev = next = 0;
- }
-
- const char* Name() const { return name.c_str(); } ///< Return the name of this attribute.
- const char* Value() const { return value.c_str(); } ///< Return the value of this attribute.
- #ifdef TIXML_USE_STL
- const std::string& ValueStr() const { return value; } ///< Return the value of this attribute.
- #endif
- int IntValue() const; ///< Return the value of this attribute, converted to an integer.
- double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
-
- // Get the tinyxml string representation
- const TIXML_STRING& NameTStr() const { return name; }
-
- /** QueryIntValue examines the value string. It is an alternative to the
- IntValue() method with richer error checking.
- If the value is an integer, it is stored in 'value' and
- the call returns TIXML_SUCCESS. If it is not
- an integer, it returns TIXML_WRONG_TYPE.
-
- A specialized but useful call. Note that for success it returns 0,
- which is the opposite of almost all other TinyXml calls.
- */
- int QueryIntValue( int* _value ) const;
- /// QueryDoubleValue examines the value string. See QueryIntValue().
- int QueryDoubleValue( double* _value ) const;
-
- void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute.
- void SetValue( const char* _value ) { value = _value; } ///< Set the value.
-
- void SetIntValue( int _value ); ///< Set the value from an integer.
- void SetDoubleValue( double _value ); ///< Set the value from a double.
-
- #ifdef TIXML_USE_STL
- /// STL std::string form.
- void SetName( const std::string& _name ) { name = _name; }
- /// STL std::string form.
- void SetValue( const std::string& _value ) { value = _value; }
- #endif
-
- /// Get the next sibling attribute in the DOM. Returns null at end.
- const TiXmlAttribute* Next() const;
- TiXmlAttribute* Next() {
- return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() );
- }
-
- /// Get the previous sibling attribute in the DOM. Returns null at beginning.
- const TiXmlAttribute* Previous() const;
- TiXmlAttribute* Previous() {
- return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() );
- }
-
- bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
- bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; }
- bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; }
-
- /* Attribute parsing starts: first letter of the name
- returns: the next char after the value end quote
- */
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- // Prints this Attribute to a FILE stream.
- virtual void Print( FILE* cfile, int depth ) const {
- Print( cfile, depth, 0 );
- }
- void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
-
- // [internal use]
- // Set the document pointer so the attribute can report errors.
- void SetDocument( TiXmlDocument* doc ) { document = doc; }
-
-private:
- TiXmlAttribute( const TiXmlAttribute& ); // not implemented.
- void operator=( const TiXmlAttribute& base ); // not allowed.
-
- TiXmlDocument* document; // A pointer back to a document, for error reporting.
- TIXML_STRING name;
- TIXML_STRING value;
- TiXmlAttribute* prev;
- TiXmlAttribute* next;
-};
-
-
-/* A class used to manage a group of attributes.
- It is only used internally, both by the ELEMENT and the DECLARATION.
-
- The set can be changed transparent to the Element and Declaration
- classes that use it, but NOT transparent to the Attribute
- which has to implement a next() and previous() method. Which makes
- it a bit problematic and prevents the use of STL.
-
- This version is implemented with circular lists because:
- - I like circular lists
- - it demonstrates some independence from the (typical) doubly linked list.
-*/
-class TiXmlAttributeSet
-{
-public:
- TiXmlAttributeSet();
- ~TiXmlAttributeSet();
-
- void Add( TiXmlAttribute* attribute );
- void Remove( TiXmlAttribute* attribute );
-
- const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
- TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
- const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
- TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
-
- const TiXmlAttribute* Find( const char* _name ) const;
- TiXmlAttribute* Find( const char* _name ) {
- return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
- }
- #ifdef TIXML_USE_STL
- const TiXmlAttribute* Find( const std::string& _name ) const;
- TiXmlAttribute* Find( const std::string& _name ) {
- return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
- }
-
- #endif
-
-private:
- //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
- //*ME: this class must be also use a hidden/disabled copy-constructor !!!
- TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed
- void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute)
-
- TiXmlAttribute sentinel;
-};
-
-
-/** The element is a container class. It has a value, the element name,
- and can contain other elements, text, comments, and unknowns.
- Elements also contain an arbitrary number of attributes.
-*/
-class TiXmlElement : public TiXmlNode
-{
-public:
- /// Construct an element.
- TiXmlElement (const char * in_value);
-
- #ifdef TIXML_USE_STL
- /// std::string constructor.
- TiXmlElement( const std::string& _value );
- #endif
-
- TiXmlElement( const TiXmlElement& );
-
- void operator=( const TiXmlElement& base );
-
- virtual ~TiXmlElement();
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- */
- const char* Attribute( const char* name ) const;
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- If the attribute exists and can be converted to an integer,
- the integer value will be put in the return 'i', if 'i'
- is non-null.
- */
- const char* Attribute( const char* name, int* i ) const;
-
- /** Given an attribute name, Attribute() returns the value
- for the attribute of that name, or null if none exists.
- If the attribute exists and can be converted to an double,
- the double value will be put in the return 'd', if 'd'
- is non-null.
- */
- const char* Attribute( const char* name, double* d ) const;
-
- /** QueryIntAttribute examines the attribute - it is an alternative to the
- Attribute() method with richer error checking.
- If the attribute is an integer, it is stored in 'value' and
- the call returns TIXML_SUCCESS. If it is not
- an integer, it returns TIXML_WRONG_TYPE. If the attribute
- does not exist, then TIXML_NO_ATTRIBUTE is returned.
- */
- int QueryIntAttribute( const char* name, int* _value ) const;
- /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
- int QueryDoubleAttribute( const char* name, double* _value ) const;
- /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
- int QueryFloatAttribute( const char* name, float* _value ) const {
- double d;
- int result = QueryDoubleAttribute( name, &d );
- if ( result == TIXML_SUCCESS ) {
- *_value = (float)d;
- }
- return result;
- }
-
- #ifdef TIXML_USE_STL
- /** Template form of the attribute query which will try to read the
- attribute into the specified type. Very easy, very powerful, but
- be careful to make sure to call this with the correct type.
-
- NOTE: This method doesn't work correctly for 'string' types.
-
- @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
- */
- template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
- {
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
-
- std::stringstream sstream( node->ValueStr() );
- sstream >> *outValue;
- if ( !sstream.fail() )
- return TIXML_SUCCESS;
- return TIXML_WRONG_TYPE;
- }
- /*
- This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string"
- but template specialization is hard to get working cross-compiler. Leaving the bug for now.
-
- // The above will fail for std::string because the space character is used as a seperator.
- // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string
- template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const
- {
- const TiXmlAttribute* node = attributeSet.Find( name );
- if ( !node )
- return TIXML_NO_ATTRIBUTE;
- *outValue = node->ValueStr();
- return TIXML_SUCCESS;
- }
- */
- #endif
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetAttribute( const char* name, const char * _value );
-
- #ifdef TIXML_USE_STL
- const std::string* Attribute( const std::string& name ) const;
- const std::string* Attribute( const std::string& name, int* i ) const;
- const std::string* Attribute( const std::string& name, double* d ) const;
- int QueryIntAttribute( const std::string& name, int* _value ) const;
- int QueryDoubleAttribute( const std::string& name, double* _value ) const;
-
- /// STL std::string form.
- void SetAttribute( const std::string& name, const std::string& _value );
- ///< STL std::string form.
- void SetAttribute( const std::string& name, int _value );
- #endif
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetAttribute( const char * name, int value );
-
- /** Sets an attribute of name to a given value. The attribute
- will be created if it does not exist, or changed if it does.
- */
- void SetDoubleAttribute( const char * name, double value );
-
- /** Deletes an attribute with the given name.
- */
- void RemoveAttribute( const char * name );
- #ifdef TIXML_USE_STL
- void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form.
- #endif
-
- const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element.
- TiXmlAttribute* FirstAttribute() { return attributeSet.First(); }
- const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element.
- TiXmlAttribute* LastAttribute() { return attributeSet.Last(); }
-
- /** Convenience function for easy access to the text inside an element. Although easy
- and concise, GetText() is limited compared to getting the TiXmlText child
- and accessing it directly.
-
- If the first child of 'this' is a TiXmlText, the GetText()
- returns the character string of the Text node, else null is returned.
-
- This is a convenient method for getting the text of simple contained text:
- @verbatim
- <foo>This is text</foo>
- const char* str = fooElement->GetText();
- @endverbatim
-
- 'str' will be a pointer to "This is text".
-
- Note that this function can be misleading. If the element foo was created from
- this XML:
- @verbatim
- <foo><b>This is text</b></foo>
- @endverbatim
-
- then the value of str would be null. The first child node isn't a text node, it is
- another element. From this XML:
- @verbatim
- <foo>This is <b>text</b></foo>
- @endverbatim
- GetText() will return "This is ".
-
- WARNING: GetText() accesses a child node - don't become confused with the
- similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
- safe type casts on the referenced node.
- */
- const char* GetText() const;
-
- /// Creates a new Element and returns it - the returned element is a copy.
- virtual TiXmlNode* Clone() const;
- // Print the Element to a FILE stream.
- virtual void Print( FILE* cfile, int depth ) const;
-
- /* Attribtue parsing starts: next char past '<'
- returns: next char past '>'
- */
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* visitor ) const;
-
-protected:
-
- void CopyTo( TiXmlElement* target ) const;
- void ClearThis(); // like clear, but initializes 'this' object as well
-
- // Used to be public [internal use]
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
- /* [internal use]
- Reads the "value" of the element -- another element, or text.
- This should terminate with the current end tag.
- */
- const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
-
-private:
-
- TiXmlAttributeSet attributeSet;
-};
-
-
-/** An XML comment.
-*/
-class TiXmlComment : public TiXmlNode
-{
-public:
- /// Constructs an empty comment.
- TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
- /// Construct a comment from text.
- TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) {
- SetValue( _value );
- }
- TiXmlComment( const TiXmlComment& );
- void operator=( const TiXmlComment& base );
-
- virtual ~TiXmlComment() {}
-
- /// Returns a copy of this Comment.
- virtual TiXmlNode* Clone() const;
- // Write this Comment to a FILE stream.
- virtual void Print( FILE* cfile, int depth ) const;
-
- /* Attribtue parsing starts: at the ! of the !--
- returns: next char past '>'
- */
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* visitor ) const;
-
-protected:
- void CopyTo( TiXmlComment* target ) const;
-
- // used to be public
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
-// virtual void StreamOut( TIXML_OSTREAM * out ) const;
-
-private:
-
-};
-
-
-/** XML text. A text node can have 2 ways to output the next. "normal" output
- and CDATA. It will default to the mode it was parsed from the XML file and
- you generally want to leave it alone, but you can change the output mode with
- SetCDATA() and query it with CDATA().
-*/
-class TiXmlText : public TiXmlNode
-{
- friend class TiXmlElement;
-public:
- /** Constructor for text element. By default, it is treated as
- normal, encoded text. If you want it be output as a CDATA text
- element, set the parameter _cdata to 'true'
- */
- TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT)
- {
- SetValue( initValue );
- cdata = false;
- }
- virtual ~TiXmlText() {}
-
- #ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
- {
- SetValue( initValue );
- cdata = false;
- }
- #endif
-
- TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); }
- void operator=( const TiXmlText& base ) { base.CopyTo( this ); }
-
- // Write this text object to a FILE stream.
- virtual void Print( FILE* cfile, int depth ) const;
-
- /// Queries whether this represents text using a CDATA section.
- bool CDATA() const { return cdata; }
- /// Turns on or off a CDATA representation of text.
- void SetCDATA( bool _cdata ) { cdata = _cdata; }
-
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* content ) const;
-
-protected :
- /// [internal use] Creates a new Element and returns it.
- virtual TiXmlNode* Clone() const;
- void CopyTo( TiXmlText* target ) const;
-
- bool Blank() const; // returns true if all white space and new lines
- // [internal use]
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
-
-private:
- bool cdata; // true if this should be input and output as a CDATA style text element
-};
-
-
-/** In correct XML the declaration is the first entry in the file.
- @verbatim
- <?xml version="1.0" standalone="yes"?>
- @endverbatim
-
- TinyXml will happily read or write files without a declaration,
- however. There are 3 possible attributes to the declaration:
- version, encoding, and standalone.
-
- Note: In this version of the code, the attributes are
- handled as special cases, not generic attributes, simply
- because there can only be at most 3 and they are always the same.
-*/
-class TiXmlDeclaration : public TiXmlNode
-{
-public:
- /// Construct an empty declaration.
- TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {}
-
-#ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlDeclaration( const std::string& _version,
- const std::string& _encoding,
- const std::string& _standalone );
-#endif
-
- /// Construct.
- TiXmlDeclaration( const char* _version,
- const char* _encoding,
- const char* _standalone );
-
- TiXmlDeclaration( const TiXmlDeclaration& copy );
- void operator=( const TiXmlDeclaration& copy );
-
- virtual ~TiXmlDeclaration() {}
-
- /// Version. Will return an empty string if none was found.
- const char *Version() const { return version.c_str (); }
- /// Encoding. Will return an empty string if none was found.
- const char *Encoding() const { return encoding.c_str (); }
- /// Is this a standalone document?
- const char *Standalone() const { return standalone.c_str (); }
-
- /// Creates a copy of this Declaration and returns it.
- virtual TiXmlNode* Clone() const;
- // Print this declaration to a FILE stream.
- virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
- virtual void Print( FILE* cfile, int depth ) const {
- Print( cfile, depth, 0 );
- }
-
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* visitor ) const;
-
-protected:
- void CopyTo( TiXmlDeclaration* target ) const;
- // used to be public
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
-
-private:
-
- TIXML_STRING version;
- TIXML_STRING encoding;
- TIXML_STRING standalone;
-};
-
-
-/** Any tag that tinyXml doesn't recognize is saved as an
- unknown. It is a tag of text, but should not be modified.
- It will be written back to the XML, unchanged, when the file
- is saved.
-
- DTD tags get thrown into TiXmlUnknowns.
-*/
-class TiXmlUnknown : public TiXmlNode
-{
-public:
- TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
- virtual ~TiXmlUnknown() {}
-
- TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); }
- void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); }
-
- /// Creates a copy of this Unknown and returns it.
- virtual TiXmlNode* Clone() const;
- // Print this Unknown to a FILE stream.
- virtual void Print( FILE* cfile, int depth ) const;
-
- virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
-
- virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* content ) const;
-
-protected:
- void CopyTo( TiXmlUnknown* target ) const;
-
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
-
-private:
-
-};
-
-
-/** Always the top level node. A document binds together all the
- XML pieces. It can be saved, loaded, and printed to the screen.
- The 'value' of a document node is the xml file name.
-*/
-class TiXmlDocument : public TiXmlNode
-{
-public:
- /// Create an empty document, that has no name.
- TiXmlDocument();
- /// Create a document with a name. The name of the document is also the filename of the xml.
- TiXmlDocument( const char * documentName );
-
- // Altered header
- bool ReadFromMemory( const char* pBuf, size_t sz, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING);
-
- #ifdef TIXML_USE_STL
- /// Constructor.
- TiXmlDocument( const std::string& documentName );
- #endif
-
- TiXmlDocument( const TiXmlDocument& copy );
- void operator=( const TiXmlDocument& copy );
-
- virtual ~TiXmlDocument() {}
-
- /** Load a file using the current document value.
- Returns true if successful. Will delete any existing
- document data before loading.
- */
- bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
- /// Save a file using the current document value. Returns true if successful.
- bool SaveFile() const;
- /// Load a file using the given filename. Returns true if successful.
- bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
- /// Save a file using the given filename. Returns true if successful.
- bool SaveFile( const char * filename ) const;
- /** Load a file using the given FILE*. Returns true if successful. Note that this method
- doesn't stream - the entire object pointed at by the FILE*
- will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
- file location. Streaming may be added in the future.
- */
- bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
- /// Save a file using the given FILE*. Returns true if successful.
- bool SaveFile( FILE* ) const;
-
- #ifdef TIXML_USE_STL
- bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version.
- {
-// StringToBuffer f( filename );
-// return ( f.buffer && LoadFile( f.buffer, encoding ));
- return LoadFile( filename.c_str(), encoding );
- }
- bool SaveFile( const std::string& filename ) const ///< STL std::string version.
- {
-// StringToBuffer f( filename );
-// return ( f.buffer && SaveFile( f.buffer ));
- return SaveFile( filename.c_str() );
- }
- #endif
-
- /** Parse the given null terminated block of xml data. Passing in an encoding to this
- method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
- to use that encoding, regardless of what TinyXml might otherwise try to detect.
- */
- virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
-
- /** Get the root element -- the only top level element -- of the document.
- In well formed XML, there should only be one. TinyXml is tolerant of
- multiple elements at the document level.
- */
- const TiXmlElement* RootElement() const { return FirstChildElement(); }
- TiXmlElement* RootElement() { return FirstChildElement(); }
-
- /** If an error occurs, Error will be set to true. Also,
- - The ErrorId() will contain the integer identifier of the error (not generally useful)
- - The ErrorDesc() method will return the name of the error. (very useful)
- - The ErrorRow() and ErrorCol() will return the location of the error (if known)
- */
- bool Error() const { return error; }
-
- /// Contains a textual (english) description of the error if one occurs.
- const char * ErrorDesc() const { return errorDesc.c_str (); }
-
- /** Generally, you probably want the error string ( ErrorDesc() ). But if you
- prefer the ErrorId, this function will fetch it.
- */
- int ErrorId() const { return errorId; }
-
- /** Returns the location (if known) of the error. The first column is column 1,
- and the first row is row 1. A value of 0 means the row and column wasn't applicable
- (memory errors, for example, have no row/column) or the parser lost the error. (An
- error in the error reporting, in that case.)
-
- @sa SetTabSize, Row, Column
- */
- int ErrorRow() const { return errorLocation.row+1; }
- int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
-
- /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
- to report the correct values for row and column. It does not change the output
- or input in any way.
-
- By calling this method, with a tab size
- greater than 0, the row and column of each node and attribute is stored
- when the file is loaded. Very useful for tracking the DOM back in to
- the source file.
-
- The tab size is required for calculating the location of nodes. If not
- set, the default of 4 is used. The tabsize is set per document. Setting
- the tabsize to 0 disables row/column tracking.
-
- Note that row and column tracking is not supported when using operator>>.
-
- The tab size needs to be enabled before the parse or load. Correct usage:
- @verbatim
- TiXmlDocument doc;
- doc.SetTabSize( 8 );
- doc.Load( "myfile.xml" );
- @endverbatim
-
- @sa Row, Column
- */
- void SetTabSize( int _tabsize ) { tabsize = _tabsize; }
-
- int TabSize() const { return tabsize; }
-
- /** If you have handled the error, it can be reset with this call. The error
- state is automatically cleared if you Parse a new XML block.
- */
- void ClearError() { error = false;
- errorId = 0;
- errorDesc = "";
- errorLocation.row = errorLocation.col = 0;
- //errorLocation.last = 0;
- }
-
- /** Write the document to standard out using formatted printing ("pretty print"). */
- void Print() const { Print( stdout, 0 ); }
-
- /* Write the document to a string using formatted printing ("pretty print"). This
- will allocate a character array (new char[]) and return it as a pointer. The
- calling code pust call delete[] on the return char* to avoid a memory leak.
- */
- //char* PrintToMemory() const;
-
- /// Print this Document to a FILE stream.
- virtual void Print( FILE* cfile, int depth = 0 ) const;
- // [internal use]
- void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
-
- virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
- virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
-
- /** Walk the XML tree visiting this node and all of its children.
- */
- virtual bool Accept( TiXmlVisitor* content ) const;
-
-protected :
- // [internal use]
- virtual TiXmlNode* Clone() const;
- #ifdef TIXML_USE_STL
- virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
- #endif
-
-private:
- void CopyTo( TiXmlDocument* target ) const;
-
- bool error;
- int errorId;
- TIXML_STRING errorDesc;
- int tabsize;
- TiXmlCursor errorLocation;
- bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write.
-};
-
-
-/**
- A TiXmlHandle is a class that wraps a node pointer with null checks; this is
- an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
- DOM structure. It is a separate utility class.
-
- Take an example:
- @verbatim
- <Document>
- <Element attributeA = "valueA">
- <Child attributeB = "value1" />
- <Child attributeB = "value2" />
- </Element>
- <Document>
- @endverbatim
-
- Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
- easy to write a *lot* of code that looks like:
-
- @verbatim
- TiXmlElement* root = document.FirstChildElement( "Document" );
- if ( root )
- {
- TiXmlElement* element = root->FirstChildElement( "Element" );
- if ( element )
- {
- TiXmlElement* child = element->FirstChildElement( "Child" );
- if ( child )
- {
- TiXmlElement* child2 = child->NextSiblingElement( "Child" );
- if ( child2 )
- {
- // Finally do something useful.
- @endverbatim
-
- And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
- of such code. A TiXmlHandle checks for null pointers so it is perfectly safe
- and correct to use:
-
- @verbatim
- TiXmlHandle docHandle( &document );
- TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
- if ( child2 )
- {
- // do something useful
- @endverbatim
-
- Which is MUCH more concise and useful.
-
- It is also safe to copy handles - internally they are nothing more than node pointers.
- @verbatim
- TiXmlHandle handleCopy = handle;
- @endverbatim
-
- What they should not be used for is iteration:
-
- @verbatim
- int i=0;
- while ( true )
- {
- TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
- if ( !child )
- break;
- // do something
- ++i;
- }
- @endverbatim
-
- It seems reasonable, but it is in fact two embedded while loops. The Child method is
- a linear walk to find the element, so this code would iterate much more than it needs
- to. Instead, prefer:
-
- @verbatim
- TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
-
- for( child; child; child=child->NextSiblingElement() )
- {
- // do something
- }
- @endverbatim
-*/
-class TiXmlHandle
-{
-public:
- /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
- TiXmlHandle( TiXmlNode* _node ) { this->node = _node; }
- /// Copy constructor
- TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; }
- TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
-
- /// Return a handle to the first child node.
- TiXmlHandle FirstChild() const;
- /// Return a handle to the first child node with the given name.
- TiXmlHandle FirstChild( const char * value ) const;
- /// Return a handle to the first child element.
- TiXmlHandle FirstChildElement() const;
- /// Return a handle to the first child element with the given name.
- TiXmlHandle FirstChildElement( const char * value ) const;
-
- /** Return a handle to the "index" child with the given name.
- The first child is 0, the second 1, etc.
- */
- TiXmlHandle Child( const char* value, int index ) const;
- /** Return a handle to the "index" child.
- The first child is 0, the second 1, etc.
- */
- TiXmlHandle Child( int index ) const;
- /** Return a handle to the "index" child element with the given name.
- The first child element is 0, the second 1, etc. Note that only TiXmlElements
- are indexed: other types are not counted.
- */
- TiXmlHandle ChildElement( const char* value, int index ) const;
- /** Return a handle to the "index" child element.
- The first child element is 0, the second 1, etc. Note that only TiXmlElements
- are indexed: other types are not counted.
- */
- TiXmlHandle ChildElement( int index ) const;
-
- #ifdef TIXML_USE_STL
- TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); }
- TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); }
-
- TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); }
- TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); }
- #endif
-
- /** Return the handle as a TiXmlNode. This may return null.
- */
- TiXmlNode* ToNode() const { return node; }
- /** Return the handle as a TiXmlElement. This may return null.
- */
- TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
- /** Return the handle as a TiXmlText. This may return null.
- */
- TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
- /** Return the handle as a TiXmlUnknown. This may return null.
- */
- TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
-
- /** @deprecated use ToNode.
- Return the handle as a TiXmlNode. This may return null.
- */
- TiXmlNode* Node() const { return ToNode(); }
- /** @deprecated use ToElement.
- Return the handle as a TiXmlElement. This may return null.
- */
- TiXmlElement* Element() const { return ToElement(); }
- /** @deprecated use ToText()
- Return the handle as a TiXmlText. This may return null.
- */
- TiXmlText* Text() const { return ToText(); }
- /** @deprecated use ToUnknown()
- Return the handle as a TiXmlUnknown. This may return null.
- */
- TiXmlUnknown* Unknown() const { return ToUnknown(); }
-
-private:
- TiXmlNode* node;
-};
-
-
-/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
-
- -# Print to memory (especially in non-STL mode)
- -# Control formatting (line endings, etc.)
-
- When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
- Before calling Accept() you can call methods to control the printing
- of the XML document. After TiXmlNode::Accept() is called, the printed document can
- be accessed via the CStr(), Str(), and Size() methods.
-
- TiXmlPrinter uses the Visitor API.
- @verbatim
- TiXmlPrinter printer;
- printer.SetIndent( "\t" );
-
- doc.Accept( &printer );
- fprintf( stdout, "%s", printer.CStr() );
- @endverbatim
-*/
-class TiXmlPrinter : public TiXmlVisitor
-{
-public:
- TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
- buffer(), indent( " " ), lineBreak( "\n" ) {}
-
- virtual bool VisitEnter( const TiXmlDocument& doc );
- virtual bool VisitExit( const TiXmlDocument& doc );
-
- virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
- virtual bool VisitExit( const TiXmlElement& element );
-
- virtual bool Visit( const TiXmlDeclaration& declaration );
- virtual bool Visit( const TiXmlText& text );
- virtual bool Visit( const TiXmlComment& comment );
- virtual bool Visit( const TiXmlUnknown& unknown );
-
- /** Set the indent characters for printing. By default 4 spaces
- but tab (\t) is also useful, or null/empty string for no indentation.
- */
- void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; }
- /// Query the indention string.
- const char* Indent() { return indent.c_str(); }
- /** Set the line breaking string. By default set to newline (\n).
- Some operating systems prefer other characters, or can be
- set to the null/empty string for no indenation.
- */
- void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; }
- /// Query the current line breaking string.
- const char* LineBreak() { return lineBreak.c_str(); }
-
- /** Switch over to "stream printing" which is the most dense formatting without
- linebreaks. Common when the XML is needed for network transmission.
- */
- void SetStreamPrinting() { indent = "";
- lineBreak = "";
- }
- /// Return the result.
- const char* CStr() { return buffer.c_str(); }
- /// Return the length of the result string.
- size_t Size() { return buffer.size(); }
-
- #ifdef TIXML_USE_STL
- /// Return the result.
- const std::string& Str() { return buffer; }
- #endif
-
-private:
- void DoIndent() {
- for( int i=0; i<depth; ++i )
- buffer += indent;
- }
- void DoLineBreak() {
- buffer += lineBreak;
- }
-
- int depth;
- bool simpleTextPrint;
- TIXML_STRING buffer;
- TIXML_STRING indent;
- TIXML_STRING lineBreak;
-};
-
-
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
-
-#endif
-
diff --git a/rotord/tinyxmlerror.cpp b/rotord/tinyxmlerror.cpp
deleted file mode 100755
index d24f63b..0000000
--- a/rotord/tinyxmlerror.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2006 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
-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
-redistribute it freely, subject to the following restrictions:
-
-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
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include "tinyxml.h"
-
-// The goal of the seperate error file is to make the first
-// step towards localization. tinyxml (currently) only supports
-// english error messages, but the could now be translated.
-//
-// It also cleans up the code a bit.
-//
-
-const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
-{
- "No error",
- "Error",
- "Failed to open file",
- "Memory allocation failed.",
- "Error parsing Element.",
- "Failed to read Element name",
- "Error reading Element value.",
- "Error reading Attributes.",
- "Error: empty tag.",
- "Error reading end tag.",
- "Error parsing Unknown.",
- "Error parsing Comment.",
- "Error parsing Declaration.",
- "Error document empty.",
- "Error null (0) or unexpected EOF found in input stream.",
- "Error parsing CDATA.",
- "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
-};
diff --git a/rotord/tinyxmlparser.cpp b/rotord/tinyxmlparser.cpp
deleted file mode 100755
index c672283..0000000
--- a/rotord/tinyxmlparser.cpp
+++ /dev/null
@@ -1,1719 +0,0 @@
-/*
-www.sourceforge.net/projects/tinyxml
-Original code (2.0 and earlier )copyright (c) 2000-2002 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
-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
-redistribute it freely, subject to the following restrictions:
-
-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
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-*/
-
-#include <ctype.h>
-#include <stddef.h>
-
-#include "tinyxml.h"
-
-//#define DEBUG_PARSER
-#if defined( DEBUG_PARSER )
-# if defined( DEBUG ) && defined( _MSC_VER )
-# include <windows.h>
-# define TIXML_LOG OutputDebugString
-# else
-# define TIXML_LOG printf
-# endif
-#endif
-
-// 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[ NUM_ENTITY ] =
-{
- { "&amp;", 5, '&' },
- { "&lt;", 4, '<' },
- { "&gt;", 4, '>' },
- { "&quot;", 6, '\"' },
- { "&apos;", 6, '\'' }
-};
-
-// Bunch of unicode info at:
-// http://www.unicode.org/faq/utf_bom.html
-// 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:
-// ef bb bf (Microsoft "lead bytes")
-// ef bf be
-// 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] =
-{
- // 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]);
- }
-}
-
-
-/*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.
-
-// 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.
-// }
-// else
-// {
-// return isalpha( anyByte );
-// }
-}
-
-
-/*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.
-
-// 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.
-// }
-// else
-// {
-// return isalnum( anyByte );
-// }
-}
-
-
-class TiXmlParsingData
-{
- friend class TiXmlDocument;
- public:
- void Stamp( const char* now, TiXmlEncoding encoding );
-
- const TiXmlCursor& Cursor() { 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;
-};
-
-
-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 );
-}
-
-
-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 ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space.
- ++p;
- else
- break;
- }
- }
- else
- {
- while ( (*p && IsWhiteSpace( *p )) || *p == '\n' || *p =='\r' )
- ++p;
- }
-
- return p;
-}
-
-#ifdef TIXML_USE_STL
-/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
-{
- 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;
-
- *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;
-}
-#endif
-
-// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
-// "assign" optimization removes over 10% of the execution time.
-//
-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;
-}
-
-const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
-{
- // 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;
-}
-
-
-bool TiXmlBase::StringEqual( const char* p,
- 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;
-}
-
-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 += strlen( endTag );
- return p;
-}
-
-#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 );
-}
-
-#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;
- }
- }
-
- 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;
-}
-
-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();
- }
-}
-
-
-TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
-{
- TiXmlNode* returnNode = 0;
-
- p = SkipWhiteSpace( p, encoding );
- if( !p || !*p || *p != '<' )
- {
- return 0;
- }
-
- TiXmlDocument* doc = GetDocument();
- 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;
- }
- else
- {
- if ( doc )
- doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
- }
- 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.
- }
- }
- }
-}
-#endif
-
-const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
-{
- p = SkipWhiteSpace( p, encoding );
- TiXmlDocument* document = GetDocument();
-
- 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 ( *p != '<' )
- {
- if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
- return 0;
- }
-
- p = SkipWhiteSpace( p+1, encoding );
-
- // 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;
- }
-
- TIXML_STRING endTag ("</");
- endTag += value;
- endTag += ">";
-
- // 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
- if ( StringEqual( p, endTag.c_str(), false, encoding ) )
- {
- p += endTag.length();
- return p;
- }
- 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 )
- {
- if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
- 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 )
- {
- node->SetValue( attrib->Value() );
- 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 )
- {
- if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
- 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;
- }
- }
-}
-#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;
- value = "";
-
- while ( p && *p && *p != '>' )
- {
- value += *p;
- ++p;
- }
-
- if ( !p )
- {
- if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
- }
- if ( *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;
- }
- }
-}
-#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 ) )
- {
- 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 += strlen( endTag );
-
- return p;
-}
-
-
-const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
-{
- p = SkipWhiteSpace( p, encoding );
- if ( !p || !*p ) return 0;
-
-// int tabsize = 4;
-// if ( document )
-// tabsize = document->TabSize();
-
- 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 ) && *p != '\n' && *p != '\r' // 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;
- }
- }
- }
-}
-#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 ) )
- {
- 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 )
- 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;
- }
- }
-}
-#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;
-}
-
-bool TiXmlText::Blank() const
-{
- for ( unsigned i=0; i<value.length(); i++ )
- if ( !IsWhiteSpace( value[i] ) )
- return false;
- return true;
-}
-
-
-bool TiXmlDocument::ReadFromMemory( const char* pBuf, size_t sz, TiXmlEncoding encoding)
-{
- // Delete the existing data:
- Clear();
- location.Clear();
-
- // Get the file size, so we can pre-allocate the string. HUGE speed impact.
- long length = (long) sz;
-
- // Strange case, but good to handle up front.
- if ( length == 0 )
- {
- SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
- return false;
- }
-
- // If we have a file, assume it is all one big XML file, and read it in.
- // The document parser may decide the document ends sooner than the entire file, however.
- TIXML_STRING data;
- data.reserve( length );
-
-
- char* buf = new char[ length+1 ];
- memset(buf,0,length+1);
-
- memcpy(buf, pBuf, length);
-
- const char* lastPos = buf;
- const char* p = buf;
-
- buf[length] = 0;
- while( *p ) {
- assert( p < (buf+length) );
- if ( *p == 0xa ) {
- // Newline character. No special rules for this. Append all the characters
- // since the last string, and include the newline.
- data.append( lastPos, (p-lastPos+1) ); // append, include the newline
- ++p; // move past the newline
- lastPos = p; // and point to the new buffer (may be 0)
- assert( p <= (buf+length) );
- }
- else if ( *p == 0xd ) {
- // Carriage return. Append what we have so far, then
- // handle moving forward in the buffer.
- if ( (p-lastPos) > 0 ) {
- data.append( lastPos, p-lastPos ); // do not add the CR
- }
- data += (char)0xa; // a proper newline
-
- if ( *(p+1) == 0xa ) {
- // Carriage return - new line sequence
- p += 2;
- lastPos = p;
- assert( p <= (buf+length) );
- }
- else {
- // it was followed by something else...that is presumably characters again.
- ++p;
- lastPos = p;
- assert( p <= (buf+length) );
- }
- }
- else {
- ++p;
- }
- }
- // Handle any left over characters.
- if ( p-lastPos ) {
- data.append( lastPos, p-lastPos );
- }
- delete [] buf;
- buf = 0;
-
- Parse( data.c_str(), 0, encoding );
-
- if ( Error() )
- return false;
- else
- return true;
-}
diff --git a/rotord/utils.cpp b/rotord/utils.cpp
deleted file mode 100644
index 9828124..0000000
--- a/rotord/utils.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "utils.h"
-
-using namespace std;
-
-//float equality
-bool fequal(const float u,const float v){
- if (abs(u-v)<FLOAT_THRESHOLD) return true;
- else return false;
-};
-bool fless_or_equal(const float u,const float v){
- //v is less or equal to u
- if (u-v>-FLOAT_THRESHOLD) return true;
- else return false;
-};
-bool fgreater_or_equal(const float u,const float v){
- //v is more or equal to u
- if (v-u>-FLOAT_THRESHOLD) return true;
- else return false;
-};
-bool fless(const float u,const float v){
- //v is less than u
- if (u-v>FLOAT_THRESHOLD) return true;
- else return false;
-};
-bool fgreater(const float u,const float v){
- //v is greater than u
- if (v-u>FLOAT_THRESHOLD) return true;
- else return false;
-};
diff --git a/rotord/utils.h b/rotord/utils.h
deleted file mode 100644
index 3859afe..0000000
--- a/rotord/utils.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <cmath>
-
-#define FLOAT_THRESHOLD .001f
-
-//float equality
-bool fequal(const float u,const float v);
-bool fless_or_equal(const float u,const float v);
-bool fgreater_or_equal(const float u,const float v);
-bool fless(const float u,const float v);
-bool fgreater(const float u,const float v);
diff --git a/rotord/vampHost.cpp b/rotord/vampHost.cpp
deleted file mode 100644
index 65755eb..0000000
--- a/rotord/vampHost.cpp
+++ /dev/null
@@ -1,815 +0,0 @@
-#include "vampHost.h"
-
-int vampHost::runPlugin(string myname, string soname, string id, string output,
- int outputNo, string inputFile, ostream& out, bool useFrames)
-{
- PluginLoader *loader = PluginLoader::getInstance();
-
- PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
-
- SNDFILE *sndfile;
- SF_INFO sfinfo;
- memset(&sfinfo, 0, sizeof(SF_INFO));
-
- sndfile = sf_open(inputFile.c_str(), SFM_READ, &sfinfo);
- if (!sndfile) {
- cerr << myname << ": ERROR: Failed to open input file \""
- << inputFile << "\": " << sf_strerror(sndfile) << endl;
- return 1;
- }
-
- Plugin *plugin = loader->loadPlugin
- (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
- if (!plugin) {
- cerr << myname << ": ERROR: Failed to load plugin \"" << id
- << "\" from library \"" << soname << "\"" << endl;
- sf_close(sndfile);
- return 1;
- }
-
- cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
-
- // Note that the following would be much simpler if we used a
- // PluginBufferingAdapter as well -- i.e. if we had passed
- // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead
- // of ADAPT_ALL_SAFE. Then we could simply specify our own block
- // size, keep the step size equal to the block size, and ignore
- // the plugin's bleatings. However, there are some issues with
- // using a PluginBufferingAdapter that make the results sometimes
- // technically different from (if effectively the same as) the
- // un-adapted plugin, so we aren't doing that here. See the
- // PluginBufferingAdapter documentation for details.
-
- int blockSize = plugin->getPreferredBlockSize();
- int stepSize = plugin->getPreferredStepSize();
-
- if (blockSize == 0) {
- blockSize = 1024;
- }
- if (stepSize == 0) {
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- stepSize = blockSize/2;
- } else {
- stepSize = blockSize;
- }
- } else if (stepSize > blockSize) {
- cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- blockSize = stepSize * 2;
- } else {
- blockSize = stepSize;
- }
- cerr << blockSize << endl;
- }
- int overlapSize = blockSize - stepSize;
- sf_count_t currentStep = 0;
- int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
-
- int channels = sfinfo.channels;
-
- float *filebuf = new float[blockSize * channels];
- float **plugbuf = new float*[channels];
- for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
-
- cerr << "Using block size = " << blockSize << ", step size = "
- << stepSize << endl;
-
- // The channel queries here are for informational purposes only --
- // a PluginChannelAdapter is being used automatically behind the
- // scenes, and it will take case of any channel mismatch
-
- int minch = plugin->getMinChannelCount();
- int maxch = plugin->getMaxChannelCount();
- cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
- cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
-
- Plugin::OutputList outputs = plugin->getOutputDescriptors();
- Plugin::OutputDescriptor od;
-
- int returnValue = 1;
- int progress = 0;
-
- RealTime rt;
- PluginWrapper *wrapper = 0;
- RealTime adjustment = RealTime::zeroTime;
-
- if (outputs.empty()) {
- cerr << "ERROR: Plugin has no outputs!" << endl;
- goto done;
- }
-
- if (outputNo < 0) {
-
- for (size_t oi = 0; oi < outputs.size(); ++oi) {
- if (outputs[oi].identifier == output) {
- outputNo = oi;
- break;
- }
- }
-
- if (outputNo < 0) {
- cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
- goto done;
- }
-
- } else {
-
- if (int(outputs.size()) <= outputNo) {
- cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
- goto done;
- }
- }
-
- od = outputs[outputNo];
- cerr << "Output is: \"" << od.identifier << "\"" << endl;
-
- if (!plugin->initialise(channels, stepSize, blockSize)) {
- cerr << "ERROR: Plugin initialise (channels = " << channels
- << ", stepSize = " << stepSize << ", blockSize = "
- << blockSize << ") failed." << endl;
- goto done;
- }
-
- wrapper = dynamic_cast<PluginWrapper *>(plugin);
- if (wrapper) {
- // See documentation for
- // PluginInputDomainAdapter::getTimestampAdjustment
- PluginInputDomainAdapter *ida =
- wrapper->getWrapper<PluginInputDomainAdapter>();
- if (ida) adjustment = ida->getTimestampAdjustment();
- }
-
- // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input.
- do {
-
- int count;
-
- if ((blockSize==stepSize) || (currentStep==0)) {
- // read a full fresh block
- if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
- cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
- break;
- }
- if (count != blockSize) --finalStepsRemaining;
- } else {
- // otherwise shunt the existing data down and read the remainder.
- memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float));
- if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
- cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
- break;
- }
- if (count != stepSize) --finalStepsRemaining;
- count += overlapSize;
- }
-
- for (int c = 0; c < channels; ++c) {
- int j = 0;
- while (j < count) {
- plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
- ++j;
- }
- while (j < blockSize) {
- plugbuf[c][j] = 0.0f;
- ++j;
- }
- }
-
- rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
-
- vampHost::printFeatures
- (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
- sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt),
- out, useFrames);
-
- if (sfinfo.frames > 0){
- int pp = progress;
- progress = lrintf((float(currentStep * stepSize) / sfinfo.frames) * 100.f);
- if (progress != pp && out) {
- cerr << "\r" << progress << "%";
- }
- }
-
- ++currentStep;
-
- } while (finalStepsRemaining > 0);
-
- if (out) cerr << "\rDone" << endl;
-
- rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
-
- vampHost::printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),
- sfinfo.samplerate, outputNo,
- plugin->getRemainingFeatures(), out, useFrames);
-
- returnValue = 0;
-
-done:
- delete plugin;
- sf_close(sndfile);
- return returnValue;
-}
-
-int vampHost::rotorRunPlugin(string soname, string id, string output,
- int outputNo, string inputFile, vector<float>& out, float& progress)
-{
- PluginLoader *loader = PluginLoader::getInstance();
-
- PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
-
- SNDFILE *sndfile;
- SF_INFO sfinfo;
- memset(&sfinfo, 0, sizeof(SF_INFO));
-
- sndfile = sf_open(inputFile.c_str(), SFM_READ, &sfinfo);
- if (!sndfile) {
- cerr << ": ERROR: Failed to open input file \""
- << inputFile << "\": " << sf_strerror(sndfile) << endl;
- return 1;
- }
-
- Plugin *plugin = loader->loadPlugin
- (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE);
- if (!plugin) {
- cerr << ": ERROR: Failed to load plugin \"" << id
- << "\" from library \"" << soname << "\"" << endl;
- sf_close(sndfile);
- return 1;
- }
-
- cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
-
- // Note that the following would be much simpler if we used a
- // PluginBufferingAdapter as well -- i.e. if we had passed
- // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead
- // of ADAPT_ALL_SAFE. Then we could simply specify our own block
- // size, keep the step size equal to the block size, and ignore
- // the plugin's bleatings. However, there are some issues with
- // using a PluginBufferingAdapter that make the results sometimes
- // technically different from (if effectively the same as) the
- // un-adapted plugin, so we aren't doing that here. See the
- // PluginBufferingAdapter documentation for details.
-
- int blockSize = plugin->getPreferredBlockSize();
- int stepSize = plugin->getPreferredStepSize();
-
- if (blockSize == 0) {
- blockSize = 1024;
- }
- if (stepSize == 0) {
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- stepSize = blockSize/2;
- } else {
- stepSize = blockSize;
- }
- } else if (stepSize > blockSize) {
- cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- blockSize = stepSize * 2;
- } else {
- blockSize = stepSize;
- }
- cerr << blockSize << endl;
- }
- int overlapSize = blockSize - stepSize;
- sf_count_t currentStep = 0;
- int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
-
- int channels = sfinfo.channels;
-
- float *filebuf = new float[blockSize * channels];
- float **plugbuf = new float*[channels];
- for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
-
- cerr << "Using block size = " << blockSize << ", step size = "
- << stepSize << endl;
-
- // The channel queries here are for informational purposes only --
- // a PluginChannelAdapter is being used automatically behind the
- // scenes, and it will take case of any channel mismatch
-
- int minch = plugin->getMinChannelCount();
- int maxch = plugin->getMaxChannelCount();
- cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
- cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
-
- Plugin::OutputList outputs = plugin->getOutputDescriptors();
- Plugin::OutputDescriptor od;
-
- int returnValue = 1;
- int prog = 0;
-
- RealTime rt;
- PluginWrapper *wrapper = 0;
- RealTime adjustment = RealTime::zeroTime;
-
- if (outputs.empty()) {
- cerr << "ERROR: Plugin has no outputs!" << endl;
- goto done;
- }
-
- if (outputNo < 0) {
-
- for (size_t oi = 0; oi < outputs.size(); ++oi) {
- if (outputs[oi].identifier == output) {
- outputNo = oi;
- break;
- }
- }
-
- if (outputNo < 0) {
- cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
- goto done;
- }
-
- } else {
-
- if (int(outputs.size()) <= outputNo) {
- cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
- goto done;
- }
- }
-
- od = outputs[outputNo];
- cerr << "Output is: \"" << od.identifier << "\"" << endl;
-
- if (!plugin->initialise(channels, stepSize, blockSize)) {
- cerr << "ERROR: Plugin initialise (channels = " << channels
- << ", stepSize = " << stepSize << ", blockSize = "
- << blockSize << ") failed." << endl;
- goto done;
- }
-
- wrapper = dynamic_cast<PluginWrapper *>(plugin);
- if (wrapper) {
- // See documentation for
- // PluginInputDomainAdapter::getTimestampAdjustment
- PluginInputDomainAdapter *ida =
- wrapper->getWrapper<PluginInputDomainAdapter>();
- if (ida) adjustment = ida->getTimestampAdjustment();
- }
-
- // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input.
- do {
-
- int count;
-
- if ((blockSize==stepSize) || (currentStep==0)) {
- // read a full fresh block
- if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) {
- cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
- break;
- }
- if (count != blockSize) --finalStepsRemaining;
- } else {
- // otherwise shunt the existing data down and read the remainder.
- memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float));
- if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) {
- cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
- break;
- }
- if (count != stepSize) --finalStepsRemaining;
- count += overlapSize;
- }
-
- for (int c = 0; c < channels; ++c) {
- int j = 0;
- while (j < count) {
- plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
- ++j;
- }
- while (j < blockSize) {
- plugbuf[c][j] = 0.0f;
- ++j;
- }
- }
-
- rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
-
- vampHost::rotorGetFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),sfinfo.samplerate, outputNo,plugin->getRemainingFeatures(), out, progress);
-
- if (sfinfo.frames > 0){
- int pp = prog;
- prog = lrintf((float(currentStep * stepSize) / sfinfo.frames) * 100.f);
- if (prog != pp ) {
- cerr << "\r" << progress << "%";
- }
- }
-
- ++currentStep;
-
- } while (finalStepsRemaining > 0);
-
- cerr << "\rDone" << endl;
-
- rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate);
-
- vampHost::rotorGetFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate),sfinfo.samplerate, outputNo,plugin->getRemainingFeatures(), out, progress);
-
- returnValue = 0;
-
-done:
- delete plugin;
- sf_close(sndfile);
- return returnValue;
-}
-
-void vampHost::printFeatures(int frame, int sr, int output,
- Plugin::FeatureSet features, ostream& out, bool useFrames)
-{
- if (features[output].size()) {
- cout << "." << features[output].size();
- }
- for (unsigned int i = 0; i < features[output].size(); ++i) {
-
- if (useFrames) {
-
- int displayFrame = frame;
-
- if (features[output][i].hasTimestamp) {
- displayFrame = RealTime::realTime2Frame
- (features[output][i].timestamp, sr);
- }
-
- out << displayFrame;
-
- if (features[output][i].hasDuration) {
- displayFrame = RealTime::realTime2Frame
- (features[output][i].duration, sr);
- out << "," << displayFrame;
- }
-
- out << ":";
-
- } else {
-
- RealTime rt = RealTime::frame2RealTime(frame, sr);
-
- if (features[output][i].hasTimestamp) {
- rt = features[output][i].timestamp;
- }
-
- out << rt.toString();
-
- if (features[output][i].hasDuration) {
- rt = features[output][i].duration;
- out<< "," << rt.toString();
- }
-
- out << ":";
- }
-
- for (unsigned int j = 0; j < features[output][i].values.size(); ++j) {
- out<< " " << features[output][i].values[j];
- }
- out << " " << features[output][i].label;
-
- out << endl;
- }
-
-}
-
-
-
-void vampHost::rotorGetFeatures(int frame, int sr, int output,Plugin::FeatureSet features, vector<float>& out, float& progress)
-{
- if (features[output].size()) {
- cout << "." << features[output].size();
- }
- for (unsigned int i = 0; i < features[output].size(); ++i) {
-
-
-
- int displayFrame = frame;
-
- if (features[output][i].hasTimestamp) {
- displayFrame = RealTime::realTime2Frame
- (features[output][i].timestamp, sr);
- }
-
- cout << displayFrame;
-
-
- cout << endl;
- }
-
-}
-
-
-int vampHost::QMAnalyser::process(const string inputFile){
- //vampHost::runPlugin("",settings.soname,settings.filtername, "",0, settings.inputFile, ostr,true);
- //would run the plugin, outputting progress to cerr and the data to ostr
- //
- //int runPlugin(string myname, string soname, string id, string output,int outputNo, string inputFile, ostream& out, bool frames);
-
-
- //we want to run a specific plugin, outputting progress to a mutex-protected passed variable
- //and ultimately passing the data back as a string?
- //or capture it as an array of floats?
- //get the progress as a float
- //how to handle errors?
-
- //debugger fucking up! program stalls after 1 request in debug!?
-
- string soname="qm-vamp-plugins";
- string id="qm-tempotracker";
- string myname="";
- string output="";
- int outputNo=0;
-
- vampHost::rotorRunPlugin(soname,id,output,outputNo,inputFile,beats,progress);
-
-}
-
-void vampHost::getTimestamps(int output,Plugin::FeatureSet features, vector<float>& out){
-
- /*
- vamp-simple-host qm-vamp-plugins:qm-tempotracker 01.wav
-
- 0.046439908: 156.61 bpm
- 0.429569160: 156.61 bpm
- 0.812698412: 161.50 bpm
- 1.184217686: 152.00 bpm
-
-
- vamp-simple-host qm-vamp-plugins:qm-segmenter 01.wav
-
- 0.000000000: 4 4
- 23.800000000: 6 6
- 44.600000000: 5 5
- 55.000000000: 7 7
- 72.800000000: 1 1
- 90.600000000: 2 2
- 109.200000000: 5 5
- 116.000000000: 3 3
- 143.800000000: 5 5
- 153.400000000: 3 3
- 163.000000000: 8 8
-
- seems to be FP seconds then another metric
- for now we can just take the first part
-
- features[output][i].timestamp is of type RealTime: represents time values to nanosecond precision
- int sec;
- int nsec;
- 1 sec = 10^9 nanosec
-
- actually maybe this would be the way to go for rotor- avoiding rounding errors etc
- for now - ideally will get a float representation
-
- features[output][i].values is a vector of floats + a description
- WE DON'T CARE ABOUT ANYTHING <.01 seconds
-
- static long realTime2Frame(const RealTime &r, unsigned int sampleRate);
-
- get a vector of floats out, using frames, presuming data has a timestamp
-
-
- this is crashing with "Aborted (core dumped)"
- if we check for timestamp
-
- */
-
- cout << "." << features[output].size();
-
- //if (!features[output][0].hasTimestamp) {
- // cerr << output << " channel, getTimestamps: error, featureset doesn't support timestamp" << endl;
- //}_
- //else {
- for (unsigned int i = 0; i < features[output].size(); ++i) {
- out.push_back( ((float)RealTime::realTime2Frame(features[output][i].timestamp, 1000))*.001f);
- cout << "feature found.\n";
- }
- //}
-}
-float vampHost::QMAnalyser::get_progress(){
- float p;
- mutex.lock();
- p=progress;
- mutex.unlock();
- return p;
-}
-bool vampHost::Analyser::init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,int _outputNo,const map<string,float> &params){
-
- //stuff that only happens once
- channels =_channels;
- samples=_samples;
- rate=_rate;
- bits=_bits;
- outputNo=_outputNo;
- //output=_output;
-
- //http://www.mega-nerd.com/libsndfile/api.html#note1
- //libsndfile returns -1..1 for fp data
- bytes=(bits>>3);
- stride=channels*bytes;
- scale=(1.0f/pow(2.0f,bits));
-
- features.clear(); //in case of reuse
- features[0.0f]=0;
-
- loader = PluginLoader::getInstance();
- key = loader->composePluginKey(soname, id);
- plugin = loader->loadPlugin(key, _rate, PluginLoader::ADAPT_ALL_SAFE);
- if (!plugin) {
- cerr << ": ERROR: Failed to load plugin \"" << id
- << "\" from library \"" << soname << "\"" << endl;
- return false;
- }
-
- cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"... Domain:";
-
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- cerr << "frequency" << endl;
- }
- else {
-
- cerr << "time" << endl;
-
- }
-
- blockSize = plugin->getPreferredBlockSize();
- stepSize = plugin->getPreferredStepSize();
-
- if (blockSize == 0) {
- blockSize = 1024;
- }
- if (stepSize == 0) {
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- stepSize = blockSize/2;
- } else {
- stepSize = blockSize;
- }
- }
- else if (stepSize > blockSize) {
- cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
- if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
- blockSize = stepSize * 2;
- } else {
- blockSize = stepSize;
- }
- cerr << blockSize << endl;
- }
- overlapSize = blockSize - stepSize;
- currentStep = 0;
- finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
-
- plugbuf = new float*[channels];
- for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
-
- cerr << "Using block size = " << blockSize << ", step size = "
- << stepSize << endl;
-
- // The channel queries here are for informational purposes only --
- // a PluginChannelAdapter is being used automatically behind the
- // scenes, and it will take case of any channel mismatch
-
- int minch = plugin->getMinChannelCount();
- int maxch = plugin->getMaxChannelCount();
- cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
- cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
-
- Plugin::OutputList outputs = plugin->getOutputDescriptors();
- Plugin::OutputDescriptor od;
-
- int returnValue = 1;
- int prog = 0;
-
- RealTime rt;
- PluginWrapper *wrapper = 0;
- RealTime adjustment = RealTime::zeroTime;
-
- if (outputs.empty()) {
- cerr << "ERROR: Plugin has no outputs!" << endl;
- return false;
- }
-
- if (outputNo < 0) {
- for (size_t oi = 0; oi < outputs.size(); ++oi) {
- if (outputs[oi].identifier == output) {
- outputNo = oi;
- break;
- }
- }
- if (outputNo < 0) {
- cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
- return false;
- }
- }
- else {
- if (int(outputs.size()) <= outputNo) {
- cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
- return false;
- }
- }
- od = outputs[outputNo];
- cerr << "Output number "<<outputNo<<": \"" << od.identifier << "\"" << endl;
-
-
- for (auto i:params){
- plugin->setParameter(i.first,i.second);
- cerr << "Set plugin parameter: "<<i.first<<" : "<<i.second<<endl;
- }
-
- if (!plugin->initialise(channels, stepSize, blockSize)) {
- cerr << "ERROR: Plugin initialise (channels = " << channels
- << ", stepSize = " << stepSize << ", blockSize = "
- << blockSize << ") failed." << endl;
- return false;
- }
-
- wrapper = dynamic_cast<PluginWrapper *>(plugin);
- if (wrapper) {
- // See documentation for
- // PluginInputDomainAdapter::getTimestampAdjustment
- PluginInputDomainAdapter *ida =wrapper->getWrapper<PluginInputDomainAdapter>();
- if (ida) adjustment = ida->getTimestampAdjustment();
- }
-
- //everything is prepared to start consuming data in blocks
-
- in_block=0;
- blocks_processed=0;
- currentStep=0;
-
- featureNo=1;
-
- return true;
-}
-void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
- int sample=0;
-
- uint16_t *_data=(uint16_t*)data;
- //process the whole frame which may be f>1<f blocks
- //when the frame is finished leave the partial block for the next frame
- while(sample<samples_in_frame) {
- while(sample<samples_in_frame&&in_block<blockSize) {
- for (int i=0;i<channels;i++) {
- //unsigned int this_val=0;
- // this_val+=data[(sample*stride)+(i*bytes)+j]<<((1-j)*8);
- //}
- //plugbuf[i][in_block]=((float)((int16_t)this_val))*scale;
- plugbuf[i][in_block]=((float)_data[sample])*scale;
- }
- in_block++;
- sample++;
- }
- if (in_block==blockSize) {
- //block is ready to be processed
- //cerr<<plugin->getIdentifier()<<" processed block "<<blocks_processed<<endl;
-
- //I /think/ that the vamp plugin keeps processing through the plugbuf until it encounters 0s
- rt = RealTime::frame2RealTime(currentStep * stepSize, rate); //48000); //setting different rate doesn't affect it
-
- Plugin::FeatureSet feat=plugin->process(plugbuf, rt);
-
- for (unsigned int i = 0; i < feat[outputNo].size(); ++i) {
- features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo;
- featureNo++;
- }
-
- //shunt it down
- for (int i=0;i<blockSize-stepSize;i++){
- for (int j=0;j<channels;j++){
- plugbuf[j][i]=plugbuf[j][i+stepSize];
- }
- }
-
- in_block-=stepSize;
- currentStep++;
- }
- }
-}
-void vampHost::Analyser::cleanup(){
-
- //process final block
- while(in_block<blockSize) {
- for (int i=0;i<channels;i++) {
- plugbuf[i][in_block]=0.0f;
- }
- in_block++;
- }
-
- rt = RealTime::frame2RealTime(currentStep * stepSize, rate); // //setting different
-
- Plugin::FeatureSet feat=plugin->process(plugbuf, rt);
-
- for (unsigned int i = 0; i < feat[outputNo].size(); ++i) {
- features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo;
- featureNo++;
- }
-
- feat=plugin->getRemainingFeatures();
-
- for (unsigned int i = 0; i < feat[outputNo].size(); ++i) {
- features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo;
- featureNo++;
- }
-
- //cerr<<plugin->getIdentifier()<<" found "<<(features.size()-1)<<" features"<<endl;
- //deal with left over data?
- for (int c = 0; c < channels; ++c) {
- delete[] plugbuf[c];
- }
- delete[] plugbuf;
- delete plugin;
-}
diff --git a/rotord/vampHost.h b/rotord/vampHost.h
deleted file mode 100644
index d1dfc81..0000000
--- a/rotord/vampHost.h
+++ /dev/null
@@ -1,92 +0,0 @@
-#include <vamp-hostsdk/PluginHostAdapter.h>
-#include <vamp-hostsdk/PluginInputDomainAdapter.h>
-#include <vamp-hostsdk/PluginLoader.h>
-
-#include "Poco/Mutex.h"
-
-#include <iostream>
-#include <fstream>
-#include <set>
-#include <sndfile.h>
-
-#include <cstring>
-#include <cstdlib>
-
-#include "system.h"
-
-#include <cmath>
-
-/*
-line 366: is returnValue the fail/succeed return value?
-*/
-
-using namespace std;
-
-using Vamp::Plugin;
-using Vamp::PluginHostAdapter;
-using Vamp::RealTime;
-using Vamp::HostExt::PluginLoader;
-using Vamp::HostExt::PluginWrapper;
-using Vamp::HostExt::PluginInputDomainAdapter;
-
-#define HOST_VERSION "1.5"
-
-namespace vampHost {
-
- class Settings{
- public:
- Settings(string _so="",string _filter="",string _input="") {
- soname=_so;
- filtername=_filter;
- inputFile=_input;
- }
- string soname;
- string filtername;
- string inputFile;
- };
- class QMAnalyser{
- public:
- int process(const string soundfile);
- float get_progress();
- vector<float> beats;
- private:
- float progress;
- Poco::Mutex mutex; //lock for progress data
- };
- class Analyser{
- //can load any vamp analysis plugin and present its data with a unified interface
- public:
- bool init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,int outputNo,const map<string,float> &params);
- void process_frame(uint8_t *data,int samples_in_frame);
- void cleanup();
-
- map<double,int> features;
- //map<time,featureNo>
- //this is the best way to store features: because map allows to search for the key below and above the present time
-
- private:
- PluginLoader *loader;
- PluginLoader::PluginKey key;
- Plugin *plugin;
- RealTime rt;
- int channels,bits,samples,rate;
- int bytes,stride;
- float scale;
- int blockSize,stepSize,overlapSize,finalStepsRemaining,currentStep,outputNo;
- int in_block,blocks_processed;
- string output;
- float **plugbuf;
-
- int featureNo;
-
- };
-
- string getQMBeats(const string soundfile);
- void printFeatures(int, int, int, Plugin::FeatureSet, ostream &, bool frames);
- void getTimestamps(int output,Plugin::FeatureSet features, vector<float>& out);
- int runPlugin(string myname, string soname, string id, string output,int outputNo, string inputFile, ostream& out, bool frames);
-
- int rotorRunPlugin(string soname, string id, string output,int outputNo, string inputFile, vector<float>& out, float& progress);
- void rotorGetFeatures(int frame, int sr, int output,Plugin::FeatureSet features, vector<float>& out, float& progress);
-
-}
diff --git a/rotord/xmlIO.cpp b/rotord/xmlIO.cpp
deleted file mode 100755
index 3a7ec61..0000000
--- a/rotord/xmlIO.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-#include "xmlIO.h"
-
-#include <vector>
-#include <string>
-#include <iostream>
-
-//----------------------------------------
-// a pretty useful tokenization system:
-static vector<string> tokenize(const string & str, const string & delim);
-static vector<string> tokenize(const string & str, const string & delim)
-{
- vector<string> tokens;
-
- size_t p0 = 0, p1 = string::npos;
- while(p0 != string::npos)
- {
- p1 = str.find_first_of(delim, p0);
- if(p1 != p0)
- {
- string token = str.substr(p0, p1 - p0);
- tokens.push_back(token);
- }
- p0 = str.find_first_not_of(delim, p1);
- }
- return tokens;
-}
-//----------------------------------------
-
-//----------------------------------------
-xmlIO::xmlIO():
- storedHandle(NULL)
-{
- level = 0;
- //we do this so that we have a valid handle
- //without the need for loadFile
- storedHandle = TiXmlHandle(&doc);
-}
-
-//----------------------------------------
-xmlIO::xmlIO(const string& xmlFile):
- storedHandle(NULL)
-{
- level = 0;
- //we do this so that we have a valid handle
- //without the need for loadFile
- storedHandle = TiXmlHandle(&doc);
- loadFile(xmlFile);
-}
-
-//---------------------------------------------------------
-xmlIO::~xmlIO()
-{
-}
-
-//---------------------------------------------------------
-void xmlIO::setVerbose(bool _verbose){
-}
-
-//---------------------------------------------------------
-void xmlIO::clear(){
- //we clear from our root level
- //this is usually the document
- //but if we are pushed - it could
- //be all the tags inside of the pushed
- //node - including the node itself!
-
- storedHandle.ToNode()->Clear();
-}
-
-//---------------------------------------------------------
-bool xmlIO::loadFile(const string& xmlFile){
-
- //string fullXmlFile = ofToDataPath(xmlFile);
-
- bool loadOkay = doc.LoadFile(xmlFile);
-
- //theo removed bool check as it would
- //return false if the file exists but was
- //empty
-
- //our push pop level should be set to 0!
- level = 0;
-
- storedHandle = TiXmlHandle(&doc);
- return loadOkay;
-}
-
-//---------------------------------------------------------
-bool xmlIO::saveFile(const string& xmlFile){
-
- //string fullXmlFile = ofToDataPath(xmlFile);
- return doc.SaveFile(xmlFile);
-}
-
-//---------------------------------------------------------
-bool xmlIO::saveFile(){
- return doc.SaveFile();
-}
-
-//---------------------------------------------------------
-void xmlIO::clearTagContents(const string& tag, int which){
- //we check it first to see if it exists
- //otherwise setValue will make a new empty tag
- if( tagExists(tag, which) )setValue(tag, "", which);
-}
-
-//---------------------------------------------------------
-void xmlIO::removeTag(const string& tag, int which){
-
- vector<string> tokens = tokenize(tag,":");
-
- //no tags so we return
- if( tokens.size() == 0 ) return;
-
- //grab the handle from the level we are at
- //normally this is the doc but could be a pushed node
- TiXmlHandle tagHandle = storedHandle;
-
- if(which < 0) which = 0;
-
- for(int x=0;x<(int)tokens.size();x++){
-
- //we only support multi tags
- //with same name at root level
- if(x > 0) which = 0;
-
- TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
-
- if ( !isRealHandle.ToNode() ) break;
- else{
- if (x == (int)tokens.size()-1){
- //if we are at the last tag and it exists
- //we use its parent to remove it - haha
- tagHandle.ToNode()->RemoveChild( isRealHandle.ToNode() );
- }
- tagHandle = isRealHandle;
- }
- }
-}
-
-//---------------------------------------------------------
-int xmlIO::getValue(const string& tag, int defaultValue, int which){
- TiXmlHandle valHandle(NULL);
- if (readTag(tag, valHandle, which)){
- return ofToInt(valHandle.ToText()->Value());
- }
- return defaultValue;
-}
-
-//---------------------------------------------------------
-double xmlIO::getValue(const string& tag, double defaultValue, int which){
- TiXmlHandle valHandle(NULL);
- if (readTag(tag, valHandle, which)){
- return ofToFloat(valHandle.ToText()->Value());
- }
- return defaultValue;
-}
-
-//---------------------------------------------------------
-string xmlIO::getValue(const string& tag, const string& defaultValue, int which){
- TiXmlHandle valHandle(NULL);
- if (readTag(tag, valHandle, which)){
- return valHandle.ToText()->ValueStr();
- }
- return defaultValue;
-}
-
-//---------------------------------------------------------
-bool xmlIO::readTag(const string& tag, TiXmlHandle& valHandle, int which){
-
- vector<string> tokens = tokenize(tag,":");
-
- TiXmlHandle tagHandle = storedHandle;
- for(int x=0;x<(int)tokens.size();x++){
- if(x == 0)tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else tagHandle = tagHandle.FirstChildElement( tokens.at(x) );
- }
-
- // once we've walked, let's get that value...
- valHandle = tagHandle.Child( 0 );
- return (valHandle.ToText() != NULL);
-}
-
-
-//---------------------------------------------------------
-bool xmlIO::pushTag(const string& tag, int which){
-
- int pos = tag.find(":");
-
- // Either find the tag specified, or the first tag if colon-seperated.
- string tagToFind((pos > 0) ? tag.substr(0,pos) :tag);
-
- //we only allow to push one tag at a time.
- TiXmlHandle isRealHandle = storedHandle.ChildElement(tagToFind, which);
-
- if( isRealHandle.ToNode() ){
- storedHandle = isRealHandle;
- level++;
- return true;
- }else{
- //ofLog( OF_LOG_ERROR, "pushTag - <" + tag + "> tag not found");
- }
-
- return false;
-}
-
-//---------------------------------------------------------
-int xmlIO::popTag(){
-
- if(level >= 1){
- TiXmlHandle parent( (storedHandle.ToNode() )->Parent() );
- storedHandle = parent;
- level--;
- }else{
- storedHandle = TiXmlHandle(&doc);
- level = 0;
- }
-
- return level;
-}
-
-//---------------------------------------------------------
-int xmlIO::getPushLevel(){
- return level;
-}
-
-//---------------------------------------------------------
-bool xmlIO::tagExists(const string& tag, int which){
-
- vector<string> tokens = tokenize(tag,":");
-
- bool found = false;
-
- //grab the handle from the level we are at
- //normally this is the doc but could be a pushed node
- TiXmlHandle tagHandle = storedHandle;
-
- if(which < 0) which = 0;
-
- for(int x=0;x<(int)tokens.size();x++){
-
- //we only support multi tags
- //with same name at root level
- if(x > 0) which = 0;
-
- TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
-
- //as soon as we find a tag that doesn't exist
- //we return false;
- if ( !isRealHandle.ToNode() ){
- found = false;
- break;
- }
- else{
- found = true;
- tagHandle = isRealHandle;
- }
- }
-
- return found;
-}
-
-
-//---------------------------------------------------------
-int xmlIO::getNumTags(const string& tag){
- //this only works for tags at the current root level
-
- int pos = tag.find(":");
-
- // Either find the tag specified, or the first tag if colon-seperated.
- string tagToFind((pos > 0) ? tag.substr(0,pos) :tag);
-
- //grab the handle from the level we are at
- //normally this is the doc but could be a pushed node
- TiXmlHandle tagHandle = storedHandle;
-
- int count = 0;
-
- //ripped from tinyXML as doing this ourselves once is a LOT! faster
- //than having this called n number of times in a while loop - we go from n*n iterations to n iterations
-
- TiXmlElement* child = ( storedHandle.FirstChildElement( tagToFind ) ).ToElement();
- for (count = 0; child; child = child->NextSiblingElement( tagToFind ), ++count){
- //nothing
- }
-
- return count;
-}
-
-
-
-//---------------------------------------------------------
-int xmlIO::writeTag(const string& tag, const string& valueStr, int which){
-
- vector<string> tokens = tokenize(tag,":");
-
- // allocate on the stack
- vector<TiXmlElement> elements;
- elements.reserve(tokens.size());
- for(int x=0;x<(int)tokens.size();x++)
- elements.push_back(tokens.at(x));
-
-
- TiXmlText Value(valueStr);
-
- // search our way up - do these tags exist?
- // find the first that DOESNT exist, then move backwards...
- TiXmlHandle tagHandle = storedHandle;
-
- bool addNewTag = false;
- if(which == -1)addNewTag = true;
-
- for(int x=0;x<(int)tokens.size();x++){
-
- if( x > 0 ){
- //multi tags of same name
- //only for the root level
- which = 0;
- addNewTag = false;
- }
-
- TiXmlHandle isRealHandle = tagHandle.ChildElement( tokens.at(x), which);
-
- if ( !isRealHandle.ToNode() || addNewTag){
-
- for(int i=(int)tokens.size()-1;i>=x;i--){
- if (i == (int)tokens.size()-1){
- elements[i].InsertEndChild(Value);
- } else {
- elements[i].InsertEndChild(elements[i+1]);
- }
- }
-
- tagHandle.ToNode()->InsertEndChild(elements[x]);
-
- break;
-
- } else {
- tagHandle = isRealHandle;
- if (x == (int)tokens.size()-1){
- // what we want to change : TiXmlHandle valHandle = tagHandle.Child( 0 );
- tagHandle.ToNode()->Clear();
- tagHandle.ToNode()->InsertEndChild(Value);
- }
- }
- }
-
-
- //lets count how many tags with our name exist so we can return an index
-
- //ripped from tinyXML as doing this ourselves once is a LOT! faster
- //than having this called n number of times in a while loop - we go from n*n iterations to n iterations
- int numSameTags;
- TiXmlElement* child = ( storedHandle.FirstChildElement( tokens.at(0) ) ).ToElement();
- for (numSameTags = 0; child; child = child->NextSiblingElement( tokens.at(0) ), ++numSameTags){
- //nothing
- }
-
- return numSameTags;
-}
-
-//---------------------------------------------------------
-int xmlIO::setValue(const string& tag, int value, int which){
- int tagID = writeTag(tag, ofToString(value).c_str(), which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::setValue(const string& tag, double value, int which){
- int tagID = writeTag(tag, ofToString(value).c_str(), which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::setValue(const string& tag, const string& value, int which){
- int tagID = writeTag(tag, value, which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addValue(const string& tag, int value){
- int tagID = writeTag(tag, ofToString(value).c_str(), -1) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addValue(const string& tag, double value){
- int tagID = writeTag(tag, ofToString(value).c_str(), -1) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addValue(const string& tag, const string& value){
- int tagID = writeTag(tag, value, -1) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addTag(const string& tag){
- int tagID = writeTag(tag, "", -1) -1;
- return tagID;
-}
-
-/*******************
-* Attribute addons *
-*******************/
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, int value, int which){
- int tagID = writeAttribute(tag, attribute, ofToString(value).c_str(), which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, int value){
- return addAttribute(tag,attribute,value,-1);
-}
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, double value, int which){
- int tagID = writeAttribute(tag, attribute, ofToString(value).c_str(), which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, double value){
- return addAttribute(tag,attribute,value,-1);
-}
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, const string& value, int which){
- int tagID = writeAttribute(tag, attribute, value, which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::addAttribute(const string& tag, const string& attribute, const string& value){
- return addAttribute(tag,attribute,value,-1);
-}
-
-//---------------------------------------------------------
-void xmlIO::removeAttribute(const string& tag, const string& attribute, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
-
- if (tagHandle.ToElement()) {
- TiXmlElement* elem = tagHandle.ToElement();
- elem->RemoveAttribute(attribute);
- }
-}
-
-//---------------------------------------------------------
-void xmlIO::clearTagAttributes(const string& tag, int which){
- vector<string> names;
- getAttributeNames( tag, names, which );
- for (vector<string>::iterator i = names.begin(); i != names.end(); i++)
- removeAttribute(tag, *i, which);
-}
-
-//---------------------------------------------------------
-int xmlIO::getNumAttributes(const string& tag, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
-
- if (tagHandle.ToElement()) {
- TiXmlElement* elem = tagHandle.ToElement();
-
- // Do stuff with the element here
- TiXmlAttribute* first = elem->FirstAttribute();
- if (first) {
- int count = 1;
- for (TiXmlAttribute* curr = first; curr != elem->LastAttribute(); curr = curr->Next())
- count++;
- return count;
- }
- }
- return 0;
-}
-
-//---------------------------------------------------------
-bool xmlIO::attributeExists(const string& tag, const string& attribute, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
-
- if (tagHandle.ToElement()) {
- TiXmlElement* elem = tagHandle.ToElement();
-
- // Do stuff with the element here
- for (TiXmlAttribute* a = elem->FirstAttribute(); a; a = a->Next()) {
- if (a->Name() == attribute)
- return true;
- }
- }
- return false;
-}
-
-//---------------------------------------------------------
-bool xmlIO::getAttributeNames(const string& tag, vector<string>& outNames, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
-
- if (tagHandle.ToElement()) {
- TiXmlElement* elem = tagHandle.ToElement();
-
- // Do stuff with the element here
- for (TiXmlAttribute* a = elem->FirstAttribute(); a; a = a->Next())
- outNames.push_back( string(a->Name()) );
- }
- return !outNames.empty();
-}
-
-//---------------------------------------------------------
-int xmlIO::getAttribute(const string& tag, const string& attribute, int defaultValue, int which){
- int value = defaultValue;
- readIntAttribute(tag, attribute, value, which);
- return value;
-}
-
-//---------------------------------------------------------
-double xmlIO::getAttribute(const string& tag, const string& attribute, double defaultValue, int which){
- double value = defaultValue;
- readDoubleAttribute(tag, attribute, value, which);
- return value;
-}
-
-//---------------------------------------------------------
-string xmlIO::getAttribute(const string& tag, const string& attribute, const string& defaultValue, int which){
- string value = defaultValue;
- readStringAttribute(tag, attribute, value, which);
- return value;
-}
-
-//---------------------------------------------------------
-int xmlIO::setAttribute(const string& tag, const string& attribute, int value, int which){
- char valueStr[255];
- sprintf(valueStr, "%i", value);
- int tagID = writeAttribute(tag, attribute, valueStr, which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::setAttribute(const string& tag, const string& attribute, double value, int which){
- char valueStr[255];
- sprintf(valueStr, "%lf", value);
- int tagID = writeAttribute(tag, attribute, valueStr, which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-int xmlIO::setAttribute(const string& tag, const string& attribute, const string& value, int which){
- int tagID = writeAttribute(tag, attribute, value, which) -1;
- return tagID;
-}
-
-//---------------------------------------------------------
-TiXmlElement* xmlIO::getElementForAttribute(const string& tag, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
- return tagHandle.ToElement();
-}
-
-//---------------------------------------------------------
-bool xmlIO::readIntAttribute(const string& tag, const string& attribute, int& outValue, int which){
-
- TiXmlElement* elem = getElementForAttribute(tag, which);
- if (elem)
- return (elem->QueryIntAttribute(attribute, &outValue) == TIXML_SUCCESS);
- return false;
-}
-
-//---------------------------------------------------------
-bool xmlIO::readDoubleAttribute(const string& tag, const string& attribute, double& outValue, int which){
-
- TiXmlElement* elem = getElementForAttribute(tag, which);
- if (elem)
- return (elem->QueryDoubleAttribute(attribute, &outValue) == TIXML_SUCCESS);
- return false;
-}
-
-//---------------------------------------------------------
-bool xmlIO::readStringAttribute(const string& tag, const string& attribute, string& outValue, int which){
-
- TiXmlElement* elem = getElementForAttribute(tag, which);
- if (elem)
- {
- const string* value = elem->Attribute(attribute);
- if (value)
- {
- outValue = *value;
- return true;
- }
- }
- return false;
-}
-
-//---------------------------------------------------------
-int xmlIO::writeAttribute(const string& tag, const string& attribute, const string& valueString, int which){
- vector<string> tokens = tokenize(tag,":");
- TiXmlHandle tagHandle = storedHandle;
- for (int x = 0; x < (int)tokens.size(); x++) {
- if (x == 0)
- tagHandle = tagHandle.ChildElement(tokens.at(x), which);
- else
- tagHandle = tagHandle.FirstChildElement(tokens.at(x));
- }
-
- int ret = 0;
- if (tagHandle.ToElement()) {
- TiXmlElement* elem = tagHandle.ToElement();
- elem->SetAttribute(attribute, valueString);
-
- // Do we really need this? We could just ignore this and remove the 'addAttribute' functions...
- // Now, just get the ID.
- int numSameTags;
- TiXmlElement* child = ( storedHandle.FirstChildElement( tokens.at(0) ) ).ToElement();
- for (numSameTags = 0; child; child = child->NextSiblingElement( tokens.at(0) ), ++numSameTags) {
- // nothing
- }
- ret = numSameTags;
- }
- return ret;
-}
-
-//---------------------------------------------------------
-bool xmlIO::loadFromBuffer( string buffer )
-{
-
- int size = buffer.size();
-
- bool loadOkay = doc.ReadFromMemory( buffer.c_str(), size);//, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING);
-
- return loadOkay;
-
-}
-//---------------------------------------------------------
-void xmlIO::copyXmlToString(string & str)
-{
- TiXmlPrinter printer;
- doc.Accept(&printer);
-
- str = printer.CStr();
-}
-
diff --git a/rotord/xmlIO.h b/rotord/xmlIO.h
deleted file mode 100755
index 84db7ca..0000000
--- a/rotord/xmlIO.h
+++ /dev/null
@@ -1,169 +0,0 @@
-#ifndef __xmlIO_
-#define __xmlIO_
-
-//#include "ofMain.h"
-//based on xmlSettings from openframeworks, manythanks!
-#include <string.h>
-#include <vector>
-#include "tinyxml.h"
-#include "ofUtils.h"
-
-using namespace std;
-
-/*
- Q: what is the which = 0 argument?
-
- A: Glad you asked - most of the time you can ignore this and treat it as if it weren't there
- But if specified it selects the nth tag with the same tag name at the current root of the document
- Normally this just means the top level tags in the document - but if you use the pushTag and popTag
- you can temporarily set the root of the document to be that specified tag.
- The main idea is to allow you to have multiple tags with the same name.
-
- So here is an example without pushTag
-
- <time>102229</time> <-- which = 0
- <time>298292</time> <-- which = 1
- <time>393393</time> <-- which = 2
- <time>447373</time> <-- which = 3
-
- But if we wanted to group these into multiple <recording> tags and have multiple time values inside
- we can use push and pop to move into the recording tags as if they were the document root
-
- <recording> <-- we temporarily push into here with pushTag("recording", 0);
- <time>19222</time> <-- to set this we call setValue("time", 19222, 0); ( which = 0 )
- <time>23232</time> <-- to set this we call setValue("time", 23232, 1); ( which = 1 )
- </recording> <-- we pop back out here with popTag();
-
- <recording> <-- we temporarily push into here with pushTag("recording", 1); <-- now we use 1 to select the 2nd recording tag
- <time>33342</time> <-- setValue("time", 33342, 0); ( which = 0 )
- <time>22722</time> <-- setValue("time", 22722, 0); ( which = 1 )
- </recording>
-
-*/
-
-
-#define MAX_TAG_VALUE_LENGTH_IN_CHARS 1024
-
-class xmlIO{
-
- public:
- xmlIO();
- xmlIO(const string& xmlFile);
-
- ~xmlIO();
-
- void setVerbose(bool _verbose);
-
- bool loadFile(const string& xmlFile);
- bool saveFile(const string& xmlFile);
- bool saveFile();
-
- void clearTagContents(const string& tag, int which = 0);
- void removeTag(const string& tag, int which = 0);
-
- bool tagExists(const string& tag, int which = 0);
-
- // removes all tags from within either the whole document
- // or the tag you are currently at using pushTag
- void clear();
-
- int getValue(const string& tag, int defaultValue, int which = 0);
- double getValue(const string& tag, double defaultValue, int which = 0);
- string getValue(const string& tag, const string& defaultValue, int which = 0);
-
- int setValue(const string& tag, int value, int which = 0);
- int setValue(const string& tag, double value, int which = 0);
- int setValue(const string& tag, const string& value, int which = 0);
-
- //advanced
-
- //-- pushTag/popTag
- //pushing a tag moves you inside it which has the effect of
- //temporarily treating the tag you are in as the document root
- //all setValue, readValue and getValue commands are then be relative to the tag you pushed.
- //this can be used with addValue to create multiple tags of the same name within
- //the pushed tag - normally addValue only lets you create multiple tags of the same
- //at the top most level.
-
- bool pushTag(const string& tag, int which = 0);
- int popTag();
- int getPushLevel();
-
- //-- numTags
- //this only works for tags at the current root level
- //use pushTag and popTag to get number of tags whithin other tags
- // both getNumTags("PT"); and getNumTags("PT:X"); will just return the
- //number of <PT> tags at the current root level.
- int getNumTags(const string& tag);
-
- //-- addValue/addTag
- //adds a tag to the document even if a tag with the same name
- //already exists - returns an index which can then be used to
- //modify the tag by passing it as the last argument to setValue
-
- //-- important - this only works for top level tags
- // to put multiple tags inside other tags - use pushTag() and popTag()
-
- int addValue(const string& tag, int value);
- int addValue(const string& tag, double value);
- int addValue(const string& tag, const string& value);
-
- int addTag(const string& tag); //adds an empty tag at the current level
-
-
- // Attribute-related methods
- int addAttribute(const string& tag, const string& attribute, int value, int which = 0);
- int addAttribute(const string& tag, const string& attribute, double value, int which = 0);
- int addAttribute(const string& tag, const string& attribute, const string& value, int which = 0);
-
- int addAttribute(const string& tag, const string& attribute, int value);
- int addAttribute(const string& tag, const string& attribute, double value);
- int addAttribute(const string& tag, const string& attribute, const string& value);
-
- void removeAttribute(const string& tag, const string& attribute, int which = 0);
- void clearTagAttributes(const string& tag, int which = 0);
-
- int getNumAttributes(const string& tag, int which = 0);
-
- bool attributeExists(const string& tag, const string& attribute, int which = 0);
-
- bool getAttributeNames(const string& tag, vector<string>& outNames, int which = 0);
-
- int getAttribute(const string& tag, const string& attribute, int defaultValue, int which = 0);
- double getAttribute(const string& tag, const string& attribute, double defaultValue, int which = 0);
- string getAttribute(const string& tag, const string& attribute, const string& defaultValue, int which = 0);
-
- int setAttribute(const string& tag, const string& attribute, int value, int which = 0);
- int setAttribute(const string& tag, const string& attribute, double value, int which = 0);
- int setAttribute(const string& tag, const string& attribute, const string& value, int which = 0);
-
- int setAttribute(const string& tag, const string& attribute, int value);
- int setAttribute(const string& tag, const string& attribute, double value);
- int setAttribute(const string& tag, const string& attribute, const string& value);
-
- bool loadFromBuffer( string buffer );
- void copyXmlToString(string & str);
-
- TiXmlDocument doc;
- bool bDocLoaded;
-
- protected:
-
- TiXmlHandle storedHandle;
- int level;
-
-
- int writeTag(const string& tag, const string& valueString, int which = 0);
- bool readTag(const string& tag, TiXmlHandle& valHandle, int which = 0); // max 1024 chars...
-
-
- int writeAttribute(const string& tag, const string& attribute, const string& valueString, int which = 0);
-
- TiXmlElement* getElementForAttribute(const string& tag, int which);
- bool readIntAttribute(const string& tag, const string& attribute, int& valueString, int which);
- bool readDoubleAttribute(const string& tag, const string& attribute, double& outValue, int which);
- bool readStringAttribute(const string& tag, const string& attribute, string& outValue, int which);
-};
-
-#endif
-