<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <cmath>
#include <string.h>
#define isl_min(x,y) ((x) < (y) ? (x) : (y))
#define isl_max(x,y) ((x) > (y) ? (x) : (y))
#define isl_floord(n,d) (((n)<0) ? -((-(n)+(d)-1)/(d)) : (n)/(d))
extern "C" void  pipeline_mask(int  C, int  R, float  threshold, float  weight, void * img_void_arg, void * mask_void_arg)
{
  unsigned char * img_flip;
  img_flip = (unsigned char *) (img_void_arg);
  float * mask_flip;
  mask_flip = (float *) (mask_void_arg);

    //float * img = (float *)malloc(sizeof(float) * 3 * (R+4) * (C+4));
/*
    #pragma omp parallel for schedule(static)
    for(int i = 0; i < R+4; i++)
        for(int j = 0; j< C+4; j++)
            for(int c = 0; c < 3; c++)
                img[c*(R+4)*(C+4) + i*(C+4) + j] = ((float)img_flip[i*(C+4)*3 + j*3 + c]) / 255.0f;
*/

  #pragma omp parallel for schedule(static)
  for (int  _T_i1 = 0; (_T_i1 <= ((R + 1) / 32)); _T_i1 = (_T_i1 + 1))
  {
    float  img[3][36][262];
    float  blurx[3][32][262];
    float  blury[3][32][262];
    float  sharpen[3][32][262];
    for (int  _T_i2 = -1; (_T_i2 <= ((C + 3) / 256)); _T_i2 = (_T_i2 + 1))
    {
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        int  _ct0 = (((R + 1) < ((32 * _T_i1) + 31)) ? (R + 1): ((32 * _T_i1) + 31));
        int  _ct1 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
        for (int  _i1 = _ct1-2; (_i1 <= _ct0+2); _i1 = (_i1 + 1))
        {
          int  _ct2 = (((C + 3) < ((256 * _T_i2) + 261))? (C + 3): ((256 * _T_i2) + 261));
          int  _ct3 = ((0 > (256 * _T_i2))? 0: (256 * _T_i2));
          #pragma ivdep
          for (int  _i2 = _ct3; (_i2 <= _ct2); _i2 = (_i2 + 1))
          {
            img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = ((float)img_flip[_i1 * (C+4) * 3 + _i2 * 3 + _i0]) / 255.0f;
          }
        }

        for (int  _i1 = _ct1; (_i1 <= _ct0); _i1 = (_i1 + 1))
        {
          int  _ct2 = (((C + 3) < ((256 * _T_i2) + 261))? (C + 3): ((256 * _T_i2) + 261));
          int  _ct3 = ((0 > (256 * _T_i2))? 0: (256 * _T_i2));
          #pragma ivdep
          for (int  _i2 = _ct3; (_i2 <= _ct2); _i2 = (_i2 + 1))
          {
            blurx[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = img[_i0][(-32 * _T_i1)-2 + _i1][(-256 * _T_i2)+_i2] * 0.0625f + img[_i0][(-32 * _T_i1)-1 + _i1][(-256 * _T_i2)+_i2] * 0.25f + img[_i0][(-32 * _T_i1)+_i1][(-256 * _T_i2)+_i2] * 0.375f + img[_i0][(-32 * _T_i1)+1 + _i1][(-256 * _T_i2)+_i2] * 0.25f + img[_i0][(-32 * _T_i1)+2 + _i1][(-256 * _T_i2)+_i2] * 0.0625f;
            //blurx[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = (((((img[(((_i0 * ((R + 4) * (C + 4))) + ((-2 + _i1) * (C + 4))) + _i2)] * 0.0625f) + (img[(((_i0 * ((R + 4) * (C + 4))) + ((-1 + _i1) * (C + 4))) + _i2)] * 0.25f)) + (img[(((_i0 * ((R + 4) * (C + 4))) + (_i1 * (C + 4))) + _i2)] * 0.375f)) + (img[(((_i0 * ((R + 4) * (C + 4))) + ((1 + _i1) * (C + 4))) + _i2)] * 0.25f)) + (img[(((_i0 * ((R + 4) * (C + 4))) + ((2 + _i1) * (C + 4))) + _i2)] * 0.0625f));
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        int  _ct4 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
        int  _ct5 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
        for (int  _i1 = _ct5; (_i1 <= _ct4); _i1 = (_i1 + 1))
        {
          int  _ct6 = (((C + 1) < ((256 * _T_i2) + 260))? (C + 1): ((256 * _T_i2) + 260));
          int  _ct7 = ((2 > ((256 * _T_i2) + 1))? 2: ((256 * _T_i2) + 1));
          #pragma ivdep
          for (int  _i2 = _ct7; (_i2 <= _ct6); _i2 = (_i2 + 1))
          {
            blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = (((((blurx[_i0][((-32 * _T_i1) + _i1)][(-2 + ((-256 * _T_i2) + _i2))] * 0.0625f) + (blurx[_i0][((-32 * _T_i1) + _i1)][(-1 + ((-256 * _T_i2) + _i2))] * 0.25f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * 0.375f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][(1 + ((-256 * _T_i2) + _i2))] * 0.25f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][(2 + ((-256 * _T_i2) + _i2))] * 0.0625f));
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        int  _ct8 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
        int  _ct9 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
        for (int  _i1 = _ct9; (_i1 <= _ct8); _i1 = (_i1 + 1))
        {
          int  _ct10 = (((C + 1) < ((256 * _T_i2) + 259))? (C + 1): ((256 * _T_i2) + 259));
          int  _ct11 = ((2 > ((256 * _T_i2) + 2))? 2: ((256 * _T_i2) + 2));
          #pragma ivdep
          for (int  _i2 = _ct11; (_i2 <= _ct10); _i2 = (_i2 + 1))
          {
            sharpen[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * (1 + weight) + blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * -(weight);
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        int  _ct12 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
        int  _ct13 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
        for (int  _i1 = _ct13; (_i1 <= _ct12); _i1 = (_i1 + 1))
        {
          int  _ct14 = (((C + 1) < ((256 * _T_i2) + 258))? (C + 1): ((256 * _T_i2) + 258));
          int  _ct15 = ((2 > ((256 * _T_i2) + 3))? 2: ((256 * _T_i2) + 3));
          #pragma ivdep
          for (int  _i2 = _ct15; (_i2 <= _ct14); _i2 = (_i2 + 1))
          {
            float  _ct16 = img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)];
            float  _ct17 = sharpen[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)];
            float  _ct18 = ((std::abs((img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] - blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)])) < threshold)? _ct16: _ct17);
            mask_flip[((((_i1-2) * (3 * C)) + ((_i2 - 2) * 3)) + (_i0))] = _ct18;
          }
        }
      }
    }
  }
}
<commit_msg>Loop bound initialization for inner loops pushed to the outer loops<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <cmath>
#include <string.h>
#define isl_min(x,y) ((x) < (y) ? (x) : (y))
#define isl_max(x,y) ((x) > (y) ? (x) : (y))
#define isl_floord(n,d) (((n)<0) ? -((-(n)+(d)-1)/(d)) : (n)/(d))
extern "C" void  pipeline_mask(int  C, int  R, float  threshold, float  weight, void * img_void_arg, void * mask_void_arg)
{
  unsigned char * img_flip;
  img_flip = (unsigned char *) (img_void_arg);
  float * mask_flip;
  mask_flip = (float *) (mask_void_arg);

  #pragma omp parallel for schedule(static)
  for (int  _T_i1 = 0; (_T_i1 <= ((R + 1) / 32)); _T_i1 = (_T_i1 + 1))
  {
    float  img[3][36][262];
    float  blurx[3][32][262];
    float  blury[3][32][262];
    float  sharpen[3][32][262];
    int  _ct0 = (((R + 1) < ((32 * _T_i1) + 31)) ? (R + 1): ((32 * _T_i1) + 31));
    int  _ct1 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
    int  _ct4 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
    int  _ct5 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
    int  _ct8 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
    int  _ct9 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
    int  _ct12 = (((R + 1) < ((32 * _T_i1) + 31))? (R + 1): ((32 * _T_i1) + 31));
    int  _ct13 = ((2 > (32 * _T_i1))? 2: (32 * _T_i1));
    for (int  _T_i2 = -1; (_T_i2 <= ((C + 3) / 256)); _T_i2 = (_T_i2 + 1))
    {
      int  _ct2 = (((C + 3) < ((256 * _T_i2) + 261))? (C + 3): ((256 * _T_i2) + 261));
      int  _ct3 = ((0 > (256 * _T_i2))? 0: (256 * _T_i2));
      int  _ct6 = (((C + 1) < ((256 * _T_i2) + 260))? (C + 1): ((256 * _T_i2) + 260));
      int  _ct7 = ((2 > ((256 * _T_i2) + 1))? 2: ((256 * _T_i2) + 1));
      int  _ct10 = (((C + 1) < ((256 * _T_i2) + 259))? (C + 1): ((256 * _T_i2) + 259));
      int  _ct11 = ((2 > ((256 * _T_i2) + 2))? 2: ((256 * _T_i2) + 2));
      int  _ct14 = (((C + 1) < ((256 * _T_i2) + 258))? (C + 1): ((256 * _T_i2) + 258));
      int  _ct15 = ((2 > ((256 * _T_i2) + 3))? 2: ((256 * _T_i2) + 3));
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        for (int  _i1 = _ct1-2; (_i1 <= _ct0+2); _i1 = (_i1 + 1))
        {
          #pragma ivdep
          for (int  _i2 = _ct3; (_i2 <= _ct2); _i2 = (_i2 + 1))
          {
            img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = ((float)img_flip[_i1 * (C+4) * 3 + _i2 * 3 + _i0]) / 255.0f;
          }
        }

        for (int  _i1 = _ct1; (_i1 <= _ct0); _i1 = (_i1 + 1))
        {
          #pragma ivdep
          for (int  _i2 = _ct3; (_i2 <= _ct2); _i2 = (_i2 + 1))
          {
            blurx[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = img[_i0][(-32 * _T_i1)-2 + _i1][(-256 * _T_i2)+_i2] * 0.0625f + img[_i0][(-32 * _T_i1)-1 + _i1][(-256 * _T_i2)+_i2] * 0.25f + img[_i0][(-32 * _T_i1)+_i1][(-256 * _T_i2)+_i2] * 0.375f + img[_i0][(-32 * _T_i1)+1 + _i1][(-256 * _T_i2)+_i2] * 0.25f + img[_i0][(-32 * _T_i1)+2 + _i1][(-256 * _T_i2)+_i2] * 0.0625f;
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        for (int  _i1 = _ct5; (_i1 <= _ct4); _i1 = (_i1 + 1))
        {
          #pragma ivdep
          for (int  _i2 = _ct7; (_i2 <= _ct6); _i2 = (_i2 + 1))
          {
            blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = (((((blurx[_i0][((-32 * _T_i1) + _i1)][(-2 + ((-256 * _T_i2) + _i2))] * 0.0625f) + (blurx[_i0][((-32 * _T_i1) + _i1)][(-1 + ((-256 * _T_i2) + _i2))] * 0.25f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * 0.375f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][(1 + ((-256 * _T_i2) + _i2))] * 0.25f)) + (blurx[_i0][((-32 * _T_i1) + _i1)][(2 + ((-256 * _T_i2) + _i2))] * 0.0625f));
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        for (int  _i1 = _ct9; (_i1 <= _ct8); _i1 = (_i1 + 1))
        {
          #pragma ivdep
          for (int  _i2 = _ct11; (_i2 <= _ct10); _i2 = (_i2 + 1))
          {
            sharpen[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] = img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * (1 + weight) + blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] * -(weight);
          }
        }
      }
      for (int  _i0 = 0; (_i0 <= 2); _i0 = (_i0 + 1))
      {
        for (int  _i1 = _ct13; (_i1 <= _ct12); _i1 = (_i1 + 1))
        {
          #pragma ivdep
          for (int  _i2 = _ct15; (_i2 <= _ct14); _i2 = (_i2 + 1))
          {
            float  _ct16 = img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)];
            float  _ct17 = sharpen[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)];
            float  _ct18 = ((std::abs((img[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)] - blury[_i0][((-32 * _T_i1) + _i1)][((-256 * _T_i2) + _i2)])) < threshold)? _ct16: _ct17);
            mask_flip[((((_i1-2) * (3 * C)) + ((_i2 - 2) * 3)) + (_i0))] = _ct18;
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 * The Biomechanical ToolKit
 * Copyright (c) 2009-2013, Arnaud Barré
 * 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(s) of the copyright holders 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.
 */

#include "btkProcessObject.h"
#include "btkConvert.h"
#include "btkLogger.h"

namespace btk
{
  /**
   * @class ProcessObject btkProcessObject.h
   * @brief Interface to create a filter/process in a pipeline.
   *
   * An inherited class has to implement the GenerateData() method and the
   * MakeOutput() metod. GenerateData() is the core of the process as it compute the outputs
   * based on the inputs and its algorithms. The method MakeOutput() is used in the
   * SetOutputNumber() and SetNthOutput() to create newly valid output.
   *
   * The following code presents the minimum required to use the pipeline principle.
   * @code
   * class Source : public btk::DataObject
   * {
   * public:
   *   typedef btkSharedPtr<Source> Pointer;
   *   static Pointer New() {return Pointer(new Source());};
   *   int GetValue() {return this->m_Val;};
   *   void SetValue(int val)
   *   {
   *     this->m_Val = val;
   *     this->Modified();
   *   };
   * private:
   *   Source() {this->m_Val = 0;};
   *   int m_Val;
   * };
   *
   * class Filter : public btk::ProcessObject
   * {
   * public:
   *   typedef btkSharedPtr<Filter> Pointer;
   *   static Pointer New() {return Pointer(new Filter());};
   *   void SetInc(int inc)
   *   {
   *     this->m_Inc = inc;
   *     this->Modified();
   *   };
   *   Source::Pointer GetInput() {return this->GetInput(0);};
   *   void SetInput(Source::Pointer input) {this->SetNthInput(0, input);};
   *   Source::Pointer GetOutput() {return this->GetOutput(0);};
   *
   * protected:
   *   Source::Pointer GetInput(int idx) {return static_pointer_cast<Source>(this->GetNthInput(idx));};
   *   Source::Pointer GetOutput(int idx) {return static_pointer_cast<Source>(this->GetNthOutput(idx));};
   *   virtual btk::DataObject::Pointer MakeOutput(int )
   *   {
   *      return Source::New();
   *   };
   *   virtual void GenerateData()
   *   {
   *     // simple algorithm : O = I + inc
   *     this->GetOutput()->SetValue(this->GetInput()->GetValue() + this->m_Inc);
   *   };
   *
   * private:
   *   Filter()
   *   {
   *     this->SetInputNumber(1);
   *     this->SetOutputNumber(1);
   *     this->m_Inc = 1;
   *   };
   *
   *   int m_Inc;
   * };
   *
   *
   * int main ()
   * {
   *   Source::Pointer src = Source::New();
   *   Filter::Pointer incFilt = Filter::New();
   *   incFilt->SetInput(src);
   *   Source::Pointer res = incFilt->GetOutput();
   *   incFilt->Update(); // same than res->Update();
   *   return 0;
   * }
   * @endcode
   *
   * @ingroup BTKCommon
   */

  /**
   * @typedef ProcessObject::Pointer
   * Smart pointer associated with a ProcessObject object.
   */

  /**
   * @typedef ProcessObject::ConstPointer
   * Smart pointer associated with a const ProcessObject object.
   */

  /**
   * @fn int ProcessObject::GetInputNumber() const
   * Returns the number of inputs.
   */

  /**
   * Returns the number of inputs which are valid (i.e. not null).
   */
  int ProcessObject::GetValidInputNumber() const
  {
    int count = 0;
    for (std::vector<DataObject::Pointer>::const_iterator it = this->m_Inputs.begin() ; it != this->m_Inputs.end() ; ++it)
    {
      if (it->get() != 0)
        count++;
    }
    return count;
  }

  /**
   * @fn int ProcessObject::GetOutputNumber() const
   * Returns the number of outputs.
   */

  /**
   * Recursive method which 1) determines the processes to update and 2)
   * generate the data by using the GenerateData() method.
   */
  void ProcessObject::Update()
  {
    if (this->m_Updating)
      return;
    this->m_Updating = true;

    for (size_t inc = 0 ; inc < this->m_Inputs.size() ; ++inc)
    {
      if (this->m_Inputs[inc].get() != 0)
      {
        this->m_Inputs[inc]->Update();
        if (this->m_Inputs[inc]->m_Timestamp >= this->m_Timestamp)
          this->m_Modified = true;
      }
    }
    if (this->m_Modified)
    {
      unsigned long int ts = this->GetTimestamp();
      this->GenerateData();
      this->Object::Modified();
      for (size_t inc = 0 ; inc < this->m_Outputs.size() ; ++inc)
      {
        if ((this->m_Outputs[inc].get() != 0) && (this->m_Outputs[inc]->GetTimestamp() > ts))
          this->m_Outputs[inc]->m_Timestamp = this->m_Timestamp;
      }
      this->m_Modified = false;
    }
    this->m_Updating = false;
  };

  /**
   * Reset the state of the process. Usefull when an exception was thrown during the generation of the data.
   */
  void ProcessObject::ResetState()
  {
    this->m_Updating = false;
  };

  /**
   * Process constructor with zero input and output. The inherited class set the number
   * of inputs/ouputs with the functions SetInputNumber() and SetOutputNumber().
   */
  ProcessObject::ProcessObject()
  : Object(),
    m_Inputs(std::vector<DataObject::Pointer>(0)),
    m_Outputs(std::vector<DataObject::Pointer>(0))
  {
    this->m_Modified = false;
    this->m_Updating = false;
  };

  /**
   * This destructor doesn't delete its ouptuts (which can be used as input by others process).
   * In fact, it says that they are disconnected of their source.
   */
  ProcessObject::~ProcessObject()
  {
    for (size_t idx = 0; idx < this->m_Outputs.size(); ++idx)
    {
      if (this->m_Outputs[idx])
        this->m_Outputs[idx]->mp_Source = 0;
    }
  };

  /**
   * Gets the input at index @a idx or an empty Pointer if @a idx is out of range.
   */
  DataObject::Pointer ProcessObject::GetNthInput(int idx)
  {
    if (idx >= static_cast<int>(m_Inputs.size()))
      return DataObject::Pointer();
    return m_Inputs[idx];
  };

  /**
   * Gets the input at index @a idx or an empty ConstPointer if @a idx is out of range.
   */
  DataObject::ConstPointer ProcessObject::GetNthInput(int idx) const
  {
    if (idx >= static_cast<int>(m_Inputs.size()))
      return DataObject::ConstPointer();
    return m_Inputs[idx];
  };

  /**
   * Sets an input of the filter. If necessary, the size of inputs is increased
   * if @a idx is greater or equal than the number of inputs.
   */
  void ProcessObject::SetNthInput(int idx, DataObject::Pointer input)
  {
    if (idx >= static_cast<int>(this->m_Inputs.size()))
      this->m_Inputs.resize(idx + 1);
    else if (input == this->m_Inputs[idx])
      return;
    m_Inputs[idx] = input;

    this->Modified();
  };

  /**
   * Returns the index of the DataObject given in input. If no DataObject
   * corresponds, then the method returns -1.
   */
  int ProcessObject::GetInputIndex(DataObject::Pointer input)
  {
    for (size_t idx = 0 ; idx < this->m_Inputs.size() ; ++idx)
    {
      if (this->m_Inputs[idx] == input)
        return static_cast<int>(idx);
    }
    return -1;
  };

  /**
   * Sets the number of inputs.
   */
  void ProcessObject::SetInputNumber(int num)
  {
    if (num == static_cast<int>(this->m_Inputs.size()))
      return;
    if (num < 0)
    {
      btkWarningMacro("Attempt to set the number of inputs to the negative value" + ToString(num) + ". The number of inputs is set to 0.");
      num = 0;
    }
    this->m_Inputs.resize(num);
    this->Modified();
  };

  /**
   * Gets the output at @a idx or a empty Pointer if @a idx is out of range.
   */
  DataObject::Pointer ProcessObject::GetNthOutput(int idx)
  {
    if (idx >= static_cast<int>(m_Outputs.size()))
      return DataObject::Pointer();
    return m_Outputs[idx];
  };

  /**
   * Gets the output at @a idx or a empty ConstPointer if @a idx is out of range.
   */
  DataObject::ConstPointer ProcessObject::GetNthOutput(int idx) const
  {
    if (idx >= static_cast<int>(this->m_Outputs.size()))
      return DataObject::ConstPointer();
    return m_Outputs[idx];
  };

  /**
   * Returns the index of the DataObject given in input. If no DataObject
   * corresponds, then the method returns -1.
   */
  int ProcessObject::GetOutputIndex(DataObject::Pointer output)
  {
    for (size_t idx = 0 ; idx < this->m_Outputs.size() ; ++idx)
    {
      if (this->m_Outputs[idx] == output)
        return static_cast<int>(idx);
    }
    return -1;
  };

  /**
   * Set the output at the index @a idx or create a new output from the method
   * MakeOutput() if the pointer in @a output is null. If necessary, the size of
   * the outputs is increased if @a idx is greater or equal than the number of
   * outputs.
   */
  void ProcessObject::SetNthOutput(int idx, DataObject::Pointer output)
  {
    if (idx >= static_cast<int>(this->m_Outputs.size()))
      this->m_Outputs.resize(idx + 1);
    else if (output == this->m_Outputs[idx])
      return;

    DataObject::Pointer oldOutput;
    if (this->m_Outputs[idx])
    {
      oldOutput = this->m_Outputs[idx];
      oldOutput->mp_Source = 0;
    }
    if (output.get() == 0)
      output = this->MakeOutput(idx);
    output->mp_Source = this;
    this->m_Outputs[idx] = output;

    this->Modified();
  };

  /**
   * Sets the number of outputs. The outputs generated used the MakeOutput() method.
   */
  void ProcessObject::SetOutputNumber(int num)
  {
    if (num == static_cast<int>(this->m_Outputs.size()))
      return;
    if (num < 0)
    {
      btkWarningMacro("Attempt to set the number of outputs to the negative value" + ToString(num) + ". The number of outputs is set to 0.");
      num = 0;
    }
    this->m_Outputs.resize(num);
    for (int inc = 0 ; inc < num ; ++inc)
    {
      this->m_Outputs[inc] = this->MakeOutput(inc);
      this->m_Outputs[inc]->mp_Source = this;
    }
    this->Modified();
  };

  /**
   * This method has to be called each time that the ProcessObject is modified.
   */
  void ProcessObject::Modified()
  {
    this->m_Modified = true;
    // this->Object::Modified();
  };

  /**
   * @fn bool ProcessObject::IsModified() const
   * Indicates if the process is modified or not.
   */

  /**
   * @fn virtual void ProcessObject::GenerateData() = 0;
   * Generates the outputs' data.
   */

  /**
   * @fn virtual DataObject::Pointer ProcessObject::MakeOutput(int idx) = 0
   * Creates and returns a DataObject::Pointer for the given index @a idx.
   */
};
<commit_msg>[UPD] If the number of outputs is modified in a filter, then the outputs already created are no more replaced.<commit_after>/*
 * The Biomechanical ToolKit
 * Copyright (c) 2009-2013, Arnaud Barré
 * 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(s) of the copyright holders 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.
 */

#include "btkProcessObject.h"
#include "btkConvert.h"
#include "btkLogger.h"

namespace btk
{
  /**
   * @class ProcessObject btkProcessObject.h
   * @brief Interface to create a filter/process in a pipeline.
   *
   * An inherited class has to implement the GenerateData() method and the
   * MakeOutput() metod. GenerateData() is the core of the process as it compute the outputs
   * based on the inputs and its algorithms. The method MakeOutput() is used in the
   * SetOutputNumber() and SetNthOutput() to create newly valid output.
   *
   * The following code presents the minimum required to use the pipeline principle.
   * @code
   * class Source : public btk::DataObject
   * {
   * public:
   *   typedef btkSharedPtr<Source> Pointer;
   *   static Pointer New() {return Pointer(new Source());};
   *   int GetValue() {return this->m_Val;};
   *   void SetValue(int val)
   *   {
   *     this->m_Val = val;
   *     this->Modified();
   *   };
   * private:
   *   Source() {this->m_Val = 0;};
   *   int m_Val;
   * };
   *
   * class Filter : public btk::ProcessObject
   * {
   * public:
   *   typedef btkSharedPtr<Filter> Pointer;
   *   static Pointer New() {return Pointer(new Filter());};
   *   void SetInc(int inc)
   *   {
   *     this->m_Inc = inc;
   *     this->Modified();
   *   };
   *   Source::Pointer GetInput() {return this->GetInput(0);};
   *   void SetInput(Source::Pointer input) {this->SetNthInput(0, input);};
   *   Source::Pointer GetOutput() {return this->GetOutput(0);};
   *
   * protected:
   *   Source::Pointer GetInput(int idx) {return static_pointer_cast<Source>(this->GetNthInput(idx));};
   *   Source::Pointer GetOutput(int idx) {return static_pointer_cast<Source>(this->GetNthOutput(idx));};
   *   virtual btk::DataObject::Pointer MakeOutput(int )
   *   {
   *      return Source::New();
   *   };
   *   virtual void GenerateData()
   *   {
   *     // simple algorithm : O = I + inc
   *     this->GetOutput()->SetValue(this->GetInput()->GetValue() + this->m_Inc);
   *   };
   *
   * private:
   *   Filter()
   *   {
   *     this->SetInputNumber(1);
   *     this->SetOutputNumber(1);
   *     this->m_Inc = 1;
   *   };
   *
   *   int m_Inc;
   * };
   *
   *
   * int main ()
   * {
   *   Source::Pointer src = Source::New();
   *   Filter::Pointer incFilt = Filter::New();
   *   incFilt->SetInput(src);
   *   Source::Pointer res = incFilt->GetOutput();
   *   incFilt->Update(); // same than res->Update();
   *   return 0;
   * }
   * @endcode
   *
   * @ingroup BTKCommon
   */

  /**
   * @typedef ProcessObject::Pointer
   * Smart pointer associated with a ProcessObject object.
   */

  /**
   * @typedef ProcessObject::ConstPointer
   * Smart pointer associated with a const ProcessObject object.
   */

  /**
   * @fn int ProcessObject::GetInputNumber() const
   * Returns the number of inputs.
   */

  /**
   * Returns the number of inputs which are valid (i.e. not null).
   */
  int ProcessObject::GetValidInputNumber() const
  {
    int count = 0;
    for (std::vector<DataObject::Pointer>::const_iterator it = this->m_Inputs.begin() ; it != this->m_Inputs.end() ; ++it)
    {
      if (it->get() != 0)
        count++;
    }
    return count;
  }

  /**
   * @fn int ProcessObject::GetOutputNumber() const
   * Returns the number of outputs.
   */

  /**
   * Recursive method which 1) determines the processes to update and 2)
   * generate the data by using the GenerateData() method.
   */
  void ProcessObject::Update()
  {
    if (this->m_Updating)
      return;
    this->m_Updating = true;

    for (size_t inc = 0 ; inc < this->m_Inputs.size() ; ++inc)
    {
      if (this->m_Inputs[inc].get() != 0)
      {
        this->m_Inputs[inc]->Update();
        if (this->m_Inputs[inc]->m_Timestamp >= this->m_Timestamp)
          this->m_Modified = true;
      }
    }
    if (this->m_Modified)
    {
      unsigned long int ts = this->GetTimestamp();
      this->GenerateData();
      this->Object::Modified();
      for (size_t inc = 0 ; inc < this->m_Outputs.size() ; ++inc)
      {
        if ((this->m_Outputs[inc].get() != 0) && (this->m_Outputs[inc]->GetTimestamp() > ts))
          this->m_Outputs[inc]->m_Timestamp = this->m_Timestamp;
      }
      this->m_Modified = false;
    }
    this->m_Updating = false;
  };

  /**
   * Reset the state of the process. Usefull when an exception was thrown during the generation of the data.
   */
  void ProcessObject::ResetState()
  {
    this->m_Updating = false;
  };

  /**
   * Process constructor with zero input and output. The inherited class set the number
   * of inputs/ouputs with the functions SetInputNumber() and SetOutputNumber().
   */
  ProcessObject::ProcessObject()
  : Object(),
    m_Inputs(std::vector<DataObject::Pointer>(0)),
    m_Outputs(std::vector<DataObject::Pointer>(0))
  {
    this->m_Modified = false;
    this->m_Updating = false;
  };

  /**
   * This destructor doesn't delete its ouptuts (which can be used as input by others process).
   * In fact, it says that they are disconnected of their source.
   */
  ProcessObject::~ProcessObject()
  {
    for (size_t idx = 0; idx < this->m_Outputs.size(); ++idx)
    {
      if (this->m_Outputs[idx])
        this->m_Outputs[idx]->mp_Source = 0;
    }
  };

  /**
   * Gets the input at index @a idx or an empty Pointer if @a idx is out of range.
   */
  DataObject::Pointer ProcessObject::GetNthInput(int idx)
  {
    if (idx >= static_cast<int>(m_Inputs.size()))
      return DataObject::Pointer();
    return m_Inputs[idx];
  };

  /**
   * Gets the input at index @a idx or an empty ConstPointer if @a idx is out of range.
   */
  DataObject::ConstPointer ProcessObject::GetNthInput(int idx) const
  {
    if (idx >= static_cast<int>(m_Inputs.size()))
      return DataObject::ConstPointer();
    return m_Inputs[idx];
  };

  /**
   * Sets an input of the filter. If necessary, the size of inputs is increased
   * if @a idx is greater or equal than the number of inputs.
   */
  void ProcessObject::SetNthInput(int idx, DataObject::Pointer input)
  {
    if (idx >= static_cast<int>(this->m_Inputs.size()))
      this->m_Inputs.resize(idx + 1);
    else if (input == this->m_Inputs[idx])
      return;
    m_Inputs[idx] = input;

    this->Modified();
  };

  /**
   * Returns the index of the DataObject given in input. If no DataObject
   * corresponds, then the method returns -1.
   */
  int ProcessObject::GetInputIndex(DataObject::Pointer input)
  {
    for (size_t idx = 0 ; idx < this->m_Inputs.size() ; ++idx)
    {
      if (this->m_Inputs[idx] == input)
        return static_cast<int>(idx);
    }
    return -1;
  };

  /**
   * Sets the number of inputs.
   */
  void ProcessObject::SetInputNumber(int num)
  {
    if (num == static_cast<int>(this->m_Inputs.size()))
      return;
    if (num < 0)
    {
      btkWarningMacro("Attempt to set the number of inputs to the negative value" + ToString(num) + ". The number of inputs is set to 0.");
      num = 0;
    }
    this->m_Inputs.resize(num);
    this->Modified();
  };

  /**
   * Gets the output at @a idx or a empty Pointer if @a idx is out of range.
   */
  DataObject::Pointer ProcessObject::GetNthOutput(int idx)
  {
    if (idx >= static_cast<int>(m_Outputs.size()))
      return DataObject::Pointer();
    return m_Outputs[idx];
  };

  /**
   * Gets the output at @a idx or a empty ConstPointer if @a idx is out of range.
   */
  DataObject::ConstPointer ProcessObject::GetNthOutput(int idx) const
  {
    if (idx >= static_cast<int>(this->m_Outputs.size()))
      return DataObject::ConstPointer();
    return m_Outputs[idx];
  };

  /**
   * Returns the index of the DataObject given in input. If no DataObject
   * corresponds, then the method returns -1.
   */
  int ProcessObject::GetOutputIndex(DataObject::Pointer output)
  {
    for (size_t idx = 0 ; idx < this->m_Outputs.size() ; ++idx)
    {
      if (this->m_Outputs[idx] == output)
        return static_cast<int>(idx);
    }
    return -1;
  };

  /**
   * Set the output at the index @a idx or create a new output from the method
   * MakeOutput() if the pointer in @a output is null. If necessary, the size of
   * the outputs is increased if @a idx is greater or equal than the number of
   * outputs.
   */
  void ProcessObject::SetNthOutput(int idx, DataObject::Pointer output)
  {
    if (idx >= static_cast<int>(this->m_Outputs.size()))
      this->m_Outputs.resize(idx + 1);
    else if (output == this->m_Outputs[idx])
      return;

    DataObject::Pointer oldOutput;
    if (this->m_Outputs[idx])
    {
      oldOutput = this->m_Outputs[idx];
      oldOutput->mp_Source = 0;
    }
    if (output.get() == 0)
      output = this->MakeOutput(idx);
    output->mp_Source = this;
    this->m_Outputs[idx] = output;

    this->Modified();
  };

  /**
   * Sets the number of outputs. The outputs generated used the MakeOutput() method.
   */
  void ProcessObject::SetOutputNumber(int num)
  {
    if (num == static_cast<int>(this->m_Outputs.size()))
      return;
    if (num < 0)
    {
      btkWarningMacro("Attempt to set the number of outputs to the negative value" + ToString(num) + ". The number of outputs is set to 0.");
      num = 0;
    }
    this->m_Outputs.resize(num);
    for (int inc = 0 ; inc < num ; ++inc)
    {
      if (this->m_Outputs[inc].get() != 0)
        continue;
      this->m_Outputs[inc] = this->MakeOutput(inc);
      this->m_Outputs[inc]->mp_Source = this;
    }
    this->Modified();
  };

  /**
   * This method has to be called each time that the ProcessObject is modified.
   */
  void ProcessObject::Modified()
  {
    this->m_Modified = true;
    // this->Object::Modified();
  };

  /**
   * @fn bool ProcessObject::IsModified() const
   * Indicates if the process is modified or not.
   */

  /**
   * @fn virtual void ProcessObject::GenerateData() = 0;
   * Generates the outputs' data.
   */

  /**
   * @fn virtual DataObject::Pointer ProcessObject::MakeOutput(int idx) = 0
   * Creates and returns a DataObject::Pointer for the given index @a idx.
   */
};
<|endoftext|>


<commit_before>/*=============================================================================

  MYPROJECT: A software package for whatever.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.

=============================================================================*/
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>
#include "mpMyFunctions.h"
#include "mpException.h"

#include <ostream>
#include <sstream>

void translate_exception(Exception const& e)
{
  std::ostringstream ss;
  ss << e.GetDescription();
  ss << " in file:" << e.GetFileName();
  ss << ", line:" << e.GetLineNumber();
  PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
}

// The name of the module should match that in CMakeLists.txt
BOOST_PYTHON_MODULE(CMakeCatchTemplatePython)
{
  boost::python::def("my_first_add_function", mp::MyFirstAddFunction);
}
<commit_msg>Issue #55: Fix missing namespace<commit_after>/*=============================================================================

  MYPROJECT: A software package for whatever.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.

=============================================================================*/
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>
#include "mpMyFunctions.h"
#include "mpException.h"

#include <ostream>
#include <sstream>

namespace mp {

void translate_exception(Exception const& e)
{
  std::ostringstream ss;
  ss << e.GetDescription();
  ss << " in file:" << e.GetFileName();
  ss << ", line:" << e.GetLineNumber();
  PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
}

// The name of the module should match that in CMakeLists.txt
BOOST_PYTHON_MODULE(CMakeCatchTemplatePython)
{
  boost::python::def("my_first_add_function", mp::MyFirstAddFunction);
}

}  // end namespace mp
<|endoftext|>


<commit_before>/**
 * Title:        CoreMIDI4J
 * Description:  Core MIDI Device Provider for Java on OS X
 * Copyright:    Copyright (c) 2015-2016
 * Company:      x.factory Librarians
 *
 * @author Derek Cook
 *
 * CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
 *
 * This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
 *
 * CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
 *
 */

#include "CoreMidiDeviceProvider.h"

/////////////////////////////////////////////////////////
// Native functions for CoreMidiDeviceProvider
/////////////////////////////////////////////////////////

/*
 * Gets the number of MIDI sources provided by the Core MIDI system
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getNumberOfSources
 * Signature: ()I
 *
 * @param env		The JNI environment
 * @param obj   The reference to the java object instance that called this native method
 *
 * @return      The number of MIDI sources provided by the Core MIDI system
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getNumberOfSources(JNIEnv *env, jobject obj) {

  return (jint) MIDIGetNumberOfSources();

}

/*
 * Gets the number of MIDI destinations provided by the Core MIDI system
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getNumberOfDestinations
 * Signature: ()I
 *
 * @param env    The JNI environment
 * @param obj    The reference to the java object instance that called this native method
 *
 * @return       The number of MIDI destinations provided by the Core MIDI system
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getNumberOfDestinations(JNIEnv *env, jobject obj) {

  return (jint) MIDIGetNumberOfDestinations();

}

/*
 * Gets the specified Core MIDI Source
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getSource
 * Signature: (I)I
 *
 * @param env            The JNI environment
 * @param obj            The reference to the java object instance that called this native method
 * @param sourceIndex    The index of the MIDI source to get
 *
 * @return               The specified Core MIDI Source
 *
 * @throws               CoreMidiEXception if the source index is not valid
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getSource(JNIEnv *env, jobject obj, jint sourceIndex) {

  if ( sourceIndex >= MIDIGetNumberOfSources() ) {

    ThrowException(env,CFSTR("MIDIGetSource"),sourceIndex);

  }

  return MIDIGetSource(sourceIndex);

}

/*
 * Gets the specified Core MIDI Destination
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getDestination
 * Signature: (I)I
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param destinationIndex      The index of the MIDI destination to get
 *
 * @return                      The specified Core MIDI Destination
 *
 * @throws                      CoreMidiEXception if the destination index is not valid
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getDestination(JNIEnv *env, jobject obj, jint destinationIndex) {

  if ( destinationIndex >= MIDIGetNumberOfDestinations() ) {

    ThrowException(env,CFSTR("MIDIGetDestination"), destinationIndex);

  }

  return MIDIGetDestination(destinationIndex);

}

/*
 * Gets the unique ID (UID) of the specified end point
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getUniqueID
 * Signature: (I)I
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param endPointReference     The end point reference
 *
 * @return                      The unique ID (UID) of the specified end point
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getUniqueID(JNIEnv *env, jobject obj, jint endPointReference) {

  SInt32 uid = 0;

  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyUniqueID, &uid);

  return uid;

}

/*
 * Safely obtains a C string pointer from a CFStringRef. We must do it this way, because CFStringGetCStringPtr
 * is free to return NULL for a variety of reasons, including simply not having an efficient way to respond.
 * However, this means that it is the responsibility of the caller to free() the returned pointer when it is
 * no longer needed, unless we returned NULL.
 *
 * @param aString  The CFStringRef
 *
 * @return         A newly allocated C string holding the contents of aString, or NULL
 *
 */
char * safeCFStringCopyUTF8String(CFStringRef aString) {
  if (aString == NULL) {
    return NULL;
  }

  CFIndex length = CFStringGetLength(aString);
  CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
  char *buffer = (char *)malloc(maxSize);
  if (CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) {
    return buffer;
  }
  free(buffer); // We failed
  return NULL;
}

/*
 * Safely prints a line describing a retrieved string for debugging purposes.
 * If the string is null, also reports that.
 *
 * @param label    Describes the string being printed
 * @param aString  The CFStringRef to be printed
 *
 */
// Uncomment this if you want to perform the (also commented out) debug printing in the function below.
//void debugPrintCFString(std::string label, CFStringRef aString) {
//  char *cString = safeCFStringCopyUTF8String(aString);
//  std::cout << label << ((cString != NULL)? cString : "<NULL pointer>") << std::endl;
//  free(cString);
//}

/*
 * Creates and gets a MidiDevice.Info object for the specified end point reference
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getMidiDeviceInfo
 * Signature: (I)Ljavax/sound/midi/MidiDevice/Info;
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param endPointReference     The end point reference
 *
 * @return                      A MidiDevice.Info object for the specified end point reference
 *
 */

JNIEXPORT jobject JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getMidiDeviceInfo(JNIEnv *env, jobject obj, jint endPointReference) {

  MIDIDeviceRef deviceReference       = NULL;
  CFStringRef   deviceName            = NULL;
  CFStringRef   deviceManufacturer    = NULL;
  CFStringRef   deviceModel           = NULL;
  SInt32        deviceOffline         = NULL;
  SInt32        deviceUniqueID        = 0;
  SInt32        deviceDriverVersion   = 0;

  MIDIEntityRef entityReference       = NULL;
  CFStringRef   entityName            = NULL;
  CFStringRef   entityManufacturer    = NULL;
  CFStringRef   entityModel           = NULL;
  SInt32        entityOffline         = NULL;
  SInt32        entityUniqueID        = 0;
  SInt32        entityDriverVersion   = 0;

  // End point reference is in method parameters
  CFStringRef   endpointName          = NULL;
  CFStringRef   endpointManufacturer  = NULL;
  CFStringRef   endpointModel         = NULL;
  SInt32        endpointOffline       = NULL;
  SInt32        endpointUniqueID      = 0;
  SInt32        endpointDriverVersion = 0;

  // Find the Java CoreMIDIDeviceInfo class and its constructor
  jclass javaClass = env->FindClass("uk/co/xfactorylibrarians/coremidi4j/CoreMidiDeviceInfo");
  jmethodID constructor = env->GetMethodID(javaClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;IILjava/lang/String;II)V");

  // Get the endpoint properties
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyName,          &endpointName);
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyModel,         &endpointModel);
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyManufacturer,  &endpointManufacturer);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyOffline,       &endpointOffline);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyUniqueID,      &endpointUniqueID);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyDriverVersion, &endpointDriverVersion);

  // Get the entity properties
  MIDIEndpointGetEntity(endPointReference, &entityReference);

  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyName,          &entityName);
  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyModel,         &entityModel);
  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyManufacturer,  &entityManufacturer);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyOffline,       &entityOffline);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyUniqueID,      &entityUniqueID);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyDriverVersion, &entityDriverVersion);

  // Get the device properties
  MIDIEntityGetDevice(entityReference, &deviceReference);

  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyName,          &deviceName); // Get this again in case our string build fails
  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyModel,         &deviceModel);
  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyManufacturer,  &deviceManufacturer);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyOffline,       &deviceOffline);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyUniqueID,      &deviceUniqueID);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyDriverVersion, &deviceDriverVersion);

  long numberOfEntities = MIDIDeviceGetNumberOfEntities(deviceReference);

