<commit_before>
#include "stdlib.h"

#include "TFile.h"
#include "TTimeStamp.h"

#include "RooStats/HistFactory/HistFactoryException.h"
#include "RooStats/HistFactory/Channel.h"

RooStats::HistFactory::Channel::Channel() :
  fName( "" ) { ; }

RooStats::HistFactory::Channel::Channel(std::string ChanName, std::string ChanInputFile) :
  fName( ChanName ), fInputFile( ChanInputFile ) { ; }

namespace RooStats{
  namespace HistFactory{
    //BadChannel = Channel();
    Channel BadChannel;
    //    BadChannel.Name = "BadChannel"; // = Channel(); //.Name = "BadChannel";
  }
}

void RooStats::HistFactory::Channel::AddSample( RooStats::HistFactory::Sample sample ) {
  sample.SetChannelName( GetName() );
  fSamples.push_back( sample );
}

void RooStats::HistFactory::Channel::Print( std::ostream& stream ) {

  stream << "\t Channel Name: " << fName
	 << "\t InputFile: " << fInputFile
	 << std::endl;

  stream << "\t Data:" << std::endl;
  fData.Print( stream );

  stream << "\t statErrorConfig:" << std::endl;
  fStatErrorConfig.Print( stream );

  if( fSamples.size() != 0 ) {

    stream << "\t Samples: " << std::endl;
    for( unsigned int i = 0; i < fSamples.size(); ++i ) {
      fSamples.at(i).Print( stream );
    }
  }

  stream << "\t End of Channel " << fName <<  std::endl;

}

void RooStats::HistFactory::Channel::PrintXML( std::string Directory, std::string Prefix ) {

  // Create an XML file for this channel

  std::cout << "Printing XML Files for channel: " << GetName() << std::endl;

  std::string XMLName = Prefix + fName + ".xml";
  if( Directory != "" ) XMLName = Directory + "/" + XMLName;

  ofstream xml( XMLName.c_str() );

  // Add the time
  xml << "<!--" << std::endl;
  xml << "This xml file created automatically on: " << std::endl;
/*
  time_t t = time(0);   // get time now
  struct tm * now = localtime( &t );
  xml << (now->tm_year + 1900) << '-'
      << (now->tm_mon + 1) << '-'
      << now->tm_mday
      << std::endl;
*/
// LM: use TTimeStamp since time_t does not work on Windows
  TTimeStamp t;
  UInt_t year = 0;
  UInt_t month = 0;
  UInt_t day = 0;
  t.GetDate(true, 0, &year, &month, &day);
  xml << year << '-'
      << month << '-'
      << day
      << std::endl;

  xml << "-->" << std::endl;

  // Add the DOCTYPE
  xml << "<!DOCTYPE Channel  SYSTEM 'HistFactorySchema.dtd'>  " << std::endl << std::endl;

  // Add the Channel
  xml << "  <Channel Name=\"" << fName << "\" InputFile=\"" << fInputFile << "\" >" << std::endl << std::endl;

  xml << "    <Data HistoName=\"" << fData.GetHistoName() << "\" "
      << "InputFile=\"" << fData.GetInputFile() << "\" "
      << "HistoPath=\"" << fData.GetHistoPath() << "\" "
      << " /> " << std::endl << std::endl;

  xml << "    <StatErrorConfig RelErrorThreshold=\"" << fStatErrorConfig.GetRelErrorThreshold() << "\" "
      << "ConstraintType=\"" << Constraint::Name( fStatErrorConfig.GetConstraintType() ) << "\" "
      << "/> " << std::endl << std::endl;

  for( unsigned int i = 0; i < fSamples.size(); ++i ) {
    fSamples.at(i).PrintXML( xml );
    xml << std::endl << std::endl;
  }

  xml << std::endl;

  xml << "  </Channel>  " << std::endl;

  xml.close();

  std::cout << "Finished printing XML files" << std::endl;

}

void RooStats::HistFactory::Channel::SetData( std::string DataHistoName, std::string DataInputFile, std::string DataHistoPath ) {

  fData.SetHistoName( DataHistoName );
  fData.SetInputFile( DataInputFile );
  fData.SetHistoPath( DataHistoPath );

}

void RooStats::HistFactory::Channel::SetData( TH1* hData ) {
  fData.SetHisto( hData );
}

void RooStats::HistFactory::Channel::SetData( double val ) {

  // For a NumberCounting measurement only
  // Set the value of data in a particular channel
  //
  // Internally, this simply creates a 1-bin TH1F for you

  std::string DataHistName = fName + "_data";

  // Histogram has 1-bin (hard-coded)
  TH1F* hData = new TH1F( DataHistName.c_str(), DataHistName.c_str(), 1, 0, 1 );
  hData->SetBinContent( 1, val );

  // Set the histogram of the internally held data
  // node of this channel to this newly created histogram
  SetData( hData );

}

void RooStats::HistFactory::Channel::SetStatErrorConfig( double StatRelErrorThreshold, Constraint::Type StatConstraintType ) {

  fStatErrorConfig.SetRelErrorThreshold( StatRelErrorThreshold );
  fStatErrorConfig.SetConstraintType( StatConstraintType );

}

void RooStats::HistFactory::Channel::SetStatErrorConfig( double StatRelErrorThreshold, std::string StatConstraintType ) {

  fStatErrorConfig.SetRelErrorThreshold( StatRelErrorThreshold );
  fStatErrorConfig.SetConstraintType( Constraint::GetType(StatConstraintType) );

}

void RooStats::HistFactory::Channel::CollectHistograms() {

  // Loop through all Samples and Systematics
  // and collect all necessary histograms

  // Get the Data Histogram:

  fData.SetHisto( GetHistogram(fData.GetInputFile(),
			       fData.GetHistoPath(),
			       fData.GetHistoName()) );

  // Get the histograms for the samples:
  for( unsigned int sampItr = 0; sampItr < fSamples.size(); ++sampItr ) {

    RooStats::HistFactory::Sample& sample = fSamples.at( sampItr );

    // Get the nominal histogram:
    std::cout << "Collecting Nominal Histogram" << std::endl;
    TH1* Nominal =  GetHistogram(sample.GetInputFile(),
				 sample.GetHistoPath(),
				 sample.GetHistoName());

    sample.SetHisto( Nominal );

    // Get the StatError Histogram (if necessary)

    if( sample.GetStatError().GetUseHisto() ) {

      sample.GetStatError().SetErrorHist( GetHistogram(sample.GetStatError().GetInputFile(),
						       sample.GetStatError().GetHistoPath(),
						       sample.GetStatError().GetHistoName()) );
    }

    // Get the HistoSys Variations:
    for( unsigned int histoSysItr = 0; histoSysItr < sample.GetHistoSysList().size(); ++histoSysItr ) {

      RooStats::HistFactory::HistoSys& histoSys = sample.GetHistoSysList().at( histoSysItr );

      histoSys.SetHistoLow( GetHistogram(histoSys.GetInputFileLow(),
					 histoSys.GetHistoPathLow(),
					 histoSys.GetHistoNameLow()) );

      histoSys.SetHistoHigh( GetHistogram(histoSys.GetInputFileHigh(),
					  histoSys.GetHistoPathHigh(),
					  histoSys.GetHistoNameHigh()) );
    } // End Loop over HistoSys

      // Get the HistoFactor Variations:
    for( unsigned int histoFactorItr = 0; histoFactorItr < sample.GetHistoFactorList().size(); ++histoFactorItr ) {

      RooStats::HistFactory::HistoFactor& histoFactor = sample.GetHistoFactorList().at( histoFactorItr );

      histoFactor.SetHistoLow( GetHistogram(histoFactor.GetInputFileLow(),
					    histoFactor.GetHistoPathLow(),
					    histoFactor.GetHistoNameLow()) );

      histoFactor.SetHistoHigh( GetHistogram(histoFactor.GetInputFileHigh(),
					     histoFactor.GetHistoPathHigh(),
					     histoFactor.GetHistoNameHigh()) );
    } // End Loop over HistoFactor

      // Get the ShapeSys Variations:
    for( unsigned int shapeSysItr = 0; shapeSysItr < sample.GetShapeSysList().size(); ++shapeSysItr ) {

      RooStats::HistFactory::ShapeSys& shapeSys = sample.GetShapeSysList().at( shapeSysItr );

      shapeSys.SetErrorHist( GetHistogram(shapeSys.GetInputFile(),
					  shapeSys.GetHistoPath(),
					  shapeSys.GetHistoName()) );
    } // End Loop over ShapeSys

  } // End Loop over Samples

  return;

}

