<commit_before>#include <iostream>

#include <opencv2/imgproc/imgproc.hpp>

#include <opencv2/gpu/gpu.hpp>

#include "CaffeBatchPrediction.hpp"

template <class MatT>
CaffeClassifier<MatT>::CaffeClassifier(const std::string& model_file,
      const std::string& trained_file,
      const std::string& mean_file,
      const std::string& label_file,
      const int batch_size) {

   if (IsGPU())
   	caffe::Caffe::set_mode(caffe::Caffe::GPU);
   else
   	caffe::Caffe::set_mode(caffe::Caffe::CPU);

   /* Set batchsize */
   batch_size_ = batch_size;

   /* Load the network - this includes model geometry and trained weights */
   net_.reset(new caffe::Net<float>(model_file, caffe::TEST));

   std::cerr << "Before Trained Layers From" << std::endl;

   net_->CopyTrainedLayersFrom(trained_file);

   std::cerr << "After Trained Layers From" << std::endl;

   CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
   CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";

   caffe::Blob<float>* input_layer = net_->input_blobs()[0];
   num_channels_ = input_layer->channels();
   CHECK(num_channels_ == 3 || num_channels_ == 1)
      << "Input layer should have 1 or 3 channels.";
   input_geometry_ = cv::Size(input_layer->width(), input_layer->height());

   /* Load the binaryproto mean file. */
   SetMean(mean_file);

   std::cerr << "After SetMean" << std::endl;

   /* Load labels. */
   // This will be used to give each index of the output
   // a human-readable name
   std::ifstream labels(label_file.c_str());
   CHECK(labels) << "Unable to open labels file " << label_file;
   std::string line;
   while (std::getline(labels, line))
      labels_.push_back(std::string(line));

   caffe::Blob<float>* output_layer = net_->output_blobs()[0];
   CHECK_EQ(labels_.size(), output_layer->channels())
      << "Number of labels is different from the output layer dimension.";

   // Pre-process Mat wrapping
   input_layer->Reshape(batch_size_, num_channels_,
	 input_geometry_.height,
	 input_geometry_.width);

   /* Forward dimension change to all layers. */
   net_->Reshape();

   // The wrap code puts the buffer for one individual channel
   // input to the net (one color channel of one image) into
   // a separate Mat
   // The inner vector here will be one Mat per channel of the
   // input to the net. The outer vector is a vector of those
   // one for each of the batched inputs.
   // This allows an easy copy from the input images
   // into the input buffers for the net
   WrapBatchInputLayer();
   std::cout << "Leaving Constructor" << std::endl;
}

// Helper function for compare - used to sort values by pair.first keys
static bool PairCompare(const std::pair<float, int>& lhs,
			const std::pair<float, int>& rhs)
{
   return lhs.first > rhs.first;
}

/* Return the indices of the top N values of vector v. */
static std::vector<int> Argmax(const std::vector<float>& v, int N)
{
   std::vector<std::pair<float, int> > pairs;
   for (size_t i = 0; i < v.size(); ++i)
      pairs.push_back(std::make_pair(v[i], i));
   std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);

   std::vector<int> result;
   for (size_t i = 0; i < N; ++i)
      result.push_back(pairs[i].second);
   return result;
}

// Given X input images, return X vectors of predictions.
// Each of the X vectors are themselves a vector which will have the
// N predictions with the highest confidences for the corresponding
// input image
template <class MatT>
std::vector< std::vector<Prediction> > CaffeClassifier<MatT>::ClassifyBatch(const std::vector< MatT > &imgs,
                                                                      size_t num_classes)
{
   // output_batch will be a flat vector of N floating point values
   // per image (1 per N output labels), repeated
   // times the number of input images batched per run
   // Convert that into the output vector of vectors
   std::vector<float> output_batch = PredictBatch(imgs);
   std::vector< std::vector<Prediction> > predictions;
   size_t labels_size = labels_.size();
   num_classes = std::min(num_classes, labels_size);

   // For each image, find the top num_classes values
   for(size_t j = 0; j < imgs.size(); j++)
   {
      // Create an output vector just for values for this image. Since
      // each image has labels_size values, that's output_batch[j*labels_size]
      // through output_batch[(j+1) * labels_size]
      std::vector<float> output(output_batch.begin() + j*labels_size, output_batch.begin() + (j+1)*labels_size);
      // For the output specific to the jth image, grab the
      // indexes of the top num_classes predictions
      std::vector<int> maxN = Argmax(output, num_classes);
      // Using those top N indexes, create a set of labels/value predictions
      // specific to this jth image
      std::vector<Prediction> prediction_single;
      for (size_t i = 0; i < num_classes; ++i)
      {
	 int idx = maxN[i];
	 prediction_single.push_back(std::make_pair(labels_[idx], output[idx]));
      }
      // Add the predictions for this image to the list of
      // predictions for all images
      predictions.push_back(std::vector<Prediction>(prediction_single));
   }
   return predictions;
}

/* Load the mean file in binaryproto format. */
template <class MatT>
void CaffeClassifier<MatT>::SetMean(const std::string& mean_file)
{
   caffe::BlobProto blob_proto;
   ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);

   /* Convert from BlobProto to Blob<float> */
   caffe::Blob<float> mean_blob;
   mean_blob.FromProto(blob_proto);
   CHECK_EQ(mean_blob.channels(), num_channels_)
      << "Number of channels of mean file doesn't match input layer.";

   /* The format of the mean file is planar 32-bit float BGR or grayscale. */
   std::vector<cv::Mat> channels;
   float* data = mean_blob.mutable_cpu_data();
   for (int i = 0; i < num_channels_; ++i)
   {
      /* Extract an individual channel. */
      cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);
      channels.push_back(channel);
      data += mean_blob.height() * mean_blob.width();
   }

   /* Merge the separate channels into a single image. */
   cv::Mat mean;
   merge(channels, mean);

   /* Compute the global mean pixel value and create a mean image
    * filled with this value. */
   cv::Scalar channel_mean = cv::mean(mean);

   // Hack to possibly convert to GpuMat - if MatT is GpuMat,
   // this will upload the Mat object to a GpuMat, otherwise
   // it will just copy it to the member variable mean_
   mean_ = MatT(input_geometry_, mean.type(), channel_mean);
}

// TODO : see if we can do this once at startup or if
// it has to be done each pass.  If it can be done once,
// we can wrap the nets in Mat arrays in the constructor
// and re-use them multiple times?
template <class MatT>
void CaffeClassifier<MatT>::setBatchSize(size_t batch_size)
{
   CHECK(batch_size >= 0);
   if (batch_size == batch_size_) return;
   batch_size_ = batch_size;
   reshapeNet();
}

template <class MatT>
void CaffeClassifier<MatT>::reshapeNet()
{
   CHECK(net_->input_blobs().size() == 1);
   caffe::Blob<float>* input_layer = net_->input_blobs()[0];
   input_layer->Reshape(batch_size_, num_channels_,
	 input_geometry_.height,
	 input_geometry_.width);
   net_->Reshape();
   WrapBatchInputLayer();
}

// Get the output values for a set of images in one flat vector
// These values will be in the same order as the labels for each
// image, and each set of labels for an image next adjacent to the
// one for the next image.
// That is, [0] = value for label 0 for the first image up to
// [n] = value for label n for the first image. It then starts again
// for the next image - [n+1] = label 0 for image #2.
template <class MatT>
std::vector<float> CaffeClassifier<MatT>::PredictBatch(const std::vector<MatT> &imgs)
{
   // Process each image so they match the format
   // expected by the net, then copy the images
   // into the net's input buffers
   PreprocessBatch(imgs);

   // Run a forward pass with the data filled in from above
   net_->ForwardPrefilled();

   /* Copy the output layer to a flat std::vector */
   caffe::Blob<float>* output_layer = net_->output_blobs()[0];
   const float* begin = output_layer->cpu_data();
   const float* end = begin + output_layer->channels()*imgs.size();
   return std::vector<float>(begin, end);
}

// Wrap input layer of the net into separate Mat objects
// This sets them up to be written with actual data
// in PreprocessBatch()
// TODO : handle
template <class MatT>
void CaffeClassifier<MatT>::WrapBatchInputLayer(void)
{
   caffe::Blob<float>* input_layer = net_->input_blobs()[0];

   int width = input_layer->width();
   int height = input_layer->height();
   int num = input_layer->num();
   float* input_data = GetBlobData(input_layer);
   input_batch.clear();
   for ( int j = 0; j < num; j++)
   {
      std::vector<MatT> input_channels;
      for (int i = 0; i < input_layer->channels(); ++i)
      {
	 MatT channel(height, width, CV_32FC1, input_data);
	 input_channels.push_back(channel);
	 input_data += width * height;
      }
      input_batch.push_back(std::vector<MatT>(input_channels));
   }
}

// Slow path for Preprocess - used if the image has to be
// color converted, resized, or resampled to float
template <class MatT>
void CaffeClassifier<MatT>::SlowPreprocess(const MatT &img, MatT &output)
{
   std::cout<< "In slow path " << std::endl;
      /* Convert the input image to the input image format of the network. */
      MatT sample;
      if (img.channels() == 3 && num_channels_ == 1)
	 cvtColor(img, sample, CV_BGR2GRAY);
      else if (img.channels() == 4 && num_channels_ == 1)
	 cvtColor(img, sample, CV_BGRA2GRAY);
      else if (img.channels() == 4 && num_channels_ == 3)
	 cvtColor(img, sample, CV_BGRA2BGR);
      else if (img.channels() == 1 && num_channels_ == 3)
	 cvtColor(img, sample, CV_GRAY2BGR);
      else
	 sample = img;

      MatT sample_resized;
      if (sample.size() != input_geometry_)
	 resize(sample, sample_resized, input_geometry_);
      else
	 sample_resized = sample;

      MatT sample_float;
      if (num_channels_ == 3)
	 sample_resized.convertTo(sample_float, CV_32FC3);
      else
	 sample_resized.convertTo(sample_float, CV_32FC1);

      subtract(sample_float, mean_, output);
}