// Uncomment these lines and debugPrintCFString (above) if you wish to view information as received on the native side during debugging.
//  std::cout << "End Point " << std::endl;
//  std::cout << "  End Point Reference                  " << endPointReference << std::endl;
//  debugPrintCFString("  End Point kMIDIPropertyName          ", endpointName);
//  debugPrintCFString("  End Point kMIDIPropertyModel         ", endpointModel);
//  debugPrintCFString("  End Point kMIDIPropertyManufacturer  ", endpointManufacturer);
//  std::cout << "  End Point kMIDIPropertyOffline       " << endpointOffline << std::endl;
//  std::cout << "  End Point kMIDIPropertyUniqueID      " << endpointUniqueID << std::endl;
//  std::cout << "  End Point kMIDIPropertyDriverVersion " << endpointDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Entity    Reference                  " << entityReference << std::endl;
//  debugPrintCFString("  Entity    kMIDIPropertyName          ", entityName);
//  debugPrintCFString("  Entity    kMIDIPropertyModel         ", entityModel);
//  debugPrintCFString("  Entity    kMIDIPropertyManufacturer  ", entityManufacturer);
//  std::cout << "  Entity    kMIDIPropertyOffline       " << entityOffline << std::endl;
//  std::cout << "  Entity    kMIDIPropertyUniqueID      " << entityUniqueID << std::endl;
//  std::cout << "  Entity    kMIDIPropertyDriverVersion " << entityDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Device    Reference                  " << deviceReference << std::endl;
//  debugPrintCFString("  Device    kMIDIPropertyName          ", deviceName);
//  debugPrintCFString("  Device    kMIDIPropertyModel         ", deviceModel);
//  debugPrintCFString("  Device    kMIDIPropertyManufacturer  ", deviceManufacturer);
//  std::cout << "  Device    kMIDIPropertyOffline       " << deviceOffline << std::endl;
//  std::cout << "  Device    kMIDIPropertyUniqueID      " << deviceUniqueID << std::endl;
//  std::cout << "  Device    kMIDIPropertyDriverVersion " << deviceDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Number of entities                   " << numberOfEntities << std::endl;
//  std::cout << std::endl;

  // Build the Device Info name. Add "CoreMIDI4J - " to the start of our device name if we can
  // And if the device has more than one entity then add the entity name
  CFMutableStringRef buildName = CFStringCreateMutable(NULL, 0);
  CFStringRef deviceInfoName;

  if ( buildName != NULL ) {

    if ( deviceName != NULL ) {

      CFStringAppend(buildName, (deviceName != NULL ) ? deviceName :  CFSTR("<Unknown Device>") );

      if ( numberOfEntities > 1 ) {

        CFStringAppend(buildName, CFSTR(" "));
        CFStringAppend(buildName, (endpointName != NULL ) ? endpointName :  CFSTR("<Unknown Endpoint>") );

      }

    } else {

      CFStringAppend(buildName, (endpointName != NULL ) ? endpointName :  CFSTR("<Unknown Device>") );

    }

    // Overwrite the deviceName with our updated one
    deviceInfoName = CFStringCreateCopy(NULL, buildName);

    // And release the temporary string
    CFRelease(buildName);

  } else {

    // Overwrite the deviceName with our updated one
    deviceInfoName = CFStringCreateCopy(NULL, deviceName);

  }

  char *deviceInfoNamePtr         = safeCFStringCopyUTF8String ( deviceInfoName );
  char *deviceInfoManufacturerPtr = safeCFStringCopyUTF8String ( endpointManufacturer ); // The end point manufacturer name is always present
  char *deviceInfoDescriptionPtr  = safeCFStringCopyUTF8String ( endpointModel );        // The end point model name is always present

  char *deviceNamePtr             = safeCFStringCopyUTF8String ( deviceName );
  char *entityNamePtr             = safeCFStringCopyUTF8String ( entityName );
  char *endPointNamePtr           = safeCFStringCopyUTF8String ( endpointName );

  // TODO - Have seen reference that the device neds to be initialised to get the version. As we are still getting zero, force the string for now
  const char *deviceInfoVersion         = "Unknown Version";

  // Create the Java Object
  jobject info = env->NewObject(javaClass,
                                constructor,
                                env->NewStringUTF(( deviceInfoNamePtr         != NULL ) ? deviceInfoNamePtr         : "<Unknown Device>"),
                                env->NewStringUTF(( deviceInfoManufacturerPtr != NULL ) ? deviceInfoManufacturerPtr : "<Unknown Manufacturer>"),
                                env->NewStringUTF(( deviceInfoDescriptionPtr  != NULL ) ? deviceInfoDescriptionPtr  : "<Unknown Description>"),
                                env->NewStringUTF(deviceInfoVersion),
                                env->NewStringUTF( ( deviceNamePtr != NULL ) ? deviceNamePtr : "<Unknown Device>"),
                                deviceReference,
                                deviceUniqueID,
                                env->NewStringUTF( ( entityNamePtr != NULL) ? entityNamePtr : "<Unknown Entity>"),
                                entityReference,
                                entityUniqueID,
                                env->NewStringUTF( ( endPointNamePtr != NULL ) ? endPointNamePtr : "<Unknown Endpoint>"),
                                endPointReference,
                                endpointUniqueID);

  free(deviceInfoNamePtr);
  free(deviceInfoManufacturerPtr);
  free(deviceInfoDescriptionPtr);
  free(deviceNamePtr);
  free(entityNamePtr);
  free(endPointNamePtr);

  return info;

}
<commit_msg>Use system encoding, don't assume UTF-8, #29<commit_after>/**
 * Title:        CoreMIDI4J
 * Description:  Core MIDI Device Provider for Java on OS X
 * Copyright:    Copyright (c) 2015-2016
 * Company:      x.factory Librarians
 *
 * @author Derek Cook
 *
 * CoreMIDI4J is an open source Service Provider Interface for supporting external MIDI devices on MAC OS X
 *
 * This file is part of the XCODE project that provides the native implementation of CoreMIDI4J
 *
 * CREDITS - This library uses principles established by OSXMIDI4J, but converted so it operates at the JNI level with no additional libraries required
 *
 */