bool RooStats::HistFactory::Channel::CheckHistograms() {

  // Check that all internal histogram pointers
  // are properly configured (ie that they're not NULL)

  try {

    if( fData.GetHisto() == NULL ) {
      std::cout << "Error: Data Histogram for channel " << GetName() << " is NULL." << std::endl;
      throw bad_hf;
    }

    // Get the histograms for the samples:
    for( unsigned int sampItr = 0; sampItr < fSamples.size(); ++sampItr ) {

      RooStats::HistFactory::Sample& sample = fSamples.at( sampItr );

      // Get the nominal histogram:
      if( sample.GetHisto() == NULL ) {
	std::cout << "Error: Nominal Histogram for sample " << sample.GetName() << " is NULL." << std::endl;
	throw bad_hf;
      }

      // Get the StatError Histogram (if necessary)
      if( sample.GetStatError().GetUseHisto() ) {
	if( sample.GetStatError().GetErrorHist() == NULL ) {
	  std::cout << "Error: Statistical Error Histogram for sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
      }

      // Get the HistoSys Variations:
      for( unsigned int histoSysItr = 0; histoSysItr < sample.GetHistoSysList().size(); ++histoSysItr ) {

	RooStats::HistFactory::HistoSys& histoSys = sample.GetHistoSysList().at( histoSysItr );

	if( histoSys.GetHistoLow() == NULL ) {
	  std::cout << "Error: HistoSyst Low for Systematic " << histoSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
	if( histoSys.GetHistoHigh() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << histoSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over HistoSys

      // Get the HistoFactor Variations:
      for( unsigned int histoFactorItr = 0; histoFactorItr < sample.GetHistoFactorList().size(); ++histoFactorItr ) {

	RooStats::HistFactory::HistoFactor& histoFactor = sample.GetHistoFactorList().at( histoFactorItr );

	if( histoFactor.GetHistoLow() == NULL ) {
	  std::cout << "Error: HistoSyst Low for Systematic " << histoFactor.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
	if( histoFactor.GetHistoHigh() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << histoFactor.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over HistoFactor

      // Get the ShapeSys Variations:
      for( unsigned int shapeSysItr = 0; shapeSysItr < sample.GetShapeSysList().size(); ++shapeSysItr ) {

	RooStats::HistFactory::ShapeSys& shapeSys = sample.GetShapeSysList().at( shapeSysItr );

	if( shapeSys.GetErrorHist() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << shapeSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over ShapeSys

    } // End Loop over Samples

  }
  catch(exception& e)
    {
      std::cout << e.what() << std::endl;
      return false;
    }

  return true;

}

TH1* RooStats::HistFactory::Channel::GetHistogram(std::string InputFile, std::string HistoPath, std::string HistoName) {

  std::cout << "Getting histogram. "
	    << " InputFile " << InputFile
	    << " HistoPath " << HistoPath
	    << " HistoName " << HistoName
	    << std::endl;

  //  TFile* file = TFile::Open( InputFile.c_str() );

  TFile* inFile = TFile::Open( InputFile.c_str() );
  if( !inFile ) {
    std::cout << "Error: Unable to open input file: " << InputFile << std::endl;
    throw bad_hf;
  }

  std::cout << "Opened input file: " << InputFile << ": " << inFile << std::endl;

  std::string HistNameFull = HistoPath + HistoName;

  if( HistoPath != std::string("") ) {
    if( HistoPath[ HistoPath.length()-1 ] != std::string("/") ) {
      std::cout << "WARNING: Histogram path is set to: " << HistoPath
		<< " but it should end with a '/' " << std::endl;
      std::cout << "Total histogram path is now: " << HistNameFull << std::endl;
    }
  }

  TH1* hist = NULL;
  try{
    hist = dynamic_cast<TH1*>( inFile->Get( HistNameFull.c_str() ) );
  }
  catch(std::exception& e)
    {
      std::cout << "Failed to cast object to TH1*" << std::endl;
      std::cout << e.what() << std::endl;
      throw bad_hf;
    }
  if( !hist ) {
    std::cout << "Failed to get histogram: " << HistNameFull
	      << " in file: " << InputFile << std::endl;
    throw bad_hf;
  }

  TH1 * ptr = (TH1 *) hist->Clone();

  if(!ptr){
    std::cerr << "Not all necessary info are set to access the input file. Check your config" << std::endl;
    std::cerr << "filename: " << InputFile
	      << "path: " << HistoPath
	      << "obj: " << HistoName << std::endl;
    throw bad_hf;
  }
  else {
    ptr->SetDirectory(0); //         for the current histogram h
  }

#ifdef DEBUG
  std::cout << "Found Histogram: " << HistoName " at address: " << ptr
	    << " with integral "   << ptr->Integral() << " and mean " << ptr->GetMean()
	    << std::endl;
#endif

  inFile->Close();

  // Done
  return ptr;

}
<commit_msg>Last missing std::.<commit_after>
#include "stdlib.h"

#include "TFile.h"
#include "TTimeStamp.h"

#include "RooStats/HistFactory/HistFactoryException.h"
#include "RooStats/HistFactory/Channel.h"

RooStats::HistFactory::Channel::Channel() :
  fName( "" ) { ; }

RooStats::HistFactory::Channel::Channel(std::string ChanName, std::string ChanInputFile) :
  fName( ChanName ), fInputFile( ChanInputFile ) { ; }

namespace RooStats{
  namespace HistFactory{
    //BadChannel = Channel();
    Channel BadChannel;
    //    BadChannel.Name = "BadChannel"; // = Channel(); //.Name = "BadChannel";
  }
}

void RooStats::HistFactory::Channel::AddSample( RooStats::HistFactory::Sample sample ) {
  sample.SetChannelName( GetName() );
  fSamples.push_back( sample );
}

void RooStats::HistFactory::Channel::Print( std::ostream& stream ) {

  stream << "\t Channel Name: " << fName
	 << "\t InputFile: " << fInputFile
	 << std::endl;

  stream << "\t Data:" << std::endl;
  fData.Print( stream );

  stream << "\t statErrorConfig:" << std::endl;
  fStatErrorConfig.Print( stream );

  if( fSamples.size() != 0 ) {

    stream << "\t Samples: " << std::endl;
    for( unsigned int i = 0; i < fSamples.size(); ++i ) {
      fSamples.at(i).Print( stream );
    }
  }

  stream << "\t End of Channel " << fName <<  std::endl;

}

void RooStats::HistFactory::Channel::PrintXML( std::string Directory, std::string Prefix ) {

  // Create an XML file for this channel

  std::cout << "Printing XML Files for channel: " << GetName() << std::endl;

  std::string XMLName = Prefix + fName + ".xml";
  if( Directory != "" ) XMLName = Directory + "/" + XMLName;

  ofstream xml( XMLName.c_str() );

  // Add the time
  xml << "<!--" << std::endl;
  xml << "This xml file created automatically on: " << std::endl;
/*
  time_t t = time(0);   // get time now
  struct tm * now = localtime( &t );
  xml << (now->tm_year + 1900) << '-'
      << (now->tm_mon + 1) << '-'
      << now->tm_mday
      << std::endl;
*/
// LM: use TTimeStamp since time_t does not work on Windows
  TTimeStamp t;
  UInt_t year = 0;
  UInt_t month = 0;
  UInt_t day = 0;
  t.GetDate(true, 0, &year, &month, &day);
  xml << year << '-'
      << month << '-'
      << day
      << std::endl;

  xml << "-->" << std::endl;

  // Add the DOCTYPE
  xml << "<!DOCTYPE Channel  SYSTEM 'HistFactorySchema.dtd'>  " << std::endl << std::endl;

  // Add the Channel
  xml << "  <Channel Name=\"" << fName << "\" InputFile=\"" << fInputFile << "\" >" << std::endl << std::endl;

  xml << "    <Data HistoName=\"" << fData.GetHistoName() << "\" "
      << "InputFile=\"" << fData.GetInputFile() << "\" "
      << "HistoPath=\"" << fData.GetHistoPath() << "\" "
      << " /> " << std::endl << std::endl;

  xml << "    <StatErrorConfig RelErrorThreshold=\"" << fStatErrorConfig.GetRelErrorThreshold() << "\" "
      << "ConstraintType=\"" << Constraint::Name( fStatErrorConfig.GetConstraintType() ) << "\" "
      << "/> " << std::endl << std::endl;

  for( unsigned int i = 0; i < fSamples.size(); ++i ) {
    fSamples.at(i).PrintXML( xml );
    xml << std::endl << std::endl;
  }

  xml << std::endl;

  xml << "  </Channel>  " << std::endl;

  xml.close();

  std::cout << "Finished printing XML files" << std::endl;

}

void RooStats::HistFactory::Channel::SetData( std::string DataHistoName, std::string DataInputFile, std::string DataHistoPath ) {

  fData.SetHistoName( DataHistoName );
  fData.SetInputFile( DataInputFile );
  fData.SetHistoPath( DataHistoPath );

}

void RooStats::HistFactory::Channel::SetData( TH1* hData ) {
  fData.SetHisto( hData );
}

void RooStats::HistFactory::Channel::SetData( double val ) {

  // For a NumberCounting measurement only
  // Set the value of data in a particular channel
  //
  // Internally, this simply creates a 1-bin TH1F for you

  std::string DataHistName = fName + "_data";

  // Histogram has 1-bin (hard-coded)
  TH1F* hData = new TH1F( DataHistName.c_str(), DataHistName.c_str(), 1, 0, 1 );
  hData->SetBinContent( 1, val );

  // Set the histogram of the internally held data
  // node of this channel to this newly created histogram
  SetData( hData );

}

void RooStats::HistFactory::Channel::SetStatErrorConfig( double StatRelErrorThreshold, Constraint::Type StatConstraintType ) {

  fStatErrorConfig.SetRelErrorThreshold( StatRelErrorThreshold );
  fStatErrorConfig.SetConstraintType( StatConstraintType );

}

void RooStats::HistFactory::Channel::SetStatErrorConfig( double StatRelErrorThreshold, std::string StatConstraintType ) {

  fStatErrorConfig.SetRelErrorThreshold( StatRelErrorThreshold );
  fStatErrorConfig.SetConstraintType( Constraint::GetType(StatConstraintType) );

}

void RooStats::HistFactory::Channel::CollectHistograms() {

  // Loop through all Samples and Systematics
  // and collect all necessary histograms

  // Get the Data Histogram:

  fData.SetHisto( GetHistogram(fData.GetInputFile(),
			       fData.GetHistoPath(),
			       fData.GetHistoName()) );

  // Get the histograms for the samples:
  for( unsigned int sampItr = 0; sampItr < fSamples.size(); ++sampItr ) {

    RooStats::HistFactory::Sample& sample = fSamples.at( sampItr );

    // Get the nominal histogram:
    std::cout << "Collecting Nominal Histogram" << std::endl;
    TH1* Nominal =  GetHistogram(sample.GetInputFile(),
				 sample.GetHistoPath(),
				 sample.GetHistoName());

    sample.SetHisto( Nominal );

    // Get the StatError Histogram (if necessary)

    if( sample.GetStatError().GetUseHisto() ) {

      sample.GetStatError().SetErrorHist( GetHistogram(sample.GetStatError().GetInputFile(),
						       sample.GetStatError().GetHistoPath(),
						       sample.GetStatError().GetHistoName()) );
    }

    // Get the HistoSys Variations:
    for( unsigned int histoSysItr = 0; histoSysItr < sample.GetHistoSysList().size(); ++histoSysItr ) {

      RooStats::HistFactory::HistoSys& histoSys = sample.GetHistoSysList().at( histoSysItr );

      histoSys.SetHistoLow( GetHistogram(histoSys.GetInputFileLow(),
					 histoSys.GetHistoPathLow(),
					 histoSys.GetHistoNameLow()) );

      histoSys.SetHistoHigh( GetHistogram(histoSys.GetInputFileHigh(),
					  histoSys.GetHistoPathHigh(),
					  histoSys.GetHistoNameHigh()) );
    } // End Loop over HistoSys

      // Get the HistoFactor Variations:
    for( unsigned int histoFactorItr = 0; histoFactorItr < sample.GetHistoFactorList().size(); ++histoFactorItr ) {

      RooStats::HistFactory::HistoFactor& histoFactor = sample.GetHistoFactorList().at( histoFactorItr );

      histoFactor.SetHistoLow( GetHistogram(histoFactor.GetInputFileLow(),
					    histoFactor.GetHistoPathLow(),
					    histoFactor.GetHistoNameLow()) );

      histoFactor.SetHistoHigh( GetHistogram(histoFactor.GetInputFileHigh(),
					     histoFactor.GetHistoPathHigh(),
					     histoFactor.GetHistoNameHigh()) );
    } // End Loop over HistoFactor

      // Get the ShapeSys Variations:
    for( unsigned int shapeSysItr = 0; shapeSysItr < sample.GetShapeSysList().size(); ++shapeSysItr ) {

      RooStats::HistFactory::ShapeSys& shapeSys = sample.GetShapeSysList().at( shapeSysItr );

      shapeSys.SetErrorHist( GetHistogram(shapeSys.GetInputFile(),
					  shapeSys.GetHistoPath(),
					  shapeSys.GetHistoName()) );
    } // End Loop over ShapeSys

  } // End Loop over Samples

  return;

}

bool RooStats::HistFactory::Channel::CheckHistograms() {

  // Check that all internal histogram pointers
  // are properly configured (ie that they're not NULL)

  try {

    if( fData.GetHisto() == NULL ) {
      std::cout << "Error: Data Histogram for channel " << GetName() << " is NULL." << std::endl;
      throw bad_hf;
    }

    // Get the histograms for the samples:
    for( unsigned int sampItr = 0; sampItr < fSamples.size(); ++sampItr ) {

      RooStats::HistFactory::Sample& sample = fSamples.at( sampItr );

      // Get the nominal histogram:
      if( sample.GetHisto() == NULL ) {
	std::cout << "Error: Nominal Histogram for sample " << sample.GetName() << " is NULL." << std::endl;
	throw bad_hf;
      }

      // Get the StatError Histogram (if necessary)
      if( sample.GetStatError().GetUseHisto() ) {
	if( sample.GetStatError().GetErrorHist() == NULL ) {
	  std::cout << "Error: Statistical Error Histogram for sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
      }

      // Get the HistoSys Variations:
      for( unsigned int histoSysItr = 0; histoSysItr < sample.GetHistoSysList().size(); ++histoSysItr ) {

	RooStats::HistFactory::HistoSys& histoSys = sample.GetHistoSysList().at( histoSysItr );

	if( histoSys.GetHistoLow() == NULL ) {
	  std::cout << "Error: HistoSyst Low for Systematic " << histoSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
	if( histoSys.GetHistoHigh() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << histoSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over HistoSys

      // Get the HistoFactor Variations:
      for( unsigned int histoFactorItr = 0; histoFactorItr < sample.GetHistoFactorList().size(); ++histoFactorItr ) {

	RooStats::HistFactory::HistoFactor& histoFactor = sample.GetHistoFactorList().at( histoFactorItr );

	if( histoFactor.GetHistoLow() == NULL ) {
	  std::cout << "Error: HistoSyst Low for Systematic " << histoFactor.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}
	if( histoFactor.GetHistoHigh() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << histoFactor.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over HistoFactor

      // Get the ShapeSys Variations:
      for( unsigned int shapeSysItr = 0; shapeSysItr < sample.GetShapeSysList().size(); ++shapeSysItr ) {

	RooStats::HistFactory::ShapeSys& shapeSys = sample.GetShapeSysList().at( shapeSysItr );

	if( shapeSys.GetErrorHist() == NULL ) {
	  std::cout << "Error: HistoSyst High for Systematic " << shapeSys.GetName()
		    << " in sample " << sample.GetName() << " is NULL." << std::endl;
	  throw bad_hf;
	}

      } // End Loop over ShapeSys

    } // End Loop over Samples

  }
  catch(std::exception& e)
    {
      std::cout << e.what() << std::endl;
      return false;
    }

  return true;

}

TH1* RooStats::HistFactory::Channel::GetHistogram(std::string InputFile, std::string HistoPath, std::string HistoName) {

  std::cout << "Getting histogram. "
	    << " InputFile " << InputFile
	    << " HistoPath " << HistoPath
	    << " HistoName " << HistoName
	    << std::endl;

  //  TFile* file = TFile::Open( InputFile.c_str() );

  TFile* inFile = TFile::Open( InputFile.c_str() );
  if( !inFile ) {
    std::cout << "Error: Unable to open input file: " << InputFile << std::endl;
    throw bad_hf;
  }

  std::cout << "Opened input file: " << InputFile << ": " << inFile << std::endl;

  std::string HistNameFull = HistoPath + HistoName;

  if( HistoPath != std::string("") ) {
    if( HistoPath[ HistoPath.length()-1 ] != std::string("/") ) {
      std::cout << "WARNING: Histogram path is set to: " << HistoPath
		<< " but it should end with a '/' " << std::endl;
      std::cout << "Total histogram path is now: " << HistNameFull << std::endl;
    }
  }

  TH1* hist = NULL;
  try{
    hist = dynamic_cast<TH1*>( inFile->Get( HistNameFull.c_str() ) );
  }
  catch(std::exception& e)
    {
      std::cout << "Failed to cast object to TH1*" << std::endl;
      std::cout << e.what() << std::endl;
      throw bad_hf;
    }
  if( !hist ) {
    std::cout << "Failed to get histogram: " << HistNameFull
	      << " in file: " << InputFile << std::endl;
    throw bad_hf;
  }

  TH1 * ptr = (TH1 *) hist->Clone();

  if(!ptr){
    std::cerr << "Not all necessary info are set to access the input file. Check your config" << std::endl;
    std::cerr << "filename: " << InputFile
	      << "path: " << HistoPath
	      << "obj: " << HistoName << std::endl;
    throw bad_hf;
  }
  else {
    ptr->SetDirectory(0); //         for the current histogram h
  }

#ifdef DEBUG
  std::cout << "Found Histogram: " << HistoName " at address: " << ptr
	    << " with integral "   << ptr->Integral() << " and mean " << ptr->GetMean()
	    << std::endl;
#endif

  inFile->Close();

  // Done
  return ptr;

}
<|endoftext|>


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

#include "security_manager/security_manager_impl.h"
#include "security_manager/crypto_manager_impl.h"
#include "protocol_handler/protocol_packet.h"
#include "utils/logger.h"
#include "utils/byte_order.h"
#include "json/json.h"

namespace security_manager {

CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")

static const char* kErrId = "id";
static const char* kErrText = "text";

SecurityManagerImpl::SecurityManagerImpl()
  : security_messages_("SecurityManager", this),
  session_observer_(NULL), crypto_manager_(NULL), protocol_handler_(NULL) {
}

void SecurityManagerImpl::OnMessageReceived(
    const ::protocol_handler::RawMessagePtr message) {
  if (message->service_type() != protocol_handler::kControl) {
    return;
  }

  SecurityMessage securityMessagePtr(new SecurityQuery());
  const bool result = securityMessagePtr->SerializeQuery(
        message->data(), message->data_size());
  if (!result) {
    // result will be false only if data less then query header
    const std::string error_text("Incorrect message received");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(message->connection_key(),
                      ERROR_INVALID_QUERY_SIZE, error_text);
    return;
  }
  securityMessagePtr->set_connection_key(message->connection_key());

  // Post message to message query for next processing in thread
  security_messages_.PostMessage(securityMessagePtr);
}

void SecurityManagerImpl::OnMobileMessageSent(
    const ::protocol_handler::RawMessagePtr ) {
}

void SecurityManagerImpl::set_session_observer(
    protocol_handler::SessionObserver *observer) {
  if (!observer) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SessionObserver.");
    return;
  }
  session_observer_ = observer;
}

void SecurityManagerImpl::set_protocol_handler(
    protocol_handler::ProtocolHandler *handler) {
  if (!handler) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to ProtocolHandler.");
    return;
  }
  protocol_handler_ = handler;
}

void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) {
  if (!crypto_manager) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to CryptoManager.");
    return;
  }
  crypto_manager_ = crypto_manager;
}

void SecurityManagerImpl::Handle(const SecurityMessage message) {
  DCHECK(message);
  LOG4CXX_INFO(logger_, "Received Security message from Mobile side");
  if (!crypto_manager_)  {
    const std::string error_text("Invalid (NULL) CryptoManager.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(message->get_connection_key(),
                      ERROR_NOT_SUPPORTED, error_text);
    return;
  }
  switch (message->get_header().query_id) {
    case SecurityQuery::SEND_HANDSHAKE_DATA:
      if (!ProccessHandshakeData(message)) {
        LOG4CXX_ERROR(logger_, "Proccess HandshakeData failed");
      }
      break;
    case SecurityQuery::SEND_INTERNAL_ERROR:
      if (!ProccessInternalError(message)) {
        LOG4CXX_ERROR(logger_, "Processing income InternalError failed");
      }
      break;
    default: {
      // SecurityQuery::InvalidQuery
      const std::string error_text("Unknown query identifier.");
      LOG4CXX_ERROR(logger_, error_text);
      SendInternalError(message->get_connection_key(),
                        ERROR_INVALID_QUERY_ID, error_text,
                        message->get_header().seq_number);
      }
      break;
    }
}

security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext(
    const uint32_t &connection_key) {
  LOG4CXX_INFO(logger_, "ProtectService processing");
  DCHECK(session_observer_);
  DCHECK(crypto_manager_);

  security_manager::SSLContext *ssl_context =
      session_observer_->GetSSLContext(connection_key, protocol_handler::kControl);
  // return exists SSLCOntext for current connection/session
  if (ssl_context) {
    return ssl_context;
  }

  ssl_context = crypto_manager_->CreateSSLContext();
  if (!ssl_context) {
    const std::string error_text("CryptoManager could not create SSL context.");
    LOG4CXX_ERROR(logger_, error_text);
    // Generate response query and post to security_messages_
    SendInternalError(connection_key, ERROR_INTERNAL,
                      error_text);
    return NULL;
  }

  const int result = session_observer_->SetSSLContext(connection_key, ssl_context);
  if (ERROR_SUCCESS != result) {
    // delete SSLContext on any error
    crypto_manager_->ReleaseSSLContext(ssl_context);
    SendInternalError(connection_key, result, "");
    return NULL;
  }
  DCHECK(session_observer_->GetSSLContext(connection_key,
                                          protocol_handler::kControl));
  LOG4CXX_DEBUG(logger_, "Set SSL context to connection_key " << connection_key);
  return ssl_context;
}

void SecurityManagerImpl::StartHandshake(uint32_t connection_key) {
  DCHECK(session_observer_);
  LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key);
  security_manager::SSLContext *ssl_context =
      session_observer_->GetSSLContext(connection_key,
                                       protocol_handler::kControl);
  if (!ssl_context) {
    const std::string error_text("StartHandshake failed, "
                                 "connection is not protected");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INTERNAL, error_text);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return;
  }

  if (ssl_context->IsInitCompleted()) {
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Success);
    return;
  }

  ssl_context->SetHandshakeContext(
        session_observer_->GetHandshakeContext(connection_key));

  size_t data_size = 0;
  const uint8_t *data = NULL;

  const security_manager::SSLContext::HandshakeResult result =
      ssl_context->StartHandshake(&data, &data_size);
  if (security_manager::SSLContext::Handshake_Result_Success != result) {
    const std::string error_text("StartHandshake failed, handshake step fail");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INTERNAL, error_text);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return;
  }
  // for client mode will be generated output data
  if (data != NULL && data_size != 0) {
    SendHandshakeBinData(connection_key, data, data_size);
  }
}
void SecurityManagerImpl::AddListener(SecurityManagerListener *const listener) {
  if (!listener) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
    return;
  }
  listeners_.push_back(listener);
}
void SecurityManagerImpl::RemoveListener(SecurityManagerListener *const listener) {
  if (!listener) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
    return;
  }
  listeners_.remove(listener);
}
void SecurityManagerImpl::NotifyListenersOnHandshakeDone(
    const uint32_t &connection_key,
    SSLContext::HandshakeResult error) {
  LOG4CXX_AUTO_TRACE(logger_);
  std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
  while (it != listeners_.end()) {
    if ((*it)->OnHandshakeDone(connection_key, error)) {
      // On get notification remove listener
      it = listeners_.erase(it);
    } else {
      ++it;
    }
  }
}

bool SecurityManagerImpl::ProccessHandshakeData(const SecurityMessage &inMessage) {
  LOG4CXX_INFO(logger_, "SendHandshakeData processing");
  DCHECK(inMessage);
  DCHECK(inMessage->get_header().query_id == SecurityQuery::SEND_HANDSHAKE_DATA);
  const uint32_t seqNumber = inMessage->get_header().seq_number;
  const uint32_t connection_key = inMessage->get_connection_key();

  LOG4CXX_DEBUG(logger_, "Received " << inMessage->get_data_size()
                << " bytes handshake data ");

  if (!inMessage->get_data_size()) {
    const std::string error_text("SendHandshakeData: null arguments size.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INVALID_QUERY_SIZE,
                      error_text, seqNumber);
    return false;
  }
  DCHECK(session_observer_);
  SSLContext *sslContext =
      session_observer_->GetSSLContext(connection_key,
                                       protocol_handler::kControl);
  if (!sslContext) {
    const std::string error_text("SendHandshakeData: No ssl context.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_SERVICE_NOT_PROTECTED,
                      error_text, seqNumber);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return false;
  }
  size_t out_data_size;
  const uint8_t *out_data;
  const SSLContext::HandshakeResult handshake_result =
      sslContext->DoHandshakeStep(inMessage->get_data(), inMessage->get_data_size(),
                                  &out_data, &out_data_size);
  if (handshake_result == SSLContext::Handshake_Result_AbnormalFail) {
    // Do not return handshake data on AbnormalFail or null returned values
    const std::string erorr_text(sslContext->LastError());
    LOG4CXX_ERROR(logger_, "SendHandshakeData: Handshake failed: " << erorr_text);
    SendInternalError(connection_key,
                      ERROR_SSL_INVALID_DATA, erorr_text, seqNumber);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    // no handshake data to send
    return false;
  }
  if (sslContext->IsInitCompleted()) {
    // On handshake success
    LOG4CXX_DEBUG(logger_, "SSL initialization finished success.");
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Success);
  } else if (handshake_result != SSLContext::Handshake_Result_Success){
    // On handshake fail
    LOG4CXX_WARN(logger_, "SSL initialization finished with fail.");
    NotifyListenersOnHandshakeDone(connection_key, handshake_result);
  }

  if (out_data && out_data_size) {
    // answer with the same seqNumber as income message
    SendHandshakeBinData(connection_key, out_data, out_data_size,
                         seqNumber);
  }
  return true;
}

bool SecurityManagerImpl::ProccessInternalError(const SecurityMessage &inMessage) {
  LOG4CXX_INFO(logger_, "Received InternalError with Json message"
                << inMessage->get_json_message());
  Json::Value root;
  Json::Reader reader;
  const bool parsingSuccessful =
      reader.parse(inMessage->get_json_message(), root);
  if (!parsingSuccessful)
    return false;
  LOG4CXX_DEBUG(logger_, "Received InternalError id " << root[kErrId].asString()
                << ", text: " << root[kErrText].asString());
  return true;
}
void SecurityManagerImpl::SendHandshakeBinData(
    const uint32_t connection_key, const uint8_t *const data,
    const size_t data_size, const uint32_t seq_number) {
  const SecurityQuery::QueryHeader header(
        SecurityQuery::NOTIFICATION,
        SecurityQuery::SEND_HANDSHAKE_DATA, seq_number);
  DCHECK(data_size < 1024 * 1024 *1024 );
  const SecurityQuery query = SecurityQuery(header, connection_key, data, data_size);
  SendQuery(query, connection_key);
  LOG4CXX_DEBUG(logger_, "Sent " << data_size << " bytes handshake data ");
}

void SecurityManagerImpl::SendInternalError(const uint32_t connection_key,
                                        const uint8_t &error_id,
                                        const std::string &erorr_text,
                                        const uint32_t seq_number) {
  Json::Value value;
  value[kErrId]   = error_id;
  value[kErrText] = erorr_text;
  const std::string error_str = value.toStyledString();
  SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION,
                                    SecurityQuery::SEND_INTERNAL_ERROR,
                                    // header save json size only (exclude last byte)
                                    seq_number, error_str.size());

  // Raw data is json string and error id at last byte
  std::vector<uint8_t> data_sending(error_str.size() + 1);
  memcpy(&data_sending[0], error_str.c_str(), error_str.size());
  data_sending[data_sending.size()-1] = error_id;

  const SecurityQuery query(header, connection_key,
                            &data_sending[0], data_sending.size());
  SendQuery(query, connection_key);
  LOG4CXX_DEBUG(logger_, "Sent Internal error id " << static_cast<int>(error_id)
                << " : \"" << erorr_text << "\".");
}

void SecurityManagerImpl::SendQuery(const SecurityQuery& query,
                                const uint32_t connection_key) {
  const std::vector<uint8_t> data_sending = query.DeserializeQuery();
  uint32_t connection_handle = 0;
  uint8_t sessionID = 0;
  uint8_t protocol_version;
  session_observer_->PairFromKey(connection_key, &connection_handle,
                                   &sessionID);
  if (session_observer_->ProtocolVersionUsed(connection_handle, sessionID,
		  protocol_version)) {
    const ::protocol_handler::RawMessagePtr rawMessagePtr(
      new protocol_handler::RawMessage(connection_key,
    		                           protocol_version,
                                       &data_sending[0], data_sending.size(),
                                       protocol_handler::kControl));
    DCHECK(protocol_handler_);
    // Add RawMessage to ProtocolHandler message query
    protocol_handler_->SendMessageToMobileApp(rawMessagePtr, false);
  }
}

const char *SecurityManagerImpl::ConfigSection() {
  return "Security Manager";
}

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

#include "security_manager/security_manager_impl.h"
#include "security_manager/crypto_manager_impl.h"
#include "protocol_handler/protocol_packet.h"
#include "utils/logger.h"
#include "utils/byte_order.h"
#include "json/json.h"

namespace security_manager {

CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")

static const char* kErrId = "id";
static const char* kErrText = "text";

SecurityManagerImpl::SecurityManagerImpl()
  : security_messages_("SecurityManager", this),
  session_observer_(NULL), crypto_manager_(NULL), protocol_handler_(NULL) {
}

void SecurityManagerImpl::OnMessageReceived(
    const ::protocol_handler::RawMessagePtr message) {
  if (message->service_type() != protocol_handler::kControl) {
    return;
  }

  SecurityMessage securityMessagePtr(new SecurityQuery());
  const bool result = securityMessagePtr->SerializeQuery(
        message->data(), message->data_size());
  if (!result) {
    // result will be false only if data less then query header
    const std::string error_text("Incorrect message received");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(message->connection_key(),
                      ERROR_INVALID_QUERY_SIZE, error_text);
    return;
  }
  securityMessagePtr->set_connection_key(message->connection_key());

  // Post message to message query for next processing in thread
  security_messages_.PostMessage(securityMessagePtr);
}

void SecurityManagerImpl::OnMobileMessageSent(
    const ::protocol_handler::RawMessagePtr ) {
}

void SecurityManagerImpl::set_session_observer(
    protocol_handler::SessionObserver *observer) {
  if (!observer) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SessionObserver.");
    return;
  }
  session_observer_ = observer;
}

void SecurityManagerImpl::set_protocol_handler(
    protocol_handler::ProtocolHandler *handler) {
  if (!handler) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to ProtocolHandler.");
    return;
  }
  protocol_handler_ = handler;
}

void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) {
  if (!crypto_manager) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to CryptoManager.");
    return;
  }
  crypto_manager_ = crypto_manager;
}

void SecurityManagerImpl::Handle(const SecurityMessage message) {
  DCHECK(message);
  LOG4CXX_INFO(logger_, "Received Security message from Mobile side");
  if (!crypto_manager_)  {
    const std::string error_text("Invalid (NULL) CryptoManager.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(message->get_connection_key(),
                      ERROR_NOT_SUPPORTED, error_text);
    return;
  }
  switch (message->get_header().query_id) {
    case SecurityQuery::SEND_HANDSHAKE_DATA:
      if (!ProccessHandshakeData(message)) {
        LOG4CXX_ERROR(logger_, "Proccess HandshakeData failed");
      }
      break;
    case SecurityQuery::SEND_INTERNAL_ERROR:
      if (!ProccessInternalError(message)) {
        LOG4CXX_ERROR(logger_, "Processing income InternalError failed");
      }
      break;
    default: {
      // SecurityQuery::InvalidQuery
      const std::string error_text("Unknown query identifier.");
      LOG4CXX_ERROR(logger_, error_text);
      SendInternalError(message->get_connection_key(),
                        ERROR_INVALID_QUERY_ID, error_text,
                        message->get_header().seq_number);
      }
      break;
    }
}

security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext(
    const uint32_t &connection_key) {
  LOG4CXX_INFO(logger_, "ProtectService processing");
  DCHECK(session_observer_);
  DCHECK(crypto_manager_);

  security_manager::SSLContext *ssl_context =
      session_observer_->GetSSLContext(connection_key, protocol_handler::kControl);
  // return exists SSLCOntext for current connection/session
  if (ssl_context) {
    return ssl_context;
  }

  ssl_context = crypto_manager_->CreateSSLContext();
  if (!ssl_context) {
    const std::string error_text("CryptoManager could not create SSL context.");
    LOG4CXX_ERROR(logger_, error_text);
    // Generate response query and post to security_messages_
    SendInternalError(connection_key, ERROR_INTERNAL,
                      error_text);
    return NULL;
  }

  const int result = session_observer_->SetSSLContext(connection_key, ssl_context);
  if (ERROR_SUCCESS != result) {
    // delete SSLContext on any error
    crypto_manager_->ReleaseSSLContext(ssl_context);
    SendInternalError(connection_key, result, "");
    return NULL;
  }
  DCHECK(session_observer_->GetSSLContext(connection_key,
                                          protocol_handler::kControl));
  LOG4CXX_DEBUG(logger_, "Set SSL context to connection_key " << connection_key);
  return ssl_context;
}

void SecurityManagerImpl::StartHandshake(uint32_t connection_key) {
  DCHECK(session_observer_);
  LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key);
  security_manager::SSLContext *ssl_context =
      session_observer_->GetSSLContext(connection_key,
                                       protocol_handler::kControl);
  if (!ssl_context) {
    const std::string error_text("StartHandshake failed, "
                                 "connection is not protected");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INTERNAL, error_text);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return;
  }

  if(crypto_manager_->IsCertificateUpdateRequired()) {
    NotifyOnCertififcateUpdateRequired();
  }

  if (ssl_context->IsInitCompleted()) {
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Success);
    return;
  }

  ssl_context->SetHandshakeContext(
        session_observer_->GetHandshakeContext(connection_key));

  size_t data_size = 0;
  const uint8_t *data = NULL;

  const security_manager::SSLContext::HandshakeResult result =
      ssl_context->StartHandshake(&data, &data_size);
  if (security_manager::SSLContext::Handshake_Result_Success != result) {
    const std::string error_text("StartHandshake failed, handshake step fail");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INTERNAL, error_text);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return;
  }
  // for client mode will be generated output data
  if (data != NULL && data_size != 0) {
    SendHandshakeBinData(connection_key, data, data_size);
  }
}
void SecurityManagerImpl::AddListener(SecurityManagerListener *const listener) {
  if (!listener) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
    return;
  }
  listeners_.push_back(listener);
}
void SecurityManagerImpl::RemoveListener(SecurityManagerListener *const listener) {
  if (!listener) {
    LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
    return;
  }
  listeners_.remove(listener);
}
void SecurityManagerImpl::NotifyListenersOnHandshakeDone(
    const uint32_t &connection_key,
    SSLContext::HandshakeResult error) {
  LOG4CXX_AUTO_TRACE(logger_);
  std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
  while (it != listeners_.end()) {
    if ((*it)->OnHandshakeDone(connection_key, error)) {
      // On get notification remove listener
      it = listeners_.erase(it);
    } else {
      ++it;
    }
  }
}