// Take each image in Mat, convert it to the correct image type,
// color depth, size to match the net input. Convert to
// F32 type, since that's what the net inputs are.
// Subtract out the mean before passing to the net input
// Then actually write the images to the net input memory buffers
template <class MatT>
void CaffeClassifier<MatT>::PreprocessBatch(const std::vector<MatT> &imgs)
{
   for (int i = 0 ; i < imgs.size(); i++)
   {
      if ((imgs[i].channels() != num_channels_) ||
	  (imgs[i].size()     != input_geometry_) ||
	  (num_channels_ == 3) && (imgs[i].type() != CV_32FC3) ||
	  (num_channels_ == 1) && (imgs[i].type() != CV_32FC1))
	 SlowPreprocess(imgs[i], sample_normalized_);
      else
	 subtract(imgs[i], mean_, sample_normalized_);

      /* This operation will write the separate BGR planes directly to the
       * input layer of the network because it is wrapped by the MatT
       * objects in input_channels. */
      std::vector<MatT> *input_channels = &input_batch.at(i);
      split(sample_normalized_, *input_channels);

#if 1
      // TODO : CPU Mats + GPU Caffe fails if this isn't here, no idea why
      if (i ==0 )
              CHECK(reinterpret_cast<float*>(input_channels->at(0).data)
                    == GetBlobData(net_->input_blobs()[0]))
                << "Input channels are not wrapping the input layer of the network.";
#endif
   }
}

// Assorted helper functions
template <class MatT>
size_t CaffeClassifier<MatT>::BatchSize(void) const
{
   return batch_size_;
}

template <class MatT>
cv::Size CaffeClassifier<MatT>::getInputGeometry(void) const
{
   return input_geometry_;
}

template <class MatT>
const MatT CaffeClassifier<MatT>::getMean(void) const
{
   return mean_;
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <> template <>
float *CaffeClassifier<cv::Mat>::GetBlobData(caffe::Blob<float> *blob)
{
   return blob->mutable_cpu_data();
}

template <> template <>
float *CaffeClassifier<cv::gpu::GpuMat>::GetBlobData(caffe::Blob<float> *blob)
{
   return blob->mutable_gpu_data();
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <>
bool CaffeClassifier<cv::Mat>::IsGPU(void) const
{
   return false;
}

template <>
bool CaffeClassifier<cv::gpu::GpuMat>::IsGPU(void) const
{
   return true;
}

template class CaffeClassifier<cv::Mat>;
template class CaffeClassifier<cv::gpu::GpuMat>;
<commit_msg>Remove debugging messages<commit_after>#include <iostream>

#include <opencv2/imgproc/imgproc.hpp>

#include <opencv2/gpu/gpu.hpp>

#include "CaffeBatchPrediction.hpp"

template <class MatT>
CaffeClassifier<MatT>::CaffeClassifier(const std::string& model_file,
      const std::string& trained_file,
      const std::string& mean_file,
      const std::string& label_file,
      const int batch_size) {

   if (IsGPU())
   	caffe::Caffe::set_mode(caffe::Caffe::GPU);
   else
   	caffe::Caffe::set_mode(caffe::Caffe::CPU);

   /* Set batchsize */
   batch_size_ = batch_size;

   /* Load the network - this includes model geometry and trained weights */
   net_.reset(new caffe::Net<float>(model_file, caffe::TEST));
   net_->CopyTrainedLayersFrom(trained_file);

   CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
   CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";

   caffe::Blob<float>* input_layer = net_->input_blobs()[0];
   num_channels_ = input_layer->channels();
   CHECK(num_channels_ == 3 || num_channels_ == 1)
      << "Input layer should have 1 or 3 channels.";
   input_geometry_ = cv::Size(input_layer->width(), input_layer->height());

   /* Load the binaryproto mean file. */
   SetMean(mean_file);

   /* Load labels. */
   // This will be used to give each index of the output
   // a human-readable name
   std::ifstream labels(label_file.c_str());
   CHECK(labels) << "Unable to open labels file " << label_file;
   std::string line;
   while (std::getline(labels, line))
      labels_.push_back(std::string(line));

   caffe::Blob<float>* output_layer = net_->output_blobs()[0];
   CHECK_EQ(labels_.size(), output_layer->channels())
      << "Number of labels is different from the output layer dimension.";

   // Pre-process Mat wrapping
   input_layer->Reshape(batch_size_, num_channels_,
	 input_geometry_.height,
	 input_geometry_.width);

   /* Forward dimension change to all layers. */
   net_->Reshape();

   // The wrap code puts the buffer for one individual channel
   // input to the net (one color channel of one image) into
   // a separate Mat
   // The inner vector here will be one Mat per channel of the
   // input to the net. The outer vector is a vector of those
   // one for each of the batched inputs.
   // This allows an easy copy from the input images
   // into the input buffers for the net
   WrapBatchInputLayer();
   std::cout << "Leaving Constructor" << std::endl;
}

// Helper function for compare - used to sort values by pair.first keys
static bool PairCompare(const std::pair<float, int>& lhs,
			const std::pair<float, int>& rhs)
{
   return lhs.first > rhs.first;
}

/* Return the indices of the top N values of vector v. */
static std::vector<int> Argmax(const std::vector<float>& v, int N)
{
   std::vector<std::pair<float, int> > pairs;
   for (size_t i = 0; i < v.size(); ++i)
      pairs.push_back(std::make_pair(v[i], i));
   std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);

   std::vector<int> result;
   for (size_t i = 0; i < N; ++i)
      result.push_back(pairs[i].second);
   return result;
}

// Given X input images, return X vectors of predictions.
// Each of the X vectors are themselves a vector which will have the
// N predictions with the highest confidences for the corresponding
// input image
template <class MatT>
std::vector< std::vector<Prediction> > CaffeClassifier<MatT>::ClassifyBatch(const std::vector< MatT > &imgs,
                                                                      size_t num_classes)
{
   // output_batch will be a flat vector of N floating point values
   // per image (1 per N output labels), repeated
   // times the number of input images batched per run
   // Convert that into the output vector of vectors
   std::vector<float> output_batch = PredictBatch(imgs);
   std::vector< std::vector<Prediction> > predictions;
   size_t labels_size = labels_.size();
   num_classes = std::min(num_classes, labels_size);

   // For each image, find the top num_classes values
   for(size_t j = 0; j < imgs.size(); j++)
   {
      // Create an output vector just for values for this image. Since
      // each image has labels_size values, that's output_batch[j*labels_size]
      // through output_batch[(j+1) * labels_size]
      std::vector<float> output(output_batch.begin() + j*labels_size, output_batch.begin() + (j+1)*labels_size);
      // For the output specific to the jth image, grab the
      // indexes of the top num_classes predictions
      std::vector<int> maxN = Argmax(output, num_classes);
      // Using those top N indexes, create a set of labels/value predictions
      // specific to this jth image
      std::vector<Prediction> prediction_single;
      for (size_t i = 0; i < num_classes; ++i)
      {
	 int idx = maxN[i];
	 prediction_single.push_back(std::make_pair(labels_[idx], output[idx]));
      }
      // Add the predictions for this image to the list of
      // predictions for all images
      predictions.push_back(std::vector<Prediction>(prediction_single));
   }
   return predictions;
}

/* Load the mean file in binaryproto format. */
template <class MatT>
void CaffeClassifier<MatT>::SetMean(const std::string& mean_file)
{
   caffe::BlobProto blob_proto;
   ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);

   /* Convert from BlobProto to Blob<float> */
   caffe::Blob<float> mean_blob;
   mean_blob.FromProto(blob_proto);
   CHECK_EQ(mean_blob.channels(), num_channels_)
      << "Number of channels of mean file doesn't match input layer.";

   /* The format of the mean file is planar 32-bit float BGR or grayscale. */
   std::vector<cv::Mat> channels;
   float* data = mean_blob.mutable_cpu_data();
   for (int i = 0; i < num_channels_; ++i)
   {
      /* Extract an individual channel. */
      cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);
      channels.push_back(channel);
      data += mean_blob.height() * mean_blob.width();
   }

   /* Merge the separate channels into a single image. */
   cv::Mat mean;
   merge(channels, mean);

   /* Compute the global mean pixel value and create a mean image
    * filled with this value. */
   cv::Scalar channel_mean = cv::mean(mean);

   // Hack to possibly convert to GpuMat - if MatT is GpuMat,
   // this will upload the Mat object to a GpuMat, otherwise
   // it will just copy it to the member variable mean_
   mean_ = MatT(input_geometry_, mean.type(), channel_mean);
}

// TODO : see if we can do this once at startup or if
// it has to be done each pass.  If it can be done once,
// we can wrap the nets in Mat arrays in the constructor
// and re-use them multiple times?
template <class MatT>
void CaffeClassifier<MatT>::setBatchSize(size_t batch_size)
{
   CHECK(batch_size >= 0);
   if (batch_size == batch_size_) return;
   batch_size_ = batch_size;
   reshapeNet();
}

