<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Suat Gedikli */

#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GL/glut.h>
#include <GL/freeglut.h>
#include <moveit/mesh_filter/gl_renderer.h>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <iostream>
#include <boost/thread.hpp>
#include <ros/console.h>

using namespace std;

mesh_filter::GLRenderer::GLRenderer (unsigned width, unsigned height, float near, float far)
  : width_ (width)
  , height_ (height)
  , fbo_id_ (0)
  , rbo_id_ (0)
  , rgb_id_ (0)
  , depth_id_ (0)
  , program_ (0)
  , near_ (near)
  , far_ (far)
  , fx_ (width >> 1) // 90 degree wide angle
  , fy_ (fx_)
  , cx_ (width >> 1)
  , cy_ (height >> 1)
{
  createGLContext ();
  initFrameBuffers ();
}

mesh_filter::GLRenderer::~GLRenderer ()
{
  if (program_)
    glDeleteProgram (program_);

  deleteFrameBuffers();
  deleteGLContext ();
}

void mesh_filter::GLRenderer::setBufferSize (unsigned width, unsigned height)
{
  if (width_ != width || height_ != height)
  {
    width_ = width;
    height_ = height;
    deleteFrameBuffers();
    initFrameBuffers();
  }
}

void mesh_filter::GLRenderer::setClippingRange (float near, float far)
{
  if (near_ <= 0)
    throw runtime_error ("near clipping plane distance needs to be larger than 0");
  if (far_ <= near_)
    throw runtime_error ("far clipping plane needs to be larger than near clipping plane distance");
  near_ = near;
  far_ = far;
}

void mesh_filter::GLRenderer::setCameraParameters (float fx, float fy, float cx, float cy)
{
  fx_ = fx;
  fy_ = fy;
  cx_ = cx;
  cy_ = cy;
}

void mesh_filter::GLRenderer::setCameraParameters () const
{
  float left = near_ * -cx_ / fx_;
  float right = near_ * (width_ - cx_) / fx_;
  float top = near_ * cy_ / fy_;
  float bottom = near_ * (cy_ - height_) / fy_;

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glFrustum (left, right, bottom, top, near_, far_);

  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt (0, 0, 0, 0, 0, 1, 0, -1, 0);
}

void mesh_filter::GLRenderer::initFrameBuffers ()
{
  glGenTextures(1, &rgb_id_);
  glBindTexture(GL_TEXTURE_2D, rgb_id_);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);

  glGenTextures(1, &depth_id_);
  glBindTexture(GL_TEXTURE_2D, depth_id_);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);

  glGenFramebuffers(1, &fbo_id_);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);

  glGenRenderbuffers(1, &rbo_id_);
  glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);

  GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT};
  glDrawBuffers(2, DrawBuffers);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
    throw runtime_error ("Couldn't create frame buffer");

  glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
}

void mesh_filter::GLRenderer::deleteFrameBuffers()
{
  if (rbo_id_)
    glDeleteRenderbuffers (1, &rbo_id_);
  if (fbo_id_)
    glDeleteFramebuffers (1, &fbo_id_);
  if (depth_id_)
    glDeleteTextures(1, &depth_id_);
  if (rgb_id_)
    glDeleteTextures(1, &rgb_id_);

  rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
}

void mesh_filter::GLRenderer::begin () const
{
  glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glViewport (0, 0, width_, height_);
  glUseProgram (program_);
  setCameraParameters ();
}

void mesh_filter::GLRenderer::callList (GLuint list) const
{
  begin ();
  glCallList( list );
  end ();
}

void mesh_filter::GLRenderer::end () const
{
  glFlush();
  glPopAttrib();
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
{
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glBindTexture(GL_TEXTURE_2D, rgb_id_);
  glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void mesh_filter::GLRenderer::getDepthBuffer(float* buffer) const
{
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glBindTexture(GL_TEXTURE_2D, depth_id_);
  glGetTexImage (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer );
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

GLuint mesh_filter::GLRenderer::setShadersFromFile (const string& vertex_filename, const string& fragment_filename)
{
  if (program_)
    glDeleteProgram (program_);

  string vertex_source, fragment_source;
  readShaderCodeFromFile(vertex_filename, vertex_source);
  readShaderCodeFromFile(fragment_filename, fragment_source);

  program_ = loadShaders(vertex_source, fragment_source);
  return program_;
}

GLuint mesh_filter::GLRenderer::setShadersFromString (const string& vertex_source, const string& fragment_source)
{
  program_ = loadShaders(vertex_source, fragment_source);
  return program_;
}

const GLuint& mesh_filter::GLRenderer::getProgramID () const
{
  return program_;
}

const float& mesh_filter::GLRenderer::getNearClippingDistance() const
{
  return near_;
}

const float& mesh_filter::GLRenderer::getFarClippingDistance() const
{
  return far_;
}

GLuint mesh_filter::GLRenderer::createShader (GLuint shaderType, const string& ShaderCode) const
{
  GLuint ShaderID = glCreateShader(shaderType);

  // Compile Shader
  char const * SourcePointer = ShaderCode.c_str();
  glShaderSource(ShaderID, 1, &SourcePointer , NULL);
  glCompileShader(ShaderID);

  // Check Shader
  GLint Result = GL_FALSE;
  glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result);
  if (Result != GL_TRUE)
  {
    int InfoLogLength;
    glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 )
    {
      vector<char> ShaderErrorMessage(InfoLogLength+1);
      glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &ShaderErrorMessage[0]);
      stringstream errorStream;
      errorStream << "Could not compile shader: " << (const char*) &ShaderErrorMessage [0];

      glDeleteShader (ShaderID);
      throw runtime_error (errorStream.str());
    }
  }
  return ShaderID;
}

void mesh_filter::GLRenderer::readShaderCodeFromFile (const string& filename, string& shader) const
{
  if (filename.empty ())
    shader = "";
  else
  {
    string ShaderCode;
    fstream ShaderFile(filename.c_str(), ios::in);
    if(ShaderFile.is_open())
    {
      stringstream buffer;
      buffer << ShaderFile.rdbuf();
      shader = buffer.str();
    }
    else
    {
      stringstream errorStream;
      errorStream << "Could not open shader code in file \"" << filename << "\"";
      throw runtime_error (errorStream.str());
    }
  }
}

GLuint mesh_filter::GLRenderer::loadShaders (const string& vertex_source, const string& fragment_source) const
{
  if (vertex_source.empty () && fragment_source.empty ())
    return 0;

  GLuint ProgramID = glCreateProgram();
  GLuint VertexShaderID = 0;
  GLuint FragmentShaderID = 0;

  if (!vertex_source.empty ())
  {
    GLuint VertexShaderID = createShader (GL_VERTEX_SHADER, vertex_source);
    glAttachShader(ProgramID, VertexShaderID);
  }

  if (!fragment_source.empty ())
  {
    GLuint FragmentShaderID = createShader(GL_FRAGMENT_SHADER, fragment_source);
    glAttachShader(ProgramID, FragmentShaderID);
  }

  glLinkProgram(ProgramID);

  // Check the program
  GLint Result = GL_FALSE;
  GLint InfoLogLength;
  glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
  glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  if ( InfoLogLength > 0 )
  {
    vector<char> ProgramErrorMessage(InfoLogLength+1);
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    std::size_t l = strnlen(&ProgramErrorMessage[0], ProgramErrorMessage.size());
    if (l > 0)
      ROS_ERROR("%s\n", &ProgramErrorMessage[0]);
  }

  if (VertexShaderID)
    glDeleteShader(VertexShaderID);

  if (FragmentShaderID)
    glDeleteShader(FragmentShaderID);

  return ProgramID;
}

map<boost::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
boost::mutex mesh_filter::GLRenderer::context_lock_;
bool mesh_filter::GLRenderer::glutInitialized_ = false;

void mesh_filter::GLRenderer::createGLContext ()
{
  boost::mutex::scoped_lock _(context_lock_);
  if (!glutInitialized_)
  {
    char buffer[1];
    char* args = buffer;
    int n = 1;

    glutInit(&n, &args);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
    glutInitialized_ = true;
  }

  // check if our thread is initialized
  boost::thread::id threadID = boost::this_thread::get_id();
  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);

  if (contextIt == context_.end())
  {
    context_ [threadID] = std::pair<unsigned, GLuint> (1, 0);
    map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);

    glutInitWindowPosition (glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
    glutInitWindowSize(1, 1);
    GLuint window_id = glutCreateWindow( "mesh_filter" );

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
      stringstream errorStream;
      errorStream << "Unable to initialize GLEW: " << glewGetErrorString(err);

      throw (runtime_error (errorStream.str()));
    }
    glutIconifyWindow();
    glutHideWindow();

    for (int i = 0 ; i < 10 ; ++i)
      glutMainLoopEvent ();

    context_ [threadID] = std::pair<unsigned, GLuint> (1, window_id);
  }
  else
    ++ (contextIt->second.first);
}