bool SecurityManagerImpl::ProccessHandshakeData(const SecurityMessage &inMessage) {
  LOG4CXX_INFO(logger_, "SendHandshakeData processing");
  DCHECK(inMessage);
  DCHECK(inMessage->get_header().query_id == SecurityQuery::SEND_HANDSHAKE_DATA);
  const uint32_t seqNumber = inMessage->get_header().seq_number;
  const uint32_t connection_key = inMessage->get_connection_key();

  LOG4CXX_DEBUG(logger_, "Received " << inMessage->get_data_size()
                << " bytes handshake data ");

  if (!inMessage->get_data_size()) {
    const std::string error_text("SendHandshakeData: null arguments size.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_INVALID_QUERY_SIZE,
                      error_text, seqNumber);
    return false;
  }
  DCHECK(session_observer_);
  SSLContext *sslContext =
      session_observer_->GetSSLContext(connection_key,
                                       protocol_handler::kControl);
  if (!sslContext) {
    const std::string error_text("SendHandshakeData: No ssl context.");
    LOG4CXX_ERROR(logger_, error_text);
    SendInternalError(connection_key, ERROR_SERVICE_NOT_PROTECTED,
                      error_text, seqNumber);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    return false;
  }
  size_t out_data_size;
  const uint8_t *out_data;
  const SSLContext::HandshakeResult handshake_result =
      sslContext->DoHandshakeStep(inMessage->get_data(), inMessage->get_data_size(),
                                  &out_data, &out_data_size);
  if (handshake_result == SSLContext::Handshake_Result_AbnormalFail) {
    // Do not return handshake data on AbnormalFail or null returned values
    const std::string erorr_text(sslContext->LastError());
    LOG4CXX_ERROR(logger_, "SendHandshakeData: Handshake failed: " << erorr_text);
    SendInternalError(connection_key,
                      ERROR_SSL_INVALID_DATA, erorr_text, seqNumber);
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Fail);
    // no handshake data to send
    return false;
  }
  if (sslContext->IsInitCompleted()) {
    // On handshake success
    LOG4CXX_DEBUG(logger_, "SSL initialization finished success.");
    NotifyListenersOnHandshakeDone(connection_key,
                                   SSLContext::Handshake_Result_Success);
  } else if (handshake_result != SSLContext::Handshake_Result_Success){
    // On handshake fail
    LOG4CXX_WARN(logger_, "SSL initialization finished with fail.");
    NotifyListenersOnHandshakeDone(connection_key, handshake_result);
  }

  if (out_data && out_data_size) {
    // answer with the same seqNumber as income message
    SendHandshakeBinData(connection_key, out_data, out_data_size,
                         seqNumber);
  }
  return true;
}