template <class MatT>
void CaffeClassifier<MatT>::reshapeNet()
{
   CHECK(net_->input_blobs().size() == 1);
   caffe::Blob<float>* input_layer = net_->input_blobs()[0];
   input_layer->Reshape(batch_size_, num_channels_,
	 input_geometry_.height,
	 input_geometry_.width);
   net_->Reshape();
   WrapBatchInputLayer();
}

// Get the output values for a set of images in one flat vector
// These values will be in the same order as the labels for each
// image, and each set of labels for an image next adjacent to the
// one for the next image.
// That is, [0] = value for label 0 for the first image up to
// [n] = value for label n for the first image. It then starts again
// for the next image - [n+1] = label 0 for image #2.
template <class MatT>
std::vector<float> CaffeClassifier<MatT>::PredictBatch(const std::vector<MatT> &imgs)
{
   // Process each image so they match the format
   // expected by the net, then copy the images
   // into the net's input buffers
   PreprocessBatch(imgs);

   // Run a forward pass with the data filled in from above
   net_->ForwardPrefilled();

   /* Copy the output layer to a flat std::vector */
   caffe::Blob<float>* output_layer = net_->output_blobs()[0];
   const float* begin = output_layer->cpu_data();
   const float* end = begin + output_layer->channels()*imgs.size();
   return std::vector<float>(begin, end);
}

// Wrap input layer of the net into separate Mat objects
// This sets them up to be written with actual data
// in PreprocessBatch()
// TODO : handle
template <class MatT>
void CaffeClassifier<MatT>::WrapBatchInputLayer(void)
{
   caffe::Blob<float>* input_layer = net_->input_blobs()[0];

   int width = input_layer->width();
   int height = input_layer->height();
   int num = input_layer->num();
   float* input_data = GetBlobData(input_layer);
   input_batch.clear();
   for ( int j = 0; j < num; j++)
   {
      std::vector<MatT> input_channels;
      for (int i = 0; i < input_layer->channels(); ++i)
      {
	 MatT channel(height, width, CV_32FC1, input_data);
	 input_channels.push_back(channel);
	 input_data += width * height;
      }
      input_batch.push_back(std::vector<MatT>(input_channels));
   }
}

// Slow path for Preprocess - used if the image has to be
// color converted, resized, or resampled to float
template <class MatT>
void CaffeClassifier<MatT>::SlowPreprocess(const MatT &img, MatT &output)
{
   std::cout<< "In slow path " << std::endl;
      /* Convert the input image to the input image format of the network. */
      MatT sample;
      if (img.channels() == 3 && num_channels_ == 1)
	 cvtColor(img, sample, CV_BGR2GRAY);
      else if (img.channels() == 4 && num_channels_ == 1)
	 cvtColor(img, sample, CV_BGRA2GRAY);
      else if (img.channels() == 4 && num_channels_ == 3)
	 cvtColor(img, sample, CV_BGRA2BGR);
      else if (img.channels() == 1 && num_channels_ == 3)
	 cvtColor(img, sample, CV_GRAY2BGR);
      else
	 sample = img;

      MatT sample_resized;
      if (sample.size() != input_geometry_)
	 resize(sample, sample_resized, input_geometry_);
      else
	 sample_resized = sample;

      MatT sample_float;
      if (num_channels_ == 3)
	 sample_resized.convertTo(sample_float, CV_32FC3);
      else
	 sample_resized.convertTo(sample_float, CV_32FC1);

      subtract(sample_float, mean_, output);
}

// Take each image in Mat, convert it to the correct image type,
// color depth, size to match the net input. Convert to
// F32 type, since that's what the net inputs are.
// Subtract out the mean before passing to the net input
// Then actually write the images to the net input memory buffers
template <class MatT>
void CaffeClassifier<MatT>::PreprocessBatch(const std::vector<MatT> &imgs)
{
   for (int i = 0 ; i < imgs.size(); i++)
   {
      if ((imgs[i].channels() != num_channels_) ||
	  (imgs[i].size()     != input_geometry_) ||
	  (num_channels_ == 3) && (imgs[i].type() != CV_32FC3) ||
	  (num_channels_ == 1) && (imgs[i].type() != CV_32FC1))
	 SlowPreprocess(imgs[i], sample_normalized_);
      else
	 subtract(imgs[i], mean_, sample_normalized_);

      /* This operation will write the separate BGR planes directly to the
       * input layer of the network because it is wrapped by the MatT
       * objects in input_channels. */
      std::vector<MatT> *input_channels = &input_batch.at(i);
      split(sample_normalized_, *input_channels);

#if 1
      // TODO : CPU Mats + GPU Caffe fails if this isn't here, no idea why
      if (i ==0 )
              CHECK(reinterpret_cast<float*>(input_channels->at(0).data)
                    == GetBlobData(net_->input_blobs()[0]))
                << "Input channels are not wrapping the input layer of the network.";
#endif
   }
}

// Assorted helper functions
template <class MatT>
size_t CaffeClassifier<MatT>::BatchSize(void) const
{
   return batch_size_;
}

template <class MatT>
cv::Size CaffeClassifier<MatT>::getInputGeometry(void) const
{
   return input_geometry_;
}