void mesh_filter::GLRenderer::deleteGLContext ()
{
  boost::mutex::scoped_lock _(context_lock_);
  boost::thread::id threadID = boost::this_thread::get_id();
  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
  if (contextIt == context_.end())
  {
    stringstream errorMsg;
    errorMsg << "No OpenGL context exists for Thread " << threadID;
    throw runtime_error (errorMsg.str ());
  }

  if ( --(contextIt->second.first) == 0)
  {
    glutDestroyWindow(contextIt->second.second);
    context_.erase(contextIt);
  }
}

GLuint mesh_filter::GLRenderer::getColorTexture() const
{
  return rgb_id_;
}

GLuint mesh_filter::GLRenderer::getDepthTexture() const
{
  return depth_id_;
}

const unsigned mesh_filter::GLRenderer::getWidth () const
{
  return width_;
}

const unsigned mesh_filter::GLRenderer::getHeight () const
{
  return height_;
}
<commit_msg>set empty display function for glut window<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Suat Gedikli */

#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GL/glut.h>
#include <GL/freeglut.h>
#include <moveit/mesh_filter/gl_renderer.h>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <iostream>
#include <boost/thread.hpp>
#include <ros/console.h>

using namespace std;

mesh_filter::GLRenderer::GLRenderer (unsigned width, unsigned height, float near, float far)
  : width_ (width)
  , height_ (height)
  , fbo_id_ (0)
  , rbo_id_ (0)
  , rgb_id_ (0)
  , depth_id_ (0)
  , program_ (0)
  , near_ (near)
  , far_ (far)
  , fx_ (width >> 1) // 90 degree wide angle
  , fy_ (fx_)
  , cx_ (width >> 1)
  , cy_ (height >> 1)
{
  createGLContext ();
  initFrameBuffers ();
}

mesh_filter::GLRenderer::~GLRenderer ()
{
  if (program_)
    glDeleteProgram (program_);

  deleteFrameBuffers();
  deleteGLContext ();
}

void mesh_filter::GLRenderer::setBufferSize (unsigned width, unsigned height)
{
  if (width_ != width || height_ != height)
  {
    width_ = width;
    height_ = height;
    deleteFrameBuffers();
    initFrameBuffers();
  }
}

void mesh_filter::GLRenderer::setClippingRange (float near, float far)
{
  if (near_ <= 0)
    throw runtime_error ("near clipping plane distance needs to be larger than 0");
  if (far_ <= near_)
    throw runtime_error ("far clipping plane needs to be larger than near clipping plane distance");
  near_ = near;
  far_ = far;
}

void mesh_filter::GLRenderer::setCameraParameters (float fx, float fy, float cx, float cy)
{
  fx_ = fx;
  fy_ = fy;
  cx_ = cx;
  cy_ = cy;
}

void mesh_filter::GLRenderer::setCameraParameters () const
{
  float left = near_ * -cx_ / fx_;
  float right = near_ * (width_ - cx_) / fx_;
  float top = near_ * cy_ / fy_;
  float bottom = near_ * (cy_ - height_) / fy_;

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glFrustum (left, right, bottom, top, near_, far_);

  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt (0, 0, 0, 0, 0, 1, 0, -1, 0);
}

void mesh_filter::GLRenderer::initFrameBuffers ()
{
  glGenTextures(1, &rgb_id_);
  glBindTexture(GL_TEXTURE_2D, rgb_id_);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);

  glGenTextures(1, &depth_id_);
  glBindTexture(GL_TEXTURE_2D, depth_id_);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glBindTexture(GL_TEXTURE_2D, 0);

  glGenFramebuffers(1, &fbo_id_);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rgb_id_, 0);

  glGenRenderbuffers(1, &rbo_id_);
  glBindRenderbuffer(GL_RENDERBUFFER, rbo_id_);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width_, height_);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_id_);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id_, 0);
  glBindRenderbuffer(GL_RENDERBUFFER, 0);

  GLenum DrawBuffers[2] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT};
  glDrawBuffers(2, DrawBuffers);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

  if (status != GL_FRAMEBUFFER_COMPLETE) // If the frame buffer does not report back as complete
    throw runtime_error ("Couldn't create frame buffer");

  glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer
}

void mesh_filter::GLRenderer::deleteFrameBuffers()
{
  if (rbo_id_)
    glDeleteRenderbuffers (1, &rbo_id_);
  if (fbo_id_)
    glDeleteFramebuffers (1, &fbo_id_);
  if (depth_id_)
    glDeleteTextures(1, &depth_id_);
  if (rgb_id_)
    glDeleteTextures(1, &rgb_id_);

  rbo_id_ = fbo_id_ = depth_id_ = rgb_id_ = 0;
}

void mesh_filter::GLRenderer::begin () const
{
  glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glViewport (0, 0, width_, height_);
  glUseProgram (program_);
  setCameraParameters ();
}

void mesh_filter::GLRenderer::callList (GLuint list) const
{
  begin ();
  glCallList( list );
  end ();
}

void mesh_filter::GLRenderer::end () const
{
  glFlush();
  glPopAttrib();
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void mesh_filter::GLRenderer::getColorBuffer(unsigned char* buffer) const
{
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glBindTexture(GL_TEXTURE_2D, rgb_id_);
  glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void mesh_filter::GLRenderer::getDepthBuffer(float* buffer) const
{
  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
  glBindTexture(GL_TEXTURE_2D, depth_id_);
  glGetTexImage (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, buffer );
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

GLuint mesh_filter::GLRenderer::setShadersFromFile (const string& vertex_filename, const string& fragment_filename)
{
  if (program_)
    glDeleteProgram (program_);

  string vertex_source, fragment_source;
  readShaderCodeFromFile(vertex_filename, vertex_source);
  readShaderCodeFromFile(fragment_filename, fragment_source);

  program_ = loadShaders(vertex_source, fragment_source);
  return program_;
}

GLuint mesh_filter::GLRenderer::setShadersFromString (const string& vertex_source, const string& fragment_source)
{
  program_ = loadShaders(vertex_source, fragment_source);
  return program_;
}

const GLuint& mesh_filter::GLRenderer::getProgramID () const
{
  return program_;
}

const float& mesh_filter::GLRenderer::getNearClippingDistance() const
{
  return near_;
}

const float& mesh_filter::GLRenderer::getFarClippingDistance() const
{
  return far_;
}

GLuint mesh_filter::GLRenderer::createShader (GLuint shaderType, const string& ShaderCode) const
{
  GLuint ShaderID = glCreateShader(shaderType);

  // Compile Shader
  char const * SourcePointer = ShaderCode.c_str();
  glShaderSource(ShaderID, 1, &SourcePointer , NULL);
  glCompileShader(ShaderID);

  // Check Shader
  GLint Result = GL_FALSE;
  glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result);
  if (Result != GL_TRUE)
  {
    int InfoLogLength;
    glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 )
    {
      vector<char> ShaderErrorMessage(InfoLogLength+1);
      glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &ShaderErrorMessage[0]);
      stringstream errorStream;
      errorStream << "Could not compile shader: " << (const char*) &ShaderErrorMessage [0];

      glDeleteShader (ShaderID);
      throw runtime_error (errorStream.str());
    }
  }
  return ShaderID;
}

void mesh_filter::GLRenderer::readShaderCodeFromFile (const string& filename, string& shader) const
{
  if (filename.empty ())
    shader = "";
  else
  {
    string ShaderCode;
    fstream ShaderFile(filename.c_str(), ios::in);
    if(ShaderFile.is_open())
    {
      stringstream buffer;
      buffer << ShaderFile.rdbuf();
      shader = buffer.str();
    }
    else
    {
      stringstream errorStream;
      errorStream << "Could not open shader code in file \"" << filename << "\"";
      throw runtime_error (errorStream.str());
    }
  }
}