bool SecurityManagerImpl::ProccessInternalError(const SecurityMessage &inMessage) {
  LOG4CXX_INFO(logger_, "Received InternalError with Json message"
                << inMessage->get_json_message());
  Json::Value root;
  Json::Reader reader;
  const bool parsingSuccessful =
      reader.parse(inMessage->get_json_message(), root);
  if (!parsingSuccessful)
    return false;
  LOG4CXX_DEBUG(logger_, "Received InternalError id " << root[kErrId].asString()
                << ", text: " << root[kErrText].asString());
  return true;
}
void SecurityManagerImpl::SendHandshakeBinData(
    const uint32_t connection_key, const uint8_t *const data,
    const size_t data_size, const uint32_t seq_number) {
  const SecurityQuery::QueryHeader header(
        SecurityQuery::NOTIFICATION,
        SecurityQuery::SEND_HANDSHAKE_DATA, seq_number);
  DCHECK(data_size < 1024 * 1024 *1024 );
  const SecurityQuery query = SecurityQuery(header, connection_key, data, data_size);
  SendQuery(query, connection_key);
  LOG4CXX_DEBUG(logger_, "Sent " << data_size << " bytes handshake data ");
}

void SecurityManagerImpl::SendInternalError(const uint32_t connection_key,
                                        const uint8_t &error_id,
                                        const std::string &erorr_text,
                                        const uint32_t seq_number) {
  Json::Value value;
  value[kErrId]   = error_id;
  value[kErrText] = erorr_text;
  const std::string error_str = value.toStyledString();
  SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION,
                                    SecurityQuery::SEND_INTERNAL_ERROR,
                                    // header save json size only (exclude last byte)
                                    seq_number, error_str.size());

  // Raw data is json string and error id at last byte
  std::vector<uint8_t> data_sending(error_str.size() + 1);
  memcpy(&data_sending[0], error_str.c_str(), error_str.size());
  data_sending[data_sending.size()-1] = error_id;

  const SecurityQuery query(header, connection_key,
                            &data_sending[0], data_sending.size());
  SendQuery(query, connection_key);
  LOG4CXX_DEBUG(logger_, "Sent Internal error id " << static_cast<int>(error_id)
                << " : \"" << erorr_text << "\".");
}

