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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
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 or http://www.mitk.org for details.

===================================================================*/

#include <mitkCommon.h>
#include <chrono>
#include <mitkIOUtil.h>
#include <mitkCommandLineParser.h>
#include <mitkException.h>

#include <mitkPhotoacousticFilterService.h>
#include <mitkBeamformingSettings.h>
#include <mitkCastToFloatImageFilter.h>

#include <itksys/SystemTools.hxx>
#include <tinyxml/tinyxml.h>

struct InputParameters
{
  mitk::Image::Pointer inputImage;
  std::string outputFilename;
  bool verbose;
  std::string settingsFile;
  std::string imageType;
};

struct BandpassSettings
{
  float highPass;
  float lowPass;
  float alphaLow;
  float alphaHigh;
  float speedOfSound;
};

struct CropSettings
{
  int above;
  int below;
  int right;
  int left;
  int zStart;
  int zEnd;
};

struct ResampleSettings
{
  double spacing;
  unsigned int dimX;
};

struct BModeSettings
{
  mitk::PhotoacousticFilterService::BModeMethod method;
  bool UseLogFilter;
};

struct ProcessSettings
{
  bool DoBeamforming;
  bool DoBandpass;
  bool DoCropping;
  bool DoResampling;
  bool DoBmode;
};

InputParameters parseInput(int argc, char* argv[])
{
  mitkCommandLineParser parser;
  parser.setCategory("MITK-Photoacoustics");
  parser.setTitle("Mitk Photoacoustics Beamforming Tool");
  parser.setDescription("Reads a nrrd file as an input and applies a beamforming method as set with the parameters defined in an additionally provided xml file.");
  parser.setContributor("Computer Assisted Medical Interventions, DKFZ");

  parser.setArgumentPrefix("--", "-");

  parser.beginGroup("Required parameters");
  parser.addArgument(
    "inputImage", "i", mitkCommandLineParser::Image,
    "Input image (mitk::Image)", "input image (.nrrd file)",
    us::Any(), false, false, false, mitkCommandLineParser::Input);
  parser.addArgument(
    "output", "o", mitkCommandLineParser::File,
    "Output filename", "output image (.nrrd file)",
    us::Any(), false, false, false, mitkCommandLineParser::Output);
  parser.addArgument(
    "settings", "s", mitkCommandLineParser::String,
    "settings file", "file containing beamforming and other specifications(.xml file)",
    us::Any(), false);
  parser.addArgument(
    "type", "t", mitkCommandLineParser::String,
    "image type", "Specifies whether to use the PA or US subsection of the xml file must be 'PA' or 'US'",
    us::Any(), false);
  parser.endGroup();

  parser.beginGroup("Optional parameters");
  parser.addArgument(
    "verbose", "v", mitkCommandLineParser::Bool,
    "Verbose Output", "Whether to produce verbose, or rather debug output. (default: false)");
  parser.endGroup();

  InputParameters input;

  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
  if (parsedArgs.size() == 0)
    exit(-1);

  input.verbose = (bool)parsedArgs.count("verbose");
  MITK_INFO(input.verbose) << "### VERBOSE OUTPUT ENABLED ###";

  if (parsedArgs.count("inputImage"))
  {
    MITK_INFO(input.verbose) << "Reading input image...";
    input.inputImage = mitk::IOUtil::Load<mitk::Image>(us::any_cast<std::string>(parsedArgs["inputImage"]));
    MITK_INFO(input.verbose) << "Reading input image...[Done]";
  }
  else
    mitkThrow() << "No input image given.";

  if (parsedArgs.count("output"))
    input.outputFilename = us::any_cast<std::string>(parsedArgs["output"]);
  else
    mitkThrow() << "No output image path given..";

  if (parsedArgs.count("settings"))
    input.settingsFile = us::any_cast<std::string>(parsedArgs["settings"]);
  else
    mitkThrow() << "No settings image path given..";

  if (parsedArgs.count("type"))
    input.imageType = us::any_cast<std::string>(parsedArgs["type"]);
  else
    mitkThrow() << "No settings image type given..";

  return input;
}

TiXmlElement* getRootChild(TiXmlElement* root, std::string childName)
{
  for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement())
  {
    if (elem->Value() == childName)
      return elem;
  }
  return nullptr;
}

void ParseXML(std::string xmlFile, InputParameters input, mitk::BeamformingSettings::Pointer *bfSet, BandpassSettings& bandpassSet, CropSettings& cropSet, ResampleSettings& resSet, BModeSettings& bmodeSet, ProcessSettings& processSet)
{
  MITK_INFO << "Loading configuration File \"" << xmlFile << "\"";
  TiXmlDocument doc(xmlFile);
  if (!doc.LoadFile())
    mitkThrow() << "Failed to load settings file \"" << xmlFile << "\" Error: " << doc.ErrorDesc();

  TiXmlElement* root = doc.FirstChildElement();
  if (root == NULL)
  {
    mitkThrow() << "Failed to load file: No root element.";
    doc.Clear();
  }

  TiXmlElement* elemtop = getRootChild(root, input.imageType);
  if(elemtop == nullptr)
      mitkThrow() << "The xml file is wrongly formatted, no element \"" << input.imageType << "\" found";

  for (TiXmlElement* elem = elemtop->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement())
  {
    std::string elemName = elem->Value();
    if (elemName == "Beamforming")
    {
      processSet.DoBeamforming = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBeamforming)
        continue;

      float SpeedOfSound = std::stof(elem->Attribute("speedOfSoundMeterPerSecond"));
      float PitchMeter = std::stof(elem->Attribute("pitchMilliMeter"))/1000;
      float TimeSpacingMicroSecond = (float)(input.inputImage->GetGeometry()->GetSpacing()[1] / 1000000);

      if (std::stof(elem->Attribute("timeSpacingMicroSecond")) > 0) {
        TimeSpacingMicroSecond = std::stof(elem->Attribute("timeSpacingMicroSecond"));
        MITK_INFO << "TIME: " << TimeSpacingMicroSecond;
      }

      float Angle = std::stof(elem->Attribute("apodizationAngle"));
      bool IsPhotoacousticImage = true;
      if (elem->Attribute("imageType") == "US") {
        IsPhotoacousticImage = false;
        MITK_INFO << "US IMAGE";
      }

      unsigned int SamplesPerLine = std::stoi(elem->Attribute("reconstructedYDimension"));
      unsigned int ReconstructionLines = std::stoi(elem->Attribute("reconstructedXDimension"));

      float ReconstructionDepth = std::stof(elem->Attribute("reconstructionDepthMeter"));
      bool UseGPU = std::stoi(elem->Attribute("useGPU"));
      unsigned int GPUBatchSize = std::stoi(elem->Attribute("GPUBatchSize"));

      std::string apodizationStr = elem->Attribute("apodizationFunction");
      mitk::BeamformingSettings::Apodization Apodization = mitk::BeamformingSettings::Apodization::Box;
      if (apodizationStr == "Box")
        Apodization = mitk::BeamformingSettings::Apodization::Box;
      else if (apodizationStr == "Hann")
        Apodization = mitk::BeamformingSettings::Apodization::Hann;
      else if (apodizationStr == "Hamm")
        Apodization = mitk::BeamformingSettings::Apodization::Hamm;
      else
        mitkThrow() << "Apodization incorrectly defined in settings";

      std::string geomStr = elem->Attribute("probeGeometry");
      mitk::BeamformingSettings::ProbeGeometry ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Linear;
      if (geomStr == "linear")
        ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Linear;
      else if(geomStr == "concave")
        ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Concave;
      else
        mitkThrow() << "geometry incorrectly defined in settings";

      float radius = std::stof(elem->Attribute("radiusMilliMeter"))/1000;

      unsigned int ApodizationArraySize = ReconstructionLines;

      std::string algorithmStr = elem->Attribute("algorithm");
      mitk::BeamformingSettings::BeamformingAlgorithm Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS;
      if (algorithmStr == "DAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS;
      else if (algorithmStr == "DMAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS;
      else if (algorithmStr == "sDMAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS;
      else
        mitkThrow() << "Beamforming algorithm incorrectly defined in settings";

      *bfSet = mitk::BeamformingSettings::New(
        PitchMeter,
        SpeedOfSound,
        TimeSpacingMicroSecond,
        Angle,
        IsPhotoacousticImage,
        SamplesPerLine,
        ReconstructionLines,
        input.inputImage->GetDimensions(),
        ReconstructionDepth,
        UseGPU,
        GPUBatchSize,
        Apodization,
        ApodizationArraySize,
        Algorithm,
        ProbeGeometry,
        radius
      );
    }
    if (elemName == "Bandpass")
    {
      processSet.DoBandpass = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBandpass)
        continue;

      bandpassSet.highPass = std::stof(elem->Attribute("highPass"));
      bandpassSet.lowPass = std::stof(elem->Attribute("lowPass"));
      bandpassSet.alphaLow = std::stof(elem->Attribute("alphaLow"));
      bandpassSet.alphaHigh = std::stof(elem->Attribute("alphaHigh"));
    }
    if (elemName == "Cropping")
    {
      processSet.DoCropping = std::stoi(elem->Attribute("do"));
      if (!processSet.DoCropping)
        continue;

      cropSet.above = std::stoi(elem->Attribute("cutAbove"));
      cropSet.below = std::stoi(elem->Attribute("cutBelow"));
      cropSet.right = std::stoi(elem->Attribute("cutRight"));
      cropSet.left = std::stoi(elem->Attribute("cutLeft"));
      cropSet.zStart = std::stoi(elem->Attribute("firstSlice"));
      cropSet.zEnd = std::stoi(elem->Attribute("cutSlices"));
    }
    if (elemName == "Resampling")
    {
      processSet.DoResampling = std::stoi(elem->Attribute("do"));
      if (!processSet.DoResampling)
        continue;

      resSet.spacing = std::stod(elem->Attribute("spacing"));
      resSet.dimX = std::stoi(elem->Attribute("dimX"));
    }
    if (elemName == "BMode")
    {
      processSet.DoBmode = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBmode)
        continue;

      std::string methodStr = elem->Attribute("method");
      if (methodStr == "EnvelopeDetection")
        bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection;
      else if (methodStr == "Abs")
        bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::Abs;
      else
        mitkThrow() << "BMode method incorrectly set in configuration file";
      bmodeSet.UseLogFilter = (bool)std::stoi(elem->Attribute("useLogFilter"));
    }
  }
}