GLuint mesh_filter::GLRenderer::loadShaders (const string& vertex_source, const string& fragment_source) const
{
  if (vertex_source.empty () && fragment_source.empty ())
    return 0;

  GLuint ProgramID = glCreateProgram();
  GLuint VertexShaderID = 0;
  GLuint FragmentShaderID = 0;

  if (!vertex_source.empty ())
  {
    GLuint VertexShaderID = createShader (GL_VERTEX_SHADER, vertex_source);
    glAttachShader(ProgramID, VertexShaderID);
  }

  if (!fragment_source.empty ())
  {
    GLuint FragmentShaderID = createShader(GL_FRAGMENT_SHADER, fragment_source);
    glAttachShader(ProgramID, FragmentShaderID);
  }

  glLinkProgram(ProgramID);

  // Check the program
  GLint Result = GL_FALSE;
  GLint InfoLogLength;
  glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
  glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
  if ( InfoLogLength > 0 )
  {
    vector<char> ProgramErrorMessage(InfoLogLength+1);
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    std::size_t l = strnlen(&ProgramErrorMessage[0], ProgramErrorMessage.size());
    if (l > 0)
      ROS_ERROR("%s\n", &ProgramErrorMessage[0]);
  }

  if (VertexShaderID)
    glDeleteShader(VertexShaderID);

  if (FragmentShaderID)
    glDeleteShader(FragmentShaderID);

  return ProgramID;
}

map<boost::thread::id, pair<unsigned, GLuint> > mesh_filter::GLRenderer::context_;
boost::mutex mesh_filter::GLRenderer::context_lock_;
bool mesh_filter::GLRenderer::glutInitialized_ = false;

namespace {
  void nullDisplayFunction(){};
}

void mesh_filter::GLRenderer::createGLContext ()
{
  boost::mutex::scoped_lock _(context_lock_);
  if (!glutInitialized_)
  {
    char buffer[1];
    char* args = buffer;
    int n = 1;

    glutInit(&n, &args);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
    glutInitialized_ = true;
  }

  // check if our thread is initialized
  boost::thread::id threadID = boost::this_thread::get_id();
  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);

  if (contextIt == context_.end())
  {
    context_ [threadID] = std::pair<unsigned, GLuint> (1, 0);
    map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);

    glutInitWindowPosition (glutGet(GLUT_SCREEN_WIDTH) + 30000, 0);
    glutInitWindowSize(1, 1);
    GLuint window_id = glutCreateWindow( "mesh_filter" );
    glutDisplayFunc(nullDisplayFunction);

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
      stringstream errorStream;
      errorStream << "Unable to initialize GLEW: " << glewGetErrorString(err);

      throw (runtime_error (errorStream.str()));
    }
    glutIconifyWindow();
    glutHideWindow();

    for (int i = 0 ; i < 10 ; ++i)
      glutMainLoopEvent ();

    context_ [threadID] = std::pair<unsigned, GLuint> (1, window_id);
  }
  else
    ++ (contextIt->second.first);
}

void mesh_filter::GLRenderer::deleteGLContext ()
{
  boost::mutex::scoped_lock _(context_lock_);
  boost::thread::id threadID = boost::this_thread::get_id();
  map<boost::thread::id, pair<unsigned, GLuint> >::iterator contextIt = context_.find(threadID);
  if (contextIt == context_.end())
  {
    stringstream errorMsg;
    errorMsg << "No OpenGL context exists for Thread " << threadID;
    throw runtime_error (errorMsg.str ());
  }

  if ( --(contextIt->second.first) == 0)
  {
    glutDestroyWindow(contextIt->second.second);
    context_.erase(contextIt);
  }
}

GLuint mesh_filter::GLRenderer::getColorTexture() const
{
  return rgb_id_;
}

GLuint mesh_filter::GLRenderer::getDepthTexture() const
{
  return depth_id_;
}

const unsigned mesh_filter::GLRenderer::getWidth () const
{
  return width_;
}

const unsigned mesh_filter::GLRenderer::getHeight () const
{
  return height_;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the FreeStreamer project,
 * (C)Copyright 2011-2013 Matias Muhonen <mmu@iki.fi>
 * See the file ''LICENSE'' for using the code.
 */

#include "http_stream.h"
#include "audio_queue.h"
#include "id3_parser.h"

/*
 * Uncomment the following line to enable the experimental ID3 tag support
 */
//#define INCLUDE_ID3TAG_SUPPORT 1

namespace astreamer {

const size_t HTTP_Stream::STREAM_BUFSIZ = Audio_Queue::AQ_BUFSIZ;

CFStringRef HTTP_Stream::httpRequestMethod   = CFSTR("GET");
CFStringRef HTTP_Stream::httpUserAgentHeader = CFSTR("User-Agent");
CFStringRef HTTP_Stream::httpUserAgentValue  = CFSTR("aStreamer/1.0");
CFStringRef HTTP_Stream::httpRangeHeader     = CFSTR("Range");
CFStringRef HTTP_Stream::icyMetaDataHeader = CFSTR("Icy-MetaData");
CFStringRef HTTP_Stream::icyMetaDataValue  = CFSTR("1"); /* always request ICY metadata, if available */

/* HTTP_Stream: public */
HTTP_Stream::HTTP_Stream() :
    m_readStream(0),
    m_scheduledInRunLoop(false),
    m_delegate(0),
    m_url(0),
    m_httpHeadersParsed(false),
    m_contentLength(0),

    m_icyStream(false),
    m_icyHeaderCR(false),
    m_icyHeadersRead(false),
    m_icyHeadersParsed(false),

    m_icyMetaDataInterval(0),
    m_dataByteReadCount(0),
    m_metaDataBytesRemaining(0),

    m_httpReadBuffer(0),
    m_icyReadBuffer(0),

    m_id3Parser(new ID3_Parser())
{
    m_id3Parser->m_delegate = this;
}

HTTP_Stream::~HTTP_Stream()
{
    close();

    if (m_httpReadBuffer) {
        delete m_httpReadBuffer, m_httpReadBuffer = 0;
    }
    if (m_icyReadBuffer) {
        delete m_icyReadBuffer, m_icyReadBuffer = 0;
    }
    if (m_url) {
        CFRelease(m_url), m_url = 0;
    }

    delete m_id3Parser, m_id3Parser = 0;
}

HTTP_Stream_Position HTTP_Stream::position()
{
    return m_position;
}

std::string HTTP_Stream::contentType()
{
    return m_contentType;
}

size_t HTTP_Stream::contentLength()
{
    return m_contentLength;
}

bool HTTP_Stream::open()
{
    HTTP_Stream_Position position;
    position.start = 0;
    position.end = 0;

    m_contentLength = 0;
#ifdef INCLUDE_ID3TAG_SUPPORT
    m_id3Parser->reset();
#endif

    return open(position);
}

bool HTTP_Stream::open(const HTTP_Stream_Position& position)
{
    bool success = false;
    CFStreamClientContext CTX = { 0, this, NULL, NULL, NULL };

    /* Already opened a read stream, return */
    if (m_readStream) {
        goto out;
    }

    /* Reset state */
    m_position = position;

    m_httpHeadersParsed = false;
    m_contentType = "";

    m_icyStream = false;
    m_icyHeaderCR = false;
    m_icyHeadersRead = false;
    m_icyHeadersParsed = false;

    m_icyHeaderLines.clear();
    m_icyMetaDataInterval = 0;
    m_dataByteReadCount = 0;
    m_metaDataBytesRemaining = 0;
    m_icyMetaData = "";

    /* Failed to create a stream */
    if (!(m_readStream = createReadStream(m_url))) {
        goto out;
    }

    if (!CFReadStreamSetClient(m_readStream, kCFStreamEventHasBytesAvailable |
	                                         kCFStreamEventEndEncountered |
	                                         kCFStreamEventErrorOccurred, readCallBack, &CTX)) {
        CFRelease(m_readStream), m_readStream = 0;
        goto out;
    }

    setScheduledInRunLoop(true);

    if (!CFReadStreamOpen(m_readStream)) {
        /* Open failed: clean */
        CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
        setScheduledInRunLoop(false);
        if (m_readStream) {
            CFRelease(m_readStream), m_readStream = 0;
        }
        goto out;
    }

    success = true;

out:
    return success;
}

void HTTP_Stream::close()
{
    /* The stream has been already closed */
    if (!m_readStream) {
        return;
    }

    CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
    setScheduledInRunLoop(false);
    CFReadStreamClose(m_readStream);
    CFRelease(m_readStream), m_readStream = 0;
}

void HTTP_Stream::setScheduledInRunLoop(bool scheduledInRunLoop)
{
    /* The stream has not been opened, or it has been already closed */
    if (!m_readStream) {
        return;
    }

    /* The state doesn't change */
    if (m_scheduledInRunLoop == scheduledInRunLoop) {
        return;
    }

    if (m_scheduledInRunLoop) {
        CFReadStreamUnscheduleFromRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    } else {
        CFReadStreamScheduleWithRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    }

    m_scheduledInRunLoop = scheduledInRunLoop;
}

void HTTP_Stream::setUrl(CFURLRef url)
{
    if (m_url) {
        CFRelease(m_url);
    }
    m_url = (CFURLRef)CFRetain(url);
}

void HTTP_Stream::id3metaDataAvailable(std::string metaData)
{
    if (m_delegate) {
        m_delegate->streamMetaDataAvailable(metaData);
    }
}

/* private */

CFReadStreamRef HTTP_Stream::createReadStream(CFURLRef url)
{
    CFReadStreamRef readStream = 0;
    CFHTTPMessageRef request;
    CFDictionaryRef proxySettings;

    if (!(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpRequestMethod, url, kCFHTTPVersion1_1))) {
        goto out;
    }

    CFHTTPMessageSetHeaderFieldValue(request, httpUserAgentHeader, httpUserAgentValue);
    CFHTTPMessageSetHeaderFieldValue(request, icyMetaDataHeader, icyMetaDataValue);

    if (m_position.start > 0 && m_position.end > m_position.start) {
        CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
                                                                NULL,
                                                                CFSTR("bytes=%lu-%lu"),
                                                                m_position.start,
                                                                m_position.end);

        CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
        CFRelease(rangeHeaderValue);
    }

    if (!(readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request, 0))) {
        goto out;
    }

    CFReadStreamSetProperty(readStream,
                            kCFStreamPropertyHTTPShouldAutoredirect,
                            kCFBooleanTrue);

    proxySettings = CFNetworkCopySystemProxySettings();
    CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
    CFRelease(proxySettings);