void SecurityManagerImpl::SendQuery(const SecurityQuery& query,
                                const uint32_t connection_key) {
  const std::vector<uint8_t> data_sending = query.DeserializeQuery();
  uint32_t connection_handle = 0;
  uint8_t sessionID = 0;
  uint8_t protocol_version;
  session_observer_->PairFromKey(connection_key, &connection_handle,
                                   &sessionID);
  if (session_observer_->ProtocolVersionUsed(connection_handle, sessionID,
		  protocol_version)) {
    const ::protocol_handler::RawMessagePtr rawMessagePtr(
      new protocol_handler::RawMessage(connection_key,
    		                           protocol_version,
                                       &data_sending[0], data_sending.size(),
                                       protocol_handler::kControl));
    DCHECK(protocol_handler_);
    // Add RawMessage to ProtocolHandler message query
    protocol_handler_->SendMessageToMobileApp(rawMessagePtr, false);
  }
}

const char *SecurityManagerImpl::ConfigSection() {
  return "Security Manager";
}

}  // namespace security_manager
<|endoftext|>


<commit_before>/*
 * fujimapBlock.hpp
 * Copyright (c) 2010 Daisuke Okanohara All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef FUJIMAP_BLOCK_HPP__
#define FUJIMAP_BLOCK_HPP__

#include "keyedge.hpp"
#include "bitvec.hpp"

#include <queue>

NS_IZENELIB_AM_BEGIN

namespace succinct{ namespace fujimap{

/*
 * Minimum Perfect Associative Array
 * used in Fujimap
 */