int main(int argc, char * argv[])
{
  auto input = parseInput(argc, argv);

  mitk::BeamformingSettings::Pointer bfSettings;
  BandpassSettings bandpassSettings{5,10,1,1,1540};
  BModeSettings bmodeSettings{ mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, false };
  CropSettings cropSettings{ 0,0,0,0,0,0 };
  ResampleSettings resSettings{ 0.15 , 256};
  ProcessSettings processSettings{ false, false, false, false, false };

  MITK_INFO << "Parsing settings XML...";
  try
  {
    ParseXML(input.settingsFile, input, &bfSettings, bandpassSettings, cropSettings, resSettings, bmodeSettings, processSettings);
  }
  catch (mitk::Exception e)
  {
    MITK_INFO << e;
    return -1;
  }

  MITK_INFO << "Parsing settings XML...[Done]";

  MITK_INFO(input.verbose) << "Beamforming input image...";
  mitk::Image::Pointer inputImage = input.inputImage;
  if (!(inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)"))
  {
    // we need a float image, so cast it here
    MITK_INFO(input.verbose) << "Casting input image to float...";
    mitk::CastToFloatImageFilter::Pointer castFilter = mitk::CastToFloatImageFilter::New();
    castFilter->SetInput(inputImage);
    castFilter->Update();
    inputImage = castFilter->GetOutput();
    MITK_INFO << inputImage->GetPixelType().GetPixelTypeAsString();
    MITK_INFO(input.verbose) << "Casting input image to float...[Done]";
  }

  mitk::PhotoacousticFilterService::Pointer m_FilterService = mitk::PhotoacousticFilterService::New();

  mitk::Image::Pointer output = inputImage;
  if (processSettings.DoBandpass)
  {
    MITK_INFO(input.verbose) << "Bandpassing input image...";
    output = m_FilterService->ApplyBandpassFilter(output, bandpassSettings.highPass*1e6, bandpassSettings.lowPass*1e6, bandpassSettings.alphaHigh, bandpassSettings.alphaLow, 1, bandpassSettings.speedOfSound, true);
    MITK_INFO(input.verbose) << "Bandpassing input image...[Done]";
  }
  if (processSettings.DoBeamforming)
  {
    MITK_INFO(input.verbose) << "Beamforming input image...";
    output = m_FilterService->ApplyBeamforming(output, bfSettings);
    MITK_INFO(input.verbose) << "Beamforming input image...[Done]";
  }
  if (processSettings.DoCropping)
  {
    int err;
    MITK_INFO(input.verbose) << "Applying Crop filter to image...";
    output = m_FilterService->ApplyCropping(output,
      cropSettings.above, cropSettings.below, cropSettings.right, cropSettings.left, cropSettings.zStart, cropSettings.zEnd, &err);
    MITK_INFO(input.verbose) << "Applying Crop filter to image...[Done]";
  }
  if (processSettings.DoBmode)
  {
    MITK_INFO(input.verbose) << "Applying BModeFilter to image...";
    output = m_FilterService->ApplyBmodeFilter(output, bmodeSettings.method, bmodeSettings.UseLogFilter);
    MITK_INFO(input.verbose) << "Applying BModeFilter to image...[Done]";
  }
  if (processSettings.DoResampling)
  {
    double spacing[3] = { output->GetGeometry()->GetSpacing()[0] * output->GetDimension(0) / resSettings.dimX, resSettings.spacing, output->GetGeometry()->GetSpacing()[2] };
    MITK_INFO(input.verbose) << "Applying Resample filter to image...";
    output = m_FilterService->ApplyResampling(output, spacing);
    if (output->GetDimension(0) != resSettings.dimX)
    {
      double dim[3] = { (double)resSettings.dimX, (double)output->GetDimension(1), (double)output->GetDimension(2) };
      output = m_FilterService->ApplyResamplingToDim(output, dim);
    }
    MITK_INFO(input.verbose) << "Applying Resample filter to image...[Done]";
  }

  MITK_INFO(input.verbose) << "Saving image...";
  mitk::IOUtil::Save(output, input.outputFilename);
  MITK_INFO(input.verbose) << "Saving image...[Done]";

  MITK_INFO(input.verbose) << "Beamforming input image...[Done]";
}
<commit_msg>caused gcc warning<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
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 or http://www.mitk.org for details.

===================================================================*/

#include <mitkCommon.h>
#include <chrono>
#include <mitkIOUtil.h>
#include <mitkCommandLineParser.h>
#include <mitkException.h>

#include <mitkPhotoacousticFilterService.h>
#include <mitkBeamformingSettings.h>
#include <mitkCastToFloatImageFilter.h>

#include <itksys/SystemTools.hxx>
#include <tinyxml/tinyxml.h>

struct InputParameters
{
  mitk::Image::Pointer inputImage;
  std::string outputFilename;
  bool verbose;
  std::string settingsFile;
  std::string imageType;
};

struct BandpassSettings
{
  float highPass;
  float lowPass;
  float alphaLow;
  float alphaHigh;
  float speedOfSound;
};

struct CropSettings
{
  int above;
  int below;
  int right;
  int left;
  int zStart;
  int zEnd;
};

struct ResampleSettings
{
  double spacing;
  unsigned int dimX;
};

struct BModeSettings
{
  mitk::PhotoacousticFilterService::BModeMethod method;
  bool UseLogFilter;
};

struct ProcessSettings
{
  bool DoBeamforming;
  bool DoBandpass;
  bool DoCropping;
  bool DoResampling;
  bool DoBmode;
};

InputParameters parseInput(int argc, char* argv[])
{
  mitkCommandLineParser parser;
  parser.setCategory("MITK-Photoacoustics");
  parser.setTitle("Mitk Photoacoustics Beamforming Tool");
  parser.setDescription("Reads a nrrd file as an input and applies a beamforming method as set with the parameters defined in an additionally provided xml file.");
  parser.setContributor("Computer Assisted Medical Interventions, DKFZ");

  parser.setArgumentPrefix("--", "-");

  parser.beginGroup("Required parameters");
  parser.addArgument(
    "inputImage", "i", mitkCommandLineParser::Image,
    "Input image (mitk::Image)", "input image (.nrrd file)",
    us::Any(), false, false, false, mitkCommandLineParser::Input);
  parser.addArgument(
    "output", "o", mitkCommandLineParser::File,
    "Output filename", "output image (.nrrd file)",
    us::Any(), false, false, false, mitkCommandLineParser::Output);
  parser.addArgument(
    "settings", "s", mitkCommandLineParser::String,
    "settings file", "file containing beamforming and other specifications(.xml file)",
    us::Any(), false);
  parser.addArgument(
    "type", "t", mitkCommandLineParser::String,
    "image type", "Specifies whether to use the PA or US subsection of the xml file must be 'PA' or 'US'",
    us::Any(), false);
  parser.endGroup();

  parser.beginGroup("Optional parameters");
  parser.addArgument(
    "verbose", "v", mitkCommandLineParser::Bool,
    "Verbose Output", "Whether to produce verbose, or rather debug output. (default: false)");
  parser.endGroup();

  InputParameters input;

  std::map<std::string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
  if (parsedArgs.size() == 0)
    exit(-1);

  input.verbose = (bool)parsedArgs.count("verbose");
  MITK_INFO(input.verbose) << "### VERBOSE OUTPUT ENABLED ###";

  if (parsedArgs.count("inputImage"))
  {
    MITK_INFO(input.verbose) << "Reading input image...";
    input.inputImage = mitk::IOUtil::Load<mitk::Image>(us::any_cast<std::string>(parsedArgs["inputImage"]));
    MITK_INFO(input.verbose) << "Reading input image...[Done]";
  }
  else
    mitkThrow() << "No input image given.";

  if (parsedArgs.count("output"))
    input.outputFilename = us::any_cast<std::string>(parsedArgs["output"]);
  else
    mitkThrow() << "No output image path given..";

  if (parsedArgs.count("settings"))
    input.settingsFile = us::any_cast<std::string>(parsedArgs["settings"]);
  else
    mitkThrow() << "No settings image path given..";

  if (parsedArgs.count("type"))
    input.imageType = us::any_cast<std::string>(parsedArgs["type"]);
  else
    mitkThrow() << "No settings image type given..";

  return input;
}

TiXmlElement* getRootChild(TiXmlElement* root, std::string childName)
{
  for (TiXmlElement* elem = root->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement())
  {
    if (elem->Value() == childName)
      return elem;
  }
  return nullptr;
}

void ParseXML(std::string xmlFile, InputParameters input, mitk::BeamformingSettings::Pointer *bfSet, BandpassSettings& bandpassSet, CropSettings& cropSet, ResampleSettings& resSet, BModeSettings& bmodeSet, ProcessSettings& processSet)
{
  MITK_INFO << "Loading configuration File \"" << xmlFile << "\"";
  TiXmlDocument doc(xmlFile);
  if (!doc.LoadFile())
    mitkThrow() << "Failed to load settings file \"" << xmlFile << "\" Error: " << doc.ErrorDesc();

  TiXmlElement* root = doc.FirstChildElement();
  if (root == NULL)
  {
    mitkThrow() << "Failed to load file: No root element.";
    doc.Clear();
  }

  TiXmlElement* elemtop = getRootChild(root, input.imageType);
  if(elemtop == nullptr)
      mitkThrow() << "The xml file is wrongly formatted, no element \"" << input.imageType << "\" found";

  for (TiXmlElement* elem = elemtop->FirstChildElement(); elem != NULL; elem = elem->NextSiblingElement())
  {
    std::string elemName = elem->Value();
    if (elemName == "Beamforming")
    {
      processSet.DoBeamforming = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBeamforming)
        continue;

      float SpeedOfSound = std::stof(elem->Attribute("speedOfSoundMeterPerSecond"));
      float PitchMeter = std::stof(elem->Attribute("pitchMilliMeter"))/1000;
      float TimeSpacingMicroSecond = (float)(input.inputImage->GetGeometry()->GetSpacing()[1] / 1000000);

      if (std::stof(elem->Attribute("timeSpacingMicroSecond")) > 0) {
        TimeSpacingMicroSecond = std::stof(elem->Attribute("timeSpacingMicroSecond"));
        MITK_INFO << "TIME: " << TimeSpacingMicroSecond;
      }

      float Angle = std::stof(elem->Attribute("apodizationAngle"));
      bool IsPhotoacousticImage = true;
      if (std::string(elem->Attribute("imageType")).compare("US") == 0) {
        IsPhotoacousticImage = false;
        MITK_INFO << "US IMAGE";
      }

      unsigned int SamplesPerLine = std::stoi(elem->Attribute("reconstructedYDimension"));
      unsigned int ReconstructionLines = std::stoi(elem->Attribute("reconstructedXDimension"));

      float ReconstructionDepth = std::stof(elem->Attribute("reconstructionDepthMeter"));
      bool UseGPU = std::stoi(elem->Attribute("useGPU"));
      unsigned int GPUBatchSize = std::stoi(elem->Attribute("GPUBatchSize"));

      std::string apodizationStr = elem->Attribute("apodizationFunction");
      mitk::BeamformingSettings::Apodization Apodization = mitk::BeamformingSettings::Apodization::Box;
      if (apodizationStr == "Box")
        Apodization = mitk::BeamformingSettings::Apodization::Box;
      else if (apodizationStr == "Hann")
        Apodization = mitk::BeamformingSettings::Apodization::Hann;
      else if (apodizationStr == "Hamm")
        Apodization = mitk::BeamformingSettings::Apodization::Hamm;
      else
        mitkThrow() << "Apodization incorrectly defined in settings";

      std::string geomStr = elem->Attribute("probeGeometry");
      mitk::BeamformingSettings::ProbeGeometry ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Linear;
      if (geomStr == "linear")
        ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Linear;
      else if(geomStr == "concave")
        ProbeGeometry = mitk::BeamformingSettings::ProbeGeometry::Concave;
      else
        mitkThrow() << "geometry incorrectly defined in settings";

      float radius = std::stof(elem->Attribute("radiusMilliMeter"))/1000;

      unsigned int ApodizationArraySize = ReconstructionLines;

      std::string algorithmStr = elem->Attribute("algorithm");
      mitk::BeamformingSettings::BeamformingAlgorithm Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS;
      if (algorithmStr == "DAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS;
      else if (algorithmStr == "DMAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS;
      else if (algorithmStr == "sDMAS")
        Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS;
      else
        mitkThrow() << "Beamforming algorithm incorrectly defined in settings";

      *bfSet = mitk::BeamformingSettings::New(
        PitchMeter,
        SpeedOfSound,
        TimeSpacingMicroSecond,
        Angle,
        IsPhotoacousticImage,
        SamplesPerLine,
        ReconstructionLines,
        input.inputImage->GetDimensions(),
        ReconstructionDepth,
        UseGPU,
        GPUBatchSize,
        Apodization,
        ApodizationArraySize,
        Algorithm,
        ProbeGeometry,
        radius
      );
    }
    if (elemName == "Bandpass")
    {
      processSet.DoBandpass = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBandpass)
        continue;

      bandpassSet.highPass = std::stof(elem->Attribute("highPass"));
      bandpassSet.lowPass = std::stof(elem->Attribute("lowPass"));
      bandpassSet.alphaLow = std::stof(elem->Attribute("alphaLow"));
      bandpassSet.alphaHigh = std::stof(elem->Attribute("alphaHigh"));
    }
    if (elemName == "Cropping")
    {
      processSet.DoCropping = std::stoi(elem->Attribute("do"));
      if (!processSet.DoCropping)
        continue;

      cropSet.above = std::stoi(elem->Attribute("cutAbove"));
      cropSet.below = std::stoi(elem->Attribute("cutBelow"));
      cropSet.right = std::stoi(elem->Attribute("cutRight"));
      cropSet.left = std::stoi(elem->Attribute("cutLeft"));
      cropSet.zStart = std::stoi(elem->Attribute("firstSlice"));
      cropSet.zEnd = std::stoi(elem->Attribute("cutSlices"));
    }
    if (elemName == "Resampling")
    {
      processSet.DoResampling = std::stoi(elem->Attribute("do"));
      if (!processSet.DoResampling)
        continue;

      resSet.spacing = std::stod(elem->Attribute("spacing"));
      resSet.dimX = std::stoi(elem->Attribute("dimX"));
    }
    if (elemName == "BMode")
    {
      processSet.DoBmode = std::stoi(elem->Attribute("do"));
      if (!processSet.DoBmode)
        continue;

      std::string methodStr = elem->Attribute("method");
      if (methodStr == "EnvelopeDetection")
        bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection;
      else if (methodStr == "Abs")
        bmodeSet.method = mitk::PhotoacousticFilterService::BModeMethod::Abs;
      else
        mitkThrow() << "BMode method incorrectly set in configuration file";
      bmodeSet.UseLogFilter = (bool)std::stoi(elem->Attribute("useLogFilter"));
    }
  }
}

int main(int argc, char * argv[])
{
  auto input = parseInput(argc, argv);

  mitk::BeamformingSettings::Pointer bfSettings;
  BandpassSettings bandpassSettings{5,10,1,1,1540};
  BModeSettings bmodeSettings{ mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, false };
  CropSettings cropSettings{ 0,0,0,0,0,0 };
  ResampleSettings resSettings{ 0.15 , 256};
  ProcessSettings processSettings{ false, false, false, false, false };

  MITK_INFO << "Parsing settings XML...";
  try
  {
    ParseXML(input.settingsFile, input, &bfSettings, bandpassSettings, cropSettings, resSettings, bmodeSettings, processSettings);
  }
  catch (mitk::Exception e)
  {
    MITK_INFO << e;
    return -1;
  }

  MITK_INFO << "Parsing settings XML...[Done]";

  MITK_INFO(input.verbose) << "Beamforming input image...";
  mitk::Image::Pointer inputImage = input.inputImage;
  if (!(inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)"))
  {
    // we need a float image, so cast it here
    MITK_INFO(input.verbose) << "Casting input image to float...";
    mitk::CastToFloatImageFilter::Pointer castFilter = mitk::CastToFloatImageFilter::New();
    castFilter->SetInput(inputImage);
    castFilter->Update();
    inputImage = castFilter->GetOutput();
    MITK_INFO << inputImage->GetPixelType().GetPixelTypeAsString();
    MITK_INFO(input.verbose) << "Casting input image to float...[Done]";
  }

  mitk::PhotoacousticFilterService::Pointer m_FilterService = mitk::PhotoacousticFilterService::New();

  mitk::Image::Pointer output = inputImage;
  if (processSettings.DoBandpass)
  {
    MITK_INFO(input.verbose) << "Bandpassing input image...";
    output = m_FilterService->ApplyBandpassFilter(output, bandpassSettings.highPass*1e6, bandpassSettings.lowPass*1e6, bandpassSettings.alphaHigh, bandpassSettings.alphaLow, 1, bandpassSettings.speedOfSound, true);
    MITK_INFO(input.verbose) << "Bandpassing input image...[Done]";
  }
  if (processSettings.DoBeamforming)
  {
    MITK_INFO(input.verbose) << "Beamforming input image...";
    output = m_FilterService->ApplyBeamforming(output, bfSettings);
    MITK_INFO(input.verbose) << "Beamforming input image...[Done]";
  }
  if (processSettings.DoCropping)
  {
    int err;
    MITK_INFO(input.verbose) << "Applying Crop filter to image...";
    output = m_FilterService->ApplyCropping(output,
      cropSettings.above, cropSettings.below, cropSettings.right, cropSettings.left, cropSettings.zStart, cropSettings.zEnd, &err);
    MITK_INFO(input.verbose) << "Applying Crop filter to image...[Done]";
  }
  if (processSettings.DoBmode)
  {
    MITK_INFO(input.verbose) << "Applying BModeFilter to image...";
    output = m_FilterService->ApplyBmodeFilter(output, bmodeSettings.method, bmodeSettings.UseLogFilter);
    MITK_INFO(input.verbose) << "Applying BModeFilter to image...[Done]";
  }
  if (processSettings.DoResampling)
  {
    double spacing[3] = { output->GetGeometry()->GetSpacing()[0] * output->GetDimension(0) / resSettings.dimX, resSettings.spacing, output->GetGeometry()->GetSpacing()[2] };
    MITK_INFO(input.verbose) << "Applying Resample filter to image...";
    output = m_FilterService->ApplyResampling(output, spacing);
    if (output->GetDimension(0) != resSettings.dimX)
    {
      double dim[3] = { (double)resSettings.dimX, (double)output->GetDimension(1), (double)output->GetDimension(2) };
      output = m_FilterService->ApplyResamplingToDim(output, dim);
    }
    MITK_INFO(input.verbose) << "Applying Resample filter to image...[Done]";
  }

  MITK_INFO(input.verbose) << "Saving image...";
  mitk::IOUtil::Save(output, input.outputFilename);
  MITK_INFO(input.verbose) << "Saving image...[Done]";

  MITK_INFO(input.verbose) << "Beamforming input image...[Done]";
}
<|endoftext|>


<commit_before>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Implementation for Mutator class.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <utility>
#include <stdexcept>

#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

#include "opflex/ofcore/OFFramework.h"
#include "opflex/modb/Mutator.h"
#include "opflex/modb/mo-internal/StoreClient.h"
#include "opflex/modb/internal/ObjectStore.h"

namespace opflex {
namespace modb {

using boost::unordered_map;
using boost::unordered_set;
using boost::shared_ptr;
using boost::make_shared;
using std::pair;
using std::make_pair;

using mointernal::StoreClient;
using mointernal::ObjectInstance;

typedef unordered_set<pair<class_id_t, URI> > uri_set_t;
typedef unordered_map<prop_id_t, uri_set_t> prop_uri_map_t;
typedef unordered_map<pair<class_id_t, URI>, prop_uri_map_t> uri_prop_uri_map_t;
typedef unordered_map<URI, shared_ptr<ObjectInstance> > obj_map_t;

class Mutator::MutatorImpl {
public:
    MutatorImpl(ofcore::OFFramework& framework_,
                const std::string& owner)
        : framework(framework_),
          client(framework.getStore().getStoreClient(owner)) { }
    MutatorImpl(const std::string& owner)
        : framework(ofcore::OFFramework::defaultInstance()),
          client(framework.getStore().getStoreClient(owner)) { }

    ofcore::OFFramework& framework;
    StoreClient& client;

    // modified objects
    obj_map_t obj_map;

    // removed objects
    unordered_set<pair<class_id_t, URI> > removed_objects;

    // added children
    uri_prop_uri_map_t added_children;
};

/**
 * Compute a hash value for a class_id/URI pair, making it suitable as
 * a key in an unordered_map
 */
size_t hash_value(pair<class_id_t, URI> const& p) {
    std::size_t seed = 0;
    boost::hash_combine(seed, p.first);
    boost::hash_combine(seed, p.second);
    return seed;
}

Mutator::Mutator(const std::string& owner)
    : pimpl(new MutatorImpl(owner)) {
    pimpl->framework.registerTLMutator(*this);
}

Mutator::Mutator(ofcore::OFFramework& framework,
                 const std::string& owner)
    : pimpl(new MutatorImpl(framework, owner)) {
    pimpl->framework.registerTLMutator(*this);
}

Mutator::~Mutator() {
    pimpl->framework.clearTLMutator();
    delete pimpl;
}

shared_ptr<ObjectInstance>& Mutator::addChild(class_id_t parent_class,
                                              const URI& parent_uri,
                                              prop_id_t parent_prop,
                                              class_id_t child_class,
                                              const URI& child_uri) {
    pimpl->added_children
        [make_pair(child_class,child_uri)]
        [parent_prop].insert(make_pair(parent_class,parent_uri));
    return modify(child_class, child_uri);
}

shared_ptr<ObjectInstance>& Mutator::modify(class_id_t class_id,
                                            const URI& uri) {
    // check for copy in mutator
    obj_map_t::iterator it = pimpl->obj_map.find(uri);
    if (it != pimpl->obj_map.end()) return it->second;
    shared_ptr<ObjectInstance> copy;
    try {
        // check for existing object
        copy = make_shared<ObjectInstance>(*pimpl->client.get(class_id,
                                                              uri).get());
    } catch (std::out_of_range e) {
        // create new object
        copy = make_shared<ObjectInstance>(class_id);
    }

    pair<obj_map_t::iterator, bool> r =
        pimpl->obj_map.insert(obj_map_t::value_type(uri, copy));
    return r.first->second;
}

void Mutator::remove(class_id_t class_id, const URI& uri) {
    pimpl->removed_objects.insert(make_pair(class_id, uri));
}

void Mutator::commit() {
    unordered_map<URI, class_id_t> notifs;
    obj_map_t::iterator objit;
    for (objit = pimpl->obj_map.begin();
         objit != pimpl->obj_map.end(); ++objit) {
        pimpl->client.put(objit->second->getClassId(), objit->first,
                          objit->second);
        pimpl->client.queueNotification(objit->second->getClassId(),
                                 objit->first,
                                 notifs);
    }
    uri_prop_uri_map_t::iterator upit;
    for (upit = pimpl->added_children.begin();
         upit != pimpl->added_children.end(); ++upit) {
        prop_uri_map_t::iterator pit;
        for (pit = upit->second.begin(); pit != upit->second.end(); ++pit) {
            uri_set_t::iterator uit;
            for (uit = pit->second.begin(); uit != pit->second.end(); ++uit) {
                pimpl->client.addChild(uit->first, uit->second, pit->first,
                                upit->first.first, upit->first.second);
                pimpl->client.queueNotification(upit->first.first,
                                         upit->first.second,
                                         notifs);

            }
        }

    }
    unordered_set<pair<class_id_t, URI> >::iterator rit;
    for (rit = pimpl->removed_objects.begin();
         rit != pimpl->removed_objects.end(); ++rit) {
        pimpl->client.remove(rit->first, rit->second, false);
        pimpl->client.queueNotification(rit->first, rit->second, notifs);
    }

    pimpl->obj_map.clear();
    pimpl->removed_objects.clear();
    pimpl->added_children.clear();

    pimpl->client.deliverNotifications(notifs);
}

} /* namespace modb */
} /* namespace opflex */
<commit_msg>Simplify mutator commit code with foreach.  Fix issue with delivery of notifications when the data is committed out of order.<commit_after>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Implementation for Mutator class.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <utility>
#include <stdexcept>

#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>

#include "opflex/ofcore/OFFramework.h"
#include "opflex/modb/Mutator.h"
#include "opflex/modb/mo-internal/StoreClient.h"
#include "opflex/modb/internal/ObjectStore.h"
#include "opflex/logging/internal/logging.hpp"

namespace opflex {
namespace modb {

using boost::unordered_map;
using boost::unordered_set;
using boost::shared_ptr;
using boost::make_shared;
using std::pair;
using std::make_pair;

using mointernal::StoreClient;
using mointernal::ObjectInstance;

typedef unordered_set<reference_t > uri_set_t;
typedef unordered_map<prop_id_t, uri_set_t> prop_uri_map_t;
typedef unordered_map<reference_t, prop_uri_map_t> uri_prop_uri_map_t;
typedef unordered_map<URI, shared_ptr<ObjectInstance> > obj_map_t;

class Mutator::MutatorImpl {
public:
    MutatorImpl(ofcore::OFFramework& framework_,
                const std::string& owner)
        : framework(framework_),
          client(framework.getStore().getStoreClient(owner)) { }
    MutatorImpl(const std::string& owner)
        : framework(ofcore::OFFramework::defaultInstance()),
          client(framework.getStore().getStoreClient(owner)) { }

    ofcore::OFFramework& framework;
    StoreClient& client;

    // modified objects
    obj_map_t obj_map;

    // removed objects
    unordered_set<pair<class_id_t, URI> > removed_objects;

    // added children
    uri_prop_uri_map_t added_children;
};

/**
 * Compute a hash value for a class_id/URI pair, making it suitable as
 * a key in an unordered_map
 */
size_t hash_value(pair<class_id_t, URI> const& p) {
    std::size_t seed = 0;
    boost::hash_combine(seed, p.first);
    boost::hash_combine(seed, p.second);
    return seed;
}

Mutator::Mutator(const std::string& owner)
    : pimpl(new MutatorImpl(owner)) {
    pimpl->framework.registerTLMutator(*this);
}

Mutator::Mutator(ofcore::OFFramework& framework,
                 const std::string& owner)
    : pimpl(new MutatorImpl(framework, owner)) {
    pimpl->framework.registerTLMutator(*this);
}

Mutator::~Mutator() {
    pimpl->framework.clearTLMutator();
    delete pimpl;
}

shared_ptr<ObjectInstance>& Mutator::addChild(class_id_t parent_class,
                                              const URI& parent_uri,
                                              prop_id_t parent_prop,
                                              class_id_t child_class,
                                              const URI& child_uri) {
    pimpl->added_children
        [make_pair(child_class,child_uri)]
        [parent_prop].insert(make_pair(parent_class,parent_uri));
    return modify(child_class, child_uri);
}

shared_ptr<ObjectInstance>& Mutator::modify(class_id_t class_id,
                                            const URI& uri) {
    // check for copy in mutator
    obj_map_t::iterator it = pimpl->obj_map.find(uri);
    if (it != pimpl->obj_map.end()) return it->second;
    shared_ptr<ObjectInstance> copy;
    try {
        // check for existing object
        copy = make_shared<ObjectInstance>(*pimpl->client.get(class_id,
                                                              uri).get());
    } catch (std::out_of_range e) {
        // create new object
        copy = make_shared<ObjectInstance>(class_id);
    }

    pair<obj_map_t::iterator, bool> r =
        pimpl->obj_map.insert(obj_map_t::value_type(uri, copy));
    return r.first->second;
}

void Mutator::remove(class_id_t class_id, const URI& uri) {
    pimpl->removed_objects.insert(make_pair(class_id, uri));
}

void Mutator::commit() {
    StoreClient::notif_t raw_notifs;
    StoreClient::notif_t notifs;
    BOOST_FOREACH(obj_map_t::value_type& objt, pimpl->obj_map) {
        pimpl->client.put(objt.second->getClassId(), objt.first,
                          objt.second);
        raw_notifs[objt.first] = objt.second->getClassId();

    }
    BOOST_FOREACH(uri_prop_uri_map_t::value_type& upt, pimpl->added_children) {
        BOOST_FOREACH(prop_uri_map_t::value_type& pt, upt.second) {
            BOOST_FOREACH(const reference_t& ut, pt.second) {
                raw_notifs[upt.first.second] = upt.first.first;
                pimpl->client.addChild(ut.first, ut.second, pt.first,
                                upt.first.first, upt.first.second);

            }
        }
    }

    BOOST_FOREACH(StoreClient::notif_t::value_type nt, raw_notifs) {
        pimpl->client.queueNotification(nt.second, nt.first, notifs);
    }

    BOOST_FOREACH(const reference_t& rt, pimpl->removed_objects) {
        pimpl->client.remove(rt.first, rt.second, false);
        pimpl->client.queueNotification(rt.first, rt.second, notifs);
    }

    pimpl->obj_map.clear();
    pimpl->removed_objects.clear();
    pimpl->added_children.clear();

    pimpl->client.deliverNotifications(notifs);
}

} /* namespace modb */
} /* namespace opflex */
<|endoftext|>


<commit_before>//===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements the lexer for assembly files.
//
//===----------------------------------------------------------------------===//

#include "AsmLexer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cerrno>
#include <cstdio>
#include <cstdlib>
using namespace llvm;

AsmLexer::AsmLexer(SourceMgr &SM) : SrcMgr(SM) {
  CurBuffer = 0;
  CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
  CurPtr = CurBuf->getBufferStart();
  TokStart = 0;
}

SMLoc AsmLexer::getLoc() const {
  return SMLoc::getFromPointer(TokStart);
}

void AsmLexer::PrintMessage(SMLoc Loc, const std::string &Msg) const {
  SrcMgr.PrintMessage(Loc, Msg);
}

/// ReturnError - Set the error to the specified string at the specified
/// location.  This is defined to always return asmtok::Error.
asmtok::TokKind AsmLexer::ReturnError(const char *Loc, const std::string &Msg) {
  SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg);
  return asmtok::Error;
}

int AsmLexer::getNextChar() {
  char CurChar = *CurPtr++;
  switch (CurChar) {
  default:
    return (unsigned char)CurChar;
  case 0: {
    // A nul character in the stream is either the end of the current buffer or
    // a random nul in the file.  Disambiguate that here.
    if (CurPtr-1 != CurBuf->getBufferEnd())
      return 0;  // Just whitespace.

    // If this is the end of an included file, pop the parent file off the
    // include stack.
    SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
    if (ParentIncludeLoc != SMLoc()) {
      CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
      CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
      CurPtr = ParentIncludeLoc.getPointer();
      return getNextChar();
    }

    // Otherwise, return end of file.
    --CurPtr;  // Another call to lex will return EOF again.
    return EOF;
  }
  }
}

/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
asmtok::TokKind AsmLexer::LexIdentifier() {
  while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' ||
         *CurPtr == '.' || *CurPtr == '@')
    ++CurPtr;
  CurStrVal.assign(TokStart, CurPtr);   // Include %
  return asmtok::Identifier;
}