out:
    if (request) {
        CFRelease(request);
    }

    return readStream;
}

void HTTP_Stream::parseHttpHeadersIfNeeded(UInt8 *buf, CFIndex bufSize)
{
    if (m_httpHeadersParsed) {
        return;
    }
    m_httpHeadersParsed = true;

    /* If the response has the "ICY 200 OK" string,
     * we are dealing with the ShoutCast protocol.
     * The HTTP headers won't be available.
     */
    std::string header;

    for (CFIndex k=0; k < bufSize; k++) {
        UInt8 c = buf[k];
        // Ignore non-ASCII chars
        if (c < 32 || c > 126) {
            continue;
        }
        header.push_back(c);
    }

    char *p = strstr(header.c_str(), "ICY 200 OK");

    // This is an ICY stream, don't try to parse the HTTP headers
    if (p) {
        m_icyStream = true;
        return;
    }

    CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(m_readStream, kCFStreamPropertyHTTPResponseHeader);
    if (response) {
        /*
         * If the server responded with the icy-metaint header, the response
         * body will be encoded in the ShoutCast protocol.
         */
        CFStringRef icyMetaIntString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-metaint"));
        if (icyMetaIntString) {
            m_icyStream = true;
            m_icyHeadersParsed = true;
            m_icyHeadersRead = true;
            m_icyMetaDataInterval = CFStringGetIntValue(icyMetaIntString);
            CFRelease(icyMetaIntString);
        }

        CFStringRef contentTypeString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Type"));
        if (contentTypeString) {
            CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(contentTypeString), kCFStringEncodingUTF8) + 1;
            char *buf = new char[len];
            if (CFStringGetCString(contentTypeString, buf, len, kCFStringEncodingUTF8)) {
                m_contentType.append(buf);
            }
            delete[] buf;

            CFRelease(contentTypeString);
        }

        CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Length"));
        if (contentLengthString) {
            m_contentLength = CFStringGetIntValue(contentLengthString);

            CFRelease(contentLengthString);
        }

        CFRelease(response);
    }

    if (m_delegate) {
        m_delegate->streamIsReadyRead();
    }
}

void HTTP_Stream::parseICYStream(UInt8 *buf, CFIndex bufSize)
{
    CFIndex offset = 0;
    if (!m_icyHeadersRead) {
        // TODO: fail after n tries?

        for (; offset < bufSize; offset++) {
            if (m_icyHeaderCR && buf[offset] == '\n') {
                m_icyHeaderLines.push_back(std::string(""));

                size_t n = m_icyHeaderLines.size();

                /* If the last two lines were empty, we have reached
                 the end of the headers */
                if (n >= 2) {
                    if (m_icyHeaderLines[n-2].empty() &&
                        m_icyHeaderLines[n-1].empty()) {
                        m_icyHeadersRead = true;
                        break;
                    }
                }

                continue;
            }

            if (buf[offset] == '\r') {
                m_icyHeaderCR = true;
                continue;
            } else {
                m_icyHeaderCR = false;
            }

            size_t numberOfLines = m_icyHeaderLines.size();

            if (numberOfLines == 0) {
                continue;
            }
            m_icyHeaderLines[numberOfLines - 1].push_back(buf[offset]);
        }
    } else if (!m_icyHeadersParsed) {
        const char *icyContentTypeHeader = "content-type:";
        const char *icyMetaDataHeader = "icy-metaint:";
        size_t icyContenTypeHeaderLength = strlen(icyContentTypeHeader);
        size_t icyMetaDataHeaderLength = strlen(icyMetaDataHeader);

        for (std::vector<std::string>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
            if (h->compare(0, icyContenTypeHeaderLength, icyContentTypeHeader) == 0) {
                m_contentType = h->substr(icyContenTypeHeaderLength, h->length() - icyContenTypeHeaderLength);
            }

            if (h->compare(0, icyMetaDataHeaderLength, icyMetaDataHeader) == 0) {
                m_icyMetaDataInterval = atoi(h->substr(icyMetaDataHeaderLength, h->length() - icyMetaDataHeaderLength).c_str());
            }
        }

        m_icyHeadersParsed = true;
        offset++;

        if (m_delegate) {
            m_delegate->streamIsReadyRead();
        }
    }

    if (!m_icyReadBuffer) {
        m_icyReadBuffer = new UInt8[STREAM_BUFSIZ];
    }

    UInt32 i=0;

    for (; offset < bufSize; offset++) {
        // is this a metadata byte?
        if (m_metaDataBytesRemaining > 0) {
            m_metaDataBytesRemaining--;

            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;

                if (m_delegate && !m_icyMetaData.empty()) {
                    m_delegate->streamMetaDataAvailable(m_icyMetaData);
                }
                m_icyMetaData.clear();
                continue;
            }

            char c = buf[offset];

            if (c < 32 || c > 126) {
                continue;
            }

            m_icyMetaData.push_back(c);
            continue;
        }

        // is this the interval byte?
        if (m_icyMetaDataInterval > 0 && m_dataByteReadCount == m_icyMetaDataInterval) {
            m_metaDataBytesRemaining = buf[offset] * 16;

            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;
            }
            continue;
        }

        // a data byte
        m_dataByteReadCount++;
        m_icyReadBuffer[i++] = buf[offset];
    }

    if (m_delegate && i > 0) {
        m_delegate->streamHasBytesAvailable(m_icyReadBuffer, i);
    }
}

void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);

    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[STREAM_BUFSIZ];
            }

            CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, STREAM_BUFSIZ);

            if (bytesRead < 0) {
                if (THIS->m_delegate) {
                    THIS->m_delegate->streamErrorOccurred();
                }
                break;
            }

            if (bytesRead > 0) {
                THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);

#ifdef INCLUDE_ID3TAG_SUPPORT
                if (THIS->m_id3Parser->wantData()) {
                    THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                }
#endif

                if (THIS->m_icyStream) {
                    THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                } else {
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
                }
            }
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}

}  // namespace astreamer
<commit_msg>Enable ID3 tag parsing by default.<commit_after>/*
 * This file is part of the FreeStreamer project,
 * (C)Copyright 2011-2013 Matias Muhonen <mmu@iki.fi>
 * See the file ''LICENSE'' for using the code.
 */

#include "http_stream.h"
#include "audio_queue.h"
#include "id3_parser.h"

/*
 * Uncomment the following line to enable the experimental ID3 tag support
 */
#define INCLUDE_ID3TAG_SUPPORT 1

namespace astreamer {

const size_t HTTP_Stream::STREAM_BUFSIZ = Audio_Queue::AQ_BUFSIZ;

CFStringRef HTTP_Stream::httpRequestMethod   = CFSTR("GET");
CFStringRef HTTP_Stream::httpUserAgentHeader = CFSTR("User-Agent");
CFStringRef HTTP_Stream::httpUserAgentValue  = CFSTR("aStreamer/1.0");
CFStringRef HTTP_Stream::httpRangeHeader     = CFSTR("Range");
CFStringRef HTTP_Stream::icyMetaDataHeader = CFSTR("Icy-MetaData");
CFStringRef HTTP_Stream::icyMetaDataValue  = CFSTR("1"); /* always request ICY metadata, if available */

/* HTTP_Stream: public */
HTTP_Stream::HTTP_Stream() :
    m_readStream(0),
    m_scheduledInRunLoop(false),
    m_delegate(0),
    m_url(0),
    m_httpHeadersParsed(false),
    m_contentLength(0),