#include "CoreMidiDeviceProvider.h"

/////////////////////////////////////////////////////////
// Native functions for CoreMidiDeviceProvider
/////////////////////////////////////////////////////////

/*
 * Gets the number of MIDI sources provided by the Core MIDI system
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getNumberOfSources
 * Signature: ()I
 *
 * @param env		The JNI environment
 * @param obj   The reference to the java object instance that called this native method
 *
 * @return      The number of MIDI sources provided by the Core MIDI system
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getNumberOfSources(JNIEnv *env, jobject obj) {

  return (jint) MIDIGetNumberOfSources();

}

/*
 * Gets the number of MIDI destinations provided by the Core MIDI system
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getNumberOfDestinations
 * Signature: ()I
 *
 * @param env    The JNI environment
 * @param obj    The reference to the java object instance that called this native method
 *
 * @return       The number of MIDI destinations provided by the Core MIDI system
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getNumberOfDestinations(JNIEnv *env, jobject obj) {

  return (jint) MIDIGetNumberOfDestinations();

}

/*
 * Gets the specified Core MIDI Source
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getSource
 * Signature: (I)I
 *
 * @param env            The JNI environment
 * @param obj            The reference to the java object instance that called this native method
 * @param sourceIndex    The index of the MIDI source to get
 *
 * @return               The specified Core MIDI Source
 *
 * @throws               CoreMidiEXception if the source index is not valid
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getSource(JNIEnv *env, jobject obj, jint sourceIndex) {

  if ( sourceIndex >= MIDIGetNumberOfSources() ) {

    ThrowException(env,CFSTR("MIDIGetSource"),sourceIndex);

  }

  return MIDIGetSource(sourceIndex);

}

/*
 * Gets the specified Core MIDI Destination
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getDestination
 * Signature: (I)I
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param destinationIndex      The index of the MIDI destination to get
 *
 * @return                      The specified Core MIDI Destination
 *
 * @throws                      CoreMidiEXception if the destination index is not valid
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getDestination(JNIEnv *env, jobject obj, jint destinationIndex) {

  if ( destinationIndex >= MIDIGetNumberOfDestinations() ) {

    ThrowException(env,CFSTR("MIDIGetDestination"), destinationIndex);

  }

  return MIDIGetDestination(destinationIndex);

}

/*
 * Gets the unique ID (UID) of the specified end point
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getUniqueID
 * Signature: (I)I
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param endPointReference     The end point reference
 *
 * @return                      The unique ID (UID) of the specified end point
 *
 */

