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

#include "src/fuzzing/fuzzer.h"

#include <iostream>
#include <string>
#include <vector>

namespace fido2_tests {
namespace {

// Prints a line stating the file being mutated, rewriting the last line of
// output.
void PrintMutatingFile(std::string_view file_name, size_t last_file_name_len) {
  // Clean last line output in case the current line to be printed is shorter.
  std::cout << "\r                   " << std::string(last_file_name_len, ' ');
  std::cout << "\rMutating from file " << file_name << ". " << std::flush;
}

void PrintFuzzingOptions(fuzzing_helpers::FuzzingOptions fuzzing_options) {
  std::cout << "\n|--- Fuzzer information ---|\n";
  std::cout << "Initial corpus path: " << fuzzing_options.corpus_path
            << InputTypeToDirectoryName(fuzzing_options.fuzzing_input_type)
            << "/\n";
  if (fuzzing_options.num_runs == 0) {
    std::cout
        << "--num_runs is not provided. The fuzzer will run indefinitely\n";
  } else {
    std::cout << "Number of runs: " << fuzzing_options.num_runs << "\n";
  }
  if (fuzzing_options.max_length == 0) {
    std::cout << "--max_length is not provided. There will be no limit\n";
  } else {
    std::cout << "Maximum input length: " << fuzzing_options.max_length << "\n";
  }
  std::cout << "Maximum mutation degree: "
            << fuzzing_options.max_mutation_degree << "\n";
  std::cout << "Seed: " << fuzzing_options.seed << "\n\n" << std::flush;
}

// Returns the string of the current timestamp in microseconds since epoch.
// Placeholder for the fuzzing input's filename.
std::string CurrentTimestampString() {
  return std::to_string(
      std::chrono::system_clock::now().time_since_epoch().count());
}

}  // namespace

Fuzzer::Fuzzer(fuzzing_helpers::FuzzingOptions fuzzing_options)
    : fuzzing_options_(fuzzing_options),
      corpus_controller_(CorpusController(fuzzing_options.fuzzing_input_type,
                                          fuzzing_options.corpus_path)),
      mutator_(
          Mutator(fuzzing_options.max_mutation_degree, fuzzing_options.seed)) {
  srand(fuzzing_options.seed);
}

void Fuzzer::Run(CommandState* command_state, DeviceInterface* device,
                 Monitor* monitor) {
  PrintFuzzingOptions(fuzzing_options_);
  size_t last_input_name_len = 0;
  while (1) {  // TODO: add num_runs
    auto [mutated_input_data, seed_input_name] = GetNextInput();
    PrintMutatingFile(seed_input_name, last_input_name_len);
    fuzzing_helpers::SendInput(device, fuzzing_options_.fuzzing_input_type,
                               mutated_input_data);
    if (monitor->DeviceCrashed(command_state)) {
      monitor->PrintCrashReport();
      std::string save_path =
          monitor->SaveCrashFile(fuzzing_options_.fuzzing_input_type,
                                 mutated_input_data, CurrentTimestampString());
      break;
    }
    last_input_name_len = seed_input_name.size();
  }
}

std::tuple<std::vector<uint8_t>, std::string> Fuzzer::GetNextInput() {
  auto [input_data, input_name] = corpus_controller_.GetRandomInput();
  mutator_.Mutate(input_data, fuzzing_options_.max_length);
  return {input_data, input_name};
}

}  // namespace fido2_tests

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

#include "src/fuzzing/fuzzer.h"

#include <iostream>
#include <string>
#include <vector>

namespace fido2_tests {
namespace {

// Prints a line stating the file being mutated, rewriting the last line of
// output.
void PrintMutatingFile(std::string_view file_name, size_t last_file_name_len) {
  // Clean last line output in case the current line to be printed is shorter.
  std::cout << "\r                   " << std::string(last_file_name_len, ' ');
  std::cout << "\rMutating from file " << file_name << ". " << std::flush;
}

void PrintFuzzingOptions(fuzzing_helpers::FuzzingOptions fuzzing_options) {
  std::cout << "\n|--- Fuzzer information ---|\n";
  std::cout << "Initial corpus path: " << fuzzing_options.corpus_path
            << InputTypeToDirectoryName(fuzzing_options.fuzzing_input_type)
            << "/\n";
  if (fuzzing_options.num_runs == 0) {
    std::cout
        << "--num_runs is not provided. The fuzzer will run indefinitely\n";
  } else {
    std::cout << "Number of runs: " << fuzzing_options.num_runs << "\n";
  }
  if (fuzzing_options.max_length == 0) {
    std::cout << "--max_length is not provided. There will be no limit\n";
  } else {
    std::cout << "Maximum input length: " << fuzzing_options.max_length << "\n";
  }
  std::cout << "Maximum mutation degree: "
            << fuzzing_options.max_mutation_degree << "\n";
  std::cout << "Seed: " << fuzzing_options.seed << "\n\n" << std::flush;
}

// Returns the string of the current timestamp in microseconds since epoch.
// Placeholder for the fuzzing input's filename.
std::string CurrentTimestampString() {
  return std::to_string(
      std::chrono::system_clock::now().time_since_epoch().count());
}

}  // namespace

Fuzzer::Fuzzer(fuzzing_helpers::FuzzingOptions fuzzing_options)
    : fuzzing_options_(fuzzing_options),
      corpus_controller_(CorpusController(fuzzing_options.fuzzing_input_type,
                                          fuzzing_options.corpus_path)),
      mutator_(
          Mutator(fuzzing_options.max_mutation_degree, fuzzing_options.seed)) {
  srand(fuzzing_options.seed);
}

void Fuzzer::Run(CommandState* command_state, DeviceInterface* device,
                 Monitor* monitor) {
  PrintFuzzingOptions(fuzzing_options_);
  size_t last_input_name_len = 0;
  int iteration = 0;
  while (fuzzing_options_.num_runs == 0 ||
         iteration < fuzzing_options_.num_runs) {
    auto [mutated_input_data, seed_input_name] = GetNextInput();
    PrintMutatingFile(seed_input_name, last_input_name_len);
    fuzzing_helpers::SendInput(device, fuzzing_options_.fuzzing_input_type,
                               mutated_input_data);
    if (monitor->DeviceCrashed(command_state)) {
      monitor->PrintCrashReport();
      std::string save_path =
          monitor->SaveCrashFile(fuzzing_options_.fuzzing_input_type,
                                 mutated_input_data, CurrentTimestampString());
      break;
    }
    last_input_name_len = seed_input_name.size();
    ++iteration;
  }
}

std::tuple<std::vector<uint8_t>, std::string> Fuzzer::GetNextInput() {
  auto [input_data, input_name] = corpus_controller_.GetRandomInput();
  mutator_.Mutate(input_data, fuzzing_options_.max_length);
  return {input_data, input_name};
}

}  // namespace fido2_tests

<|endoftext|>


<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.

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

#ifndef __itkStreamlineTrackingFilter_txx
#define __itkStreamlineTrackingFilter_txx

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#include "itkStreamlineTrackingFilter.h"
#include <itkImageRegionConstIterator.h>
#include <itkImageRegionConstIteratorWithIndex.h>
#include <itkImageRegionIterator.h>

#define _USE_MATH_DEFINES
#include <math.h>

namespace itk {

//#define QBALL_RECON_PI       M_PI

template< class TTensorPixelType, class TPDPixelType>
StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::StreamlineTrackingFilter():
    m_FaThreshold(0.2),
    m_StepSize(0.2),
    m_MaxLength(10000),
    m_SeedsPerVoxel(1)
{
    // At least 1 inputs is necessary for a vector image.
    // For images added one at a time we need at least six
    this->SetNumberOfRequiredInputs( 1 );
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::BeforeThreadedGenerateData()
{
    m_FiberPolyData = FiberPolyDataType::New();
    m_Points = vtkPoints::New();
    m_Cells = vtkCellArray::New();

    typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) );
    m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(0);
    m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(1);
    m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(2);