/// LexPercent: Register: %[a-zA-Z0-9]+
asmtok::TokKind AsmLexer::LexPercent() {
  if (!isalnum(*CurPtr))
    return ReturnError(TokStart, "invalid register name");
  while (isalnum(*CurPtr))
    ++CurPtr;
  CurStrVal.assign(TokStart, CurPtr);   // Skip %
  return asmtok::Register;
}

/// LexSlash: Slash: /
///           C-Style Comment: /* ... */
asmtok::TokKind AsmLexer::LexSlash() {
  if (*CurPtr != '*')
    return asmtok::Slash;

  // C Style comment.
  ++CurPtr;  // skip the star.
  while (1) {
    int CurChar = getNextChar();
    switch (CurChar) {
    case EOF:
      return ReturnError(TokStart, "unterminated comment");
    case '*':
      // End of the comment?
      if (CurPtr[0] != '/') break;

      ++CurPtr;   // End the */.
      return LexToken();
    }
  }
}

/// LexHash: Comment: #[^\n]*
asmtok::TokKind AsmLexer::LexHash() {
  int CurChar = getNextChar();
  while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF)
    CurChar = getNextChar();

  if (CurChar == EOF)
    return asmtok::Eof;
  return asmtok::EndOfStatement;
}

/// LexDigit: First character is [0-9].
///   Local Label: [0-9][:]
///   Forward/Backward Label: [0-9][fb]
///   Binary integer: 0b[01]+
///   Octal integer: 0[0-7]+
///   Hex integer: 0x[0-9a-fA-F]+
///   Decimal integer: [1-9][0-9]*
/// TODO: FP literal.
asmtok::TokKind AsmLexer::LexDigit() {
  if (*CurPtr == ':')
    return ReturnError(TokStart, "FIXME: local label not implemented");
  if (*CurPtr == 'f' || *CurPtr == 'b')
    return ReturnError(TokStart, "FIXME: directional label not implemented");

  // Decimal integer: [1-9][0-9]*
  if (CurPtr[-1] != '0') {
    while (isdigit(*CurPtr))
      ++CurPtr;
    CurIntVal = strtoll(TokStart, 0, 10);
    return asmtok::IntVal;
  }

  if (*CurPtr == 'b') {
    ++CurPtr;
    const char *NumStart = CurPtr;
    while (CurPtr[0] == '0' || CurPtr[0] == '1')
      ++CurPtr;

    // Requires at least one binary digit.
    if (CurPtr == NumStart)
      return ReturnError(CurPtr-2, "Invalid binary number");
    CurIntVal = strtoll(NumStart, 0, 2);
    return asmtok::IntVal;
  }

  if (*CurPtr == 'x') {
    ++CurPtr;
    const char *NumStart = CurPtr;
    while (isxdigit(CurPtr[0]))
      ++CurPtr;

    // Requires at least one hex digit.
    if (CurPtr == NumStart)
      return ReturnError(CurPtr-2, "Invalid hexadecimal number");

    errno = 0;
    CurIntVal = strtoll(NumStart, 0, 16);
    if (errno == EINVAL)
      return ReturnError(CurPtr-2, "Invalid hexadecimal number");
    if (errno == ERANGE) {
      errno = 0;
      CurIntVal = (int64_t)strtoull(NumStart, 0, 16);
      if (errno == EINVAL)
        return ReturnError(CurPtr-2, "Invalid hexadecimal number");
      if (errno == ERANGE)
        return ReturnError(CurPtr-2, "Hexadecimal number out of range");
    }
    return asmtok::IntVal;
  }

  // Must be an octal number, it starts with 0.
  while (*CurPtr >= '0' && *CurPtr <= '7')
    ++CurPtr;
  CurIntVal = strtoll(TokStart, 0, 8);
  return asmtok::IntVal;
}