    m_icyStream(false),
    m_icyHeaderCR(false),
    m_icyHeadersRead(false),
    m_icyHeadersParsed(false),

    m_icyMetaDataInterval(0),
    m_dataByteReadCount(0),
    m_metaDataBytesRemaining(0),

    m_httpReadBuffer(0),
    m_icyReadBuffer(0),

    m_id3Parser(new ID3_Parser())
{
    m_id3Parser->m_delegate = this;
}

HTTP_Stream::~HTTP_Stream()
{
    close();

    if (m_httpReadBuffer) {
        delete m_httpReadBuffer, m_httpReadBuffer = 0;
    }
    if (m_icyReadBuffer) {
        delete m_icyReadBuffer, m_icyReadBuffer = 0;
    }
    if (m_url) {
        CFRelease(m_url), m_url = 0;
    }

    delete m_id3Parser, m_id3Parser = 0;
}

HTTP_Stream_Position HTTP_Stream::position()
{
    return m_position;
}

std::string HTTP_Stream::contentType()
{
    return m_contentType;
}

size_t HTTP_Stream::contentLength()
{
    return m_contentLength;
}

bool HTTP_Stream::open()
{
    HTTP_Stream_Position position;
    position.start = 0;
    position.end = 0;

    m_contentLength = 0;
#ifdef INCLUDE_ID3TAG_SUPPORT
    m_id3Parser->reset();
#endif

    return open(position);
}

bool HTTP_Stream::open(const HTTP_Stream_Position& position)
{
    bool success = false;
    CFStreamClientContext CTX = { 0, this, NULL, NULL, NULL };

    /* Already opened a read stream, return */
    if (m_readStream) {
        goto out;
    }

    /* Reset state */
    m_position = position;

    m_httpHeadersParsed = false;
    m_contentType = "";

    m_icyStream = false;
    m_icyHeaderCR = false;
    m_icyHeadersRead = false;
    m_icyHeadersParsed = false;

    m_icyHeaderLines.clear();
    m_icyMetaDataInterval = 0;
    m_dataByteReadCount = 0;
    m_metaDataBytesRemaining = 0;
    m_icyMetaData = "";

    /* Failed to create a stream */
    if (!(m_readStream = createReadStream(m_url))) {
        goto out;
    }

    if (!CFReadStreamSetClient(m_readStream, kCFStreamEventHasBytesAvailable |
	                                         kCFStreamEventEndEncountered |
	                                         kCFStreamEventErrorOccurred, readCallBack, &CTX)) {
        CFRelease(m_readStream), m_readStream = 0;
        goto out;
    }

    setScheduledInRunLoop(true);

    if (!CFReadStreamOpen(m_readStream)) {
        /* Open failed: clean */
        CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
        setScheduledInRunLoop(false);
        if (m_readStream) {
            CFRelease(m_readStream), m_readStream = 0;
        }
        goto out;
    }

    success = true;

out:
    return success;
}

void HTTP_Stream::close()
{
    /* The stream has been already closed */
    if (!m_readStream) {
        return;
    }

    CFReadStreamSetClient(m_readStream, 0, NULL, NULL);
    setScheduledInRunLoop(false);
    CFReadStreamClose(m_readStream);
    CFRelease(m_readStream), m_readStream = 0;
}

void HTTP_Stream::setScheduledInRunLoop(bool scheduledInRunLoop)
{
    /* The stream has not been opened, or it has been already closed */
    if (!m_readStream) {
        return;
    }

    /* The state doesn't change */
    if (m_scheduledInRunLoop == scheduledInRunLoop) {
        return;
    }

    if (m_scheduledInRunLoop) {
        CFReadStreamUnscheduleFromRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    } else {
        CFReadStreamScheduleWithRunLoop(m_readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    }

    m_scheduledInRunLoop = scheduledInRunLoop;
}

void HTTP_Stream::setUrl(CFURLRef url)
{
    if (m_url) {
        CFRelease(m_url);
    }
    m_url = (CFURLRef)CFRetain(url);
}

void HTTP_Stream::id3metaDataAvailable(std::string metaData)
{
    if (m_delegate) {
        m_delegate->streamMetaDataAvailable(metaData);
    }
}

/* private */

CFReadStreamRef HTTP_Stream::createReadStream(CFURLRef url)
{
    CFReadStreamRef readStream = 0;
    CFHTTPMessageRef request;
    CFDictionaryRef proxySettings;

    if (!(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpRequestMethod, url, kCFHTTPVersion1_1))) {
        goto out;
    }

    CFHTTPMessageSetHeaderFieldValue(request, httpUserAgentHeader, httpUserAgentValue);
    CFHTTPMessageSetHeaderFieldValue(request, icyMetaDataHeader, icyMetaDataValue);

    if (m_position.start > 0 && m_position.end > m_position.start) {
        CFStringRef rangeHeaderValue = CFStringCreateWithFormat(NULL,
                                                                NULL,
                                                                CFSTR("bytes=%lu-%lu"),
                                                                m_position.start,
                                                                m_position.end);

        CFHTTPMessageSetHeaderFieldValue(request, httpRangeHeader, rangeHeaderValue);
        CFRelease(rangeHeaderValue);
    }

    if (!(readStream = CFReadStreamCreateForStreamedHTTPRequest(kCFAllocatorDefault, request, 0))) {
        goto out;
    }

    CFReadStreamSetProperty(readStream,
                            kCFStreamPropertyHTTPShouldAutoredirect,
                            kCFBooleanTrue);

    proxySettings = CFNetworkCopySystemProxySettings();
    CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxySettings);
    CFRelease(proxySettings);

out:
    if (request) {
        CFRelease(request);
    }

    return readStream;
}

void HTTP_Stream::parseHttpHeadersIfNeeded(UInt8 *buf, CFIndex bufSize)
{
    if (m_httpHeadersParsed) {
        return;
    }
    m_httpHeadersParsed = true;

    /* If the response has the "ICY 200 OK" string,
     * we are dealing with the ShoutCast protocol.
     * The HTTP headers won't be available.
     */
    std::string header;

    for (CFIndex k=0; k < bufSize; k++) {
        UInt8 c = buf[k];
        // Ignore non-ASCII chars
        if (c < 32 || c > 126) {
            continue;
        }
        header.push_back(c);
    }

    char *p = strstr(header.c_str(), "ICY 200 OK");

    // This is an ICY stream, don't try to parse the HTTP headers
    if (p) {
        m_icyStream = true;
        return;
    }

    CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(m_readStream, kCFStreamPropertyHTTPResponseHeader);
    if (response) {
        /*
         * If the server responded with the icy-metaint header, the response
         * body will be encoded in the ShoutCast protocol.
         */
        CFStringRef icyMetaIntString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("icy-metaint"));
        if (icyMetaIntString) {
            m_icyStream = true;
            m_icyHeadersParsed = true;
            m_icyHeadersRead = true;
            m_icyMetaDataInterval = CFStringGetIntValue(icyMetaIntString);
            CFRelease(icyMetaIntString);
        }

        CFStringRef contentTypeString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Type"));
        if (contentTypeString) {
            CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(contentTypeString), kCFStringEncodingUTF8) + 1;
            char *buf = new char[len];
            if (CFStringGetCString(contentTypeString, buf, len, kCFStringEncodingUTF8)) {
                m_contentType.append(buf);
            }
            delete[] buf;

            CFRelease(contentTypeString);
        }

        CFStringRef contentLengthString = CFHTTPMessageCopyHeaderFieldValue(response, CFSTR("Content-Length"));
        if (contentLengthString) {
            m_contentLength = CFStringGetIntValue(contentLengthString);

            CFRelease(contentLengthString);
        }

        CFRelease(response);
    }

    if (m_delegate) {
        m_delegate->streamIsReadyRead();
    }
}