    m_PolyDataContainer = itk::VectorContainer< int, FiberPolyDataType >::New();
    for (int i=0; i<this->GetNumberOfThreads(); i++)
    {
        FiberPolyDataType poly = FiberPolyDataType::New();
        m_PolyDataContainer->InsertElement(i, poly);
    }

    if (m_MaskImage.IsNull())
    {
        itk::Vector<double, 3> spacing = inputImage->GetSpacing();
        itk::Point<double, 3> origin = inputImage->GetOrigin();
        itk::Matrix<double, 3, 3> direction = inputImage->GetDirection();
        ImageRegion<3> imageRegion = inputImage->GetLargestPossibleRegion();

        // initialize crossings image
        m_MaskImage = ItkUcharImgType::New();
        m_MaskImage->SetSpacing( spacing );
        m_MaskImage->SetOrigin( origin );
        m_MaskImage->SetDirection( direction );
        m_MaskImage->SetRegions( imageRegion );
        m_MaskImage->Allocate();
        m_MaskImage->FillBuffer(1);
    }
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
                       int threadId)
{
    FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId);
    vtkSmartPointer<vtkPoints> Points = vtkPoints::New();
    vtkSmartPointer<vtkCellArray> Cells = vtkCellArray::New();

    typedef itk::DiffusionTensor3D<TTensorPixelType>    TensorType;
    typedef ImageRegionConstIterator< InputImageType >  InputIteratorType;
    typedef ImageRegionConstIterator< ItkUcharImgType >  MaskIteratorType;
    typedef typename InputImageType::PixelType          InputTensorType;
    typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) );

    InputIteratorType it(inputImage, outputRegionForThread );
    MaskIteratorType mit(m_MaskImage, outputRegionForThread );
    it.GoToBegin();
    mit.GoToBegin();
    while( !it.IsAtEnd() )
    {
        if (mit.Value()==0)
        {
            ++mit;
            ++it;
            continue;
        }

        typename TensorType::EigenValuesArrayType eigenvalues;
        typename TensorType::EigenVectorsMatrixType eigenvectors;

        for (int s=0; s<m_SeedsPerVoxel; s++)
        {
            unsigned long counter = 0;
            vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
            typename InputImageType::IndexType index = it.GetIndex();
            itk::ContinuousIndex<double, 3> pos;

            if (m_SeedsPerVoxel>1)
            {
                pos[0] = index[0]+(double)(rand()%99-49)/100;
                pos[1] = index[1]+(double)(rand()%99-49)/100;
                pos[2] = index[2]+(double)(rand()%99-49)/100;
            }
            else
            {
                pos[0] = index[0];
                pos[1] = index[1];
                pos[2] = index[2];
            }

            int step = 0;
            vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0);
            while (step < m_MaxLength)
            {
                ++step;

                index[0] = round(pos[0]);
                index[1] = round(pos[1]);
                index[2] = round(pos[2]);

                if (index[0] < 0 || index[0]>=m_ImageSize[0])
                    break;
                if (index[1] < 0 || index[1]>=m_ImageSize[1])
                    break;
                if (index[2] < 0 || index[2]>=m_ImageSize[2])
                    break;

                typename InputImageType::PixelType tensor = inputImage->GetPixel(index);
                if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold)
                {
                    tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);

                    int eIndex = 2;
                    if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) )
                        eIndex = 0;
                    else if(eigenvalues[1] >= eigenvalues[2])
                        eIndex = 1;

                    vnl_vector_fixed<double,3> dir;
                    dir[0] = eigenvectors(eIndex, 0);
                    dir[1] = eigenvectors(eIndex, 1);
                    dir[2] = eigenvectors(eIndex, 2);
                    dir.normalize();

                    if (!dirOld.is_zero())
                    {
                        float angle = dot_product(dirOld, dir);
                        if (angle<0)
                            dir *= -1;
                        angle = fabs(dot_product(dirOld, dir));
                        if (angle<0.7)
                            break;
                    }
                    dirOld = dir;

                    dir *= m_StepSize;

                    itk::Point<double> worldPos;
                    inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos );

                    vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer());
                    container->GetPointIds()->InsertNextId(id);
                    counter++;

                    pos[0] += dir[0];
                    pos[1] += dir[1];
                    pos[2] += dir[2];
                }
            }
            if (counter>0)
                Cells->InsertNextCell(container);
        }
        ++mit;
        ++it;
    }

    poly->SetPoints(Points);
    poly->SetLines(Cells);

    std::cout << "Thread " << threadId << " finished tracking" << std::endl;
}

template< class TTensorPixelType,
          class TPDPixelType>
vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2)
{
    vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
    vtkSmartPointer<vtkCellArray> vNewLines = poly1->GetLines();
    vtkSmartPointer<vtkPoints> vNewPoints = poly1->GetPoints();

    vtkSmartPointer<vtkCellArray> vLines = poly2->GetLines();
    vLines->InitTraversal();
    for( int i=0; i<vLines->GetNumberOfCells(); i++ )
    {
        vtkIdType   numPoints(0);
        vtkIdType*  points(NULL);
        vLines->GetNextCell ( numPoints, points );

        vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
        for( int j=0; j<numPoints; j++)
        {
            vtkIdType id = vNewPoints->InsertNextPoint(poly2->GetPoint(points[j]));
            container->GetPointIds()->InsertNextId(id);
        }
        vNewLines->InsertNextCell(container);
    }

    // initialize polydata
    vNewPolyData->SetPoints(vNewPoints);
    vNewPolyData->SetLines(vNewLines);

    return vNewPolyData;
}
template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::AfterThreadedGenerateData()
{
    MITK_INFO << "Generating polydata ";
    m_FiberPolyData = m_PolyDataContainer->GetElement(0);
    for (int i=1; i<this->GetNumberOfThreads(); i++)
    {
        m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i));
    }
    MITK_INFO << "done";
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::PrintSelf(std::ostream& os, Indent indent) const
{
}

}
#endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx
<commit_msg>added reverse component of streamline tracking<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.

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

#ifndef __itkStreamlineTrackingFilter_txx
#define __itkStreamlineTrackingFilter_txx

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#include "itkStreamlineTrackingFilter.h"
#include <itkImageRegionConstIterator.h>
#include <itkImageRegionConstIteratorWithIndex.h>
#include <itkImageRegionIterator.h>

#define _USE_MATH_DEFINES
#include <math.h>

namespace itk {

//#define QBALL_RECON_PI       M_PI

template< class TTensorPixelType, class TPDPixelType>
StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::StreamlineTrackingFilter():
    m_FaThreshold(0.2),
    m_StepSize(0.2),
    m_MaxLength(10000),
    m_SeedsPerVoxel(1)
{
    // At least 1 inputs is necessary for a vector image.
    // For images added one at a time we need at least six
    this->SetNumberOfRequiredInputs( 1 );
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::BeforeThreadedGenerateData()
{
    m_FiberPolyData = FiberPolyDataType::New();
    m_Points = vtkPoints::New();
    m_Cells = vtkCellArray::New();

    typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) );
    m_ImageSize[0] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(0);
    m_ImageSize[1] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(1);
    m_ImageSize[2] = inputImage->GetLargestPossibleRegion().GetSize().GetElement(2);

    m_PolyDataContainer = itk::VectorContainer< int, FiberPolyDataType >::New();
    for (int i=0; i<this->GetNumberOfThreads(); i++)
    {
        FiberPolyDataType poly = FiberPolyDataType::New();
        m_PolyDataContainer->InsertElement(i, poly);
    }