template <class MatT>
const MatT CaffeClassifier<MatT>::getMean(void) const
{
   return mean_;
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <> template <>
float *CaffeClassifier<cv::Mat>::GetBlobData(caffe::Blob<float> *blob)
{
   return blob->mutable_cpu_data();
}

template <> template <>
float *CaffeClassifier<cv::gpu::GpuMat>::GetBlobData(caffe::Blob<float> *blob)
{
   return blob->mutable_gpu_data();
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <>
bool CaffeClassifier<cv::Mat>::IsGPU(void) const
{
   return false;
}

template <>
bool CaffeClassifier<cv::gpu::GpuMat>::IsGPU(void) const
{
   return true;
}

template class CaffeClassifier<cv::Mat>;
template class CaffeClassifier<cv::gpu::GpuMat>;
<|endoftext|>


<commit_before>/*
 * tests.cpp
 *
 *  Created on: Jul 6, 2017
 *      Author: blroot
 */

#include <gtest/gtest.h>
#include "vec3.h"

using namespace math;

TEST(Vec3Test, NullVec) {
	vec3 v = vec3();

    ASSERT_EQ(v.x, 0.0f);
    ASSERT_EQ(v.y, 0.0f);
    ASSERT_EQ(v.z, 0.0f);
}

TEST(Vec3Test, UnitVecCreation) {
	vec3 v = vec3(1.0f, 1.0f, 1.0f);

    ASSERT_EQ(v.x, 1.0f);
    ASSERT_EQ(v.y, 1.0f);
    ASSERT_EQ(v.z, 1.0f);
}

TEST(Vec3Test, Add) {
	vec3 v = vec3(1.0f, 6.0f, 1.0f);
	vec3 w = vec3(5.0f, 1.0f, 0.0f);

	vec3 u = v + w;

	ASSERT_EQ(u.x, 6.0f);
	ASSERT_EQ(u.y, 7.0f);
	ASSERT_EQ(u.z, 1.0f);
}

TEST(Vec3Test, Substract) {
	vec3 v = vec3(1.0f, 6.0f, 1.0f);
	vec3 w = vec3(5.0f, 1.0f, 0.0f);

	vec3 u = v - w;

	ASSERT_EQ(u.x, -4.0f);
	ASSERT_EQ(u.y, 5.0f);
	ASSERT_EQ(u.z, 1.0f);
}

TEST(Vec3Test, ByScalarProduct) {
	vec3 v = vec3(1.0f, 6.0f, 2.0f);

	vec3 u = 5*v;

	ASSERT_EQ(u.x, 5.0f);
	ASSERT_EQ(u.y, 30.0f);
	ASSERT_EQ(u.z, 10.0f);
}

TEST(Vec3Test, Normalize) {
	vec3 v = vec3(5.0f, 3.0f, 2.0f);
	vec3 versor_v = v.normalize();

    ASSERT_FLOAT_EQ(versor_v.x, 0.8111071);
    ASSERT_FLOAT_EQ(versor_v.y, 0.48666427);
    ASSERT_FLOAT_EQ(versor_v.z, 0.32444283);
}

TEST(Vec3Test, Cross) {
	vec3 v = vec3(1.0f, 0.0f, 0.0f);
	vec3 w = vec3(0.0f, 1.0f, 0.0f);

	vec3 u = v.cross(w);

	ASSERT_EQ(u.x, 0.0f);
	ASSERT_EQ(u.y, 0.0f);
	ASSERT_EQ(u.z, 1.0f);
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>test name fixed<commit_after>/*
 * tests.cpp
 *
 *  Created on: Jul 6, 2017
 *      Author: blroot
 */

#include <gtest/gtest.h>
#include "vec3.h"

using namespace math;

TEST(Vec3Test, NullVec) {
	vec3 v = vec3();

    ASSERT_EQ(v.x, 0.0f);
    ASSERT_EQ(v.y, 0.0f);
    ASSERT_EQ(v.z, 0.0f);
}

TEST(Vec3Test, UnitVecCreation) {
	vec3 v = vec3(1.0f, 1.0f, 1.0f);

    ASSERT_EQ(v.x, 1.0f);
    ASSERT_EQ(v.y, 1.0f);
    ASSERT_EQ(v.z, 1.0f);
}

TEST(Vec3Test, Add) {
	vec3 v = vec3(1.0f, 6.0f, 1.0f);
	vec3 w = vec3(5.0f, 1.0f, 0.0f);

	vec3 u = v + w;

	ASSERT_EQ(u.x, 6.0f);
	ASSERT_EQ(u.y, 7.0f);
	ASSERT_EQ(u.z, 1.0f);
}

TEST(Vec3Test, Substract) {
	vec3 v = vec3(1.0f, 6.0f, 1.0f);
	vec3 w = vec3(5.0f, 1.0f, 0.0f);

	vec3 u = v - w;

	ASSERT_EQ(u.x, -4.0f);
	ASSERT_EQ(u.y, 5.0f);
	ASSERT_EQ(u.z, 1.0f);
}

TEST(Vec3Test, ScalarMultiplication) {
	vec3 v = vec3(1.0f, 6.0f, 2.0f);

	vec3 u = 5*v;

	ASSERT_EQ(u.x, 5.0f);
	ASSERT_EQ(u.y, 30.0f);
	ASSERT_EQ(u.z, 10.0f);
}

TEST(Vec3Test, Normalize) {
	vec3 v = vec3(5.0f, 3.0f, 2.0f);
	vec3 versor_v = v.normalize();

    ASSERT_FLOAT_EQ(versor_v.x, 0.8111071);
    ASSERT_FLOAT_EQ(versor_v.y, 0.48666427);
    ASSERT_FLOAT_EQ(versor_v.z, 0.32444283);
}

TEST(Vec3Test, Cross) {
	vec3 v = vec3(1.0f, 0.0f, 0.0f);
	vec3 w = vec3(0.0f, 1.0f, 0.0f);

	vec3 u = v.cross(w);

	ASSERT_EQ(u.x, 0.0f);
	ASSERT_EQ(u.y, 0.0f);
	ASSERT_EQ(u.z, 1.0f);
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "interface/VideoCommonDefs.h"
#include "VaapiUtils.h"

namespace YamiMediaCodec {

uint8_t* mapSurfaceToImage(VADisplay display, intptr_t surface, VAImage& image)
{
    uint8_t* p = NULL;
    VAStatus status = vaDeriveImage(display, (VASurfaceID)surface, &image);
    if (!checkVaapiStatus(status, "vaDeriveImage"))
        return NULL;
    status = vaMapBuffer(display, image.buf, (void**)&p);
    if (!checkVaapiStatus(status, "vaMapBuffer")) {
        checkVaapiStatus(vaDestroyImage(display, image.image_id), "vaDestroyImage");
        return NULL;
    }
    return p;
}

void unmapImage(VADisplay display, const VAImage& image)
{
    checkVaapiStatus(vaUnmapBuffer(display, image.buf), "vaUnmapBuffer");
    checkVaapiStatus(vaDestroyImage(display, image.image_id), "vaDestroyImage");
}

//return rt format, 0 for unsupported
uint32_t getRtFormat(uint32_t fourcc)
{
    switch (fourcc) {
    case YAMI_FOURCC_NV12:
    case YAMI_FOURCC_I420:
    case YAMI_FOURCC_YV12:
    case YAMI_FOURCC_IMC3:
        return VA_RT_FORMAT_YUV420;
    case YAMI_FOURCC_422H:
    case YAMI_FOURCC_422V:
    case YAMI_FOURCC_YUY2:
        return VA_RT_FORMAT_YUV422;
    case YAMI_FOURCC_444P:
        return VA_RT_FORMAT_YUV444;
    case YAMI_FOURCC_RGBX:
    case YAMI_FOURCC_RGBA:
    case YAMI_FOURCC_BGRX:
    case YAMI_FOURCC_BGRA:
        return VA_RT_FORMAT_RGB32;
    }
    ERROR("get rt format for %.4s failed", (char*)&fourcc);
    return 0;
}
}
<commit_msg>vaapi: support P010 in getRtFormat<commit_after>/*
 * Copyright 2016 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "interface/VideoCommonDefs.h"
#include "VaapiUtils.h"

namespace YamiMediaCodec {

uint8_t* mapSurfaceToImage(VADisplay display, intptr_t surface, VAImage& image)
{
    uint8_t* p = NULL;
    VAStatus status = vaDeriveImage(display, (VASurfaceID)surface, &image);
    if (!checkVaapiStatus(status, "vaDeriveImage"))
        return NULL;
    status = vaMapBuffer(display, image.buf, (void**)&p);
    if (!checkVaapiStatus(status, "vaMapBuffer")) {
        checkVaapiStatus(vaDestroyImage(display, image.image_id), "vaDestroyImage");
        return NULL;
    }
    return p;
}

void unmapImage(VADisplay display, const VAImage& image)
{
    checkVaapiStatus(vaUnmapBuffer(display, image.buf), "vaUnmapBuffer");
    checkVaapiStatus(vaDestroyImage(display, image.image_id), "vaDestroyImage");
}

//return rt format, 0 for unsupported
uint32_t getRtFormat(uint32_t fourcc)
{
    switch (fourcc) {
    case YAMI_FOURCC_NV12:
    case YAMI_FOURCC_I420:
    case YAMI_FOURCC_YV12:
    case YAMI_FOURCC_IMC3:
        return VA_RT_FORMAT_YUV420;
    case YAMI_FOURCC_422H:
    case YAMI_FOURCC_422V:
    case YAMI_FOURCC_YUY2:
        return VA_RT_FORMAT_YUV422;
    case YAMI_FOURCC_444P:
        return VA_RT_FORMAT_YUV444;
#if VA_CHECK_VERSION(0, 38, 1)
    case YAMI_FOURCC_P010:
        return VA_RT_FORMAT_YUV420_10BPP;
#endif
    case YAMI_FOURCC_RGBX:
    case YAMI_FOURCC_RGBA:
    case YAMI_FOURCC_BGRX:
    case YAMI_FOURCC_BGRA:
        return VA_RT_FORMAT_RGB32;
    }
    ERROR("get rt format for %.4s failed", (char*)&fourcc);
    return 0;
}
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/visualization/software-license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <cassert>
#include <cstdlib>

#include "SamplerCSVWriter.h"
#include "Sample.h"
#include "Sampler.h"
#include "Model.h"

namespace madai {

int SamplerCSVWriter
::GenerateSamplesAndSaveToFile(
    Sampler & sampler,
    Model & model,
    std::ostream & outFile,
    int NumberOfSamples,
    int NumberOfBurnInSamples,
    bool UseEmulatorCovariance,
    bool WriteLogLikelihoodGradients,
    std::ostream * progress)
{
  model.SetUseModelCovarianceToCalulateLogLikelihood(UseEmulatorCovariance);
  sampler.SetModel( &model );
  int step = NumberOfBurnInSamples / 100, percent = 0;
  if ( step < 1 ) {
    step = 1; // avoid div-by-zero error
  }
  for ( int count = 0; count < NumberOfBurnInSamples; count++ ) {
    if (progress != NULL) {
      if ( count % step == 0 ) {
        (*progress) << '\r' << "Burn in percent done: " << percent++ << "%  ";
        progress->flush();
      }
    }
    sampler.NextSample(); // Discard samples in the burn-in phase
  }
  step = NumberOfSamples / 100, percent = 0;
  if ( step < 1 ) {
    step = 1; // avoid div-by-zero error
  }

  WriteHeader( outFile, model.GetParameters(), model.GetScalarOutputNames(),
               WriteLogLikelihoodGradients);

  for (int count = 0; count < NumberOfSamples; count ++) {
    if (progress != NULL) {
      if (count % step == 0)
        (*progress) <<  '\r' << "Sampler percent done: " << percent++ << "%  ";
      progress->flush();
    }
    Sample sample = sampler.NextSample();

    WriteSample( outFile, sample, WriteLogLikelihoodGradients );
  }
  if (progress != NULL) {
    (*progress) << "\r                            \r";
    progress->flush();
  }

  return EXIT_SUCCESS;
}

void
SamplerCSVWriter
::WriteHeader( std::ostream & o,
               const std::vector< Parameter > & params,
               const std::vector< std::string > & outputs,
               bool WriteLogLikelihoodGradients)
{
  if ( !params.empty() ) {
    std::vector< Parameter >::const_iterator itr = params.begin();
    o << '"' << itr->m_Name << '"';
    for ( itr++; itr < params.end(); itr++ ) {
      o << ',' << '"' << itr->m_Name << '"';
    }
    if ( !outputs.empty() ) {
      o << ',';
    }
  }
  if ( !outputs.empty() ) {
    std::vector<std::string>::const_iterator itr = outputs.begin();
    //std::cout << "Output name: " << *itr << std::endl;
    o << '"' << *itr << '"';
    for ( itr++; itr < outputs.end(); itr++ ) {
      o << ',' << '"' << *itr << '"';
    }
  }
  o << ",\"LogLikelihood\"";
  if( WriteLogLikelihoodGradients ) {
    if ( !outputs.empty() ) {
      for ( std::vector<std::string>::const_iterator itr = outputs.begin();
            itr < outputs.end(); itr++ )
      {
        o << ',' << "\"" << *itr << "*dLL/dsigma_" << *itr << '"';
      }
    }
  }
  o << "\n";
}

/** Utility for writing a vector to an output stream
 *
 * The vector elements are delimited by the given delimiter */
template <class T>
void write_vector( std::ostream& o, std::vector< T > const & v, char delim ) {
  if ( !v.empty() ) {
    typename std::vector< T >::const_iterator itr = v.begin();
    o << *(itr++);
    while ( itr < v.end() ) {
      o << delim << *(itr++);
    }
  }
}

void
SamplerCSVWriter
::WriteSample( std::ostream & out, const Sample & sample,
            bool WriteLogLikelihoodGradients)
{
  write_vector( out, sample.m_ParameterValues, ',' );
  out << ',';

  if ( sample.m_OutputValues.size() > 0 ) {
    write_vector( out, sample.m_OutputValues, ',' );
    out << ',';
  }
  out << sample.m_LogLikelihood;
  if( WriteLogLikelihoodGradients ) {
    if ( sample.m_OutputValues.size() > 0 ) {
      out << ',';
      write_vector( out, sample.m_LikelihoodErrorGradient, ',' );
    }
  }
  if ( sample.m_Comments.size() > 0 ) {
    out << ",\"";
    write_vector( out, sample.m_Comments, ';' );
    out << '"';
  }
  out << '\n';

  out.flush();
}

} // end namespace madai
<commit_msg>Updated the csv writer to use the new sample member names.<commit_after>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/visualization/software-license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <cassert>
#include <cstdlib>

#include "SamplerCSVWriter.h"
#include "Sample.h"
#include "Sampler.h"
#include "Model.h"

namespace madai {

int SamplerCSVWriter
::GenerateSamplesAndSaveToFile(
    Sampler & sampler,
    Model & model,
    std::ostream & outFile,
    int NumberOfSamples,
    int NumberOfBurnInSamples,
    bool UseEmulatorCovariance,
    bool WriteLogLikelihoodGradients,
    std::ostream * progress)
{
  model.SetUseModelCovarianceToCalulateLogLikelihood(UseEmulatorCovariance);
  sampler.SetModel( &model );
  int step = NumberOfBurnInSamples / 100, percent = 0;
  if ( step < 1 ) {
    step = 1; // avoid div-by-zero error
  }
  for ( int count = 0; count < NumberOfBurnInSamples; count++ ) {
    if (progress != NULL) {
      if ( count % step == 0 ) {
        (*progress) << '\r' << "Burn in percent done: " << percent++ << "%  ";
        progress->flush();
      }
    }
    sampler.NextSample(); // Discard samples in the burn-in phase
  }
  step = NumberOfSamples / 100, percent = 0;
  if ( step < 1 ) {
    step = 1; // avoid div-by-zero error
  }

  WriteHeader( outFile, model.GetParameters(), model.GetScalarOutputNames(),
               WriteLogLikelihoodGradients);

  for (int count = 0; count < NumberOfSamples; count ++) {
    if (progress != NULL) {
      if (count % step == 0)
        (*progress) <<  '\r' << "Sampler percent done: " << percent++ << "%  ";
      progress->flush();
    }
    Sample sample = sampler.NextSample();

    WriteSample( outFile, sample, WriteLogLikelihoodGradients );
  }
  if (progress != NULL) {
    (*progress) << "\r                            \r";
    progress->flush();
  }

  return EXIT_SUCCESS;
}

void
SamplerCSVWriter
::WriteHeader( std::ostream & o,
               const std::vector< Parameter > & params,
               const std::vector< std::string > & outputs,
               bool WriteLogLikelihoodGradients)
{
  if ( !params.empty() ) {
    std::vector< Parameter >::const_iterator itr = params.begin();
    o << '"' << itr->m_Name << '"';
    for ( itr++; itr < params.end(); itr++ ) {
      o << ',' << '"' << itr->m_Name << '"';
    }
    if ( !outputs.empty() ) {
      o << ',';
    }
  }
  if ( !outputs.empty() ) {
    std::vector<std::string>::const_iterator itr = outputs.begin();
    //std::cout << "Output name: " << *itr << std::endl;
    o << '"' << *itr << '"';
    for ( itr++; itr < outputs.end(); itr++ ) {
      o << ',' << '"' << *itr << '"';
    }
  }
  o << ",\"LogLikelihood\"";
  if( WriteLogLikelihoodGradients ) {
    if ( !outputs.empty() ) {
      for ( std::vector<std::string>::const_iterator itr = outputs.begin();
            itr < outputs.end(); itr++ )
      {
        o << ',' << "\"" << *itr << "*dLL/dsigma_" << *itr << '"';
      }
    }
  }
  o << "\n";
}

/** Utility for writing a vector to an output stream
 *
 * The vector elements are delimited by the given delimiter */
template <class T>
void write_vector( std::ostream& o, std::vector< T > const & v, char delim ) {
  if ( !v.empty() ) {
    typename std::vector< T >::const_iterator itr = v.begin();
    o << *(itr++);
    while ( itr < v.end() ) {
      o << delim << *(itr++);
    }
  }
}

void
SamplerCSVWriter
::WriteSample( std::ostream & out, const Sample & sample,
            bool WriteLogLikelihoodGradients)
{
  write_vector( out, sample.m_ParameterValues, ',' );
  out << ',';

  if ( sample.m_OutputValues.size() > 0 ) {
    write_vector( out, sample.m_OutputValues, ',' );
    out << ',';
  }
  out << sample.m_LogLikelihood;
  if( WriteLogLikelihoodGradients ) {
    if ( sample.m_OutputValues.size() > 0 ) {
      out << ',';
      write_vector( out, sample.m_LogLikelihoodErrorGradient, ',' );
    }
  }
  if ( sample.m_Comments.size() > 0 ) {
    out << ",\"";
    write_vector( out, sample.m_Comments, ';' );
    out << '"';
  }
  out << '\n';

  out.flush();
}

} // end namespace madai
<|endoftext|>


<commit_before><commit_msg>update<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(HOST_OS_WINDOWS)

#include "vm/virtual_memory.h"

#include "platform/assert.h"
#include "vm/os.h"

#include "vm/isolate.h"

namespace dart {

uword VirtualMemory::page_size_ = 0;

void VirtualMemory::InitOnce() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  page_size_ = info.dwPageSize;
}

VirtualMemory* VirtualMemory::Allocate(intptr_t size,
                                       bool is_executable,
                                       const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, prot);
  if (address == NULL) {
    return NULL;
  }
  MemoryRegion region(address, size);
  return new VirtualMemory(region, region);
}

VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
                                              intptr_t alignment,
                                              bool is_executable,
                                              const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  ASSERT(Utils::IsAligned(alignment, page_size_));
  intptr_t reserved_size = size + alignment;
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, reserved_size, MEM_RESERVE, prot);
  if (address == NULL) {
    return NULL;
  }

  void* aligned_address = reinterpret_cast<void*>(
      Utils::RoundUp(reinterpret_cast<uword>(address), alignment));
  if (VirtualAlloc(aligned_address, size, MEM_COMMIT, prot) !=
      aligned_address) {
    VirtualFree(address, reserved_size, MEM_RELEASE);
    return NULL;
  }

  MemoryRegion region(aligned_address, size);
  MemoryRegion reserved(address, reserved_size);
  return new VirtualMemory(region, reserved);
}