/// LexQuote: String: "..."
asmtok::TokKind AsmLexer::LexQuote() {
  int CurChar = getNextChar();
  // TODO: does gas allow multiline string constants?
  while (CurChar != '"') {
    if (CurChar == '\\') {
      // Allow \", etc.
      CurChar = getNextChar();
    }

    if (CurChar == EOF)
      return ReturnError(TokStart, "unterminated string constant");

    CurChar = getNextChar();
  }

  CurStrVal.assign(TokStart, CurPtr);   // include quotes.
  return asmtok::String;
}

asmtok::TokKind AsmLexer::LexToken() {
  TokStart = CurPtr;
  // This always consumes at least one character.
  int CurChar = getNextChar();

  switch (CurChar) {
  default:
    // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
    if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
      return LexIdentifier();

    // Unknown character, emit an error.
    return ReturnError(TokStart, "invalid character in input");
  case EOF: return asmtok::Eof;
  case 0:
  case ' ':
  case '\t':
    // Ignore whitespace.
    return LexToken();
  case '\n': // FALL THROUGH.
  case '\r': // FALL THROUGH.
  case ';': return asmtok::EndOfStatement;
  case ':': return asmtok::Colon;
  case '+': return asmtok::Plus;
  case '-': return asmtok::Minus;
  case '~': return asmtok::Tilde;
  case '(': return asmtok::LParen;
  case ')': return asmtok::RParen;
  case '*': return asmtok::Star;
  case ',': return asmtok::Comma;
  case '$': return asmtok::Dollar;
  case '%': return LexPercent();
  case '/': return LexSlash();
  case '#': return LexHash();
  case '"': return LexQuote();
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
    return LexDigit();

  // TODO: Quoted identifiers (objc methods etc)
  // local labels: [0-9][:]
  // Forward/backward labels: [0-9][fb]
  // Integers, fp constants, character constants.
  }
}
<commit_msg>get a definition of strull on windows, thanks to Howard Su.<commit_after>//===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements the lexer for assembly files.
//
//===----------------------------------------------------------------------===//