    if (m_MaskImage.IsNull())
    {
        itk::Vector<double, 3> spacing = inputImage->GetSpacing();
        itk::Point<double, 3> origin = inputImage->GetOrigin();
        itk::Matrix<double, 3, 3> direction = inputImage->GetDirection();
        ImageRegion<3> imageRegion = inputImage->GetLargestPossibleRegion();

        // initialize crossings image
        m_MaskImage = ItkUcharImgType::New();
        m_MaskImage->SetSpacing( spacing );
        m_MaskImage->SetOrigin( origin );
        m_MaskImage->SetDirection( direction );
        m_MaskImage->SetRegions( imageRegion );
        m_MaskImage->Allocate();
        m_MaskImage->FillBuffer(1);
    }
    std::cout << "starting streamline tracking" << std::endl;
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread,
                       int threadId)
{
    FiberPolyDataType poly = m_PolyDataContainer->GetElement(threadId);
    vtkSmartPointer<vtkPoints> Points = vtkPoints::New();
    vtkSmartPointer<vtkCellArray> Cells = vtkCellArray::New();

    typedef itk::DiffusionTensor3D<TTensorPixelType>    TensorType;
    typedef ImageRegionConstIterator< InputImageType >  InputIteratorType;
    typedef ImageRegionConstIterator< ItkUcharImgType >  MaskIteratorType;
    typedef typename InputImageType::PixelType          InputTensorType;
    typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) );

    InputIteratorType it(inputImage, outputRegionForThread );
    MaskIteratorType mit(m_MaskImage, outputRegionForThread );
    it.GoToBegin();
    mit.GoToBegin();
    while( !it.IsAtEnd() )
    {
        if (mit.Value()==0)
        {
            ++mit;
            ++it;
            continue;
        }

        typename TensorType::EigenValuesArrayType eigenvalues;
        typename TensorType::EigenVectorsMatrixType eigenvectors;

        for (int s=0; s<m_SeedsPerVoxel; s++)
        {
            unsigned long counter = 0;
            vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
            std::vector< vtkIdType > pointISs;
            typename InputImageType::IndexType index = it.GetIndex();
            itk::ContinuousIndex<double, 3> pos;
            itk::ContinuousIndex<double, 3> start;

            if (m_SeedsPerVoxel>1)
            {
                pos[0] = index[0]+(double)(rand()%99-49)/100;
                pos[1] = index[1]+(double)(rand()%99-49)/100;
                pos[2] = index[2]+(double)(rand()%99-49)/100;
            }
            else
            {
                pos[0] = index[0];
                pos[1] = index[1];
                pos[2] = index[2];
            }
            start = pos;

            int step = 0;
            vnl_vector_fixed<double,3> dirOld; dirOld.fill(0.0);
            // do forward tracking
            while (step < m_MaxLength)
            {
                ++step;

                index[0] = round(pos[0]);
                index[1] = round(pos[1]);
                index[2] = round(pos[2]);

                if (index[0] < 0 || index[0]>=m_ImageSize[0])
                    break;
                if (index[1] < 0 || index[1]>=m_ImageSize[1])
                    break;
                if (index[2] < 0 || index[2]>=m_ImageSize[2])
                    break;

                typename InputImageType::PixelType tensor = inputImage->GetPixel(index);
                if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold)
                {
                    tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);

                    int eIndex = 2;
                    if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) )
                        eIndex = 0;
                    else if(eigenvalues[1] >= eigenvalues[2])
                        eIndex = 1;

                    vnl_vector_fixed<double,3> dir;
                    dir[0] = eigenvectors(eIndex, 0);
                    dir[1] = eigenvectors(eIndex, 1);
                    dir[2] = eigenvectors(eIndex, 2);
                    dir.normalize();

                    if (!dirOld.is_zero())
                    {
                        float angle = dot_product(dirOld, dir);
                        if (angle<0)
                            dir *= -1;
                        angle = fabs(dot_product(dirOld, dir));
                        if (angle<0.7)
                            break;
                    }
                    dirOld = dir;

                    dir *= m_StepSize;

                    itk::Point<double> worldPos;
                    inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos );

                    vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer());
                    pointISs.push_back(id);
                    counter++;

                    pos[0] += dir[0];
                    pos[1] += dir[1];
                    pos[2] += dir[2];
                }
            }

            // insert reverse IDs
            while (!pointISs.empty())
            {
                container->GetPointIds()->InsertNextId(pointISs.back());
                pointISs.pop_back();
            }

            // do backward tracking
            index = it.GetIndex();
            pos = start;
            dirOld.fill(0.0);
            while (step < m_MaxLength)
            {
                ++step;

                index[0] = round(pos[0]);
                index[1] = round(pos[1]);
                index[2] = round(pos[2]);

                if (index[0] < 0 || index[0]>=m_ImageSize[0])
                    break;
                if (index[1] < 0 || index[1]>=m_ImageSize[1])
                    break;
                if (index[2] < 0 || index[2]>=m_ImageSize[2])
                    break;

                typename InputImageType::PixelType tensor = inputImage->GetPixel(index);
                if(tensor.GetTrace()!=0 && tensor.GetFractionalAnisotropy()>m_FaThreshold)
                {
                    tensor.ComputeEigenAnalysis(eigenvalues, eigenvectors);

                    int eIndex = 2;
                    if( (eigenvalues[0] >= eigenvalues[1]) && (eigenvalues[0] >= eigenvalues[2]) )
                        eIndex = 0;
                    else if(eigenvalues[1] >= eigenvalues[2])
                        eIndex = 1;

                    vnl_vector_fixed<double,3> dir;
                    dir[0] = eigenvectors(eIndex, 0);
                    dir[1] = eigenvectors(eIndex, 1);
                    dir[2] = eigenvectors(eIndex, 2);
                    dir.normalize();
                    dir *= -1; // reverse direction

                    if (!dirOld.is_zero())
                    {
                        float angle = dot_product(dirOld, dir);
                        if (angle<0)
                            dir *= -1;
                        angle = fabs(dot_product(dirOld, dir));
                        if (angle<0.7)
                            break;
                    }
                    dirOld = dir;

                    dir *= m_StepSize;

                    itk::Point<double> worldPos;
                    inputImage->TransformContinuousIndexToPhysicalPoint( pos, worldPos );

                    vtkIdType id = Points->InsertNextPoint(worldPos.GetDataPointer());
                    container->GetPointIds()->InsertNextId(id);
                    counter++;

                    pos[0] += dir[0];
                    pos[1] += dir[1];
                    pos[2] += dir[2];
                }
            }

            if (counter>0)
                Cells->InsertNextCell(container);
        }
        ++mit;
        ++it;
    }

    poly->SetPoints(Points);
    poly->SetLines(Cells);

    std::cout << "Thread " << threadId << " finished tracking" << std::endl;
}

template< class TTensorPixelType,
          class TPDPixelType>
vtkSmartPointer< vtkPolyData > StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::AddPolyData(FiberPolyDataType poly1, FiberPolyDataType poly2)
{
    vtkSmartPointer<vtkPolyData> vNewPolyData = vtkSmartPointer<vtkPolyData>::New();
    vtkSmartPointer<vtkCellArray> vNewLines = poly1->GetLines();
    vtkSmartPointer<vtkPoints> vNewPoints = poly1->GetPoints();

    vtkSmartPointer<vtkCellArray> vLines = poly2->GetLines();
    vLines->InitTraversal();
    for( int i=0; i<vLines->GetNumberOfCells(); i++ )
    {
        vtkIdType   numPoints(0);
        vtkIdType*  points(NULL);
        vLines->GetNextCell ( numPoints, points );

        vtkSmartPointer<vtkPolyLine> container = vtkSmartPointer<vtkPolyLine>::New();
        for( int j=0; j<numPoints; j++)
        {
            vtkIdType id = vNewPoints->InsertNextPoint(poly2->GetPoint(points[j]));
            container->GetPointIds()->InsertNextId(id);
        }
        vNewLines->InsertNextCell(container);
    }

    // initialize polydata
    vNewPolyData->SetPoints(vNewPoints);
    vNewPolyData->SetLines(vNewLines);

    return vNewPolyData;
}
template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::AfterThreadedGenerateData()
{
    MITK_INFO << "Generating polydata ";
    m_FiberPolyData = m_PolyDataContainer->GetElement(0);
    for (int i=1; i<this->GetNumberOfThreads(); i++)
    {
        m_FiberPolyData = AddPolyData(m_FiberPolyData, m_PolyDataContainer->GetElement(i));
    }
    MITK_INFO << "done";
}