void HTTP_Stream::parseICYStream(UInt8 *buf, CFIndex bufSize)
{
    CFIndex offset = 0;
    if (!m_icyHeadersRead) {
        // TODO: fail after n tries?

        for (; offset < bufSize; offset++) {
            if (m_icyHeaderCR && buf[offset] == '\n') {
                m_icyHeaderLines.push_back(std::string(""));

                size_t n = m_icyHeaderLines.size();

                /* If the last two lines were empty, we have reached
                 the end of the headers */
                if (n >= 2) {
                    if (m_icyHeaderLines[n-2].empty() &&
                        m_icyHeaderLines[n-1].empty()) {
                        m_icyHeadersRead = true;
                        break;
                    }
                }

                continue;
            }

            if (buf[offset] == '\r') {
                m_icyHeaderCR = true;
                continue;
            } else {
                m_icyHeaderCR = false;
            }

            size_t numberOfLines = m_icyHeaderLines.size();

            if (numberOfLines == 0) {
                continue;
            }
            m_icyHeaderLines[numberOfLines - 1].push_back(buf[offset]);
        }
    } else if (!m_icyHeadersParsed) {
        const char *icyContentTypeHeader = "content-type:";
        const char *icyMetaDataHeader = "icy-metaint:";
        size_t icyContenTypeHeaderLength = strlen(icyContentTypeHeader);
        size_t icyMetaDataHeaderLength = strlen(icyMetaDataHeader);

        for (std::vector<std::string>::iterator h = m_icyHeaderLines.begin(); h != m_icyHeaderLines.end(); ++h) {
            if (h->compare(0, icyContenTypeHeaderLength, icyContentTypeHeader) == 0) {
                m_contentType = h->substr(icyContenTypeHeaderLength, h->length() - icyContenTypeHeaderLength);
            }

            if (h->compare(0, icyMetaDataHeaderLength, icyMetaDataHeader) == 0) {
                m_icyMetaDataInterval = atoi(h->substr(icyMetaDataHeaderLength, h->length() - icyMetaDataHeaderLength).c_str());
            }
        }

        m_icyHeadersParsed = true;
        offset++;

        if (m_delegate) {
            m_delegate->streamIsReadyRead();
        }
    }

    if (!m_icyReadBuffer) {
        m_icyReadBuffer = new UInt8[STREAM_BUFSIZ];
    }

    UInt32 i=0;

    for (; offset < bufSize; offset++) {
        // is this a metadata byte?
        if (m_metaDataBytesRemaining > 0) {
            m_metaDataBytesRemaining--;

            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;

                if (m_delegate && !m_icyMetaData.empty()) {
                    m_delegate->streamMetaDataAvailable(m_icyMetaData);
                }
                m_icyMetaData.clear();
                continue;
            }

            char c = buf[offset];

            if (c < 32 || c > 126) {
                continue;
            }

            m_icyMetaData.push_back(c);
            continue;
        }

        // is this the interval byte?
        if (m_icyMetaDataInterval > 0 && m_dataByteReadCount == m_icyMetaDataInterval) {
            m_metaDataBytesRemaining = buf[offset] * 16;

            if (m_metaDataBytesRemaining == 0) {
                m_dataByteReadCount = 0;
            }
            continue;
        }

        // a data byte
        m_dataByteReadCount++;
        m_icyReadBuffer[i++] = buf[offset];
    }

    if (m_delegate && i > 0) {
        m_delegate->streamHasBytesAvailable(m_icyReadBuffer, i);
    }
}

void HTTP_Stream::readCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo)
{
    HTTP_Stream *THIS = static_cast<HTTP_Stream*>(clientCallBackInfo);

    switch (eventType) {
        case kCFStreamEventHasBytesAvailable: {
            if (!THIS->m_httpReadBuffer) {
                THIS->m_httpReadBuffer = new UInt8[STREAM_BUFSIZ];
            }

            CFIndex bytesRead = CFReadStreamRead(stream, THIS->m_httpReadBuffer, STREAM_BUFSIZ);

            if (bytesRead < 0) {
                if (THIS->m_delegate) {
                    THIS->m_delegate->streamErrorOccurred();
                }
                break;
            }

            if (bytesRead > 0) {
                THIS->parseHttpHeadersIfNeeded(THIS->m_httpReadBuffer, bytesRead);

#ifdef INCLUDE_ID3TAG_SUPPORT
                if (THIS->m_id3Parser->wantData()) {
                    THIS->m_id3Parser->feedData(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                }
#endif

                if (THIS->m_icyStream) {
                    THIS->parseICYStream(THIS->m_httpReadBuffer, bytesRead);
                } else {
                    if (THIS->m_delegate) {
                        THIS->m_delegate->streamHasBytesAvailable(THIS->m_httpReadBuffer, (UInt32)bytesRead);
                    }
                }
            }
            break;
        }
        case kCFStreamEventEndEncountered: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamEndEncountered();
            }
            break;
        }
        case kCFStreamEventErrorOccurred: {
            if (THIS->m_delegate) {
                THIS->m_delegate->streamErrorOccurred();
            }
            break;
        }
    }
}

}  // namespace astreamer
<|endoftext|>


<commit_before>//===========================================
//  PC-BSD source code
//  Copyright (c) 2015, PC-BSD Software/iXsystems
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
// Note: This was almost entirely written by Tim McCormick in 2009 for
//   the first PC-BSD library, and copied here by Ken Moore in 2015
//===========================================
#include "backend-network.h"
#include "backend-general.h"

//#include "sysadm-global.h"

using namespace backend;

//====================
//   STATIC LISTING FUNCTION
//====================
QStringList NetDevice::listNetDevices(){
  QStringList result;
  struct ifaddrs *ifap;
  getifaddrs(&ifap);
  char ifName[IFNAMSIZ];
   //Probe the system for each device (one at a time)
  while (ifap != NULL){
     strncpy(ifName, ifap->ifa_name, IFNAMSIZ);
     if (result.contains(ifName) == 0) result += ifName;
     ifap = ifap->ifa_next;
  }
  //Close the
  freeifaddrs(ifap);
  return result;
}

//=====================
//          CLASS FUNCTIONS
//=====================
//Get the name of the device (taking off any numbers)
QString NetDevice::devName(){
   uint pos = name.indexOf(QRegExp("[0-9]+$"));
   QString result = name;
   result.truncate(pos);
   return result;
}

//Return just the number of the device (removing the name)
uint NetDevice::devNum(){
   uint pos = name.indexOf(QRegExp("[0-9]+$"));
   return name.mid(pos).toInt();
}

//Fetch the IP and return it as a QString
QString NetDevice::ipAsString(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(PF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFADDR, &ifr);
   struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
   close(s); //close the file descriptor
   return QString(inet_ntoa(in));
}

//Fetch the IPv6 and return it as a QString
QString NetDevice::ipv6AsString(){
  //Get the sockaddr for the device
  struct sockaddr *sadd = 0;
  struct ifaddrs *addrs;
  if( 0!=getifaddrs( &addrs ) ){ qDebug() << "Could not get addrs"; return ""; }
  while(sadd==0 && addrs!=0){
    if( QString(addrs->ifa_name)==name && addrs->ifa_addr->sa_family==AF_INET6){
      //Found device (with IPv6 address)
      sadd = addrs->ifa_addr;
      break;
    }else{
      //Move to the next device
      addrs = addrs->ifa_next;
    }
  }
  // Causes crash in some cases
  //free(addrs);
  if(sadd==0){ qDebug() << "No socket address found"; return ""; }
  //Now get the IPv6 address in string form
  char straddr[INET6_ADDRSTRLEN];
  int err = getnameinfo(sadd, sadd->sa_len, straddr, sizeof(straddr),NULL, 0, NI_NUMERICHOST);
  if(err!=0){
    qDebug() << "getnameinfo error:" << gai_strerror(err);
    return "";
  }else{
    return QString(straddr);
  }
}

//Fetch the netmask and return it as a QString
QString NetDevice::netmaskAsString(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(PF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFNETMASK, &ifr);
   struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
  close(s); //close the file descriptor
   return QString(inet_ntoa(in));
}

//Returns the description string for the device
QString NetDevice::desc(){
  QString name, num, parent;
  if( isWireless() ){ parent = getWifiParent(); }

  if(!parent.isEmpty()){
    name = num = parent;
      uint pos = name.indexOf(QRegExp("[0-9]+$"));
      name.truncate(pos);
      num.remove(0,pos);
  }else{
    name = devName();
    num = QString::number(devNum());
  }
  return General::sysctl("dev." + name + "." + num + ".%desc");
}

//Fetch the mac address as a QString
QString NetDevice::macAsString(){
   int mib[6];
   size_t len;
   char *buf;
   struct sockaddr_dl *sdl;
   char *ptr;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1);
   ptr = (char *) LLADDR(sdl);

   QString mac;
   for (uint i=0; i < 6; i++){
      mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0');
      if(i<5){ mac += ":"; }
   }
   return mac;
}

//Get the status of the device (active, associated, etc...)
QString NetDevice::mediaStatusAsString(){
   struct ifmediareq ifm;
   memset(&ifm, 0, sizeof(struct ifmediareq));

   strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFMEDIA, &ifm);
   QString status;

   switch (IFM_TYPE(ifm.ifm_active)){
      case IFM_FDDI:
      case IFM_TOKEN:
         if (ifm.ifm_status & IFM_ACTIVE) status = "inserted";
         else status = "no ring";
         break;
      case IFM_IEEE80211:
         if (ifm.ifm_status & IFM_ACTIVE) status = "associated";
         else status = "no carrier";
         break;
      default:
         if (ifm.ifm_status & IFM_ACTIVE) status = "active";
         else status = "no carrier";
   }
  close(s); //close the file descriptor
  return status;
}