#include "AsmLexer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Config/config.h"  // for strtoull.
#include <cerrno>
#include <cstdio>
#include <cstdlib>
using namespace llvm;

AsmLexer::AsmLexer(SourceMgr &SM) : SrcMgr(SM) {
  CurBuffer = 0;
  CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
  CurPtr = CurBuf->getBufferStart();
  TokStart = 0;
}

SMLoc AsmLexer::getLoc() const {
  return SMLoc::getFromPointer(TokStart);
}

void AsmLexer::PrintMessage(SMLoc Loc, const std::string &Msg) const {
  SrcMgr.PrintMessage(Loc, Msg);
}

/// ReturnError - Set the error to the specified string at the specified
/// location.  This is defined to always return asmtok::Error.
asmtok::TokKind AsmLexer::ReturnError(const char *Loc, const std::string &Msg) {
  SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg);
  return asmtok::Error;
}

int AsmLexer::getNextChar() {
  char CurChar = *CurPtr++;
  switch (CurChar) {
  default:
    return (unsigned char)CurChar;
  case 0: {
    // A nul character in the stream is either the end of the current buffer or
    // a random nul in the file.  Disambiguate that here.
    if (CurPtr-1 != CurBuf->getBufferEnd())
      return 0;  // Just whitespace.

    // If this is the end of an included file, pop the parent file off the
    // include stack.
    SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
    if (ParentIncludeLoc != SMLoc()) {
      CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
      CurBuf = SrcMgr.getMemoryBuffer(CurBuffer);
      CurPtr = ParentIncludeLoc.getPointer();
      return getNextChar();
    }

    // Otherwise, return end of file.
    --CurPtr;  // Another call to lex will return EOF again.
    return EOF;
  }
  }
}

/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
asmtok::TokKind AsmLexer::LexIdentifier() {
  while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' ||
         *CurPtr == '.' || *CurPtr == '@')
    ++CurPtr;
  CurStrVal.assign(TokStart, CurPtr);   // Include %
  return asmtok::Identifier;
}

/// LexPercent: Register: %[a-zA-Z0-9]+
asmtok::TokKind AsmLexer::LexPercent() {
  if (!isalnum(*CurPtr))
    return ReturnError(TokStart, "invalid register name");
  while (isalnum(*CurPtr))
    ++CurPtr;
  CurStrVal.assign(TokStart, CurPtr);   // Skip %
  return asmtok::Register;
}

/// LexSlash: Slash: /
///           C-Style Comment: /* ... */
asmtok::TokKind AsmLexer::LexSlash() {
  if (*CurPtr != '*')
    return asmtok::Slash;

  // C Style comment.
  ++CurPtr;  // skip the star.
  while (1) {
    int CurChar = getNextChar();
    switch (CurChar) {
    case EOF:
      return ReturnError(TokStart, "unterminated comment");
    case '*':
      // End of the comment?
      if (CurPtr[0] != '/') break;

      ++CurPtr;   // End the */.
      return LexToken();
    }
  }
}

/// LexHash: Comment: #[^\n]*
asmtok::TokKind AsmLexer::LexHash() {
  int CurChar = getNextChar();
  while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF)
    CurChar = getNextChar();

  if (CurChar == EOF)
    return asmtok::Eof;
  return asmtok::EndOfStatement;
}

/// LexDigit: First character is [0-9].
///   Local Label: [0-9][:]
///   Forward/Backward Label: [0-9][fb]
///   Binary integer: 0b[01]+
///   Octal integer: 0[0-7]+
///   Hex integer: 0x[0-9a-fA-F]+
///   Decimal integer: [1-9][0-9]*
/// TODO: FP literal.
asmtok::TokKind AsmLexer::LexDigit() {
  if (*CurPtr == ':')
    return ReturnError(TokStart, "FIXME: local label not implemented");
  if (*CurPtr == 'f' || *CurPtr == 'b')
    return ReturnError(TokStart, "FIXME: directional label not implemented");

  // Decimal integer: [1-9][0-9]*
  if (CurPtr[-1] != '0') {
    while (isdigit(*CurPtr))
      ++CurPtr;
    CurIntVal = strtoll(TokStart, 0, 10);
    return asmtok::IntVal;
  }

  if (*CurPtr == 'b') {
    ++CurPtr;
    const char *NumStart = CurPtr;
    while (CurPtr[0] == '0' || CurPtr[0] == '1')
      ++CurPtr;

    // Requires at least one binary digit.
    if (CurPtr == NumStart)
      return ReturnError(CurPtr-2, "Invalid binary number");
    CurIntVal = strtoll(NumStart, 0, 2);
    return asmtok::IntVal;
  }

  if (*CurPtr == 'x') {
    ++CurPtr;
    const char *NumStart = CurPtr;
    while (isxdigit(CurPtr[0]))
      ++CurPtr;

    // Requires at least one hex digit.
    if (CurPtr == NumStart)
      return ReturnError(CurPtr-2, "Invalid hexadecimal number");

    errno = 0;
    CurIntVal = strtoll(NumStart, 0, 16);
    if (errno == EINVAL)
      return ReturnError(CurPtr-2, "Invalid hexadecimal number");
    if (errno == ERANGE) {
      errno = 0;
      CurIntVal = (int64_t)strtoull(NumStart, 0, 16);
      if (errno == EINVAL)
        return ReturnError(CurPtr-2, "Invalid hexadecimal number");
      if (errno == ERANGE)
        return ReturnError(CurPtr-2, "Hexadecimal number out of range");
    }
    return asmtok::IntVal;
  }

  // Must be an octal number, it starts with 0.
  while (*CurPtr >= '0' && *CurPtr <= '7')
    ++CurPtr;
  CurIntVal = strtoll(TokStart, 0, 8);
  return asmtok::IntVal;
}

/// LexQuote: String: "..."
asmtok::TokKind AsmLexer::LexQuote() {
  int CurChar = getNextChar();
  // TODO: does gas allow multiline string constants?
  while (CurChar != '"') {
    if (CurChar == '\\') {
      // Allow \", etc.
      CurChar = getNextChar();
    }

    if (CurChar == EOF)
      return ReturnError(TokStart, "unterminated string constant");

    CurChar = getNextChar();
  }

  CurStrVal.assign(TokStart, CurPtr);   // include quotes.
  return asmtok::String;
}