template< class TTensorPixelType,
          class TPDPixelType>
void StreamlineTrackingFilter< TTensorPixelType,
TPDPixelType>
::PrintSelf(std::ostream& os, Indent indent) const
{
}

}
#endif // __itkDiffusionQballPrincipleDirectionsImageFilter_txx
<|endoftext|>


<commit_before>/*
* BigInt Assignment Operators
* (C) 1999-2007 Jack Lloyd
*     2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/bigint.h>
#include <botan/internal/mp_core.h>
#include <botan/internal/bit_ops.h>
#include <algorithm>

namespace Botan {

/*
* Addition Operator
*/
BigInt& BigInt::operator+=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(sign() == y.sign())
      bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);
   else
      {
      int32_t relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         secure_vector<word> z(reg_size - 1);
         bigint_sub3(z.data(), y.data(), reg_size - 1, data(), x_sw);
         std::swap(m_reg, z);
         set_sign(y.sign());
         }
      else if(relative_size == 0)
         {
         zeroise(m_reg);
         set_sign(Positive);
         }
      else if(relative_size > 0)
         bigint_sub2(mutable_data(), x_sw, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Subtraction Operator
*/
BigInt& BigInt::operator-=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   int32_t relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(relative_size < 0)
      {
      if(sign() == y.sign())
         bigint_sub2_rev(mutable_data(), y.data(), y_sw);
      else
         bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);

      set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(sign() == y.sign())
         {
         clear();
         set_sign(Positive);
         }
      else
         bigint_shl1(mutable_data(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(sign() == y.sign())
         bigint_sub2(mutable_data(), x_sw, y.data(), y_sw);
      else
         bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Multiplication Operator
*/
BigInt& BigInt::operator*=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();
   set_sign((sign() == y.sign()) ? Positive : Negative);

   if(x_sw == 0 || y_sw == 0)
      {
      clear();
      set_sign(Positive);
      }
   else if(x_sw == 1 && y_sw)
      {
      grow_to(y_sw + 2);
      bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0));
      }
   else if(y_sw == 1 && x_sw)
      {
      grow_to(x_sw + 2);
      bigint_linmul2(mutable_data(), x_sw, y.word_at(0));
      }
   else
      {
      grow_to(size() + y.size());

      secure_vector<word> z(data(), data() + x_sw);
      secure_vector<word> workspace(size());
      bigint_mul(*this, BigInt(*this), y, workspace.data());
      }

   return (*this);
   }

/*
* Division Operator
*/
BigInt& BigInt::operator/=(const BigInt& y)
   {
   if(y.sig_words() == 1 && is_power_of_2(y.word_at(0)))
      (*this) >>= (y.bits() - 1);
   else
      (*this) = (*this) / y;
   return (*this);
   }

/*
* Modulo Operator
*/
BigInt& BigInt::operator%=(const BigInt& mod)
   {
   return (*this = (*this) % mod);
   }

/*
* Modulo Operator
*/
word BigInt::operator%=(word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();

   if(is_power_of_2(mod))
       {
       word result = (word_at(0) & (mod - 1));
       clear();
       grow_to(2);
       m_reg[0] = result;
       return result;
       }

   word remainder = 0;

   for(size_t j = sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, word_at(j-1), mod);
   clear();
   grow_to(2);

   if(remainder && sign() == BigInt::Negative)
      m_reg[0] = mod - remainder;
   else
      m_reg[0] = remainder;

   set_sign(BigInt::Positive);

   return word_at(0);
   }

/*
* Left Shift Operator
*/
BigInt& BigInt::operator<<=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS,
                   words = sig_words();

      grow_to(words + shift_words + (shift_bits ? 1 : 0));
      bigint_shl1(mutable_data(), words, shift_words, shift_bits);
      }

   return (*this);
   }

/*
* Right Shift Operator
*/
BigInt& BigInt::operator>>=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS;

      bigint_shr1(mutable_data(), sig_words(), shift_words, shift_bits);

      if(is_zero())
         set_sign(Positive);
      }

   return (*this);
   }

}
<commit_msg>Remove needless variable<commit_after>/*
* BigInt Assignment Operators
* (C) 1999-2007 Jack Lloyd
*     2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/bigint.h>
#include <botan/internal/mp_core.h>
#include <botan/internal/bit_ops.h>
#include <algorithm>

namespace Botan {

/*
* Addition Operator
*/
BigInt& BigInt::operator+=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(sign() == y.sign())
      bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);
   else
      {
      int32_t relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         secure_vector<word> z(reg_size - 1);
         bigint_sub3(z.data(), y.data(), reg_size - 1, data(), x_sw);
         std::swap(m_reg, z);
         set_sign(y.sign());
         }
      else if(relative_size == 0)
         {
         zeroise(m_reg);
         set_sign(Positive);
         }
      else if(relative_size > 0)
         bigint_sub2(mutable_data(), x_sw, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Subtraction Operator
*/
BigInt& BigInt::operator-=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();

   int32_t relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

   const size_t reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(relative_size < 0)
      {
      if(sign() == y.sign())
         bigint_sub2_rev(mutable_data(), y.data(), y_sw);
      else
         bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);

      set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(sign() == y.sign())
         {
         clear();
         set_sign(Positive);
         }
      else
         bigint_shl1(mutable_data(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(sign() == y.sign())
         bigint_sub2(mutable_data(), x_sw, y.data(), y_sw);
      else
         bigint_add2(mutable_data(), reg_size - 1, y.data(), y_sw);
      }

   return (*this);
   }

/*
* Multiplication Operator
*/
BigInt& BigInt::operator*=(const BigInt& y)
   {
   const size_t x_sw = sig_words(), y_sw = y.sig_words();
   set_sign((sign() == y.sign()) ? Positive : Negative);

   if(x_sw == 0 || y_sw == 0)
      {
      clear();
      set_sign(Positive);
      }
   else if(x_sw == 1 && y_sw)
      {
      grow_to(y_sw + 2);
      bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0));
      }
   else if(y_sw == 1 && x_sw)
      {
      grow_to(x_sw + 2);
      bigint_linmul2(mutable_data(), x_sw, y.word_at(0));
      }
   else
      {
      grow_to(size() + y.size());
      secure_vector<word> workspace(size());
      bigint_mul(*this, BigInt(*this), y, workspace.data());
      }

   return (*this);
   }

/*
* Division Operator
*/
BigInt& BigInt::operator/=(const BigInt& y)
   {
   if(y.sig_words() == 1 && is_power_of_2(y.word_at(0)))
      (*this) >>= (y.bits() - 1);
   else
      (*this) = (*this) / y;
   return (*this);
   }

/*
* Modulo Operator
*/
BigInt& BigInt::operator%=(const BigInt& mod)
   {
   return (*this = (*this) % mod);
   }

/*
* Modulo Operator
*/
word BigInt::operator%=(word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();

   if(is_power_of_2(mod))
       {
       word result = (word_at(0) & (mod - 1));
       clear();
       grow_to(2);
       m_reg[0] = result;
       return result;
       }

   word remainder = 0;

   for(size_t j = sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, word_at(j-1), mod);
   clear();
   grow_to(2);

   if(remainder && sign() == BigInt::Negative)
      m_reg[0] = mod - remainder;
   else
      m_reg[0] = remainder;

   set_sign(BigInt::Positive);

   return word_at(0);
   }