JNIEXPORT jint JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getUniqueID(JNIEnv *env, jobject obj, jint endPointReference) {

  SInt32 uid = 0;

  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyUniqueID, &uid);

  return uid;

}

/*
 * Safely obtains a C string pointer from a CFStringRef. We must do it this way, because CFStringGetCStringPtr
 * is free to return NULL for a variety of reasons, including simply not having an efficient way to respond.
 * However, this means that it is the responsibility of the caller to free() the returned pointer when it is
 * no longer needed, unless we returned NULL.
 *
 * @param aString  The CFStringRef
 *
 * @return         A newly allocated C string holding the contents of aString, or NULL
 *
 */
char * safeCFStringCopyToC(CFStringRef aString) {
  if (aString == NULL) {
    return NULL;
  }

  CFIndex length = CFStringGetLength(aString);
  CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, CFStringGetSystemEncoding()) + 1;
  char *buffer = (char *)malloc(maxSize);
  if (CFStringGetCString(aString, buffer, maxSize, CFStringGetSystemEncoding())) {
    return buffer;
  }
  free(buffer); // We failed
  return NULL;
}

/*
 * Safely prints a line describing a retrieved string for debugging purposes.
 * If the string is null, also reports that.
 *
 * @param label    Describes the string being printed
 * @param aString  The CFStringRef to be printed
 *
 */