asmtok::TokKind AsmLexer::LexToken() {
  TokStart = CurPtr;
  // This always consumes at least one character.
  int CurChar = getNextChar();

  switch (CurChar) {
  default:
    // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
    if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
      return LexIdentifier();

    // Unknown character, emit an error.
    return ReturnError(TokStart, "invalid character in input");
  case EOF: return asmtok::Eof;
  case 0:
  case ' ':
  case '\t':
    // Ignore whitespace.
    return LexToken();
  case '\n': // FALL THROUGH.
  case '\r': // FALL THROUGH.
  case ';': return asmtok::EndOfStatement;
  case ':': return asmtok::Colon;
  case '+': return asmtok::Plus;
  case '-': return asmtok::Minus;
  case '~': return asmtok::Tilde;
  case '(': return asmtok::LParen;
  case ')': return asmtok::RParen;
  case '*': return asmtok::Star;
  case ',': return asmtok::Comma;
  case '$': return asmtok::Dollar;
  case '%': return LexPercent();
  case '/': return LexSlash();
  case '#': return LexHash();
  case '"': return LexQuote();
  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
    return LexDigit();

  // TODO: Quoted identifiers (objc methods etc)
  // local labels: [0-9][:]
  // Forward/backward labels: [0-9][fb]
  // Integers, fp constants, character constants.
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/plugin_var_tracker.h"

#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "ppapi/c/dev/ppp_class_deprecated.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/plugin_array_buffer_var.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/proxy_object_var.h"
#include "ppapi/shared_impl/api_id.h"
#include "ppapi/shared_impl/var.h"

namespace ppapi {
namespace proxy {

PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i)
    : dispatcher(d),
      host_object_id(i) {
}

bool PluginVarTracker::HostVar::operator<(const HostVar& other) const {
  if (dispatcher < other.dispatcher)
    return true;
  if (other.dispatcher < dispatcher)
    return false;
  return host_object_id < other.host_object_id;
}

PluginVarTracker::PluginVarTracker() {
}

PluginVarTracker::~PluginVarTracker() {
}

PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var,
                                              PluginDispatcher* dispatcher) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_var.type == PP_VARTYPE_OBJECT);

  // Get the object.
  scoped_refptr<ProxyObjectVar> object(
      FindOrMakePluginVarFromHostVar(host_var, dispatcher));

  // Actually create the PP_Var, this will add all the tracking info but not
  // adjust any refcounts.
  PP_Var ret = GetOrCreateObjectVarID(object.get());

  VarInfo& info = GetLiveVar(ret)->second;
  if (info.ref_count > 0) {
    // We already had a reference to it before. That means the renderer now has
    // two references on our behalf. We want to transfer that extra reference
    // to our list. This means we addref in the plugin, and release the extra
    // one in the renderer.
    SendReleaseObjectMsg(*object);
  }
  info.ref_count++;
  return ret;
}

PP_Var PluginVarTracker::TrackObjectWithNoReference(
    const PP_Var& host_var,
    PluginDispatcher* dispatcher) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_var.type == PP_VARTYPE_OBJECT);

  // Get the object.
  scoped_refptr<ProxyObjectVar> object(
      FindOrMakePluginVarFromHostVar(host_var, dispatcher));

  // Actually create the PP_Var, this will add all the tracking info but not
  // adjust any refcounts.
  PP_Var ret = GetOrCreateObjectVarID(object.get());

  VarInfo& info = GetLiveVar(ret)->second;
  info.track_with_no_reference_count++;
  return ret;
}

void PluginVarTracker::StopTrackingObjectWithNoReference(
    const PP_Var& plugin_var) {
  DCHECK(CalledOnValidThread());
  DCHECK(plugin_var.type == PP_VARTYPE_OBJECT);

  VarMap::iterator found = GetLiveVar(plugin_var);
  if (found == live_vars_.end()) {
    NOTREACHED();
    return;
  }

  DCHECK(found->second.track_with_no_reference_count > 0);
  found->second.track_with_no_reference_count--;
  DeleteObjectInfoIfNecessary(found);
}

PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const {
  DCHECK(CalledOnValidThread());

  if (plugin_object.type != PP_VARTYPE_OBJECT) {
    NOTREACHED();
    return PP_MakeUndefined();
  }

  Var* var = GetVar(plugin_object);
  ProxyObjectVar* object = var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return PP_MakeUndefined();
  }

  // Make a var with the host ID.
  PP_Var ret = { PP_VARTYPE_OBJECT };
  ret.value.as_id = object->host_var_id();
  return ret;
}

PluginDispatcher* PluginVarTracker::DispatcherForPluginObject(
    const PP_Var& plugin_object) const {
  DCHECK(CalledOnValidThread());

  if (plugin_object.type != PP_VARTYPE_OBJECT)
    return NULL;

  VarMap::const_iterator found = GetLiveVar(plugin_object);
  if (found == live_vars_.end())
    return NULL;

  ProxyObjectVar* object = found->second.var->AsProxyObjectVar();
  if (!object)
    return NULL;
  return object->dispatcher();
}

void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher,
                                         const PP_Var& host_object) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_object.type == PP_VARTYPE_OBJECT);

  // Convert the host object to a normal var valid in the plugin.
  HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find(
      HostVar(dispatcher, static_cast<int32>(host_object.value.as_id)));
  if (found == host_var_to_plugin_var_.end()) {
    NOTREACHED();
    return;
  }

  // Now just release the object given the plugin var ID.
  ReleaseVar(found->second);
}

void PluginVarTracker::DidDeleteInstance(PP_Instance instance) {
  // See the comment above user_data_to_plugin_ in the header file. We assume
  // there aren't that many objects so a brute-force search is reasonable.
  UserDataToPluginImplementedVarMap::iterator i =
      user_data_to_plugin_.begin();
  while (i != user_data_to_plugin_.end()) {
    if (i->second.instance == instance) {
      if (!i->second.plugin_object_id) {
        // This object is for the freed instance and the plugin is not holding
        // any references to it. Deallocate immediately.
        UserDataToPluginImplementedVarMap::iterator to_remove = i;
        ++i;
        to_remove->second.ppp_class->Deallocate(to_remove->first);
        user_data_to_plugin_.erase(to_remove);
      } else {
        // The plugin is holding refs to this object. We don't want to call
        // Deallocate since the plugin may be depending on those refs to keep
        // its data alive. To avoid crashes in this case, just clear out the
        // instance to mark it and continue. When the plugin refs go to 0,
        // we'll notice there is no instance and call Deallocate.
        i->second.instance = 0;
        ++i;
      }
    } else {
      ++i;
    }
  }
}

ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
  return new PluginArrayBufferVar(size_in_bytes);
}

void PluginVarTracker::PluginImplementedObjectCreated(
    PP_Instance instance,
    const PP_Var& created_var,
    const PPP_Class_Deprecated* ppp_class,
    void* ppp_class_data) {
  PluginImplementedVar p;
  p.ppp_class = ppp_class;
  p.instance = instance;
  p.plugin_object_id = created_var.value.as_id;
  user_data_to_plugin_[ppp_class_data] = p;

  // Link the user data to the object.
  ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar();
  object->set_user_data(ppp_class_data);
}

void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) {
  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(user_data);
  if (found == user_data_to_plugin_.end()) {
    NOTREACHED();
    return;
  }
  user_data_to_plugin_.erase(found);
}

bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) {
  return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end();
}

bool PluginVarTracker::ValidatePluginObjectCall(
    const PPP_Class_Deprecated* ppp_class,
    void* user_data) {
  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(user_data);
  if (found == user_data_to_plugin_.end())
    return false;
  return found->second.ppp_class == ppp_class;
}

int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
  // Normal adding.
  int32 new_id = VarTracker::AddVarInternal(var, mode);

  // Need to add proxy objects to the host var map.
  ProxyObjectVar* proxy_object = var->AsProxyObjectVar();
  if (proxy_object) {
    HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id());
    DCHECK(host_var_to_plugin_var_.find(host_var) ==
           host_var_to_plugin_var_.end());  // Adding an object twice, use
                                            // FindOrMakePluginVarFromHostVar.
    host_var_to_plugin_var_[host_var] = new_id;
  }
  return new_id;
}

void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) {
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return;
  }

  DCHECK(iter->second.ref_count == 0);

  // Got an AddRef for an object we have no existing reference for.
  // We need to tell the browser we've taken a ref. This comes up when the
  // browser passes an object as an input param and holds a ref for us.
  // This must be a sync message since otherwise the "addref" will actually
  // occur after the return to the browser of the sync function that
  // presumably sent the object.
  SendAddRefObjectMsg(*object);
}

void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return;
  }

  // Notify the host we're no longer holding our ref.
  DCHECK(iter->second.ref_count == 0);
  SendReleaseObjectMsg(*object);

  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(object->user_data());
  if (found != user_data_to_plugin_.end()) {
    // This object is implemented in the plugin.
    if (found->second.instance == 0) {
      // Instance is destroyed. This means that we'll never get a Deallocate
      // call from the renderer and we should do so now.
      found->second.ppp_class->Deallocate(found->first);
      user_data_to_plugin_.erase(found);
    } else {
      // The plugin is releasing its last reference to an object it implements.
      // Clear the tracking data that links our "plugin implemented object" to
      // the var. If the instance is destroyed and there is no ID, we know that
      // we should just call Deallocate on the object data.
      //
      // See the plugin_object_id declaration for more info.
      found->second.plugin_object_id = 0;
    }
  }

  // This will optionally delete the info from live_vars_.
  VarTracker::ObjectGettingZeroRef(iter);
}

bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
  // Get the info before calling the base class's version of this function,
  // which may delete the object.
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  HostVar host_var(object->dispatcher(), object->host_var_id());

  if (!VarTracker::DeleteObjectInfoIfNecessary(iter))
    return false;

  // Clean up the host var mapping.
  DCHECK(host_var_to_plugin_var_.find(host_var) !=
         host_var_to_plugin_var_.end());
  host_var_to_plugin_var_.erase(host_var);
  return true;
}

PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) {
  // We can't use object->GetPPVar() because we don't want to affect the
  // refcount, so we have to add everything manually here.
  int32 var_id = object->GetExistingVarID();
  if (!var_id) {
    var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE);
    object->AssignVarID(var_id);
  }

  PP_Var ret = { PP_VARTYPE_OBJECT };
  ret.value.as_id = var_id;
  return ret;
}

void PluginVarTracker::SendAddRefObjectMsg(
    const ProxyObjectVar& proxy_object) {
  int unused;
  proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject(
      API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused));
}

void PluginVarTracker::SendReleaseObjectMsg(
    const ProxyObjectVar& proxy_object) {
  proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
      API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id()));
}

scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar(
    const PP_Var& var,
    PluginDispatcher* dispatcher) {
  DCHECK(var.type == PP_VARTYPE_OBJECT);
  HostVar host_var(dispatcher, var.value.as_id);

  HostVarToPluginVarMap::iterator found =
      host_var_to_plugin_var_.find(host_var);
  if (found == host_var_to_plugin_var_.end()) {
    // Create a new object.
    return scoped_refptr<ProxyObjectVar>(
        new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id)));
  }

  // Have this host var, look up the object.
  VarMap::iterator ret = live_vars_.find(found->second);
  DCHECK(ret != live_vars_.end());

  // All objects should be proxy objects.
  DCHECK(ret->second.var->AsProxyObjectVar());
  return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar());
}

}  // namesace proxy
}  // namespace ppapi
<commit_msg>Try to fix a crash in the var tracking.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/plugin_var_tracker.h"