/*
* Left Shift Operator
*/
BigInt& BigInt::operator<<=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS,
                   words = sig_words();

      grow_to(words + shift_words + (shift_bits ? 1 : 0));
      bigint_shl1(mutable_data(), words, shift_words, shift_bits);
      }

   return (*this);
   }

/*
* Right Shift Operator
*/
BigInt& BigInt::operator>>=(size_t shift)
   {
   if(shift)
      {
      const size_t shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS;

      bigint_shr1(mutable_data(), sig_words(), shift_words, shift_bits);

      if(is_zero())
         set_sign(Positive);
      }

   return (*this);
   }

}
<|endoftext|>


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

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 Mathieu Malaterre
  All rights reserved.
  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "gdcmGlobal.h"
#include "gdcmDicts.h"
#include "gdcmDefs.h"
#include "gdcmFilename.h"

#include <limits.h> // PATH_MAX
#include <string.h> // strcpy
#ifdef _WIN32
#include <windows.h> // MAX_PATH
#endif

namespace gdcm
{

// Must NOT be initialized.  Default initialization to zero is
// necessary.
unsigned int GlobalCount;

class GlobalInternal
{
public:
  GlobalInternal():GlobalDicts(),GlobalDefs() {}
  Dicts GlobalDicts; // Part 6 + Part 4 elements
// TODO need H table for TransferSyntax / MediaStorage / Part 3 ...
  Defs GlobalDefs;