template <class ValueType>
class FujimapBlock
{
    static const double C_R = 1.3; ///< Redundancy for bit array (>1.3)
    static const uint64_t intercept = 10;

public:
    FujimapBlock(); ///< Default Constructor
    ~FujimapBlock(); ///< Default Destructor

    int build(std::vector<KeyEdge<ValueType> >& keyEdges,
              const uint64_t seed, const uint64_t fpLen,
              const EncodeType et); ///< build an associative map
    ValueType getVal(const KeyEdge<ValueType>& ke) const; ///< return a value corresponding to the given KeyEdge
    void save(std::ofstream& ofs) const; ///< save the status in ofs
    void load(std::ifstream& ifs); ///< load the status from ifs

    uint64_t getSeed() const;

    size_t getKeyNum() const; ///<return the number of registered keys
    size_t getWorkingSize() const; ///<return the current working size

private:
    void test();

    BitVec<ValueType> B_;

    uint64_t keyNum_;
    ValueType minCodeVal_;
    ValueType maxCodeVal_;
    uint64_t maxCodeLen_;
    uint64_t fpLen_;
    uint64_t seed_;
    uint64_t bn_;
    EncodeType et_;
};

template <class ValueType>
FujimapBlock<ValueType>::FujimapBlock()
    : keyNum_(0)
    , minCodeVal_(0)
    , maxCodeVal_(0)
    , maxCodeLen_(0)
    , fpLen_(FPLEN)
    , seed_(0x12345678)
    , bn_(0)
    , et_(BINARY)
{
}

template <class ValueType>
FujimapBlock<ValueType>::~FujimapBlock()
{
}

template <class ValueType>
ValueType FujimapBlock<ValueType>::getVal(const KeyEdge<ValueType>& ke) const
{
    if (B_.bvBitSize() == 0)
    {
        return (ValueType)NOTFOUND;
    }

    uint64_t blockSize = (et_ == BINARY) ? (maxCodeLen_ + fpLen_) : 1;
    if (fpLen_ != 0)
    {
        uint64_t fpCheck = 0;
        for (uint64_t i = 0; i < R; ++i)
        {
            fpCheck ^= B_.get64Bits(ke.get(i, bn_) * blockSize, fpLen_);
        }
        if (fpCheck != FujimapCommon::maskCheckLen(ke.v[0] ^ ke.v[1], fpLen_))
        {
            return (ValueType)NOTFOUND;
        }
    }

    ValueType code = 0;
    for (uint64_t i = 0; i < R; ++i)
    {
        code ^= B_.getBits(ke.get(i, bn_) * blockSize + fpLen_, maxCodeLen_);
    }

    if (et_ == GAMMA)
    {
        code = FujimapCommon::gammaDecode(code);
    }

    if (code > maxCodeVal_)
    {
        return (ValueType)NOTFOUND;
    }

    return code + minCodeVal_;
}

template <class ValueType>
uint64_t FujimapBlock<ValueType>::getSeed() const
{
    return seed_;
}

template <class ValueType>
int FujimapBlock<ValueType>::build(
        std::vector<KeyEdge<ValueType> >& keyEdges,
        const uint64_t seed, const uint64_t fpLen,
        const EncodeType et)
{
    keyNum_ = static_cast<uint64_t>(keyEdges.size());
    seed_   = seed;
    fpLen_  = fpLen;
    et_     = et;

    minCodeVal_ = (ValueType)-1;
    maxCodeVal_ = 0;
    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        if (keyEdges[i].code < minCodeVal_)
        {
            minCodeVal_ = keyEdges[i].code;
        }
    }

    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        keyEdges[i].code -= minCodeVal_;
        if (keyEdges[i].code > maxCodeVal_)
        {
            maxCodeVal_ = keyEdges[i].code;
        }
    }

    uint64_t totalCodeLen = 0;
    if (et_ == BINARY)
    {
        maxCodeLen_  = FujimapCommon::log2(maxCodeVal_);
        totalCodeLen = (maxCodeLen_ + fpLen_) * keyNum_;
        bn_          = (uint64_t)(keyNum_ * C_R / (double)R + intercept);
    }
    else if (et_ == GAMMA)
    {
        for (size_t i = 0; i < keyEdges.size(); ++i)
        {
            totalCodeLen += FujimapCommon::gammaLen(keyEdges[i].code);
        }
        totalCodeLen += fpLen_ * keyNum_;
        maxCodeLen_   = FujimapCommon::gammaLen(maxCodeVal_);
        bn_           = totalCodeLen * C_R / R + intercept; // <= keyNum_ * maxCodeLen_ * C_R / R + 10
    }
    else
    {
        assert(false);
    }

    uint64_t maxCodeFPLen = maxCodeLen_ + fpLen_;
    uint64_t pointsPerKey = (et_ == BINARY) ? 1 : maxCodeFPLen;

    // set_ keyEdge
    uint64_t space = (et_ == BINARY) ? 0 : maxCodeFPLen;
    std::vector<uint8_t> degs(bn_ * R + space);
    std::vector<uint64_t> offset_s(bn_ * R + space + 1);

    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        const KeyEdge<ValueType>& ke(keyEdges[i]);
        uint64_t len = (et_ == BINARY) ? 1 : FujimapCommon::gammaLen(ke.code) + fpLen_;
        for (uint64_t j = 0; j < R; ++j)
        {
            uint64_t t = ke.get(j, bn_);
            for (uint64_t k = 0; k < len; ++k)
            {
                if (degs[t + k] == 0xFF)
                {
                    return -1;
                }
                ++degs[t + k];
            }
        }
    }

    // set_ offset_s
    uint64_t sum = 0;
    for (size_t i = 0; i < degs.size(); ++i)
    {
        offset_s[i] = sum;
        sum += degs[i];
        degs[i] = 0;
    }
    offset_s.back() = sum;

    // set_ edges
    uint64_t totalEdgeNum = (et_ == BINARY) ? keyNum_ * R : totalCodeLen * R;
    std::vector<uint64_t> edges(totalEdgeNum);
    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        const KeyEdge<ValueType>& ke(keyEdges[i]);
        uint64_t len = (et_ == BINARY) ? 1 : FujimapCommon::gammaLen(ke.code) + fpLen_;
        for (uint64_t j = 0; j < R; ++j)
        {
            uint64_t t = ke.get(j, bn_);
            for (uint64_t k = 0; k < len; ++k)
            {
                edges[offset_s[t + k] + degs[t + k]++] = i * pointsPerKey + k;
            }
        }
    }

    // init q
    std::queue<uint64_t> q;
    for (size_t i = 0; i < degs.size(); ++i)
    {
        if (degs[i] == 1)
        {
            q.push(edges[offset_s[i]]);
        }
    }

    std::vector<std::pair<uint64_t, uint8_t> > extractedEdges;
    uint64_t assignNum = keyNum_ * pointsPerKey;

    BitVec<uint64_t> visitedEdges(assignNum);
    uint64_t deletedNum = 0;
    while (!q.empty())
    {
        uint64_t v = q.front();
        q.pop();

        if (visitedEdges.getBit(v)) continue;
        visitedEdges.setBit(v);
        ++deletedNum;

        uint64_t keyID  = v / pointsPerKey;
        uint64_t offset = v % pointsPerKey;

        const KeyEdge<ValueType>& ke(keyEdges[keyID]);
        int choosed = -1;
        for (uint64_t i = 0; i < R; ++i)
        {
            const uint64_t t = ke.get(i, bn_);
            --degs[t + offset];

            if (degs[t + offset] == 0)
            {
                choosed = i;
                continue;
            }
            else if (degs[t + offset] >= 2)
            {
                continue;
            }
            // degs[t] == 1
            const uint64_t end = offset_s[t + offset + 1];
            for (uint64_t j = offset_s[t + offset]; j < end; ++j)
            {
                if (!visitedEdges.getBit(edges[j]))
                {
                    q.push(edges[j]);
                    break;
                }
            }
        }
        assert(choosed != -1);
        extractedEdges.push_back(std::make_pair(v, choosed));
    }

    if (et_ == BINARY && deletedNum != keyNum_)
    {
        return -1;
    }
    else if (et_ == GAMMA && deletedNum != totalCodeLen)
    {
        return -1;
    }

    assert(q.empty());

    if (et_ == BINARY)
    {
        B_.resize(bn_ * maxCodeFPLen * R);
    }
    else if (et_ == GAMMA)
    {
        B_.resize(bn_ * R + space);
    }
    else
    {
        assert(false);
    }

    uint64_t blockSize = (et_ == BINARY ) ? maxCodeFPLen : 1;
    BitVec<uint64_t> visitedVerticies(assignNum * R);
    std::reverse(extractedEdges.begin(), extractedEdges.end());
    for (std::vector<std::pair<uint64_t, uint8_t> >::const_iterator it =
            extractedEdges.begin(); it != extractedEdges.end(); ++it)
    {
        const uint64_t v = it->first;

        uint64_t keyID  = v / pointsPerKey;
        uint64_t offset = v % pointsPerKey;

        const KeyEdge<ValueType>& ke(keyEdges[keyID]);

        uint64_t signature = FujimapCommon::maskCheckLen(ke.v[0] ^ ke.v[1], fpLen_);
        if (et_ == BINARY)
        {
            ValueType bits = ke.code;
            for (uint64_t i = 0; i < R; ++i)
            {
                const uint64_t t = ke.get(i, bn_);
                if (!(visitedVerticies.getBit(t + offset)))
                {
                    continue;
                }
                signature ^= B_.get64Bits(t * blockSize + offset, fpLen_);
                bits ^= B_.getBits(t * blockSize + offset + fpLen_, maxCodeLen_);
            }

            const uint64_t set_Pos = ke.get(it->second, bn_);
            B_.set64Bits(set_Pos * blockSize + offset, fpLen_, signature);
            B_.setBits(set_Pos * blockSize + offset + fpLen_, maxCodeLen_, bits);
            visitedVerticies.setBit(set_Pos + offset);
        }
        else if (et_ == GAMMA)
        {
            bool bit;
            if (offset < fpLen_)
            {
                bit = (signature >> offset) & 1;
            }
            else
            {
                bit = FujimapCommon::gammaEncodeBit(offset - fpLen_, ke.code);
            }
            for (uint64_t i = 0; i < R; ++i)
            {
                const uint64_t t = ke.get(i, bn_);
                if (!(visitedVerticies.getBit(t + offset)))
                {
                    continue;
                }
                bit ^= B_.getBit(t * blockSize + offset);
            }

            const uint64_t set_Pos = ke.get(it->second, bn_);
            B_.set64Bits(set_Pos * blockSize + offset, 1, bit);
            visitedVerticies.setBit(set_Pos + offset);
        }
        else
        {
            assert(false);
        }
    }

    return 0;
}