QString NetDevice::gatewayAsString(){
  QString info = General::RunCommand("nice netstat -n -r").split("\n").filter(name).filter("default").join("\n");
  if(info.isEmpty()){ return ""; }
  //Pull the gateway out of the first line (<default> <gateway>)
  info = info.replace("\t"," ").section("\n",0,0).simplified(); //ensure proper parsing
  return  info.section(" ",1,1);
}

//Check if a device is wireless or not
bool NetDevice::isWireless(){
   struct ifmediareq ifm;
   memset(&ifm, 0, sizeof(struct ifmediareq));

   strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFMEDIA, &ifm);
  bool iswifi = (IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211);
  close(s); //close the file descriptor
   return iswifi;
}

//Get the parent device (if this is a wireless wlan)
QString NetDevice::getWifiParent(){
   if(!name.contains("wlan")){ return ""; }
   return General::sysctl("net.wlan." + QString::number(this->devNum()) + ".%parent");
}

//See if the device is setup to use DHCP
bool NetDevice::usesDHCP(){
  //The system does not keep track of how the device's address was assigned
  //  so the closest we can get to this is to see if the system is setup to use
  //  DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15)
  return !Network::readRcConf().filter(name).filter("DHCP").isEmpty();
}

//See if the device is currently in use
bool NetDevice::isUp(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFFLAGS, &ifr);
   bool isup = (ifr.ifr_flags & IFF_UP);
   close(s); //close the file descriptor
   return  isup;
}

//Determine the number of packets received by the device
long NetDevice::packetsRx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_ipackets;
}

//Determine the number of packets transmitted by the device
long NetDevice::packetsTx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_opackets;
}

//Determine the number of errors received
long NetDevice::errorsRx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_ierrors;
}

//Determine the number of errors transmitted
long NetDevice::errorsTx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_oerrors;
}

//=========================
//   SETTING FUNCTIONS (requires root)
//=========================
void NetDevice::setUp(bool up){
  //This only sets it up/down for the current session - does not change usage on next boot
  General::RunCommand("ifconfig "+name+" "+ (up ? "up": "down") );
}
<commit_msg>Remove the IFM_TOKEN and IFM_FDDI usage from pc-networkmanager - removed from FreeBSD.<commit_after>//===========================================
//  PC-BSD source code
//  Copyright (c) 2015, PC-BSD Software/iXsystems
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
// Note: This was almost entirely written by Tim McCormick in 2009 for
//   the first PC-BSD library, and copied here by Ken Moore in 2015
//===========================================
#include "backend-network.h"
#include "backend-general.h"

//#include "sysadm-global.h"

using namespace backend;

//====================
//   STATIC LISTING FUNCTION
//====================
QStringList NetDevice::listNetDevices(){
  QStringList result;
  struct ifaddrs *ifap;
  getifaddrs(&ifap);
  char ifName[IFNAMSIZ];
   //Probe the system for each device (one at a time)
  while (ifap != NULL){
     strncpy(ifName, ifap->ifa_name, IFNAMSIZ);
     if (result.contains(ifName) == 0) result += ifName;
     ifap = ifap->ifa_next;
  }
  //Close the
  freeifaddrs(ifap);
  return result;
}

//=====================
//          CLASS FUNCTIONS
//=====================
//Get the name of the device (taking off any numbers)
QString NetDevice::devName(){
   uint pos = name.indexOf(QRegExp("[0-9]+$"));
   QString result = name;
   result.truncate(pos);
   return result;
}

//Return just the number of the device (removing the name)
uint NetDevice::devNum(){
   uint pos = name.indexOf(QRegExp("[0-9]+$"));
   return name.mid(pos).toInt();
}

//Fetch the IP and return it as a QString
QString NetDevice::ipAsString(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(PF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFADDR, &ifr);
   struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
   close(s); //close the file descriptor
   return QString(inet_ntoa(in));
}

//Fetch the IPv6 and return it as a QString
QString NetDevice::ipv6AsString(){
  //Get the sockaddr for the device
  struct sockaddr *sadd = 0;
  struct ifaddrs *addrs;
  if( 0!=getifaddrs( &addrs ) ){ qDebug() << "Could not get addrs"; return ""; }
  while(sadd==0 && addrs!=0){
    if( QString(addrs->ifa_name)==name && addrs->ifa_addr->sa_family==AF_INET6){
      //Found device (with IPv6 address)
      sadd = addrs->ifa_addr;
      break;
    }else{
      //Move to the next device
      addrs = addrs->ifa_next;
    }
  }
  // Causes crash in some cases
  //free(addrs);
  if(sadd==0){ qDebug() << "No socket address found"; return ""; }
  //Now get the IPv6 address in string form
  char straddr[INET6_ADDRSTRLEN];
  int err = getnameinfo(sadd, sadd->sa_len, straddr, sizeof(straddr),NULL, 0, NI_NUMERICHOST);
  if(err!=0){
    qDebug() << "getnameinfo error:" << gai_strerror(err);
    return "";
  }else{
    return QString(straddr);
  }
}

//Fetch the netmask and return it as a QString
QString NetDevice::netmaskAsString(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(PF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFNETMASK, &ifr);
   struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
  close(s); //close the file descriptor
   return QString(inet_ntoa(in));
}

//Returns the description string for the device
QString NetDevice::desc(){
  QString name, num, parent;
  if( isWireless() ){ parent = getWifiParent(); }

  if(!parent.isEmpty()){
    name = num = parent;
      uint pos = name.indexOf(QRegExp("[0-9]+$"));
      name.truncate(pos);
      num.remove(0,pos);
  }else{
    name = devName();
    num = QString::number(devNum());
  }
  return General::sysctl("dev." + name + "." + num + ".%desc");
}

//Fetch the mac address as a QString
QString NetDevice::macAsString(){
   int mib[6];
   size_t len;
   char *buf;
   struct sockaddr_dl *sdl;
   char *ptr;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1);
   ptr = (char *) LLADDR(sdl);

   QString mac;
   for (uint i=0; i < 6; i++){
      mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0');
      if(i<5){ mac += ":"; }
   }
   return mac;
}

//Get the status of the device (active, associated, etc...)
QString NetDevice::mediaStatusAsString(){
   struct ifmediareq ifm;
   memset(&ifm, 0, sizeof(struct ifmediareq));

   strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFMEDIA, &ifm);
   QString status;

   switch (IFM_TYPE(ifm.ifm_active)){
      case IFM_IEEE80211:
         if (ifm.ifm_status & IFM_ACTIVE) status = "associated";
         else status = "no carrier";
         break;
      default:
         if (ifm.ifm_status & IFM_ACTIVE) status = "active";
         else status = "no carrier";
   }
  close(s); //close the file descriptor
  return status;
}

QString NetDevice::gatewayAsString(){
  QString info = General::RunCommand("nice netstat -n -r").split("\n").filter(name).filter("default").join("\n");
  if(info.isEmpty()){ return ""; }
  //Pull the gateway out of the first line (<default> <gateway>)
  info = info.replace("\t"," ").section("\n",0,0).simplified(); //ensure proper parsing
  return  info.section(" ",1,1);
}

//Check if a device is wireless or not
bool NetDevice::isWireless(){
   struct ifmediareq ifm;
   memset(&ifm, 0, sizeof(struct ifmediareq));

   strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFMEDIA, &ifm);
  bool iswifi = (IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211);
  close(s); //close the file descriptor
   return iswifi;
}

//Get the parent device (if this is a wireless wlan)
QString NetDevice::getWifiParent(){
   if(!name.contains("wlan")){ return ""; }
   return General::sysctl("net.wlan." + QString::number(this->devNum()) + ".%parent");
}

//See if the device is setup to use DHCP
bool NetDevice::usesDHCP(){
  //The system does not keep track of how the device's address was assigned
  //  so the closest we can get to this is to see if the system is setup to use
  //  DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15)
  return !Network::readRcConf().filter(name).filter("DHCP").isEmpty();
}

//See if the device is currently in use
bool NetDevice::isUp(){
   struct ifreq ifr;
   memset(&ifr, 0, sizeof(struct ifreq));

   strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
   int s = socket(AF_INET, SOCK_DGRAM, 0);

   ioctl(s, SIOCGIFFLAGS, &ifr);
   bool isup = (ifr.ifr_flags & IFF_UP);
   close(s); //close the file descriptor
   return  isup;
}

//Determine the number of packets received by the device
long NetDevice::packetsRx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_ipackets;
}

//Determine the number of packets transmitted by the device
long NetDevice::packetsTx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_opackets;
}