  // Ressource paths:
  // By default only construct two paths:
  // - The official install dir (need to keep in sinc with cmakelist variable
  // - a dynamic one, so that gdcm is somewhat rellocatable
  // - on some system where it make sense the path where the Resource should be located
  void LoadDefaultPaths()
    {
    assert( RessourcePaths.empty() );
    const char filename2[] = GDCM_CMAKE_INSTALL_PREFIX "/" GDCM_INSTALL_DATA_DIR "/XML/";
    RessourcePaths.push_back( filename2 );
    const char filename3[] = GDCM_CMAKE_INSTALL_PREFIX " " GDCM_API_VERSION "/" GDCM_INSTALL_DATA_DIR "/XML/";
    RessourcePaths.push_back( filename3 );
    const char *curprocfn = System::GetCurrentProcessFileName();
    if( curprocfn )
      {
      Filename fn( curprocfn );
      std::string str = fn.GetPath();
      str += "/../" GDCM_INSTALL_DATA_DIR "/XML/";
      RessourcePaths.push_back( str );
      }
    const char *respath = System::GetCurrentResourcesDirectory();
    if( respath )
      {
      RessourcePaths.push_back( respath );
      }
#ifdef GDCM_BUILD_TESTING
    // Needed for backward compat and dashboard
    const char src_path[] = GDCM_SOURCE_DIR "/Source/InformationObjectDefinition/";
    RessourcePaths.push_back( src_path );
#endif
    }
  std::vector<std::string> RessourcePaths;
};

Global::Global()
{
  if(++GlobalCount == 1)
    {
    assert( Internals == NULL ); // paranoid
    Internals = new GlobalInternal;
    assert( Internals->GlobalDicts.IsEmpty() );
    // Fill in with default values now !
    // at startup time is safer as later call might be from different thread
    // thus initialization of std::map would be all skrew up
    Internals->GlobalDicts.LoadDefaults();
    assert( Internals->GlobalDefs.IsEmpty() );
    // Same goes for GlobalDefs:
    //Internals->GlobalDefs.LoadDefaults();
    Internals->LoadDefaultPaths();
    }
}

Global::~Global()
{
  if(--GlobalCount == 0)
    {
    //Internals->GlobalDicts.Unload();
    delete Internals;
    Internals = NULL; // paranoid
    }
}

bool Global::LoadResourcesFiles()
{
  assert( Internals != NULL ); // paranoid
  const char *filename = Locate( "Part3.xml" );
  if( filename )
    {
    if( Internals->GlobalDefs.IsEmpty() )
      Internals->GlobalDefs.LoadFromFile(filename);
    return true;
    }
  // resource manager was not set properly
  return false;
}

bool Global::Append(const char *path)
{
  if( !System::FileIsDirectory(path) )
    {
    return false;
    }
  Internals->RessourcePaths.push_back( path );
  return true;
}

bool Global::Prepend(const char *path)
{
  if( !System::FileIsDirectory(path) )
    {
    return false;
    }
  Internals->RessourcePaths.insert( Internals->RessourcePaths.begin(), path );
  return true;
}

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

const char *Global::Locate(const char *resfile) const
{
#ifdef _WIN32
  static char path[MAX_PATH];
#else
  static char path[PATH_MAX];
#endif

  std::vector<std::string>::const_iterator it = Internals->RessourcePaths.begin();
  for( ; it != Internals->RessourcePaths.end(); ++it)
    {
    const std::string &p = *it;
    gdcmDebugMacro( "Trying to locate in: " << p );
    std::string fullpath = p + "/" + resfile;
    if( System::FileExists(fullpath.c_str()) )
      {
      // we found a match
      // check no invalid write access possible:
      if( fullpath.size() >= sizeof(path) )
        {
        gdcmDebugMacro( "Impossible happen: path is too long" );
        return NULL;
        }
      strcpy(path, fullpath.c_str() );
      return path;
      }
    }
  // no match sorry  :(
  return NULL;
}

Dicts const &Global::GetDicts() const
{
  assert( !Internals->GlobalDicts.IsEmpty() );
  return Internals->GlobalDicts;
}

Dicts &Global::GetDicts()
{
  assert( !Internals->GlobalDicts.IsEmpty() );
  return Internals->GlobalDicts;
}

Defs const &Global::GetDefs() const
{
  assert( !Internals->GlobalDefs.IsEmpty() );
  return Internals->GlobalDefs;
}

Global& Global::GetInstance()
{
  return GlobalInstance;
}

// Purposely not initialized.  ClassInitialize will handle it.
GlobalInternal * Global::Internals;

} // end namespace gdcm
<commit_msg>BUG: Prevent gdcm "missing implementation" error on macOS<commit_after>/*=========================================================================

  Program: GDCM (Grassroots DICOM). A DICOM library

  Copyright (c) 2006-2011 Mathieu Malaterre
  All rights reserved.
  See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "gdcmGlobal.h"
#include "gdcmDicts.h"
#include "gdcmDefs.h"
#include "gdcmFilename.h"

#include <limits.h> // PATH_MAX
#include <string.h> // strcpy
#ifdef _WIN32
#include <windows.h> // MAX_PATH
#endif

namespace gdcm
{

// Must NOT be initialized.  Default initialization to zero is
// necessary.
unsigned int GlobalCount;

class GlobalInternal
{
public:
  GlobalInternal():GlobalDicts(),GlobalDefs() {}
  Dicts GlobalDicts; // Part 6 + Part 4 elements
// TODO need H table for TransferSyntax / MediaStorage / Part 3 ...
  Defs GlobalDefs;

  // Ressource paths:
  // By default only construct two paths:
  // - The official install dir (need to keep in sinc with cmakelist variable
  // - a dynamic one, so that gdcm is somewhat rellocatable
  // - on some system where it make sense the path where the Resource should be located
  void LoadDefaultPaths()
    {
    assert( RessourcePaths.empty() );
    const char filename2[] = GDCM_CMAKE_INSTALL_PREFIX "/" GDCM_INSTALL_DATA_DIR "/XML/";
    RessourcePaths.push_back( filename2 );
    const char filename3[] = GDCM_CMAKE_INSTALL_PREFIX " " GDCM_API_VERSION "/" GDCM_INSTALL_DATA_DIR "/XML/";
    RessourcePaths.push_back( filename3 );
    const char *curprocfn = System::GetCurrentProcessFileName();
    if( curprocfn )
      {
      Filename fn( curprocfn );
      std::string str = fn.GetPath();
      str += "/../" GDCM_INSTALL_DATA_DIR "/XML/";
      RessourcePaths.push_back( str );
      }
    const char *respath = System::GetCurrentResourcesDirectory();
    if( respath )
      {
      RessourcePaths.push_back( respath );
      }
#ifdef GDCM_BUILD_TESTING
    // Needed for backward compat and dashboard
    const char src_path[] = GDCM_SOURCE_DIR "/Source/InformationObjectDefinition/";
    RessourcePaths.push_back( src_path );
#endif
    }
  std::vector<std::string> RessourcePaths;
};

Global::Global()
{
  if(++GlobalCount == 1)
    {
    assert( Internals == NULL ); // paranoid
    Internals = new GlobalInternal;
    assert( Internals->GlobalDicts.IsEmpty() );
    // Fill in with default values now !
    // at startup time is safer as later call might be from different thread
    // thus initialization of std::map would be all skrew up
    Internals->GlobalDicts.LoadDefaults();
    assert( Internals->GlobalDefs.IsEmpty() );
    // Same goes for GlobalDefs:
    //Internals->GlobalDefs.LoadDefaults();
    //Internals->LoadDefaultPaths();
    }
}

Global::~Global()
{
  if(--GlobalCount == 0)
    {
    //Internals->GlobalDicts.Unload();
    delete Internals;
    Internals = NULL; // paranoid
    }
}

bool Global::LoadResourcesFiles()
{
  assert( Internals != NULL ); // paranoid
  const char *filename = Locate( "Part3.xml" );
  if( filename )
    {
    if( Internals->GlobalDefs.IsEmpty() )
      Internals->GlobalDefs.LoadFromFile(filename);
    return true;
    }
  // resource manager was not set properly
  return false;
}

bool Global::Append(const char *path)
{
  if( !System::FileIsDirectory(path) )
    {
    return false;
    }
  Internals->RessourcePaths.push_back( path );
  return true;
}

bool Global::Prepend(const char *path)
{
  if( !System::FileIsDirectory(path) )
    {
    return false;
    }
  Internals->RessourcePaths.insert( Internals->RessourcePaths.begin(), path );
  return true;
}

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

const char *Global::Locate(const char *resfile) const
{
#ifdef _WIN32
  static char path[MAX_PATH];
#else
  static char path[PATH_MAX];
#endif

  std::vector<std::string>::const_iterator it = Internals->RessourcePaths.begin();
  for( ; it != Internals->RessourcePaths.end(); ++it)
    {
    const std::string &p = *it;
    gdcmDebugMacro( "Trying to locate in: " << p );
    std::string fullpath = p + "/" + resfile;
    if( System::FileExists(fullpath.c_str()) )
      {
      // we found a match
      // check no invalid write access possible:
      if( fullpath.size() >= sizeof(path) )
        {
        gdcmDebugMacro( "Impossible happen: path is too long" );
        return NULL;
        }
      strcpy(path, fullpath.c_str() );
      return path;
      }
    }
  // no match sorry  :(
  return NULL;
}

Dicts const &Global::GetDicts() const
{
  assert( !Internals->GlobalDicts.IsEmpty() );
  return Internals->GlobalDicts;
}

Dicts &Global::GetDicts()
{
  assert( !Internals->GlobalDicts.IsEmpty() );
  return Internals->GlobalDicts;
}

Defs const &Global::GetDefs() const
{
  assert( !Internals->GlobalDefs.IsEmpty() );
  return Internals->GlobalDefs;
}

Global& Global::GetInstance()
{
  return GlobalInstance;
}

// Purposely not initialized.  ClassInitialize will handle it.
GlobalInternal * Global::Internals;

} // end namespace gdcm
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2015 Pedro Côrte-Real
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/TiffIFD.h"
#include "common/Common.h"            // for getHostEndianness, uint32, make_...
#include "common/NORangesSet.h"       // for NORangesSet
#include "common/RawspeedException.h" // for RawspeedException
#include "io/IOException.h"           // for IOException
#include "tiff/TiffEntry.h"           // for TiffEntry
#include "tiff/TiffTag.h"             // for TiffTag, ::DNGPRIVATEDATA, ::EXI...
#include <algorithm>                  // for move
#include <cstdint>                    // for UINT32_MAX
#include <map>                        // for map, _Rb_tree_const_iterator, al...
#include <memory>                     // for default_delete, unique_ptr
#include <string>                     // for operator==, string, basic_string
#include <utility>                    // for pair
#include <vector>                     // for vector

using std::string;
using std::vector;

namespace rawspeed {

void TiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
  assert(ifds);

  TiffEntryOwner t;

  auto origPos = bs->getPosition();

  try {
    t = std::make_unique<TiffEntry>(this, bs);
  } catch (IOException&) { // Ignore unparsable entry
    // fix probably broken position due to interruption by exception
    // i.e. setting it to the next entry.
    bs->setPosition(origPos + 12);
    return;
  }

  try {
    switch (t->tag) {
    case DNGPRIVATEDATA:
      add(parseDngPrivateData(ifds, t.get()));
      break;

    case MAKERNOTE:
    case MAKERNOTE_ALT:
      add(parseMakerNote(ifds, t.get()));
      break;

    case FUJI_RAW_IFD:
    case SUBIFDS:
    case EXIFIFDPOINTER:
      for (uint32 j = 0; j < t->count; j++)
        add(std::make_unique<TiffIFD>(this, ifds, *bs, t->getU32(j)));
      break;

    default:
      add(move(t));
    }
  } catch (RawspeedException&) { // Unparsable private data are added as entries
    add(move(t));
  }
}

TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {}

TiffIFD::TiffIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
                 const DataBuffer& data, uint32 offset)
    : TiffIFD(parent_) {
  // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
  // TiffRootIFD in a tiff file
  if (offset == UINT32_MAX)
    return;

  assert(ifds);

  checkOverflow();

  ByteStream bs(data);
  bs.setPosition(offset);

  // Directory entries in this IFD
  auto numEntries = bs.getU16();

  // 2 bytes for entry count
  // each entry is 12 bytes
  // 4-byte offset to the next IFD at the end
  const auto IFDFullSize = 2 + 4 + 12 * numEntries;
  const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
  if (!ifds->emplace(IFDBuf).second)
    ThrowTPE("Two IFD's overlap. Raw corrupt!");

  for (uint32 i = 0; i < numEntries; i++)
    parseIFDEntry(ifds, &bs);

  nextIFD = bs.getU32();
}

TiffRootIFDOwner TiffIFD::parseDngPrivateData(NORangesSet<Buffer>* ifds,
                                              TiffEntry* t) {
  assert(ifds);

  /*
  1. Six bytes containing the zero-terminated string "Adobe".
     (The DNG specification calls for the DNGPrivateData tag to start with an
      ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of
     data is being stored here.
     Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following);
     This is the length of the original MakerNote data.
     (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file
     (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data
     (stored according to the byte order given above).
  6. The contents of the MakerNote tag.
     This is a simple byte-for-byte copy, with no modification.
  */
  ByteStream& bs = t->getData();
  if (!bs.skipPrefix("Adobe", 6))
    ThrowTPE("Not Adobe Private data");

  if (!bs.skipPrefix("MakN", 4))
    ThrowTPE("Not Makernote");

  bs.setByteOrder(Endianness::big);
  uint32 makerNoteSize = bs.getU32();
  if (makerNoteSize > bs.getRemainSize())
    ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt");

  bs.setByteOrder(getTiffByteOrder(bs, 0, "DNG makernote"));
  bs.skipBytes(2);

  uint32 makerNoteOffset = bs.getU32();
  makerNoteSize -= 6; // update size of orinial maker note, we skipped 2+4 bytes

  // Update the underlying buffer of t, such that the maker note data starts at its original offset
  bs.rebase(makerNoteOffset, makerNoteSize);

  return parseMakerNote(ifds, t);
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffRootIFDOwner TiffIFD::parseMakerNote(NORangesSet<Buffer>* ifds,
                                         TiffEntry* t) {
  assert(ifds);

  // go up the IFD tree and try to find the MAKE entry on each level.
  // we can not go all the way to the top first because this partial tree
  // is not yet added to the TiffRootIFD.
  TiffIFD* p = this;
  TiffEntry* makeEntry;
  do {
    makeEntry = p->getEntryRecursive(MAKE);
    p = p->parent;
  } while (!makeEntry && p);
  string make = makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";

  ByteStream bs = t->getData();

  // helper function for easy setup of ByteStream buffer for the different maker note types
  // 'rebase' means position 0 of new stream equals current position
  // 'newPosition' is the position where the IFD starts
  // 'byteOrderOffset' is the position wher the 2 magic bytes (II/MM) may be found
  // 'context' is a string providing error information in case the byte order parsing should fail
  auto setup = [&bs](bool rebase, uint32 newPosition,
                     uint32 byteOrderOffset = 0,
                     const char *context = nullptr) {
    if (rebase)
      bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
    if (context)
      bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
    bs.skipBytes(newPosition);
  };

  if (bs.hasPrefix("AOC\0", 4)) {
    setup(false, 6, 4, "Pentax makernote");
  } else if (bs.hasPrefix("PENTAX", 6)) {
    setup(true, 10, 8, "Pentax makernote");
  } else if (bs.hasPrefix("FUJIFILM\x0c\x00\x00\x00", 12)) {
    bs.setByteOrder(Endianness::little);
    setup(true, 12);
  } else if (bs.hasPrefix("Nikon\x00\x02", 7)) {
    // this is Nikon type 3 maker note format
    // TODO: implement Nikon type 1 maker note format
    // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
    bs.skipBytes(10);
    setup(true, 8, 0, "Nikon makernote");
  } else if (bs.hasPrefix("OLYMPUS", 7)) { // new Olympus
    setup(true, 12);
  } else if (bs.hasPrefix("OLYMP", 5)) {   // old Olympus
    setup(true, 8);
  } else if (bs.hasPrefix("EPSON", 5)) {
    setup(false, 8);
  } else if (bs.hasPatternAt("Exif", 4, 6)) {
    // TODO: for none of the rawsamples.ch files from Panasonic is this true, instead their MakerNote start with "Panasonic"
    // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
    // This TIFF is 0 offset based
    setup(false, 20, 12, "Panosonic makernote");
  } else if (make == "SAMSUNG") {
    // Samsung has no identification in its MakerNote but starts with the IFD right away
    setup(true, 0);
  } else {
    // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.

    // At least one MAKE has not been handled explicitly and starts its MakerNote with an endian prefix: Kodak
    if (bs.skipPrefix("II", 2)) {
      bs.setByteOrder(Endianness::little);
    } else if (bs.skipPrefix("MM", 2)) {
      bs.setByteOrder(Endianness::big);
    }
  }

  // Attempt to parse the rest as an IFD
  return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
}