VirtualMemory::~VirtualMemory() {
  if (!vm_owns_region() || (reserved_.size() == 0)) {
    return;
  }
  if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
    FATAL("VirtualFree failed");
  }
}

bool VirtualMemory::FreeSubSegment(void* address,
                                   intptr_t size) {
  // On Windows only the entire segment returned by VirtualAlloc
  // can be freed. Therefore we will have to waste these unused
  // virtual memory sub-segments.
  return false;
}

void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
  ASSERT(Thread::Current()->IsMutatorThread() ||
         Isolate::Current()->mutator_thread()->IsAtSafepoint());
  uword start_address = reinterpret_cast<uword>(address);
  uword end_address = start_address + size;
  uword page_address = Utils::RoundDown(start_address, PageSize());
  DWORD prot = 0;
  switch (mode) {
    case kNoAccess:
      prot = PAGE_NOACCESS;
      break;
    case kReadOnly:
      prot = PAGE_READONLY;
      break;
    case kReadWrite:
      prot = PAGE_READWRITE;
      break;
    case kReadExecute:
      prot = PAGE_EXECUTE_READ;
      break;
    case kReadWriteExecute:
      prot = PAGE_EXECUTE_READWRITE;
      break;
  }
  DWORD old_prot = 0;
  if (VirtualProtect(reinterpret_cast<void*>(page_address),
                     end_address - page_address, prot, &old_prot) == 0) {
    FATAL1("VirtualProtect failed %d\n", GetLastError());
  }
}

}  // namespace dart

#endif  // defined(HOST_OS_WINDOWS)
<commit_msg>[vm][windows] Implement VirtualMemory::FreeSubSegment<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(HOST_OS_WINDOWS)

#include "vm/virtual_memory.h"

#include "platform/assert.h"
#include "vm/os.h"

#include "vm/isolate.h"

namespace dart {

uword VirtualMemory::page_size_ = 0;

void VirtualMemory::InitOnce() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  page_size_ = info.dwPageSize;
}

VirtualMemory* VirtualMemory::Allocate(intptr_t size,
                                       bool is_executable,
                                       const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, prot);
  if (address == NULL) {
    return NULL;
  }
  MemoryRegion region(address, size);
  return new VirtualMemory(region, region);
}

VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
                                              intptr_t alignment,
                                              bool is_executable,
                                              const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  ASSERT(Utils::IsAligned(alignment, page_size_));
  intptr_t reserved_size = size + alignment;
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, reserved_size, MEM_RESERVE, prot);
  if (address == NULL) {
    return NULL;
  }

  void* aligned_address = reinterpret_cast<void*>(
      Utils::RoundUp(reinterpret_cast<uword>(address), alignment));
  if (VirtualAlloc(aligned_address, size, MEM_COMMIT, prot) !=
      aligned_address) {
    VirtualFree(address, reserved_size, MEM_RELEASE);
    return NULL;
  }

  MemoryRegion region(aligned_address, size);
  MemoryRegion reserved(address, reserved_size);
  return new VirtualMemory(region, reserved);
}

VirtualMemory::~VirtualMemory() {
  // Note that the size of the reserved region might be set to 0 by
  // Truncate(0, true) but that does not actually release the mapping
  // itself. The only way to release the mapping is to invoke VirtualFree
  // with original base pointer and MEM_RELEASE.
  if (!vm_owns_region()) {
    return;
  }
  if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
    FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
  }
}

bool VirtualMemory::FreeSubSegment(void* address,
                                   intptr_t size) {
  if (VirtualFree(address, size, MEM_DECOMMIT) == 0) {
    FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
  }
  return true;
}

void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
  ASSERT(Thread::Current()->IsMutatorThread() ||
         Isolate::Current()->mutator_thread()->IsAtSafepoint());
  uword start_address = reinterpret_cast<uword>(address);
  uword end_address = start_address + size;
  uword page_address = Utils::RoundDown(start_address, PageSize());
  DWORD prot = 0;
  switch (mode) {
    case kNoAccess:
      prot = PAGE_NOACCESS;
      break;
    case kReadOnly:
      prot = PAGE_READONLY;
      break;
    case kReadWrite:
      prot = PAGE_READWRITE;
      break;
    case kReadExecute:
      prot = PAGE_EXECUTE_READ;
      break;
    case kReadWriteExecute:
      prot = PAGE_EXECUTE_READWRITE;
      break;
  }
  DWORD old_prot = 0;
  if (VirtualProtect(reinterpret_cast<void*>(page_address),
                     end_address - page_address, prot, &old_prot) == 0) {
    FATAL1("VirtualProtect failed %d\n", GetLastError());
  }
}

}  // namespace dart

#endif  // defined(HOST_OS_WINDOWS)
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006  Brad Hards <bradh@frogmouth.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "pk11func.h"
#include "nss.h"

#include <QtCrypto>
#include <QtCore>

#include <qstringlist.h>

//-----------------------------------------------------------
class nssHashContext : public QCA::HashContext
{
public:
    nssHashContext( QCA::Provider *p, const QString &type) : QCA::HashContext(p, type)
    {
	SECStatus s;

	NSS_NoDB_Init(".");

	m_status = 0;

	/* Get a slot to use for the crypto operations */
	m_slot = PK11_GetInternalKeySlot();
	if (!m_slot)
	{
	    qDebug() << "GetInternalKeySlot failed";
	    m_status = 1;
	    return;
	}

	if ( QString("md2") == type ) {
	    m_hashAlgo = SEC_OID_MD2;
	}
	else if ( QString("md5") == type ) {
	    m_hashAlgo = SEC_OID_MD5;
	}
	else if ( QString("sha1") == type ) {
	    m_hashAlgo = SEC_OID_SHA1;
	}
	else if ( QString("sha256") == type ) {
	    m_hashAlgo = SEC_OID_SHA256;
	}
	else if ( QString("sha384") == type ) {
	    m_hashAlgo = SEC_OID_SHA384;
	}
	else if ( QString("sha512") == type ) {
	    m_hashAlgo = SEC_OID_SHA512;
	} else {
	    qDebug() << "Unknown provider type: " << type;
	    return; /* this will probably cause a segfault... */
	}

	m_context = PK11_CreateDigestContext(m_hashAlgo);
	if (! m_context) {
	    qDebug() << "CreateDigestContext failed";
	    return;
	}

	s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    ~nssHashContext()
    {
	PK11_DestroyContext(m_context, PR_TRUE);
	if (m_slot)
	    PK11_FreeSlot(m_slot);
    }

    Context *clone() const
    {
	return new nssHashContext(*this);
    }

    void clear()
    {
	SECStatus s;

	PK11_DestroyContext(m_context, PR_TRUE);

	m_context = PK11_CreateDigestContext(m_hashAlgo);
	if (! m_context) {
	    qDebug() << "CreateDigestContext failed";
	    return;
	}

	s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    void update(const QSecureArray &a)
    {
	PK11_DigestOp(m_context, (const unsigned char*)a.data(), a.size());
    }

    QSecureArray final()
    {
	unsigned int len = 0;
	QSecureArray a( 64 );
	PK11_DigestFinal(m_context, (unsigned char*)a.data(), &len, a.size());
	a.resize(len);
	return a;
    }

private:
    PK11SlotInfo *m_slot;
    int m_status;
    PK11Context *m_context;
    SECOidTag m_hashAlgo;
};

//==========================================================
class nssProvider : public QCA::Provider
{
public:
    void init()
    {
    }

    ~nssProvider()
    {
    }

    QString name() const
    {
	return "qca-nss";
    }

    QStringList features() const
    {
	QStringList list;
	list += "md2";
	list += "md5";
	list += "sha1";
	list += "sha256";
	list += "sha384";
	list += "sha512";
	return list;
    }

    Context *createContext(const QString &type)
    {
	if ( type == "md2" )
	    return new nssHashContext( this, type );
	if ( type == "md5" )
	    return new nssHashContext( this, type );
	if ( type == "sha1" )
	    return new nssHashContext( this, type );
	if ( type == "sha256" )
	    return new nssHashContext( this, type );
	if ( type == "sha384" )
	    return new nssHashContext( this, type );
	if ( type == "sha512" )
	    return new nssHashContext( this, type );
	else
	    return 0;
    }
private:

};

class nssPlugin : public QCAPlugin
{
	Q_OBJECT
	Q_INTERFACES( QCAPlugin )
public:
	virtual QCA::Provider *createProvider() { return new nssProvider; }
};

#include "qca-nss.moc"

Q_EXPORT_PLUGIN2(qca-nss, nssPlugin);

<commit_msg>Add HMAC support for the NSS provider.<commit_after>/*
 * Copyright (C) 2006  Brad Hards <bradh@frogmouth.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#include "pk11func.h"
#include "nss.h"
#include "hasht.h"

#include <QtCrypto>
#include <QtCore>

#include <qstringlist.h>

//-----------------------------------------------------------
class nssHashContext : public QCA::HashContext
{
public:
    nssHashContext( QCA::Provider *p, const QString &type) : QCA::HashContext(p, type)
    {
	SECStatus s;

	NSS_NoDB_Init(".");

	m_status = 0;

	/* Get a slot to use for the crypto operations */
	m_slot = PK11_GetInternalKeySlot();
	if (!m_slot)
	{
	    qDebug() << "GetInternalKeySlot failed";
	    m_status = 1;
	    return;
	}

	if ( QString("md2") == type ) {
	    m_hashAlgo = SEC_OID_MD2;
	}
	else if ( QString("md5") == type ) {
	    m_hashAlgo = SEC_OID_MD5;
	}
	else if ( QString("sha1") == type ) {
	    m_hashAlgo = SEC_OID_SHA1;
	}
	else if ( QString("sha256") == type ) {
	    m_hashAlgo = SEC_OID_SHA256;
	}
	else if ( QString("sha384") == type ) {
	    m_hashAlgo = SEC_OID_SHA384;
	}
	else if ( QString("sha512") == type ) {
	    m_hashAlgo = SEC_OID_SHA512;
	} else {
	    qDebug() << "Unknown provider type: " << type;
	    return; /* this will probably cause a segfault... */
	}

	m_context = PK11_CreateDigestContext(m_hashAlgo);
	if (! m_context) {
	    qDebug() << "CreateDigestContext failed";
	    return;
	}

	s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    ~nssHashContext()
    {
	PK11_DestroyContext(m_context, PR_TRUE);
	if (m_slot)
	    PK11_FreeSlot(m_slot);
    }

    Context *clone() const
    {
	return new nssHashContext(*this);
    }

    void clear()
    {
	SECStatus s;

	PK11_DestroyContext(m_context, PR_TRUE);

	m_context = PK11_CreateDigestContext(m_hashAlgo);
	if (! m_context) {
	    qDebug() << "CreateDigestContext failed";
	    return;
	}

	s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    void update(const QSecureArray &a)
    {
	PK11_DigestOp(m_context, (const unsigned char*)a.data(), a.size());
    }

    QSecureArray final()
    {
	unsigned int len = 0;
	QSecureArray a( 64 );
	PK11_DigestFinal(m_context, (unsigned char*)a.data(), &len, a.size());
	a.resize(len);
	return a;
    }

private:
    PK11SlotInfo *m_slot;
    int m_status;
    PK11Context *m_context;
    SECOidTag m_hashAlgo;
};

//-----------------------------------------------------------
class nssHmacContext : public QCA::MACContext
{
public:
    nssHmacContext( QCA::Provider *p, const QString &type) : QCA::MACContext(p, type)
    {
	NSS_NoDB_Init(".");

	m_status = 0;

	/* Get a slot to use for the crypto operations */
	m_slot = PK11_GetInternalKeySlot();
	if (!m_slot)
	{
	    qDebug() << "GetInternalKeySlot failed";
	    m_status = 1;
	    return;
	}

	if ( QString("hmac(md5)") == type ) {
	    m_macAlgo = CKM_MD5_HMAC;
	}
	else if ( QString("hmac(sha1)") == type ) {
	    m_macAlgo = CKM_SHA_1_HMAC;
	}
	else if ( QString("hmac(sha256)") == type ) {
	    m_macAlgo = CKM_SHA256_HMAC;
	}
	else if ( QString("hmac(sha384)") == type ) {
	    m_macAlgo = CKM_SHA384_HMAC;
	}
	else if ( QString("hmac(sha512)") == type ) {
	    m_macAlgo = CKM_SHA512_HMAC;
	}
	else if ( QString("hmac(ripemd160)") == type ) {
	    m_macAlgo = CKM_RIPEMD160_HMAC;
	}
	else {
	    qDebug() << "Unknown provider type: " << type;
	    return; /* this will probably cause a segfault... */
	}
    }

    ~nssHmacContext()
    {
	PK11_DestroyContext(m_context, PR_TRUE);
	if (m_slot)
	    PK11_FreeSlot(m_slot);
    }

    Context *clone() const
    {
	return new nssHmacContext(*this);
    }

    void clear()
    {
	PK11_DestroyContext(m_context, PR_TRUE);

	SECItem noParams;
	noParams.data = 0;
	noParams.len = 0;

	m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams);
	if (! m_context) {
	    qDebug() << "CreateContextBySymKey failed";
	    return;
	}

	SECStatus s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    QCA::KeyLength keyLength() const
    {
        return anyKeyLength();
    }

    void setup(const QCA::SymmetricKey &key)
    {
        /* turn the raw key into a SECItem */
        SECItem keyItem;
	keyItem.data = (unsigned char*) key.data();
	keyItem.len = key.size();

	m_nssKey = PK11_ImportSymKey(m_slot, m_macAlgo, PK11_OriginUnwrap, CKA_SIGN, &keyItem, NULL);

	SECItem noParams;
	noParams.data = 0;
	noParams.len = 0;

	m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams);
	if (! m_context) {
	    qDebug() << "CreateContextBySymKey failed";
	    return;
	}

	SECStatus s = PK11_DigestBegin(m_context);
	if (s != SECSuccess) {
	    qDebug() << "DigestBegin failed";
	    return;
	}
    }

    void update(const QSecureArray &a)
    {
	PK11_DigestOp(m_context, (const unsigned char*)a.data(), a.size());
    }

    void final( QSecureArray *out)
    {
	// NSS doesn't appear to be able to tell us how big the digest will
	// be for a given algorithm until after we finalise it, so we work
	// around the problem a bit.
	out->resize( HASH_LENGTH_MAX ); // assume the biggest hash size we know
	unsigned int len = 0;
	PK11_DigestFinal(m_context, (unsigned char*)out->data(), &len, out->size());
	out->resize(len); // and fix it up later
    }

private:
    PK11SlotInfo *m_slot;
    int m_status;
    PK11Context *m_context;
    CK_MECHANISM_TYPE m_macAlgo;
    PK11SymKey* m_nssKey;
};

//==========================================================
class nssProvider : public QCA::Provider
{
public:
    void init()
    {
    }