// Uncomment this if you want to perform the (also commented out) debug printing in the function below.
//void debugPrintCFString(std::string label, CFStringRef aString) {
//  char *cString = safeCFStringCopyUTF8String(aString);
//  std::cout << label << ((cString != NULL)? cString : "<NULL pointer>") << std::endl;
//  free(cString);
//}

/*
 * Creates and gets a MidiDevice.Info object for the specified end point reference
 *
 * Class:     com_coremidi4j_CoreMidiDeviceProvider
 * Method:    getMidiDeviceInfo
 * Signature: (I)Ljavax/sound/midi/MidiDevice/Info;
 *
 * @param env                   The JNI environment
 * @param obj                   The reference to the java object instance that called this native method
 * @param endPointReference     The end point reference
 *
 * @return                      A MidiDevice.Info object for the specified end point reference
 *
 */

JNIEXPORT jobject JNICALL Java_uk_co_xfactorylibrarians_coremidi4j_CoreMidiDeviceProvider_getMidiDeviceInfo(JNIEnv *env, jobject obj, jint endPointReference) {

  MIDIDeviceRef deviceReference       = NULL;
  CFStringRef   deviceName            = NULL;
  CFStringRef   deviceManufacturer    = NULL;
  CFStringRef   deviceModel           = NULL;
  SInt32        deviceOffline         = NULL;
  SInt32        deviceUniqueID        = 0;
  SInt32        deviceDriverVersion   = 0;

  MIDIEntityRef entityReference       = NULL;
  CFStringRef   entityName            = NULL;
  CFStringRef   entityManufacturer    = NULL;
  CFStringRef   entityModel           = NULL;
  SInt32        entityOffline         = NULL;
  SInt32        entityUniqueID        = 0;
  SInt32        entityDriverVersion   = 0;

  // End point reference is in method parameters
  CFStringRef   endpointName          = NULL;
  CFStringRef   endpointManufacturer  = NULL;
  CFStringRef   endpointModel         = NULL;
  SInt32        endpointOffline       = NULL;
  SInt32        endpointUniqueID      = 0;
  SInt32        endpointDriverVersion = 0;

  // Find the Java CoreMIDIDeviceInfo class and its constructor
  jclass javaClass = env->FindClass("uk/co/xfactorylibrarians/coremidi4j/CoreMidiDeviceInfo");
  jmethodID constructor = env->GetMethodID(javaClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;IILjava/lang/String;II)V");

  // Get the endpoint properties
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyName,          &endpointName);
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyModel,         &endpointModel);
  MIDIObjectGetStringProperty (endPointReference, kMIDIPropertyManufacturer,  &endpointManufacturer);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyOffline,       &endpointOffline);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyUniqueID,      &endpointUniqueID);
  MIDIObjectGetIntegerProperty(endPointReference, kMIDIPropertyDriverVersion, &endpointDriverVersion);

  // Get the entity properties
  MIDIEndpointGetEntity(endPointReference, &entityReference);

  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyName,          &entityName);
  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyModel,         &entityModel);
  MIDIObjectGetStringProperty (entityReference, kMIDIPropertyManufacturer,  &entityManufacturer);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyOffline,       &entityOffline);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyUniqueID,      &entityUniqueID);
  MIDIObjectGetIntegerProperty(entityReference, kMIDIPropertyDriverVersion, &entityDriverVersion);

  // Get the device properties
  MIDIEntityGetDevice(entityReference, &deviceReference);

  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyName,          &deviceName); // Get this again in case our string build fails
  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyModel,         &deviceModel);
  MIDIObjectGetStringProperty (deviceReference, kMIDIPropertyManufacturer,  &deviceManufacturer);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyOffline,       &deviceOffline);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyUniqueID,      &deviceUniqueID);
  MIDIObjectGetIntegerProperty(deviceReference, kMIDIPropertyDriverVersion, &deviceDriverVersion);

  long numberOfEntities = MIDIDeviceGetNumberOfEntities(deviceReference);