#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "ppapi/c/dev/ppp_class_deprecated.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/plugin_array_buffer_var.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/proxy_object_var.h"
#include "ppapi/shared_impl/api_id.h"
#include "ppapi/shared_impl/var.h"

namespace ppapi {
namespace proxy {

PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i)
    : dispatcher(d),
      host_object_id(i) {
}

bool PluginVarTracker::HostVar::operator<(const HostVar& other) const {
  if (dispatcher < other.dispatcher)
    return true;
  if (other.dispatcher < dispatcher)
    return false;
  return host_object_id < other.host_object_id;
}

PluginVarTracker::PluginVarTracker() {
}

PluginVarTracker::~PluginVarTracker() {
}

PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var,
                                              PluginDispatcher* dispatcher) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_var.type == PP_VARTYPE_OBJECT);

  // Get the object.
  scoped_refptr<ProxyObjectVar> object(
      FindOrMakePluginVarFromHostVar(host_var, dispatcher));

  // Actually create the PP_Var, this will add all the tracking info but not
  // adjust any refcounts.
  PP_Var ret = GetOrCreateObjectVarID(object.get());

  VarInfo& info = GetLiveVar(ret)->second;
  if (info.ref_count > 0) {
    // We already had a reference to it before. That means the renderer now has
    // two references on our behalf. We want to transfer that extra reference
    // to our list. This means we addref in the plugin, and release the extra
    // one in the renderer.
    SendReleaseObjectMsg(*object);
  }
  info.ref_count++;
  return ret;
}

PP_Var PluginVarTracker::TrackObjectWithNoReference(
    const PP_Var& host_var,
    PluginDispatcher* dispatcher) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_var.type == PP_VARTYPE_OBJECT);

  // Get the object.
  scoped_refptr<ProxyObjectVar> object(
      FindOrMakePluginVarFromHostVar(host_var, dispatcher));

  // Actually create the PP_Var, this will add all the tracking info but not
  // adjust any refcounts.
  PP_Var ret = GetOrCreateObjectVarID(object.get());

  VarInfo& info = GetLiveVar(ret)->second;
  info.track_with_no_reference_count++;
  return ret;
}

void PluginVarTracker::StopTrackingObjectWithNoReference(
    const PP_Var& plugin_var) {
  DCHECK(CalledOnValidThread());
  DCHECK(plugin_var.type == PP_VARTYPE_OBJECT);

  VarMap::iterator found = GetLiveVar(plugin_var);
  if (found == live_vars_.end()) {
    NOTREACHED();
    return;
  }

  DCHECK(found->second.track_with_no_reference_count > 0);
  found->second.track_with_no_reference_count--;
  DeleteObjectInfoIfNecessary(found);
}

PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const {
  DCHECK(CalledOnValidThread());

  if (plugin_object.type != PP_VARTYPE_OBJECT) {
    NOTREACHED();
    return PP_MakeUndefined();
  }

  Var* var = GetVar(plugin_object);
  ProxyObjectVar* object = var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return PP_MakeUndefined();
  }

  // Make a var with the host ID.
  PP_Var ret = { PP_VARTYPE_OBJECT };
  ret.value.as_id = object->host_var_id();
  return ret;
}

PluginDispatcher* PluginVarTracker::DispatcherForPluginObject(
    const PP_Var& plugin_object) const {
  DCHECK(CalledOnValidThread());

  if (plugin_object.type != PP_VARTYPE_OBJECT)
    return NULL;

  VarMap::const_iterator found = GetLiveVar(plugin_object);
  if (found == live_vars_.end())
    return NULL;

  ProxyObjectVar* object = found->second.var->AsProxyObjectVar();
  if (!object)
    return NULL;
  return object->dispatcher();
}

void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher,
                                         const PP_Var& host_object) {
  DCHECK(CalledOnValidThread());
  DCHECK(host_object.type == PP_VARTYPE_OBJECT);

  // Convert the host object to a normal var valid in the plugin.
  HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find(
      HostVar(dispatcher, static_cast<int32>(host_object.value.as_id)));
  if (found == host_var_to_plugin_var_.end()) {
    NOTREACHED();
    return;
  }

  // Now just release the object given the plugin var ID.
  ReleaseVar(found->second);
}

void PluginVarTracker::DidDeleteInstance(PP_Instance instance) {
  // Calling the destructors on plugin objects may in turn release other
  // objects which will mutate the map out from under us. So do a two-step
  // process of identifying the ones to delete, and then delete them.
  //
  // See the comment above user_data_to_plugin_ in the header file. We assume
  // there aren't that many objects so a brute-force search is reasonable.
  std::vector<void*> user_data_to_delete;
  for (UserDataToPluginImplementedVarMap::const_iterator i =
           user_data_to_plugin_.begin();
       i != user_data_to_plugin_.end();
       ++i) {
    if (i->second.instance == instance)
      user_data_to_delete.push_back(i->first);
  }

  for (size_t i = 0; i < user_data_to_delete.size(); i++) {
    UserDataToPluginImplementedVarMap::iterator found =
        user_data_to_plugin_.find(user_data_to_delete[i]);
    if (found == user_data_to_plugin_.end())
      continue;  // Object removed from list while we were iterating.

    if (!found->second.plugin_object_id) {
      // This object is for the freed instance and the plugin is not holding
      // any references to it. Deallocate immediately.
      found->second.ppp_class->Deallocate(found->first);
      user_data_to_plugin_.erase(found);
    } else {
      // The plugin is holding refs to this object. We don't want to call
      // Deallocate since the plugin may be depending on those refs to keep
      // its data alive. To avoid crashes in this case, just clear out the
      // instance to mark it and continue. When the plugin refs go to 0,
      // we'll notice there is no instance and call Deallocate.
      found->second.instance = 0;
    }
  }
}

ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
  return new PluginArrayBufferVar(size_in_bytes);
}

void PluginVarTracker::PluginImplementedObjectCreated(
    PP_Instance instance,
    const PP_Var& created_var,
    const PPP_Class_Deprecated* ppp_class,
    void* ppp_class_data) {
  PluginImplementedVar p;
  p.ppp_class = ppp_class;
  p.instance = instance;
  p.plugin_object_id = created_var.value.as_id;
  user_data_to_plugin_[ppp_class_data] = p;

  // Link the user data to the object.
  ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar();
  object->set_user_data(ppp_class_data);
}

void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) {
  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(user_data);
  if (found == user_data_to_plugin_.end()) {
    NOTREACHED();
    return;
  }
  user_data_to_plugin_.erase(found);
}

bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) {
  return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end();
}

bool PluginVarTracker::ValidatePluginObjectCall(
    const PPP_Class_Deprecated* ppp_class,
    void* user_data) {
  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(user_data);
  if (found == user_data_to_plugin_.end())
    return false;
  return found->second.ppp_class == ppp_class;
}

int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
  // Normal adding.
  int32 new_id = VarTracker::AddVarInternal(var, mode);

  // Need to add proxy objects to the host var map.
  ProxyObjectVar* proxy_object = var->AsProxyObjectVar();
  if (proxy_object) {
    HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id());
    DCHECK(host_var_to_plugin_var_.find(host_var) ==
           host_var_to_plugin_var_.end());  // Adding an object twice, use
                                            // FindOrMakePluginVarFromHostVar.
    host_var_to_plugin_var_[host_var] = new_id;
  }
  return new_id;
}

void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) {
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return;
  }

  DCHECK(iter->second.ref_count == 0);

  // Got an AddRef for an object we have no existing reference for.
  // We need to tell the browser we've taken a ref. This comes up when the
  // browser passes an object as an input param and holds a ref for us.
  // This must be a sync message since otherwise the "addref" will actually
  // occur after the return to the browser of the sync function that
  // presumably sent the object.
  SendAddRefObjectMsg(*object);
}

void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  if (!object) {
    NOTREACHED();
    return;
  }

  // Notify the host we're no longer holding our ref.
  DCHECK(iter->second.ref_count == 0);
  SendReleaseObjectMsg(*object);

  UserDataToPluginImplementedVarMap::iterator found =
      user_data_to_plugin_.find(object->user_data());
  if (found != user_data_to_plugin_.end()) {
    // This object is implemented in the plugin.
    if (found->second.instance == 0) {
      // Instance is destroyed. This means that we'll never get a Deallocate
      // call from the renderer and we should do so now.
      found->second.ppp_class->Deallocate(found->first);
      user_data_to_plugin_.erase(found);
    } else {
      // The plugin is releasing its last reference to an object it implements.
      // Clear the tracking data that links our "plugin implemented object" to
      // the var. If the instance is destroyed and there is no ID, we know that
      // we should just call Deallocate on the object data.
      //
      // See the plugin_object_id declaration for more info.
      found->second.plugin_object_id = 0;
    }
  }

  // This will optionally delete the info from live_vars_.
  VarTracker::ObjectGettingZeroRef(iter);
}

bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
  // Get the info before calling the base class's version of this function,
  // which may delete the object.
  ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
  HostVar host_var(object->dispatcher(), object->host_var_id());

  if (!VarTracker::DeleteObjectInfoIfNecessary(iter))
    return false;

  // Clean up the host var mapping.
  DCHECK(host_var_to_plugin_var_.find(host_var) !=
         host_var_to_plugin_var_.end());
  host_var_to_plugin_var_.erase(host_var);
  return true;
}

PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) {
  // We can't use object->GetPPVar() because we don't want to affect the
  // refcount, so we have to add everything manually here.
  int32 var_id = object->GetExistingVarID();
  if (!var_id) {
    var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE);
    object->AssignVarID(var_id);
  }

  PP_Var ret = { PP_VARTYPE_OBJECT };
  ret.value.as_id = var_id;
  return ret;
}

void PluginVarTracker::SendAddRefObjectMsg(
    const ProxyObjectVar& proxy_object) {
  int unused;
  proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject(
      API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused));
}

void PluginVarTracker::SendReleaseObjectMsg(
    const ProxyObjectVar& proxy_object) {
  proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
      API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id()));
}

scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar(
    const PP_Var& var,
    PluginDispatcher* dispatcher) {
  DCHECK(var.type == PP_VARTYPE_OBJECT);
  HostVar host_var(dispatcher, var.value.as_id);

  HostVarToPluginVarMap::iterator found =
      host_var_to_plugin_var_.find(host_var);
  if (found == host_var_to_plugin_var_.end()) {
    // Create a new object.
    return scoped_refptr<ProxyObjectVar>(
        new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id)));
  }

  // Have this host var, look up the object.
  VarMap::iterator ret = live_vars_.find(found->second);
  DCHECK(ret != live_vars_.end());

  // All objects should be proxy objects.
  DCHECK(ret->second.var->AsProxyObjectVar());
  return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar());
}

}  // namesace proxy
}  // namespace ppapi
<|endoftext|>


