diff options
| author | Comment <tim@gray.(none)> | 2013-07-26 22:46:00 +0100 |
|---|---|---|
| committer | Comment <tim@gray.(none)> | 2013-07-26 22:46:00 +0100 |
| commit | 3d7eea02aa7a155b84c8c74ecbfd55a1941a9297 (patch) | |
| tree | d49d6ac97a0df08f5ea7e6c6c291acca0f65cd12 | |
| parent | 7092eaaae3e844a68804b8a6b6825381e9a81443 (diff) | |
tidy files
| -rw-r--r-- | rotord/Makefile | 9 | ||||
| -rw-r--r-- | rotord/Pixels.cpp | 90 | ||||
| -rw-r--r-- | rotord/Pixels.h | 28 | ||||
| -rw-r--r-- | rotord/cvimage.cpp | 156 | ||||
| -rw-r--r-- | rotord/cvimage.h | 191 | ||||
| -rw-r--r-- | rotord/graph.cpp | 150 | ||||
| -rw-r--r-- | rotord/image.h | 211 | ||||
| -rwxr-xr-x | rotord/libavwrapper.cpp | 1657 | ||||
| -rwxr-xr-x | rotord/libavwrapper.h | 279 | ||||
| -rw-r--r-- | rotord/nodes_audio_analysis.h | 47 | ||||
| -rw-r--r-- | rotord/nodes_drawing.h | 43 | ||||
| -rwxr-xr-x | rotord/ofUtils.cpp | 745 | ||||
| -rwxr-xr-x | rotord/ofUtils.h | 223 | ||||
| -rw-r--r-- | rotord/params.h | 0 | ||||
| -rw-r--r-- | rotord/rendercontext.cpp | 386 | ||||
| -rwxr-xr-x | rotord/rotor.cpp | 361 | ||||
| -rwxr-xr-x | rotord/rotor.h | 1391 | ||||
| -rwxr-xr-x | rotord/rotord.cpp | 230 | ||||
| -rwxr-xr-x | rotord/rotord.h | 136 | ||||
| -rw-r--r-- | rotord/system.h | 75 | ||||
| -rwxr-xr-x | rotord/tinyxml.cpp | 1888 | ||||
| -rwxr-xr-x | rotord/tinyxml.h | 1807 | ||||
| -rwxr-xr-x | rotord/tinyxmlerror.cpp | 53 | ||||
| -rwxr-xr-x | rotord/tinyxmlparser.cpp | 1719 | ||||
| -rw-r--r-- | rotord/utils.cpp | 29 | ||||
| -rw-r--r-- | rotord/utils.h | 10 | ||||
| -rw-r--r-- | rotord/vampHost.cpp | 815 | ||||
| -rw-r--r-- | rotord/vampHost.h | 92 | ||||
| -rwxr-xr-x | rotord/xmlIO.cpp | 673 | ||||
| -rwxr-xr-x | rotord/xmlIO.h | 169 |
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 ℑ //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 ℑ - } - - //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 ¶meter,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=÷_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 ℑ - } - } - } - 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 ℑ - } - } - 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=γ - 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=γ - 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 ℑ - } - } - 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 ℑ - } - } - } - 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. - // © -- 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 ] = -{ - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 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> ¶ms){ - - //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> ¶ms); - 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 - |