// Uncomment these lines and debugPrintCFString (above) if you wish to view information as received on the native side during debugging.
//  std::cout << "End Point " << std::endl;
//  std::cout << "  End Point Reference                  " << endPointReference << std::endl;
//  debugPrintCFString("  End Point kMIDIPropertyName          ", endpointName);
//  debugPrintCFString("  End Point kMIDIPropertyModel         ", endpointModel);
//  debugPrintCFString("  End Point kMIDIPropertyManufacturer  ", endpointManufacturer);
//  std::cout << "  End Point kMIDIPropertyOffline       " << endpointOffline << std::endl;
//  std::cout << "  End Point kMIDIPropertyUniqueID      " << endpointUniqueID << std::endl;
//  std::cout << "  End Point kMIDIPropertyDriverVersion " << endpointDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Entity    Reference                  " << entityReference << std::endl;
//  debugPrintCFString("  Entity    kMIDIPropertyName          ", entityName);
//  debugPrintCFString("  Entity    kMIDIPropertyModel         ", entityModel);
//  debugPrintCFString("  Entity    kMIDIPropertyManufacturer  ", entityManufacturer);
//  std::cout << "  Entity    kMIDIPropertyOffline       " << entityOffline << std::endl;
//  std::cout << "  Entity    kMIDIPropertyUniqueID      " << entityUniqueID << std::endl;
//  std::cout << "  Entity    kMIDIPropertyDriverVersion " << entityDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Device    Reference                  " << deviceReference << std::endl;
//  debugPrintCFString("  Device    kMIDIPropertyName          ", deviceName);
//  debugPrintCFString("  Device    kMIDIPropertyModel         ", deviceModel);
//  debugPrintCFString("  Device    kMIDIPropertyManufacturer  ", deviceManufacturer);
//  std::cout << "  Device    kMIDIPropertyOffline       " << deviceOffline << std::endl;
//  std::cout << "  Device    kMIDIPropertyUniqueID      " << deviceUniqueID << std::endl;
//  std::cout << "  Device    kMIDIPropertyDriverVersion " << deviceDriverVersion << std::endl;
//  std::cout << std::endl;
//  std::cout << "  Number of entities                   " << numberOfEntities << std::endl;
//  std::cout << std::endl;

  // Build the Device Info name. Add "CoreMIDI4J - " to the start of our device name if we can
  // And if the device has more than one entity then add the entity name
  CFMutableStringRef buildName = CFStringCreateMutable(NULL, 0);
  CFStringRef deviceInfoName;

  if ( buildName != NULL ) {

    if ( deviceName != NULL ) {

      CFStringAppend(buildName, (deviceName != NULL ) ? deviceName :  CFSTR("<Unknown Device>") );

      if ( numberOfEntities > 1 ) {

        CFStringAppend(buildName, CFSTR(" "));
        CFStringAppend(buildName, (endpointName != NULL ) ? endpointName :  CFSTR("<Unknown Endpoint>") );

      }

    } else {

      CFStringAppend(buildName, (endpointName != NULL ) ? endpointName :  CFSTR("<Unknown Device>") );

    }

    // Overwrite the deviceName with our updated one
    deviceInfoName = CFStringCreateCopy(NULL, buildName);

    // And release the temporary string
    CFRelease(buildName);

  } else {

    // Overwrite the deviceName with our updated one
    deviceInfoName = CFStringCreateCopy(NULL, deviceName);

  }

  char *deviceInfoNamePtr         = safeCFStringCopyToC ( deviceInfoName );
  char *deviceInfoManufacturerPtr = safeCFStringCopyToC ( endpointManufacturer ); // The end point manufacturer name is always present
  char *deviceInfoDescriptionPtr  = safeCFStringCopyToC ( endpointModel );        // The end point model name is always present

  char *deviceNamePtr             = safeCFStringCopyToC ( deviceName );
  char *entityNamePtr             = safeCFStringCopyToC ( entityName );
  char *endPointNamePtr           = safeCFStringCopyToC ( endpointName );

  // TODO - Have seen reference that the device neds to be initialised to get the version. As we are still getting zero, force the string for now
  const char *deviceInfoVersion         = "Unknown Version";

  // Create the Java Object
  jobject info = env->NewObject(javaClass,
                                constructor,
                                env->NewStringUTF(( deviceInfoNamePtr         != NULL ) ? deviceInfoNamePtr         : "<Unknown Device>"),
                                env->NewStringUTF(( deviceInfoManufacturerPtr != NULL ) ? deviceInfoManufacturerPtr : "<Unknown Manufacturer>"),
                                env->NewStringUTF(( deviceInfoDescriptionPtr  != NULL ) ? deviceInfoDescriptionPtr  : "<Unknown Description>"),
                                env->NewStringUTF(deviceInfoVersion),
                                env->NewStringUTF( ( deviceNamePtr != NULL ) ? deviceNamePtr : "<Unknown Device>"),
                                deviceReference,
                                deviceUniqueID,
                                env->NewStringUTF( ( entityNamePtr != NULL) ? entityNamePtr : "<Unknown Entity>"),
                                entityReference,
                                entityUniqueID,
                                env->NewStringUTF( ( endPointNamePtr != NULL ) ? endPointNamePtr : "<Unknown Endpoint>"),
                                endPointReference,
                                endpointUniqueID);

  free(deviceInfoNamePtr);
  free(deviceInfoManufacturerPtr);
  free(deviceInfoDescriptionPtr);
  free(deviceNamePtr);
  free(entityNamePtr);
  free(endPointNamePtr);

  return info;

}
<|endoftext|>