    ~nssProvider()
    {
    }

    QString name() const
    {
	return "qca-nss";
    }

    QStringList features() const
    {
	QStringList list;

	list += "md2";
	list += "md5";
	list += "sha1";
	list += "sha256";
	list += "sha384";
	list += "sha512";

	list += "hmac(md5)";
	list += "hmac(sha1)";
	list += "hmac(sha256)";
	list += "hmac(sha384)";
	list += "hmac(sha512)";
	// appears to not be implemented in NSS
	// list += "hmac(ripemd160)";
	return list;
    }

    Context *createContext(const QString &type)
    {
	if ( type == "md2" )
	    return new nssHashContext( this, type );
	if ( type == "md5" )
	    return new nssHashContext( this, type );
	if ( type == "sha1" )
	    return new nssHashContext( this, type );
	if ( type == "sha256" )
	    return new nssHashContext( this, type );
	if ( type == "sha384" )
	    return new nssHashContext( this, type );
	if ( type == "sha512" )
	    return new nssHashContext( this, type );

	if ( type == "hmac(md5)" )
	    return new nssHmacContext( this, type );
	if ( type == "hmac(sha1)" )
	    return new nssHmacContext( this, type );
	if ( type == "hmac(sha256)" )
	    return new nssHmacContext( this, type );
	if ( type == "hmac(sha384)" )
	    return new nssHmacContext( this, type );
	if ( type == "hmac(sha512)" )
	    return new nssHmacContext( this, type );
	if ( type == "hmac(ripemd160)" )
	    return new nssHmacContext( this, type );
	else
	    return 0;
    }
private:

};

class nssPlugin : public QCAPlugin
{
	Q_OBJECT
	Q_INTERFACES( QCAPlugin )
public:
	virtual QCA::Provider *createProvider() { return new nssProvider; }
};

#include "qca-nss.moc"

Q_EXPORT_PLUGIN2(qca-nss, nssPlugin);

<|endoftext|>


<commit_before>/*
* Block Ciphers via OpenSSL
* (C) 1999-2010,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/block_cipher.h>
#include <botan/internal/safeint.h>
#include <botan/internal/openssl.h>
#include <openssl/evp.h>

namespace Botan {

namespace {

class OpenSSL_BlockCipher final : public BlockCipher
   {
   public:
      OpenSSL_BlockCipher(const std::string& name,
                          const EVP_CIPHER* cipher);

      OpenSSL_BlockCipher(const std::string& name,
                          const EVP_CIPHER* cipher,
                          size_t kl_min, size_t kl_max, size_t kl_mod);

      ~OpenSSL_BlockCipher();

      void clear() override;
      std::string provider() const override { return "openssl"; }
      std::string name() const override { return m_cipher_name; }
      std::unique_ptr<BlockCipher> new_object() const override;

      size_t block_size() const override { return m_block_sz; }

      Key_Length_Specification key_spec() const override { return m_cipher_key_spec; }

      void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
         {
         verify_key_set(m_key_set);
         int out_len = 0;
         const size_t total_bytes = blocks * m_block_sz;
         const int itotal_bytes = checked_cast_to<int>(total_bytes);
         if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, itotal_bytes))
            throw OpenSSL_Error("EVP_EncryptUpdate", ERR_get_error());
         }

      void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
         {
         verify_key_set(m_key_set);
         int out_len = 0;
         const size_t total_bytes = blocks * m_block_sz;
         const int itotal_bytes = checked_cast_to<int>(total_bytes);
         if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, itotal_bytes))
            throw OpenSSL_Error("EVP_DecryptUpdate", ERR_get_error());
         }

      void key_schedule(const uint8_t key[], size_t key_len) override;

      size_t m_block_sz;
      Key_Length_Specification m_cipher_key_spec;
      std::string m_cipher_name;
      EVP_CIPHER_CTX *m_encrypt;
      EVP_CIPHER_CTX *m_decrypt;
      bool m_key_set;
   };

OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
                                         const EVP_CIPHER* algo) :
   m_block_sz(EVP_CIPHER_block_size(algo)),
   m_cipher_key_spec(EVP_CIPHER_key_length(algo)),
   m_cipher_name(algo_name),
   m_key_set(false)
   {
   if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
      throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");

   m_encrypt = EVP_CIPHER_CTX_new();
   m_decrypt = EVP_CIPHER_CTX_new();
   if (m_encrypt == nullptr || m_decrypt == nullptr)
      throw OpenSSL_Error("Can't allocate new context", ERR_get_error());

   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);

   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
                                         const EVP_CIPHER* algo,
                                         size_t key_min,
                                         size_t key_max,
                                         size_t key_mod) :
   m_block_sz(EVP_CIPHER_block_size(algo)),
   m_cipher_key_spec(key_min, key_max, key_mod),
   m_cipher_name(algo_name),
   m_key_set(false)
   {
   if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
      throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");

   m_encrypt = EVP_CIPHER_CTX_new();
   m_decrypt = EVP_CIPHER_CTX_new();
   if (m_encrypt == nullptr || m_decrypt == nullptr)
      throw OpenSSL_Error("Can't allocate new context", ERR_get_error());

   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);

   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

OpenSSL_BlockCipher::~OpenSSL_BlockCipher()
   {
   EVP_CIPHER_CTX_cleanup(m_encrypt);
   EVP_CIPHER_CTX_cleanup(m_decrypt);

   EVP_CIPHER_CTX_free(m_encrypt);
   EVP_CIPHER_CTX_free(m_decrypt);
   }

/*
* Set the key
*/
void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length)
   {
   secure_vector<uint8_t> full_key(key, key + length);

   if(m_cipher_name == "TripleDES" && length == 16)
      {
      full_key += std::make_pair(key, 8);
      }
   else
      {
      const int ilength = checked_cast_to<int>(length);
      if(EVP_CIPHER_CTX_set_key_length(m_encrypt, ilength) == 0 ||
         EVP_CIPHER_CTX_set_key_length(m_decrypt, ilength) == 0)
         throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " +
                                m_cipher_name);
      }

   if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   m_key_set = true;
   }

/*
* Return a clone of this object
*/
std::unique_ptr<BlockCipher> OpenSSL_BlockCipher::new_object() const
   {
   return std::make_unique<OpenSSL_BlockCipher>(
      m_cipher_name,
      EVP_CIPHER_CTX_cipher(m_encrypt),
      m_cipher_key_spec.minimum_keylength(),
      m_cipher_key_spec.maximum_keylength(),
      m_cipher_key_spec.keylength_multiple());
   }