//Determine the number of errors received
long NetDevice::errorsRx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_ierrors;
}

//Determine the number of errors transmitted
long NetDevice::errorsTx(){
   int mib[6];
   size_t len;
   char *buf;
   struct if_msghdr *ifm;

   mib[0] = CTL_NET;
   mib[1] = AF_ROUTE;
   mib[2] = 0;
   mib[3] = AF_LINK;
   mib[4] = NET_RT_IFLIST;
   mib[5] = if_nametoindex(name.toLocal8Bit());

   //First find the size of the return, so we can adjust buf accordingly
   sysctl(mib, 6, NULL, &len, NULL, 0);
   buf = (char *) malloc(len);
   sysctl(mib, 6, buf, &len, NULL, 0);

   ifm = (if_msghdr *) buf;

   return ifm->ifm_data.ifi_oerrors;
}

//=========================
//   SETTING FUNCTIONS (requires root)
//=========================
void NetDevice::setUp(bool up){
  //This only sets it up/down for the current session - does not change usage on next boot
  General::RunCommand("ifconfig "+name+" "+ (up ? "up": "down") );
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_IO_FileAccessException_inl_
#define _Stroika_Foundation_IO_FileAccessException_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

namespace Stroika::Foundation::IO {

    using Characters::String;

    /**
     * This exception is thrown when a given file is opened, or creation attempted, etc. It is a failure due to
     * file (or directory) access permissions. It nearly always is the result of an operation (attempted and failed)
     * on a given file (which is usually given in the object). It also is the result of a perticular operation/access
     * failure (like read, write, or list).
     *
     *  // @todo - this should subclass from Execution::Exception<filesystem::filesystem_error> - but needs some work...
     */

    class [[deprecated ("use IO::FileSystem::Exception instead (with make_error_code (errc::permission_denied) )- Since Stroika v2.1d18")]] FileAccessException : public Execution::SystemErrorException<>
    {
    private:
        using inherited = Execution::SystemErrorException<>;

    public:
        /**
         *  This is almost equally likely to be errc::permission_denied or errc::no_such_file_or_directory. So best to call
         *  with explicit error_code, but if not we can guess.
         */
        FileAccessException (const optional<String>& fileName = nullopt, const optional<FileAccessMode>& fileAccessMode = nullopt);
        FileAccessException (error_code ec, const optional<String>& fileName = nullopt, const optional<FileAccessMode>& fileAccessMode = nullopt);

    public:
        /**
         *  If filename not specified, empty string returned (backwards compat)
         */
        nonvirtual optional<String> GetFileName () const;

    public:
        /**
         *  If fileAccessMode not specified, FileAccessMode::eReadWrite returned (backwards compat)
         */
        nonvirtual optional<FileAccessMode> GetFileAccessMode () const;

    public:
        nonvirtual FileAccessMode GetFileAccessModeValue (FileAccessMode defaultVal = FileAccessMode::eReadWrite) const { return fFileAccessMode_.value_or (defaultVal); }

    private:
        optional<String>         fFileName_;
        optional<FileAccessMode> fFileAccessMode_;
    };

        /**
     *  ** DEPRECATED - use DeclareActivity or IO::FileSystem::Exception::Throw....if with pathname args
     */
#define Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAME_ACCCESS_HELPER(USEFILENAME, USEACCESSMODE) \
    catch (const Stroika::Foundation::IO::FileAccessException& e)                                                  \
    {                                                                                \
        Stroika::Foundation::Execution::Throw (                                                                    \
            Stroika::Foundation::IO::FileAccessException (                                                         \
                (Memory::OptionalValue (optional<Characters::String>{USEFILENAME}, e.GetFileName ())),             \
                (Memory::OptionalValue (optional<IO::FileAccessMode>{USEACCESSMODE}, e.GetFileAccessMode ()))));   \
    }

        /**
     *  ** DEPRECATED - use DeclareActivity or IO::FileSystem::Exception::Throw....if with pathname args
      */
#define Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAMESONLY_HELPER(USEFILENAME) \
    Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAME_ACCCESS_HELPER (USEFILENAME, e.GetFileAccessMode ())

    /*
     ********************************************************************************
     ***************************** IO::FileAccessException **************************
     ********************************************************************************
     */
    inline optional<String> FileAccessException::GetFileName () const
    {
        return fFileName_;
    }
    inline optional<FileAccessMode> FileAccessException::GetFileAccessMode () const
    {
        return fFileAccessMode_;
    }
    inline FileAccessException::FileAccessException (const optional<String>& fileName, const optional<FileAccessMode>& fileAccessMode)
        : FileAccessException (make_error_code (errc::permission_denied), fileName, fileAccessMode)
    {
    }

}

#endif /*_Stroika_Foundation_IO_FileAccessException_inl_*/
<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_IO_FileAccessException_inl_
#define _Stroika_Foundation_IO_FileAccessException_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

namespace Stroika::Foundation::IO {

    using Characters::String;

    /**
     *  // @todo - this should subclass from Execution::Exception<filesystem::filesystem_error> - but needs some work...
     */
    class [[deprecated ("use IO::FileSystem::Exception instead (with make_error_code (errc::permission_denied) )- Since Stroika v2.1d18")]] FileAccessException : public Execution::SystemErrorException<>
    {
    private:
        using inherited = Execution::SystemErrorException<>;

    public:
        /**
         *  This is almost equally likely to be errc::permission_denied or errc::no_such_file_or_directory. So best to call
         *  with explicit error_code, but if not we can guess.
         */
        FileAccessException (const optional<String>& fileName = nullopt, const optional<FileAccessMode>& fileAccessMode = nullopt);
        FileAccessException (error_code ec, const optional<String>& fileName = nullopt, const optional<FileAccessMode>& fileAccessMode = nullopt);

    public:
        /**
         *  If filename not specified, empty string returned (backwards compat)
         */
        nonvirtual optional<String> GetFileName () const;

    public:
        /**
         *  If fileAccessMode not specified, FileAccessMode::eReadWrite returned (backwards compat)
         */
        nonvirtual optional<FileAccessMode> GetFileAccessMode () const;

    public:
        nonvirtual FileAccessMode GetFileAccessModeValue (FileAccessMode defaultVal = FileAccessMode::eReadWrite) const { return fFileAccessMode_.value_or (defaultVal); }

    private:
        optional<String>         fFileName_;
        optional<FileAccessMode> fFileAccessMode_;
    };

        /**
     *  ** DEPRECATED - use DeclareActivity or IO::FileSystem::Exception::Throw....if with pathname args
     */
#define Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAME_ACCCESS_HELPER(USEFILENAME, USEACCESSMODE) \
    catch (const Stroika::Foundation::IO::FileAccessException& e)                                                  \
    {                                                                                \
        Stroika::Foundation::Execution::Throw (                                                                    \
            Stroika::Foundation::IO::FileAccessException (                                                         \
                (Memory::OptionalValue (optional<Characters::String>{USEFILENAME}, e.GetFileName ())),             \
                (Memory::OptionalValue (optional<IO::FileAccessMode>{USEACCESSMODE}, e.GetFileAccessMode ()))));   \
    }

        /**
     *  ** DEPRECATED - use DeclareActivity or IO::FileSystem::Exception::Throw....if with pathname args
      */
#define Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAMESONLY_HELPER(USEFILENAME) \
    Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAME_ACCCESS_HELPER (USEFILENAME, e.GetFileAccessMode ())

    /*
     ********************************************************************************
     ***************************** IO::FileAccessException **************************
     ********************************************************************************
     */
    inline optional<String> FileAccessException::GetFileName () const
    {
        return fFileName_;
    }
    inline optional<FileAccessMode> FileAccessException::GetFileAccessMode () const
    {
        return fFileAccessMode_;
    }
    inline FileAccessException::FileAccessException (const optional<String>& fileName, const optional<FileAccessMode>& fileAccessMode)
        : FileAccessException (make_error_code (errc::permission_denied), fileName, fileAccessMode)
    {
    }

}

#endif /*_Stroika_Foundation_IO_FileAccessException_inl_*/
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2306
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1354481 by johtaylo@johtaylo-jtincrementor-increment on 2016/12/17 03:00:05<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2307
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1608
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1065141 by johtaylo@johtaylo-JTBUILDER03-increment on 2014/08/12 03:00:11<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1609
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2582
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1510302 by johtaylo@johtaylo-jtincrementor2-increment on 2018/01/31 03:00:05<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2583
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2345
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1365827 by johtaylo@johtaylo-jtincrementor-increment on 2017/01/25 03:00:09<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2346
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2261
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1334447 by johtaylo@johtaylo-jtincrementor-increment on 2016/11/01 03:00:04<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 2262
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>