<commit_before>/*
* (C) 2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_PSK_DB)

#include <botan/psk_db.h>

#if defined(BOTAN_HAS_SQLITE3)
  #include <botan/psk_db_sql.h>
  #include <botan/sqlite3.h>
#endif

namespace Botan_Tests {

namespace {

class Test_Map_PSK_Db : public Botan::Encrypted_PSK_Database
   {
   public:
      Test_Map_PSK_Db(const Botan::secure_vector<uint8_t>& master_key) :
         Botan::Encrypted_PSK_Database(master_key)
         {}

      void test_entry(Test::Result& result,
                      const std::string& index, const std::string& value)
         {
         auto i = m_vals.find(index);

         if(i == m_vals.end())
            {
            result.test_failure("Expected to find encrypted name " + index);
            }
         else
            {
            result.test_eq("Encrypted value", i->second, value);
            }
         }

      void kv_set(const std::string& index, const std::string& value) override
         {
         m_vals[index] = value;
         }

      std::string kv_get(const std::string& index) const override
         {
         auto i = m_vals.find(index);
         if(i == m_vals.end())
            return "";
         return i->second;
         }

      void kv_del(const std::string& index) override
         {
         auto i = m_vals.find(index);
         if(i != m_vals.end())
            {
            m_vals.erase(i);
            }
         }

      std::set<std::string> kv_get_all() const override
         {
         std::set<std::string> names;

         for(auto kv : m_vals)
            {
            names.insert(kv.first);
            }

         return names;
         }

   private:
      std::map<std::string, std::string> m_vals;
   };

}

class PSK_DB_Tests final : public Test
   {
   public:

      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         results.push_back(test_psk_db());

#if defined(BOTAN_HAS_SQLITE3)
         results.push_back(test_psk_sql_db());
#endif

         return results;
         }

   private:

      Test::Result test_psk_db()
         {
         Test::Result result("PSK_DB");

         const Botan::secure_vector<uint8_t> zeros(32);
         Test_Map_PSK_Db db(zeros);

         db.set_str("name", "value");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name", "value1");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "7R8am3x/gLawOzMp5WwIJg==");
         result.test_eq("DB read", db.get_str("name"), "value1");

         db.set_str("name", "value");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name2", "value");
         db.test_entry(result, "7CvsM7HDCZsV6VsFwWylNg==", "BqVQo4rdwOmf+ItCzEmjAg==");
         result.test_eq("DB read", db.get_str("name2"), "value");

         db.set_vec("name2", zeros);
         db.test_entry(result, "7CvsM7HDCZsV6VsFwWylNg==", "x+I1bUF/fJYPOTvKwOihEPWGR1XGzVuyRdsw4n5gpBRzNR7LjH7vjw==");
         result.test_eq("DB read", db.get("name2"), zeros);

         // Test longer names
         db.set_str("leroy jeeeeeeeenkins", "chicken");
         db.test_entry(result, "KyYo272vlSjClM2F0OZBMlRYjr33ZXv2jN1oY8OfCEs=", "tCl1qShSTsXi9tA5Kpo9vg==");
         result.test_eq("DB read", db.get_str("leroy jeeeeeeeenkins"), "chicken");

         std::set<std::string> all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 3);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("name2"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         db.remove("name2");

         all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 2);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         result.test_throws("exception if get called on non-existent PSK",
                            "Invalid argument Named PSK not located",
                            [&]() { db.get("name2"); });

         // test that redundant remove calls accepted
         db.remove("name2");

         return result;
         }

#if defined(BOTAN_HAS_SQLITE3)

      void test_entry(Test::Result& result,
                      std::shared_ptr<Botan::SQL_Database> db,
                      const std::string& table,
                      const std::string& expected_name,
                      const std::string& expected_value)
         {
         auto stmt = db->new_statement("select psk_value from " + table + " where psk_name='" + expected_name + "'");

         bool got_it = stmt->step();
         result.confirm("Had expected name", got_it);

         if(got_it)
            {
            result.test_eq("Had expected value", stmt->get_str(0), expected_value);
            }
         }

      Test::Result test_psk_sql_db()
         {
         Test::Result result("PSK_DB SQL");

         const Botan::secure_vector<uint8_t> zeros(32);
         const std::string table_name = "bobby";
         std::shared_ptr<Botan::SQL_Database> sqldb = std::make_shared<Botan::Sqlite3_Database>(":memory:");

         Botan::Encrypted_PSK_Database_SQL db(zeros, sqldb, table_name);
         db.set_str("name", "value");

         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name", "value1");
         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "7R8am3x/gLawOzMp5WwIJg==");
         result.test_eq("DB read", db.get_str("name"), "value1");

         db.set_str("name", "value");
         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name2", "value");
         test_entry(result, sqldb, table_name, "7CvsM7HDCZsV6VsFwWylNg==", "BqVQo4rdwOmf+ItCzEmjAg==");
         result.test_eq("DB read", db.get_str("name2"), "value");

         db.set_vec("name2", zeros);
         test_entry(result, sqldb, table_name, "7CvsM7HDCZsV6VsFwWylNg==", "x+I1bUF/fJYPOTvKwOihEPWGR1XGzVuyRdsw4n5gpBRzNR7LjH7vjw==");
         result.test_eq("DB read", db.get("name2"), zeros);

         // Test longer names
         db.set_str("leroy jeeeeeeeenkins", "chicken");
         test_entry(result, sqldb, table_name, "KyYo272vlSjClM2F0OZBMlRYjr33ZXv2jN1oY8OfCEs=", "tCl1qShSTsXi9tA5Kpo9vg==");
         result.test_eq("DB read", db.get_str("leroy jeeeeeeeenkins"), "chicken");

         std::set<std::string> all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 3);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("name2"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         db.remove("name2");

         all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 2);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         result.test_throws("exception if get called on non-existent PSK",
                            "Invalid argument Named PSK not located",
                            [&]() { db.get("name2"); });

         // test that redundant remove calls accepted
         db.remove("name2");

         return result;
         }
#endif

   };

BOTAN_REGISTER_TEST("psk_db", PSK_DB_Tests);

}

#endif
<commit_msg>Add a test for distinct master keys in a single PSK_DB<commit_after>/*
* (C) 2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_PSK_DB)

#include <botan/psk_db.h>

#if defined(BOTAN_HAS_SQLITE3)
  #include <botan/psk_db_sql.h>
  #include <botan/sqlite3.h>
#endif

namespace Botan_Tests {

namespace {

class Test_Map_PSK_Db : public Botan::Encrypted_PSK_Database
   {
   public:
      Test_Map_PSK_Db(const Botan::secure_vector<uint8_t>& master_key) :
         Botan::Encrypted_PSK_Database(master_key)
         {}

      void test_entry(Test::Result& result,
                      const std::string& index, const std::string& value)
         {
         auto i = m_vals.find(index);

         if(i == m_vals.end())
            {
            result.test_failure("Expected to find encrypted name " + index);
            }
         else
            {
            result.test_eq("Encrypted value", i->second, value);
            }
         }

      void kv_set(const std::string& index, const std::string& value) override
         {
         m_vals[index] = value;
         }

      std::string kv_get(const std::string& index) const override
         {
         auto i = m_vals.find(index);
         if(i == m_vals.end())
            return "";
         return i->second;
         }

      void kv_del(const std::string& index) override
         {
         auto i = m_vals.find(index);
         if(i != m_vals.end())
            {
            m_vals.erase(i);
            }
         }

      std::set<std::string> kv_get_all() const override
         {
         std::set<std::string> names;

         for(auto kv : m_vals)
            {
            names.insert(kv.first);
            }

         return names;
         }

   private:
      std::map<std::string, std::string> m_vals;
   };

}

class PSK_DB_Tests final : public Test
   {
   public:

      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         results.push_back(test_psk_db());

#if defined(BOTAN_HAS_SQLITE3)
         results.push_back(test_psk_sql_db());
#endif

         return results;
         }

   private:

      Test::Result test_psk_db()
         {
         Test::Result result("PSK_DB");

         const Botan::secure_vector<uint8_t> zeros(32);
         Test_Map_PSK_Db db(zeros);

         db.set_str("name", "value");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name", "value1");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "7R8am3x/gLawOzMp5WwIJg==");
         result.test_eq("DB read", db.get_str("name"), "value1");

         db.set_str("name", "value");
         db.test_entry(result, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name2", "value");
         db.test_entry(result, "7CvsM7HDCZsV6VsFwWylNg==", "BqVQo4rdwOmf+ItCzEmjAg==");
         result.test_eq("DB read", db.get_str("name2"), "value");

         db.set_vec("name2", zeros);
         db.test_entry(result, "7CvsM7HDCZsV6VsFwWylNg==", "x+I1bUF/fJYPOTvKwOihEPWGR1XGzVuyRdsw4n5gpBRzNR7LjH7vjw==");
         result.test_eq("DB read", db.get("name2"), zeros);

         // Test longer names
         db.set_str("leroy jeeeeeeeenkins", "chicken");
         db.test_entry(result, "KyYo272vlSjClM2F0OZBMlRYjr33ZXv2jN1oY8OfCEs=", "tCl1qShSTsXi9tA5Kpo9vg==");
         result.test_eq("DB read", db.get_str("leroy jeeeeeeeenkins"), "chicken");

         std::set<std::string> all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 3);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("name2"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         db.remove("name2");

         all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 2);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         result.test_throws("exception if get called on non-existent PSK",
                            "Invalid argument Named PSK not located",
                            [&]() { db.get("name2"); });

         // test that redundant remove calls accepted
         db.remove("name2");

         return result;
         }

#if defined(BOTAN_HAS_SQLITE3)

      void test_entry(Test::Result& result,
                      std::shared_ptr<Botan::SQL_Database> db,
                      const std::string& table,
                      const std::string& expected_name,
                      const std::string& expected_value)
         {
         auto stmt = db->new_statement("select psk_value from " + table + " where psk_name='" + expected_name + "'");

         bool got_it = stmt->step();
         result.confirm("Had expected name", got_it);

         if(got_it)
            {
            result.test_eq("Had expected value", stmt->get_str(0), expected_value);
            }
         }

      Test::Result test_psk_sql_db()
         {
         Test::Result result("PSK_DB SQL");

         const Botan::secure_vector<uint8_t> zeros(32);
         const Botan::secure_vector<uint8_t> not_zeros = Test::rng().random_vec(32);

         const std::string table_name = "bobby";
         std::shared_ptr<Botan::SQL_Database> sqldb = std::make_shared<Botan::Sqlite3_Database>(":memory:");

         Botan::Encrypted_PSK_Database_SQL db(zeros, sqldb, table_name);
         db.set_str("name", "value");

         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name", "value1");
         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "7R8am3x/gLawOzMp5WwIJg==");
         result.test_eq("DB read", db.get_str("name"), "value1");

         db.set_str("name", "value");
         test_entry(result, sqldb, table_name, "CUCJjJgWSa079ubutJQwlw==", "clYJSAf9CThuL96CP+rAfA==");
         result.test_eq("DB read", db.get_str("name"), "value");

         db.set_str("name2", "value");
         test_entry(result, sqldb, table_name, "7CvsM7HDCZsV6VsFwWylNg==", "BqVQo4rdwOmf+ItCzEmjAg==");
         result.test_eq("DB read", db.get_str("name2"), "value");

         db.set_vec("name2", zeros);
         test_entry(result, sqldb, table_name, "7CvsM7HDCZsV6VsFwWylNg==", "x+I1bUF/fJYPOTvKwOihEPWGR1XGzVuyRdsw4n5gpBRzNR7LjH7vjw==");
         result.test_eq("DB read", db.get("name2"), zeros);

         // Test longer names
         db.set_str("leroy jeeeeeeeenkins", "chicken");
         test_entry(result, sqldb, table_name, "KyYo272vlSjClM2F0OZBMlRYjr33ZXv2jN1oY8OfCEs=", "tCl1qShSTsXi9tA5Kpo9vg==");
         result.test_eq("DB read", db.get_str("leroy jeeeeeeeenkins"), "chicken");

         /*
         * Test that we can have another database in the same table with distinct key
         * without any problems.
         */
         Botan::Encrypted_PSK_Database_SQL db2(not_zeros, sqldb, table_name);
         db2.set_str("name", "price&value");
         result.test_eq("DB read", db2.get_str("name"), "price&value");
         result.test_eq("DB2 size", db2.list_names().size(), 1);

         std::set<std::string> all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 3);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("name2"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         db.remove("name2");

         all_names = db.list_names();

         result.test_eq("Expected number of names", all_names.size(), 2);
         result.test_eq("Have expected name", all_names.count("name"), 1);
         result.test_eq("Have expected name", all_names.count("leroy jeeeeeeeenkins"), 1);

         result.test_throws("exception if get called on non-existent PSK",
                            "Invalid argument Named PSK not located",
                            [&]() { db.get("name2"); });

         // test that redundant remove calls accepted
         db.remove("name2");

         return result;
         }