/*
* Clear memory of sensitive data
*/
void OpenSSL_BlockCipher::clear()
   {
   const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt);

   m_key_set = false;

   if(!EVP_CIPHER_CTX_cleanup(m_encrypt))
      throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_cleanup(m_decrypt))
      throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt", ERR_get_error());
   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);
   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

}

std::unique_ptr<BlockCipher>
make_openssl_block_cipher(const std::string& name)
   {
#define MAKE_OPENSSL_BLOCK(evp_fn) \
   std::make_unique<OpenSSL_BlockCipher>(name, evp_fn()))
#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod)       \
   std::make_unique<OpenSSL_BlockCipher>(name, evp_fn(), kl_min, kl_max, kl_mod)

#if defined(BOTAN_HAS_AES) && !defined(OPENSSL_NO_AES)
   if(name == "AES-128")
      return MAKE_OPENSSL_BLOCK(EVP_aes_128_ecb);
   if(name == "AES-192")
      return MAKE_OPENSSL_BLOCK(EVP_aes_192_ecb);
   if(name == "AES-256")
      return MAKE_OPENSSL_BLOCK(EVP_aes_256_ecb);
#endif

#if defined(BOTAN_HAS_CAMELLIA) && !defined(OPENSSL_NO_CAMELLIA)
   if(name == "Camellia-128")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_128_ecb);
   if(name == "Camellia-192")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_192_ecb);
   if(name == "Camellia-256")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_256_ecb);
#endif

#if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES)
   if(name == "DES")
      return MAKE_OPENSSL_BLOCK(EVP_des_ecb);
   if(name == "TripleDES")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
#endif

#if defined(BOTAN_HAS_BLOWFISH) && !defined(OPENSSL_NO_BF)
   if(name == "Blowfish")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_bf_ecb, 1, 56, 1);
#endif

#if defined(BOTAN_HAS_CAST_128) && !defined(OPENSSL_NO_CAST)
   if(name == "CAST-128")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_cast5_ecb, 1, 16, 1);
#endif

#if defined(BOTAN_HAS_SEED) && !defined(OPENSSL_NO_SEED)
   if(name == "SEED")
      return MAKE_OPENSSL_BLOCK(EVP_seed_ecb);
#endif

   return nullptr;
   }

}

<commit_msg>Fix OpenSSL build<commit_after>/*
* Block Ciphers via OpenSSL
* (C) 1999-2010,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/block_cipher.h>
#include <botan/internal/safeint.h>
#include <botan/internal/openssl.h>
#include <openssl/evp.h>

namespace Botan {

namespace {

class OpenSSL_BlockCipher final : public BlockCipher
   {
   public:
      OpenSSL_BlockCipher(const std::string& name,
                          const EVP_CIPHER* cipher);

      OpenSSL_BlockCipher(const std::string& name,
                          const EVP_CIPHER* cipher,
                          size_t kl_min, size_t kl_max, size_t kl_mod);

      ~OpenSSL_BlockCipher();

      void clear() override;
      std::string provider() const override { return "openssl"; }
      std::string name() const override { return m_cipher_name; }
      std::unique_ptr<BlockCipher> new_object() const override;

      size_t block_size() const override { return m_block_sz; }

      Key_Length_Specification key_spec() const override { return m_cipher_key_spec; }

      void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
         {
         verify_key_set(m_key_set);
         int out_len = 0;
         const size_t total_bytes = blocks * m_block_sz;
         const int itotal_bytes = checked_cast_to<int>(total_bytes);
         if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, itotal_bytes))
            throw OpenSSL_Error("EVP_EncryptUpdate", ERR_get_error());
         }

      void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
         {
         verify_key_set(m_key_set);
         int out_len = 0;
         const size_t total_bytes = blocks * m_block_sz;
         const int itotal_bytes = checked_cast_to<int>(total_bytes);
         if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, itotal_bytes))
            throw OpenSSL_Error("EVP_DecryptUpdate", ERR_get_error());
         }

      void key_schedule(const uint8_t key[], size_t key_len) override;

      size_t m_block_sz;
      Key_Length_Specification m_cipher_key_spec;
      std::string m_cipher_name;
      EVP_CIPHER_CTX *m_encrypt;
      EVP_CIPHER_CTX *m_decrypt;
      bool m_key_set;
   };

OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
                                         const EVP_CIPHER* algo) :
   m_block_sz(EVP_CIPHER_block_size(algo)),
   m_cipher_key_spec(EVP_CIPHER_key_length(algo)),
   m_cipher_name(algo_name),
   m_key_set(false)
   {
   if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
      throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");

   m_encrypt = EVP_CIPHER_CTX_new();
   m_decrypt = EVP_CIPHER_CTX_new();
   if (m_encrypt == nullptr || m_decrypt == nullptr)
      throw OpenSSL_Error("Can't allocate new context", ERR_get_error());

   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);

   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
                                         const EVP_CIPHER* algo,
                                         size_t key_min,
                                         size_t key_max,
                                         size_t key_mod) :
   m_block_sz(EVP_CIPHER_block_size(algo)),
   m_cipher_key_spec(key_min, key_max, key_mod),
   m_cipher_name(algo_name),
   m_key_set(false)
   {
   if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
      throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");

   m_encrypt = EVP_CIPHER_CTX_new();
   m_decrypt = EVP_CIPHER_CTX_new();
   if (m_encrypt == nullptr || m_decrypt == nullptr)
      throw OpenSSL_Error("Can't allocate new context", ERR_get_error());

   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);

   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

OpenSSL_BlockCipher::~OpenSSL_BlockCipher()
   {
   EVP_CIPHER_CTX_cleanup(m_encrypt);
   EVP_CIPHER_CTX_cleanup(m_decrypt);

   EVP_CIPHER_CTX_free(m_encrypt);
   EVP_CIPHER_CTX_free(m_decrypt);
   }

/*
* Set the key
*/
void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length)
   {
   secure_vector<uint8_t> full_key(key, key + length);

   if(m_cipher_name == "TripleDES" && length == 16)
      {
      full_key += std::make_pair(key, 8);
      }
   else
      {
      const int ilength = checked_cast_to<int>(length);
      if(EVP_CIPHER_CTX_set_key_length(m_encrypt, ilength) == 0 ||
         EVP_CIPHER_CTX_set_key_length(m_decrypt, ilength) == 0)
         throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " +
                                m_cipher_name);
      }

   if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());

   m_key_set = true;
   }

/*
* Return a clone of this object
*/
std::unique_ptr<BlockCipher> OpenSSL_BlockCipher::new_object() const
   {
   return std::make_unique<OpenSSL_BlockCipher>(
      m_cipher_name,
      EVP_CIPHER_CTX_cipher(m_encrypt),
      m_cipher_key_spec.minimum_keylength(),
      m_cipher_key_spec.maximum_keylength(),
      m_cipher_key_spec.keylength_multiple());
   }

/*
* Clear memory of sensitive data
*/
void OpenSSL_BlockCipher::clear()
   {
   const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt);

   m_key_set = false;

   if(!EVP_CIPHER_CTX_cleanup(m_encrypt))
      throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_cleanup(m_decrypt))
      throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt", ERR_get_error());
   EVP_CIPHER_CTX_init(m_encrypt);
   EVP_CIPHER_CTX_init(m_decrypt);
   if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error());
   if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
      throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error());
   if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
      throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
   }

}

std::unique_ptr<BlockCipher>
make_openssl_block_cipher(const std::string& name)
   {
#define MAKE_OPENSSL_BLOCK(evp_fn) \
   std::make_unique<OpenSSL_BlockCipher>(name, evp_fn())
#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod)       \
   std::make_unique<OpenSSL_BlockCipher>(name, evp_fn(), kl_min, kl_max, kl_mod)

#if defined(BOTAN_HAS_AES) && !defined(OPENSSL_NO_AES)
   if(name == "AES-128")
      return MAKE_OPENSSL_BLOCK(EVP_aes_128_ecb);
   if(name == "AES-192")
      return MAKE_OPENSSL_BLOCK(EVP_aes_192_ecb);
   if(name == "AES-256")
      return MAKE_OPENSSL_BLOCK(EVP_aes_256_ecb);
#endif

#if defined(BOTAN_HAS_CAMELLIA) && !defined(OPENSSL_NO_CAMELLIA)
   if(name == "Camellia-128")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_128_ecb);
   if(name == "Camellia-192")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_192_ecb);
   if(name == "Camellia-256")
      return MAKE_OPENSSL_BLOCK(EVP_camellia_256_ecb);
#endif

#if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES)
   if(name == "DES")
      return MAKE_OPENSSL_BLOCK(EVP_des_ecb);
   if(name == "TripleDES")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
#endif

#if defined(BOTAN_HAS_BLOWFISH) && !defined(OPENSSL_NO_BF)
   if(name == "Blowfish")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_bf_ecb, 1, 56, 1);
#endif

#if defined(BOTAN_HAS_CAST_128) && !defined(OPENSSL_NO_CAST)
   if(name == "CAST-128")
      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_cast5_ecb, 1, 16, 1);
#endif

#if defined(BOTAN_HAS_SEED) && !defined(OPENSSL_NO_SEED)
   if(name == "SEED")
      return MAKE_OPENSSL_BLOCK(EVP_seed_ecb);
#endif

   return nullptr;
   }

}

<|endoftext|>