template <class ValueType>
size_t FujimapBlock<ValueType>::getKeyNum() const
{
    return keyNum_;
}

template <class ValueType>
size_t FujimapBlock<ValueType>::getWorkingSize() const
{
    return B_.bvBitSize();
}

template <class ValueType>
void FujimapBlock<ValueType>::save(std::ofstream& ofs) const
{
    ofs.write((const char*)(&keyNum_),     sizeof(keyNum_));
    ofs.write((const char*)(&minCodeVal_), sizeof(minCodeVal_));
    ofs.write((const char*)(&maxCodeVal_), sizeof(maxCodeVal_));
    ofs.write((const char*)(&maxCodeLen_), sizeof(maxCodeLen_));
    ofs.write((const char*)(&fpLen_),      sizeof(fpLen_));
    ofs.write((const char*)(&seed_),       sizeof(seed_));
    ofs.write((const char*)(&bn_),         sizeof(bn_));
    ofs.write((const char*)(&et_),         sizeof(et_));

    B_.write(ofs);
}

template <class ValueType>
void FujimapBlock<ValueType>::load(std::ifstream& ifs)
{
    ifs.read((char*)(&keyNum_),     sizeof(keyNum_));
    ifs.read((char*)(&minCodeVal_), sizeof(minCodeVal_));
    ifs.read((char*)(&maxCodeVal_), sizeof(maxCodeVal_));
    ifs.read((char*)(&maxCodeLen_), sizeof(maxCodeLen_));
    ifs.read((char*)(&fpLen_),      sizeof(fpLen_));
    ifs.read((char*)(&seed_),       sizeof(seed_));
    ifs.read((char*)(&bn_),         sizeof(bn_));
    ifs.read((char*)(&et_),         sizeof(et_));

    B_.read(ifs);
}

}}

NS_IZENELIB_AM_END

#endif // FUJIMAP_BLOCK_HPP__
<commit_msg>constexpr is required by c++11 for fujimap<commit_after>/*
 * fujimapBlock.hpp
 * Copyright (c) 2010 Daisuke Okanohara All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef FUJIMAP_BLOCK_HPP__
#define FUJIMAP_BLOCK_HPP__

#include "keyedge.hpp"
#include "bitvec.hpp"

#include <queue>

NS_IZENELIB_AM_BEGIN

namespace succinct{ namespace fujimap{

/*
 * Minimum Perfect Associative Array
 * used in Fujimap
 */
template <class ValueType>
class FujimapBlock
{
    static constexpr double C_R = 1.3; ///< Redundancy for bit array (>1.3)
    static constexpr uint64_t intercept = 10;

public:
    FujimapBlock(); ///< Default Constructor
    ~FujimapBlock(); ///< Default Destructor

    int build(std::vector<KeyEdge<ValueType> >& keyEdges,
              const uint64_t seed, const uint64_t fpLen,
              const EncodeType et); ///< build an associative map
    ValueType getVal(const KeyEdge<ValueType>& ke) const; ///< return a value corresponding to the given KeyEdge
    void save(std::ofstream& ofs) const; ///< save the status in ofs
    void load(std::ifstream& ifs); ///< load the status from ifs

    uint64_t getSeed() const;

    size_t getKeyNum() const; ///<return the number of registered keys
    size_t getWorkingSize() const; ///<return the current working size

private:
    void test();

    BitVec<ValueType> B_;

    uint64_t keyNum_;
    ValueType minCodeVal_;
    ValueType maxCodeVal_;
    uint64_t maxCodeLen_;
    uint64_t fpLen_;
    uint64_t seed_;
    uint64_t bn_;
    EncodeType et_;
};

template <class ValueType>
FujimapBlock<ValueType>::FujimapBlock()
    : keyNum_(0)
    , minCodeVal_(0)
    , maxCodeVal_(0)
    , maxCodeLen_(0)
    , fpLen_(FPLEN)
    , seed_(0x12345678)
    , bn_(0)
    , et_(BINARY)
{
}

template <class ValueType>
FujimapBlock<ValueType>::~FujimapBlock()
{
}

template <class ValueType>
ValueType FujimapBlock<ValueType>::getVal(const KeyEdge<ValueType>& ke) const
{
    if (B_.bvBitSize() == 0)
    {
        return (ValueType)NOTFOUND;
    }

    uint64_t blockSize = (et_ == BINARY) ? (maxCodeLen_ + fpLen_) : 1;
    if (fpLen_ != 0)
    {
        uint64_t fpCheck = 0;
        for (uint64_t i = 0; i < R; ++i)
        {
            fpCheck ^= B_.get64Bits(ke.get(i, bn_) * blockSize, fpLen_);
        }
        if (fpCheck != FujimapCommon::maskCheckLen(ke.v[0] ^ ke.v[1], fpLen_))
        {
            return (ValueType)NOTFOUND;
        }
    }

    ValueType code = 0;
    for (uint64_t i = 0; i < R; ++i)
    {
        code ^= B_.getBits(ke.get(i, bn_) * blockSize + fpLen_, maxCodeLen_);
    }

    if (et_ == GAMMA)
    {
        code = FujimapCommon::gammaDecode(code);
    }

    if (code > maxCodeVal_)
    {
        return (ValueType)NOTFOUND;
    }

    return code + minCodeVal_;
}

template <class ValueType>
uint64_t FujimapBlock<ValueType>::getSeed() const
{
    return seed_;
}