std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
  vector<const TiffIFD*> matchingIFDs;
  if (entries.find(tag) != entries.end()) {
    matchingIFDs.push_back(this);
  }
  for (auto& i : subIFDs) {
    vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
    matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
  }
  return matchingIFDs;
}

const TiffIFD* TiffIFD::getIFDWithTag(TiffTag tag, uint32 index) const
{
  auto ifds = getIFDsWithTag(tag);
  if (index >= ifds.size())
    ThrowTPE("failed to find %u ifs with tag 0x%04x", index + 1, tag);
  return ifds[index];
}

TiffEntry* __attribute__((pure)) TiffIFD::getEntryRecursive(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i != entries.end()) {
    return i->second.get();
  }
  for (auto &j : subIFDs) {
    TiffEntry *entry = j->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return nullptr;
}

void TiffIFD::checkOverflow() {
  TiffIFD* p = this;
  int i = 0;
  while ((p = p->parent) != nullptr) {
    i++;
    if (i > 5)
      ThrowTPE("TiffIFD cascading overflow.");
  }
}

void TiffIFD::add(TiffIFDOwner subIFD) {
  checkOverflow();
  if (subIFDs.size() > 100)
    ThrowTPE("TIFF file has too many SubIFDs, probably broken");
  subIFD->parent = this;
  subIFDs.push_back(move(subIFD));
}

void TiffIFD::add(TiffEntryOwner entry) {
  entry->parent = this;
  entries[entry->tag] = move(entry);
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i == entries.end())
    ThrowTPE("Entry 0x%x not found.", tag);
  return i->second.get();
}

TiffID TiffRootIFD::getID() const
{
  TiffID id;
  auto makeE = getEntryRecursive(MAKE);
  auto modelE = getEntryRecursive(MODEL);

  if (!makeE)
    ThrowTPE("Failed to find MAKE entry.");
  if (!modelE)
    ThrowTPE("Failed to find MODEL entry.");

  id.make = trimSpaces(makeE->getString());
  id.model = trimSpaces(modelE->getString());

  return id;
}

} // namespace rawspeed
<commit_msg>TiffIFD::parseIFDEntry(): do not parse DNGPRIVATEDATA. Unused, unsafe.<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2015 Pedro Côrte-Real
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/TiffIFD.h"
#include "common/Common.h"            // for getHostEndianness, uint32, make_...
#include "common/NORangesSet.h"       // for NORangesSet
#include "common/RawspeedException.h" // for RawspeedException
#include "io/IOException.h"           // for IOException
#include "tiff/TiffEntry.h"           // for TiffEntry
#include "tiff/TiffTag.h"             // for TiffTag, ::DNGPRIVATEDATA, ::EXI...
#include <algorithm>                  // for move
#include <cstdint>                    // for UINT32_MAX
#include <map>                        // for map, _Rb_tree_const_iterator, al...
#include <memory>                     // for default_delete, unique_ptr
#include <string>                     // for operator==, string, basic_string
#include <utility>                    // for pair
#include <vector>                     // for vector

using std::string;
using std::vector;

namespace rawspeed {

void TiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
  assert(ifds);

  TiffEntryOwner t;

  auto origPos = bs->getPosition();

  try {
    t = std::make_unique<TiffEntry>(this, bs);
  } catch (IOException&) { // Ignore unparsable entry
    // fix probably broken position due to interruption by exception
    // i.e. setting it to the next entry.
    bs->setPosition(origPos + 12);
    return;
  }

  try {
    switch (t->tag) {
    case DNGPRIVATEDATA:
      // These are arbitrairly 'rebased', to preserve the offsets, but as it is
      // implemented right now, that could trigger UB (pointer arithmetics,
      // creating pointer to unowned memory, etc). And since this is not even
      // used anywhere right now, let's not
      //   add(parseDngPrivateData(ifds, t.get()));
      // but just add them as entries. (e.g. ArwDecoder uses WB from them)
      add(move(t));
      break;

    case MAKERNOTE:
    case MAKERNOTE_ALT:
      add(parseMakerNote(ifds, t.get()));
      break;

    case FUJI_RAW_IFD:
    case SUBIFDS:
    case EXIFIFDPOINTER:
      for (uint32 j = 0; j < t->count; j++)
        add(std::make_unique<TiffIFD>(this, ifds, *bs, t->getU32(j)));
      break;

    default:
      add(move(t));
    }
  } catch (RawspeedException&) { // Unparsable private data are added as entries
    add(move(t));
  }
}

TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {}