#endif

   };

BOTAN_REGISTER_TEST("psk_db", PSK_DB_Tests);

}

#endif
<|endoftext|>


<commit_before>#include "../test.h"
#include <cstdio>

extern "C" {

#include "udp-json-parser/json.h"
#include "udp-json-builder/json-builder.h"

} // extern "C"

static void GenStat(Stat* s, const json_value* v) {
    switch (v->type) {
    case json_object:
        for (size_t i = 0; i < v->u.object.length; i++) {
            const json_object_entry* e = v->u.object.values + i;
            GenStat(s, e->value);
            s->stringLength += e->name_length;
        }
        s->stringCount += v->u.object.length;
        s->memberCount += v->u.object.length;
        s->objectCount++;
        break;

    case json_array:
        for (size_t i = 0; i < v->u.array.length; i++)
            GenStat(s, v->u.array.values[i]);
        s->arrayCount++;
        s->elementCount += v->u.array.length;
        break;

    case json_string:
        s->stringCount++;
        s->stringLength += v->u.string.length;
        break;

    case json_integer:
    case json_double:
        s->numberCount++;
        break;

    case json_boolean:
        if (v->u.boolean)
            s->trueCount++;
        else
            s->falseCount++;
        break;

    case json_null:
        s->nullCount++;
        break;
    }
}

class UdpjsonParseResult : public ParseResultBase {
public:
    UdpjsonParseResult() : root() {}
    ~UdpjsonParseResult() { json_value_free(root); }

    json_value *root;
};

class UdpjsonStringResult : public StringResultBase {
public:
    UdpjsonStringResult() : s() {}
    ~UdpjsonStringResult() { free(s); }

    virtual const char* c_str() const { return s; }

    char* s;
};

class UdpjsonTest : public TestBase {
public:
    UdpjsonTest() : TestBase("udp/json-parser|builder") {
	}

    virtual ParseResultBase* Parse(const char* json, size_t length) const {
        UdpjsonParseResult* pr = new UdpjsonParseResult;
        json_settings settings = {};
        settings.value_extra = json_builder_extra;  /* space for json-builder state */
        char error[128];
        pr->root = json_parse_ex(&settings, json, length, error);
        if (!pr->root) {
            delete pr;
            return 0;
        }
    	return pr;
    }

    // Very slow in the current version.
#if 0
    virtual StringResultBase* Stringify(const ParseResultBase* parseResult) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        UdpjsonStringResult* sr = new UdpjsonStringResult;
        json_serialize_opts opts = { json_serialize_mode_packed, 0, 0 };
        sr->s = (char*)malloc(json_measure_ex(pr->root, opts));
        json_serialize_ex(sr->s, pr->root, opts);
        return sr;
    }

    virtual StringResultBase* Prettify(const ParseResultBase* parseResult) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        UdpjsonStringResult* sr = new UdpjsonStringResult;
        json_serialize_opts opts = { json_serialize_mode_multiline, 0, 4 };
        sr->s = (char*)malloc(json_measure_ex(pr->root, opts));
        json_serialize_ex(sr->s, pr->root, opts);
        return sr;
    }
#endif

    virtual bool Statistics(const ParseResultBase* parseResult, Stat* stat) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        memset(stat, 0, sizeof(Stat));
        GenStat(stat, pr->root);
        return true;
    }
};

REGISTER_TEST(UdpjsonTest);
<commit_msg>Clean up<commit_after>#include "../test.h"

extern "C" {

#include "udp-json-parser/json.h"
#include "udp-json-builder/json-builder.h"

} // extern "C"

static void GenStat(Stat* s, const json_value* v) {
    switch (v->type) {
    case json_object:
        for (size_t i = 0; i < v->u.object.length; i++) {
            const json_object_entry* e = v->u.object.values + i;
            GenStat(s, e->value);
            s->stringLength += e->name_length;
        }
        s->stringCount += v->u.object.length;
        s->memberCount += v->u.object.length;
        s->objectCount++;
        break;

    case json_array:
        for (size_t i = 0; i < v->u.array.length; i++)
            GenStat(s, v->u.array.values[i]);
        s->arrayCount++;
        s->elementCount += v->u.array.length;
        break;

    case json_string:
        s->stringCount++;
        s->stringLength += v->u.string.length;
        break;

    case json_integer:
    case json_double:
        s->numberCount++;
        break;

    case json_boolean:
        if (v->u.boolean)
            s->trueCount++;
        else
            s->falseCount++;
        break;

    case json_null:
        s->nullCount++;
        break;
    }
}

class UdpjsonParseResult : public ParseResultBase {
public:
    UdpjsonParseResult() : root() {}
    ~UdpjsonParseResult() { json_value_free(root); }

    json_value *root;
};

class UdpjsonStringResult : public StringResultBase {
public:
    UdpjsonStringResult() : s() {}
    ~UdpjsonStringResult() { free(s); }

    virtual const char* c_str() const { return s; }

    char* s;
};

class UdpjsonTest : public TestBase {
public:
    UdpjsonTest() : TestBase("udp/json-parser|builder") {
	}

    virtual ParseResultBase* Parse(const char* json, size_t length) const {
        UdpjsonParseResult* pr = new UdpjsonParseResult;
        json_settings settings = {};
        settings.value_extra = json_builder_extra;  /* space for json-builder state */
        char error[128];
        pr->root = json_parse_ex(&settings, json, length, error);
        if (!pr->root) {
            delete pr;
            return 0;
        }
    	return pr;
    }

    // Very slow in the current version.
#if 0
    virtual StringResultBase* Stringify(const ParseResultBase* parseResult) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        UdpjsonStringResult* sr = new UdpjsonStringResult;
        json_serialize_opts opts = { json_serialize_mode_packed, 0, 0 };
        sr->s = (char*)malloc(json_measure_ex(pr->root, opts));
        json_serialize_ex(sr->s, pr->root, opts);
        return sr;
    }

    virtual StringResultBase* Prettify(const ParseResultBase* parseResult) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        UdpjsonStringResult* sr = new UdpjsonStringResult;
        json_serialize_opts opts = { json_serialize_mode_multiline, 0, 4 };
        sr->s = (char*)malloc(json_measure_ex(pr->root, opts));
        json_serialize_ex(sr->s, pr->root, opts);
        return sr;
    }
#endif

    virtual bool Statistics(const ParseResultBase* parseResult, Stat* stat) const {
        const UdpjsonParseResult* pr = static_cast<const UdpjsonParseResult*>(parseResult);
        memset(stat, 0, sizeof(Stat));
        GenStat(stat, pr->root);
        return true;
    }
};

REGISTER_TEST(UdpjsonTest);
<|endoftext|>