<commit_before>// Copyright (c) 2015, 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 "bin/vmservice_dartium.h"

#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/eventhandler.h"
#include "bin/platform.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "bin/vmservice_impl.h"
#include "zlib/zlib.h"

namespace dart {
namespace bin {

#define CHECK_RESULT(result)                                                   \
  if (Dart_IsError(result)) {                                                  \
    fprintf(stderr, "CHECK_RESULT failed: %s", Dart_GetError(result));         \
    Dart_ExitScope();                                                          \
    Dart_ShutdownIsolate();                                                    \
    return 0;                                                                  \
  }

static const char* DEFAULT_VM_SERVICE_SERVER_IP = "127.0.0.1";
static const int DEFAULT_VM_SERVICE_SERVER_PORT = 0;

void VmServiceServer::Bootstrap() {
  if (!Platform::Initialize()) {
    fprintf(stderr, "Platform::Initialize() failed\n");
  }
  DartUtils::SetOriginalWorkingDirectory();
  Thread::InitOnce();
  TimerUtils::InitOnce();
  EventHandler::Start();
}

Dart_Isolate VmServiceServer::CreateIsolate(const uint8_t* snapshot_buffer) {
  ASSERT(snapshot_buffer != NULL);
  // Create the isolate.
  IsolateData* isolate_data =
      new IsolateData(DART_VM_SERVICE_ISOLATE_NAME, NULL, NULL, NULL);
  char* error = 0;
  Dart_Isolate isolate =
      Dart_CreateIsolate(DART_VM_SERVICE_ISOLATE_NAME, "main", snapshot_buffer,
                         NULL, NULL, isolate_data, &error);
  if (!isolate) {
    fprintf(stderr, "Dart_CreateIsolate failed: %s\n", error);
    return 0;
  }

  Dart_EnterScope();
  Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
  Builtin::SetNativeResolver(Builtin::kIOLibrary);

  ASSERT(Dart_IsServiceIsolate(isolate));
  if (!VmService::Setup(
          DEFAULT_VM_SERVICE_SERVER_IP, DEFAULT_VM_SERVICE_SERVER_PORT,
          false /* running_precompiled */, false /* disable origin checks */,
          false /* trace_loading */)) {
    fprintf(stderr, "Vmservice::Setup failed: %s\n",
            VmService::GetErrorMessage());
    isolate = NULL;
  }
  Dart_ExitScope();
  Dart_ExitIsolate();
  return isolate;
}

const char* VmServiceServer::GetServerAddress() {
  return VmService::GetServerAddress();
}

void VmServiceServer::DecompressAssets(const uint8_t* input,
                                       unsigned int input_len,
                                       uint8_t** output,
                                       unsigned int* output_length) {
  ASSERT(input != NULL);
  ASSERT(input_len > 0);
  ASSERT(output != NULL);
  ASSERT(output_length != NULL);

  // Initialize output.
  *output = NULL;
  *output_length = 0;

  const unsigned int kChunkSize = 256 * 1024;
  uint8_t chunk_out[kChunkSize];
  z_stream strm;
  strm.zalloc = Z_NULL;
  strm.zfree = Z_NULL;
  strm.opaque = Z_NULL;
  strm.avail_in = 0;
  strm.next_in = 0;
  int ret = inflateInit2(&strm, 32 + MAX_WBITS);
  ASSERT(ret == Z_OK);

  unsigned int input_cursor = 0;
  unsigned int output_cursor = 0;
  do {
    // Setup input.
    unsigned int size_in = input_len - input_cursor;
    if (size_in > kChunkSize) {
      size_in = kChunkSize;
    }
    strm.avail_in = size_in;
    strm.next_in = const_cast<uint8_t*>(&input[input_cursor]);

    // Inflate until we've exhausted the current input chunk.
    do {
      // Setup output.
      strm.avail_out = kChunkSize;
      strm.next_out = &chunk_out[0];
      // Inflate.
      ret = inflate(&strm, Z_SYNC_FLUSH);
      // We either hit the end of the stream or made forward progress.
      ASSERT((ret == Z_STREAM_END) || (ret == Z_OK));
      // Grow output buffer size.
      unsigned int size_out = kChunkSize - strm.avail_out;
      *output_length += size_out;
      *output = reinterpret_cast<uint8_t*>(realloc(*output, *output_length));
      // Copy output.
      memmove(&((*output)[output_cursor]), &chunk_out[0], size_out);
      output_cursor += size_out;
    } while (strm.avail_out == 0);

    // We've processed size_in bytes.
    input_cursor += size_in;

    // We're finished decompressing when zlib tells us.
  } while (ret != Z_STREAM_END);

  inflateEnd(&strm);
}

/* DISALLOW_ALLOCATION */
void VmServiceServer::operator delete(void* pointer) {
  fprintf(stderr, "unreachable code\n");
  abort();
}

}  // namespace bin
}  // namespace dart
<commit_msg>Support for IPV6 for observatory in Dartium.<commit_after>// Copyright (c) 2015, 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 "bin/vmservice_dartium.h"

#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/eventhandler.h"
#include "bin/platform.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "bin/vmservice_impl.h"
#include "zlib/zlib.h"

namespace dart {
namespace bin {

#define CHECK_RESULT(result)                                                   \
  if (Dart_IsError(result)) {                                                  \
    fprintf(stderr, "CHECK_RESULT failed: %s", Dart_GetError(result));         \
    Dart_ExitScope();                                                          \
    Dart_ShutdownIsolate();                                                    \
    return 0;                                                                  \
  }

static const char* DART_IPV6_ONLY_FLAG = "DART_IPV6_ONLY";
static const char* DEFAULT_VM_SERVICE_SERVER_IP_V6 = "::1";
static const char* DEFAULT_VM_SERVICE_SERVER_IP_V4 = "127.0.0.1";
static const int DEFAULT_VM_SERVICE_SERVER_PORT = 0;

static bool IsIpv6Only() {
  char* v = getenv(DART_IPV6_ONLY_FLAG);
  if (!v) return 0;
  return v[0] == '1';
}

void VmServiceServer::Bootstrap() {
  if (!Platform::Initialize()) {
    fprintf(stderr, "Platform::Initialize() failed\n");
  }
  DartUtils::SetOriginalWorkingDirectory();
  Thread::InitOnce();
  TimerUtils::InitOnce();
  EventHandler::Start();
}

Dart_Isolate VmServiceServer::CreateIsolate(const uint8_t* snapshot_buffer) {
  ASSERT(snapshot_buffer != NULL);
  // Create the isolate.
  IsolateData* isolate_data =
      new IsolateData(DART_VM_SERVICE_ISOLATE_NAME, NULL, NULL, NULL);
  char* error = 0;
  Dart_Isolate isolate =
      Dart_CreateIsolate(DART_VM_SERVICE_ISOLATE_NAME, "main", snapshot_buffer,
                         NULL, NULL, isolate_data, &error);
  if (!isolate) {
    fprintf(stderr, "Dart_CreateIsolate failed: %s\n", error);
    return 0;
  }

  Dart_EnterScope();
  Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
  Builtin::SetNativeResolver(Builtin::kIOLibrary);

  ASSERT(Dart_IsServiceIsolate(isolate));
  if (!VmService::Setup(
          IsIpv6Only() ? DEFAULT_VM_SERVICE_SERVER_IP_V6 :
                 DEFAULT_VM_SERVICE_SERVER_IP_V4,
          DEFAULT_VM_SERVICE_SERVER_PORT,
          false /* running_precompiled */, false /* disable origin checks */,
          false /* trace_loading */)) {
    fprintf(stderr, "Vmservice::Setup failed: %s\n",
            VmService::GetErrorMessage());
    isolate = NULL;
  }
  Dart_ExitScope();
  Dart_ExitIsolate();
  return isolate;
}

const char* VmServiceServer::GetServerAddress() {
  return VmService::GetServerAddress();
}

void VmServiceServer::DecompressAssets(const uint8_t* input,
                                       unsigned int input_len,
                                       uint8_t** output,
                                       unsigned int* output_length) {
  ASSERT(input != NULL);
  ASSERT(input_len > 0);
  ASSERT(output != NULL);
  ASSERT(output_length != NULL);

  // Initialize output.
  *output = NULL;
  *output_length = 0;

  const unsigned int kChunkSize = 256 * 1024;
  uint8_t chunk_out[kChunkSize];
  z_stream strm;
  strm.zalloc = Z_NULL;
  strm.zfree = Z_NULL;
  strm.opaque = Z_NULL;
  strm.avail_in = 0;
  strm.next_in = 0;
  int ret = inflateInit2(&strm, 32 + MAX_WBITS);
  ASSERT(ret == Z_OK);

  unsigned int input_cursor = 0;
  unsigned int output_cursor = 0;
  do {
    // Setup input.
    unsigned int size_in = input_len - input_cursor;
    if (size_in > kChunkSize) {
      size_in = kChunkSize;
    }
    strm.avail_in = size_in;
    strm.next_in = const_cast<uint8_t*>(&input[input_cursor]);

    // Inflate until we've exhausted the current input chunk.
    do {
      // Setup output.
      strm.avail_out = kChunkSize;
      strm.next_out = &chunk_out[0];
      // Inflate.
      ret = inflate(&strm, Z_SYNC_FLUSH);
      // We either hit the end of the stream or made forward progress.
      ASSERT((ret == Z_STREAM_END) || (ret == Z_OK));
      // Grow output buffer size.
      unsigned int size_out = kChunkSize - strm.avail_out;
      *output_length += size_out;
      *output = reinterpret_cast<uint8_t*>(realloc(*output, *output_length));
      // Copy output.
      memmove(&((*output)[output_cursor]), &chunk_out[0], size_out);
      output_cursor += size_out;
    } while (strm.avail_out == 0);

    // We've processed size_in bytes.
    input_cursor += size_in;

    // We're finished decompressing when zlib tells us.
  } while (ret != Z_STREAM_END);

  inflateEnd(&strm);
}

/* DISALLOW_ALLOCATION */
void VmServiceServer::operator delete(void* pointer) {
  fprintf(stderr, "unreachable code\n");
  abort();
}

}  // namespace bin
}  // namespace dart
<|endoftext|>


<commit_before><commit_msg>WaE: unreachable code<commit_after><|endoftext|>


<commit_before><commit_msg>TableRef: use relative references where appropriate<commit_after><|endoftext|>


<commit_before><commit_msg>loplugin:simplifybool<commit_after><|endoftext|>


<commit_before><commit_msg>in COUNT() use ConvertStringToValue() for literal string arguments<commit_after><|endoftext|>