TiffIFD::TiffIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
                 const DataBuffer& data, uint32 offset)
    : TiffIFD(parent_) {
  // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
  // TiffRootIFD in a tiff file
  if (offset == UINT32_MAX)
    return;

  assert(ifds);

  checkOverflow();

  ByteStream bs(data);
  bs.setPosition(offset);

  // Directory entries in this IFD
  auto numEntries = bs.getU16();

  // 2 bytes for entry count
  // each entry is 12 bytes
  // 4-byte offset to the next IFD at the end
  const auto IFDFullSize = 2 + 4 + 12 * numEntries;
  const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
  if (!ifds->emplace(IFDBuf).second)
    ThrowTPE("Two IFD's overlap. Raw corrupt!");

  for (uint32 i = 0; i < numEntries; i++)
    parseIFDEntry(ifds, &bs);

  nextIFD = bs.getU32();
}

TiffRootIFDOwner TiffIFD::parseDngPrivateData(NORangesSet<Buffer>* ifds,
                                              TiffEntry* t) {
  assert(ifds);

  /*
  1. Six bytes containing the zero-terminated string "Adobe".
     (The DNG specification calls for the DNGPrivateData tag to start with an
      ASCII string identifying the creator/format).
  2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of
     data is being stored here.
     Note that this is not zero-terminated.
  3. A four-byte count (number of data bytes following);
     This is the length of the original MakerNote data.
     (This is always in "most significant byte first" format).
  4. 2 bytes: the byte-order indicator from the original file
     (the usual 'MM'/4D4D or 'II'/4949).
  5. 4 bytes: the original file offset for the MakerNote tag data
     (stored according to the byte order given above).
  6. The contents of the MakerNote tag.
     This is a simple byte-for-byte copy, with no modification.
  */
  ByteStream& bs = t->getData();
  if (!bs.skipPrefix("Adobe", 6))
    ThrowTPE("Not Adobe Private data");

  if (!bs.skipPrefix("MakN", 4))
    ThrowTPE("Not Makernote");

  bs.setByteOrder(Endianness::big);
  uint32 makerNoteSize = bs.getU32();
  if (makerNoteSize > bs.getRemainSize())
    ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt");

  bs.setByteOrder(getTiffByteOrder(bs, 0, "DNG makernote"));
  bs.skipBytes(2);

  uint32 makerNoteOffset = bs.getU32();
  makerNoteSize -= 6; // update size of orinial maker note, we skipped 2+4 bytes

  // Update the underlying buffer of t, such that the maker note data starts at its original offset
  bs.rebase(makerNoteOffset, makerNoteSize);

  return parseMakerNote(ifds, t);
}

/* This will attempt to parse makernotes and return it as an IFD */
TiffRootIFDOwner TiffIFD::parseMakerNote(NORangesSet<Buffer>* ifds,
                                         TiffEntry* t) {
  assert(ifds);

  // go up the IFD tree and try to find the MAKE entry on each level.
  // we can not go all the way to the top first because this partial tree
  // is not yet added to the TiffRootIFD.
  TiffIFD* p = this;
  TiffEntry* makeEntry;
  do {
    makeEntry = p->getEntryRecursive(MAKE);
    p = p->parent;
  } while (!makeEntry && p);
  string make = makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";

  ByteStream bs = t->getData();

  // helper function for easy setup of ByteStream buffer for the different maker note types
  // 'rebase' means position 0 of new stream equals current position
  // 'newPosition' is the position where the IFD starts
  // 'byteOrderOffset' is the position wher the 2 magic bytes (II/MM) may be found
  // 'context' is a string providing error information in case the byte order parsing should fail
  auto setup = [&bs](bool rebase, uint32 newPosition,
                     uint32 byteOrderOffset = 0,
                     const char *context = nullptr) {
    if (rebase)
      bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
    if (context)
      bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
    bs.skipBytes(newPosition);
  };

  if (bs.hasPrefix("AOC\0", 4)) {
    setup(false, 6, 4, "Pentax makernote");
  } else if (bs.hasPrefix("PENTAX", 6)) {
    setup(true, 10, 8, "Pentax makernote");
  } else if (bs.hasPrefix("FUJIFILM\x0c\x00\x00\x00", 12)) {
    bs.setByteOrder(Endianness::little);
    setup(true, 12);
  } else if (bs.hasPrefix("Nikon\x00\x02", 7)) {
    // this is Nikon type 3 maker note format
    // TODO: implement Nikon type 1 maker note format
    // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
    bs.skipBytes(10);
    setup(true, 8, 0, "Nikon makernote");
  } else if (bs.hasPrefix("OLYMPUS", 7)) { // new Olympus
    setup(true, 12);
  } else if (bs.hasPrefix("OLYMP", 5)) {   // old Olympus
    setup(true, 8);
  } else if (bs.hasPrefix("EPSON", 5)) {
    setup(false, 8);
  } else if (bs.hasPatternAt("Exif", 4, 6)) {
    // TODO: for none of the rawsamples.ch files from Panasonic is this true, instead their MakerNote start with "Panasonic"
    // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
    // This TIFF is 0 offset based
    setup(false, 20, 12, "Panosonic makernote");
  } else if (make == "SAMSUNG") {
    // Samsung has no identification in its MakerNote but starts with the IFD right away
    setup(true, 0);
  } else {
    // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.

    // At least one MAKE has not been handled explicitly and starts its MakerNote with an endian prefix: Kodak
    if (bs.skipPrefix("II", 2)) {
      bs.setByteOrder(Endianness::little);
    } else if (bs.skipPrefix("MM", 2)) {
      bs.setByteOrder(Endianness::big);
    }
  }

  // Attempt to parse the rest as an IFD
  return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
}

std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
  vector<const TiffIFD*> matchingIFDs;
  if (entries.find(tag) != entries.end()) {
    matchingIFDs.push_back(this);
  }
  for (auto& i : subIFDs) {
    vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
    matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
  }
  return matchingIFDs;
}

const TiffIFD* TiffIFD::getIFDWithTag(TiffTag tag, uint32 index) const
{
  auto ifds = getIFDsWithTag(tag);
  if (index >= ifds.size())
    ThrowTPE("failed to find %u ifs with tag 0x%04x", index + 1, tag);
  return ifds[index];
}

TiffEntry* __attribute__((pure)) TiffIFD::getEntryRecursive(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i != entries.end()) {
    return i->second.get();
  }
  for (auto &j : subIFDs) {
    TiffEntry *entry = j->getEntryRecursive(tag);
    if (entry)
      return entry;
  }
  return nullptr;
}

void TiffIFD::checkOverflow() {
  TiffIFD* p = this;
  int i = 0;
  while ((p = p->parent) != nullptr) {
    i++;
    if (i > 5)
      ThrowTPE("TiffIFD cascading overflow.");
  }
}

void TiffIFD::add(TiffIFDOwner subIFD) {
  checkOverflow();
  if (subIFDs.size() > 100)
    ThrowTPE("TIFF file has too many SubIFDs, probably broken");
  subIFD->parent = this;
  subIFDs.push_back(move(subIFD));
}

void TiffIFD::add(TiffEntryOwner entry) {
  entry->parent = this;
  entries[entry->tag] = move(entry);
}

TiffEntry* TiffIFD::getEntry(TiffTag tag) const {
  auto i = entries.find(tag);
  if (i == entries.end())
    ThrowTPE("Entry 0x%x not found.", tag);
  return i->second.get();
}

TiffID TiffRootIFD::getID() const
{
  TiffID id;
  auto makeE = getEntryRecursive(MAKE);
  auto modelE = getEntryRecursive(MODEL);

  if (!makeE)
    ThrowTPE("Failed to find MAKE entry.");
  if (!modelE)
    ThrowTPE("Failed to find MODEL entry.");

  id.make = trimSpaces(makeE->getString());
  id.model = trimSpaces(modelE->getString());

  return id;
}

} // namespace rawspeed
<|endoftext|>