template <class ValueType>
int FujimapBlock<ValueType>::build(
        std::vector<KeyEdge<ValueType> >& keyEdges,
        const uint64_t seed, const uint64_t fpLen,
        const EncodeType et)
{
    keyNum_ = static_cast<uint64_t>(keyEdges.size());
    seed_   = seed;
    fpLen_  = fpLen;
    et_     = et;

    minCodeVal_ = (ValueType)-1;
    maxCodeVal_ = 0;
    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        if (keyEdges[i].code < minCodeVal_)
        {
            minCodeVal_ = keyEdges[i].code;
        }
    }

    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        keyEdges[i].code -= minCodeVal_;
        if (keyEdges[i].code > maxCodeVal_)
        {
            maxCodeVal_ = keyEdges[i].code;
        }
    }

    uint64_t totalCodeLen = 0;
    if (et_ == BINARY)
    {
        maxCodeLen_  = FujimapCommon::log2(maxCodeVal_);
        totalCodeLen = (maxCodeLen_ + fpLen_) * keyNum_;
        bn_          = (uint64_t)(keyNum_ * C_R / (double)R + intercept);
    }
    else if (et_ == GAMMA)
    {
        for (size_t i = 0; i < keyEdges.size(); ++i)
        {
            totalCodeLen += FujimapCommon::gammaLen(keyEdges[i].code);
        }
        totalCodeLen += fpLen_ * keyNum_;
        maxCodeLen_   = FujimapCommon::gammaLen(maxCodeVal_);
        bn_           = totalCodeLen * C_R / R + intercept; // <= keyNum_ * maxCodeLen_ * C_R / R + 10
    }
    else
    {
        assert(false);
    }

    uint64_t maxCodeFPLen = maxCodeLen_ + fpLen_;
    uint64_t pointsPerKey = (et_ == BINARY) ? 1 : maxCodeFPLen;

    // set_ keyEdge
    uint64_t space = (et_ == BINARY) ? 0 : maxCodeFPLen;
    std::vector<uint8_t> degs(bn_ * R + space);
    std::vector<uint64_t> offset_s(bn_ * R + space + 1);

    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        const KeyEdge<ValueType>& ke(keyEdges[i]);
        uint64_t len = (et_ == BINARY) ? 1 : FujimapCommon::gammaLen(ke.code) + fpLen_;
        for (uint64_t j = 0; j < R; ++j)
        {
            uint64_t t = ke.get(j, bn_);
            for (uint64_t k = 0; k < len; ++k)
            {
                if (degs[t + k] == 0xFF)
                {
                    return -1;
                }
                ++degs[t + k];
            }
        }
    }

    // set_ offset_s
    uint64_t sum = 0;
    for (size_t i = 0; i < degs.size(); ++i)
    {
        offset_s[i] = sum;
        sum += degs[i];
        degs[i] = 0;
    }
    offset_s.back() = sum;

    // set_ edges
    uint64_t totalEdgeNum = (et_ == BINARY) ? keyNum_ * R : totalCodeLen * R;
    std::vector<uint64_t> edges(totalEdgeNum);
    for (size_t i = 0; i < keyEdges.size(); ++i)
    {
        const KeyEdge<ValueType>& ke(keyEdges[i]);
        uint64_t len = (et_ == BINARY) ? 1 : FujimapCommon::gammaLen(ke.code) + fpLen_;
        for (uint64_t j = 0; j < R; ++j)
        {
            uint64_t t = ke.get(j, bn_);
            for (uint64_t k = 0; k < len; ++k)
            {
                edges[offset_s[t + k] + degs[t + k]++] = i * pointsPerKey + k;
            }
        }
    }

    // init q
    std::queue<uint64_t> q;
    for (size_t i = 0; i < degs.size(); ++i)
    {
        if (degs[i] == 1)
        {
            q.push(edges[offset_s[i]]);
        }
    }

    std::vector<std::pair<uint64_t, uint8_t> > extractedEdges;
    uint64_t assignNum = keyNum_ * pointsPerKey;

    BitVec<uint64_t> visitedEdges(assignNum);
    uint64_t deletedNum = 0;
    while (!q.empty())
    {
        uint64_t v = q.front();
        q.pop();

        if (visitedEdges.getBit(v)) continue;
        visitedEdges.setBit(v);
        ++deletedNum;

        uint64_t keyID  = v / pointsPerKey;
        uint64_t offset = v % pointsPerKey;

        const KeyEdge<ValueType>& ke(keyEdges[keyID]);
        int choosed = -1;
        for (uint64_t i = 0; i < R; ++i)
        {
            const uint64_t t = ke.get(i, bn_);
            --degs[t + offset];

            if (degs[t + offset] == 0)
            {
                choosed = i;
                continue;
            }
            else if (degs[t + offset] >= 2)
            {
                continue;
            }
            // degs[t] == 1
            const uint64_t end = offset_s[t + offset + 1];
            for (uint64_t j = offset_s[t + offset]; j < end; ++j)
            {
                if (!visitedEdges.getBit(edges[j]))
                {
                    q.push(edges[j]);
                    break;
                }
            }
        }
        assert(choosed != -1);
        extractedEdges.push_back(std::make_pair(v, choosed));
    }

    if (et_ == BINARY && deletedNum != keyNum_)
    {
        return -1;
    }
    else if (et_ == GAMMA && deletedNum != totalCodeLen)
    {
        return -1;
    }

    assert(q.empty());

    if (et_ == BINARY)
    {
        B_.resize(bn_ * maxCodeFPLen * R);
    }
    else if (et_ == GAMMA)
    {
        B_.resize(bn_ * R + space);
    }
    else
    {
        assert(false);
    }

    uint64_t blockSize = (et_ == BINARY ) ? maxCodeFPLen : 1;
    BitVec<uint64_t> visitedVerticies(assignNum * R);
    std::reverse(extractedEdges.begin(), extractedEdges.end());
    for (std::vector<std::pair<uint64_t, uint8_t> >::const_iterator it =
            extractedEdges.begin(); it != extractedEdges.end(); ++it)
    {
        const uint64_t v = it->first;

        uint64_t keyID  = v / pointsPerKey;
        uint64_t offset = v % pointsPerKey;

        const KeyEdge<ValueType>& ke(keyEdges[keyID]);

        uint64_t signature = FujimapCommon::maskCheckLen(ke.v[0] ^ ke.v[1], fpLen_);
        if (et_ == BINARY)
        {
            ValueType bits = ke.code;
            for (uint64_t i = 0; i < R; ++i)
            {
                const uint64_t t = ke.get(i, bn_);
                if (!(visitedVerticies.getBit(t + offset)))
                {
                    continue;
                }
                signature ^= B_.get64Bits(t * blockSize + offset, fpLen_);
                bits ^= B_.getBits(t * blockSize + offset + fpLen_, maxCodeLen_);
            }

            const uint64_t set_Pos = ke.get(it->second, bn_);
            B_.set64Bits(set_Pos * blockSize + offset, fpLen_, signature);
            B_.setBits(set_Pos * blockSize + offset + fpLen_, maxCodeLen_, bits);
            visitedVerticies.setBit(set_Pos + offset);
        }
        else if (et_ == GAMMA)
        {
            bool bit;
            if (offset < fpLen_)
            {
                bit = (signature >> offset) & 1;
            }
            else
            {
                bit = FujimapCommon::gammaEncodeBit(offset - fpLen_, ke.code);
            }
            for (uint64_t i = 0; i < R; ++i)
            {
                const uint64_t t = ke.get(i, bn_);
                if (!(visitedVerticies.getBit(t + offset)))
                {
                    continue;
                }
                bit ^= B_.getBit(t * blockSize + offset);
            }

            const uint64_t set_Pos = ke.get(it->second, bn_);
            B_.set64Bits(set_Pos * blockSize + offset, 1, bit);
            visitedVerticies.setBit(set_Pos + offset);
        }
        else
        {
            assert(false);
        }
    }

    return 0;
}

template <class ValueType>
size_t FujimapBlock<ValueType>::getKeyNum() const
{
    return keyNum_;
}

template <class ValueType>
size_t FujimapBlock<ValueType>::getWorkingSize() const
{
    return B_.bvBitSize();
}

template <class ValueType>
void FujimapBlock<ValueType>::save(std::ofstream& ofs) const
{
    ofs.write((const char*)(&keyNum_),     sizeof(keyNum_));
    ofs.write((const char*)(&minCodeVal_), sizeof(minCodeVal_));
    ofs.write((const char*)(&maxCodeVal_), sizeof(maxCodeVal_));
    ofs.write((const char*)(&maxCodeLen_), sizeof(maxCodeLen_));
    ofs.write((const char*)(&fpLen_),      sizeof(fpLen_));
    ofs.write((const char*)(&seed_),       sizeof(seed_));
    ofs.write((const char*)(&bn_),         sizeof(bn_));
    ofs.write((const char*)(&et_),         sizeof(et_));

    B_.write(ofs);
}

template <class ValueType>
void FujimapBlock<ValueType>::load(std::ifstream& ifs)
{
    ifs.read((char*)(&keyNum_),     sizeof(keyNum_));
    ifs.read((char*)(&minCodeVal_), sizeof(minCodeVal_));
    ifs.read((char*)(&maxCodeVal_), sizeof(maxCodeVal_));
    ifs.read((char*)(&maxCodeLen_), sizeof(maxCodeLen_));
    ifs.read((char*)(&fpLen_),      sizeof(fpLen_));
    ifs.read((char*)(&seed_),       sizeof(seed_));
    ifs.read((char*)(&bn_),         sizeof(bn_));
    ifs.read((char*)(&et_),         sizeof(et_));

    B_.read(ifs);
}

}}

NS_IZENELIB_AM_END

#endif // FUJIMAP_BLOCK_HPP__
<|endoftext|>


<commit_before><commit_msg>Re-enable TAA & SSAO by default<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "fileutils.h"
#include "infocdbbackend.h"
#include "cdbwriter.h"

class InfoCdbBackendUnitTest : public QObject
{
    Q_OBJECT
    InfoCdbBackend *backend;

private slots:
    void initTestCase();
    void listKeys();
    void listPlugins();
};

void InfoCdbBackendUnitTest::initTestCase()
{
    // FIXME: LOCAL_DIR
    CDBWriter writer("cache.cdb");
    writer.add("KEYS", "Battery.Charging");
    writer.add("KEYS", "Internet.BytesOut");
    writer.add("PLUGINS", "contextkit-dbus");
    writer.close();

    utilSetEnv("CONTEXT_PROVIDERS", LOCAL_DIR);
    utilSetEnv("CONTEXT_CORE_DECLARATIONS", "/dev/null");
    backend = new InfoCdbBackend();
}

void InfoCdbBackendUnitTest::listKeys()
{
    QStringList keys = backend->listKeys();
    QCOMPARE(keys.count(), 2);
    QVERIFY(keys.contains("Battery.Charging"));
    QVERIFY(keys.contains("Internet.BytesOut"));
}

void InfoCdbBackendUnitTest::listPlugins()
{
    QStringList plugins = backend->listPlugins();
    QCOMPARE(plugins.count(), 1);
    QVERIFY(plugins.contains("contextkit-dbus"));
}

#include "infocdbbackendunittest.moc"
QTEST_MAIN(InfoCdbBackendUnitTest);
<commit_msg>listKeysForPlugin.<commit_after>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "fileutils.h"
#include "infocdbbackend.h"
#include "cdbwriter.h"

class InfoCdbBackendUnitTest : public QObject
{
    Q_OBJECT
    InfoCdbBackend *backend;

private slots:
    void initTestCase();
    void listKeys();
    void listPlugins();
    void listKeysForPlugin();
};

void InfoCdbBackendUnitTest::initTestCase()
{
    // FIXME: LOCAL_DIR
    CDBWriter writer("cache.cdb");
    writer.add("KEYS", "Battery.Charging");
    writer.add("KEYS", "Internet.BytesOut");
    writer.add("PLUGINS", "contextkit-dbus");
    writer.add("contextkit-dbus:KEYS", "Battery.Charging");
    writer.add("contextkit-dbus:KEYS", "Battery.BytesOut");
    writer.close();

    utilSetEnv("CONTEXT_PROVIDERS", LOCAL_DIR);
    utilSetEnv("CONTEXT_CORE_DECLARATIONS", "/dev/null");
    backend = new InfoCdbBackend();
}

void InfoCdbBackendUnitTest::listKeys()
{
    QStringList keys = backend->listKeys();
    QCOMPARE(keys.count(), 2);
    QVERIFY(keys.contains("Battery.Charging"));
    QVERIFY(keys.contains("Internet.BytesOut"));
}

void InfoCdbBackendUnitTest::listPlugins()
{
    QStringList plugins = backend->listPlugins();
    QCOMPARE(plugins.count(), 1);
    QVERIFY(plugins.contains("contextkit-dbus"));
}

void InfoCdbBackendUnitTest::listKeysForPlugin()
{
    QStringList keys1 = backend->listKeysForPlugin("contextkit-dbus");
    QCOMPARE(keys1.count(), 2);
    QVERIFY(keys1.contains("Battery.Charging"));
    QVERIFY(keys1.contains("Internet.BytesOut"));

    QStringList keys2 = backend->listKeysForPlugin("non-existant");
    QCOMPARE(keys2.count(), 1);
}

#include "infocdbbackendunittest.moc"
QTEST_MAIN(InfoCdbBackendUnitTest);
<|endoftext|>