<commit_before>/*

  This program will add histograms (see note) and Trees from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Wildcarding and indirect files are also supported
    hadd result.root  myfil*.root
   will merge all files in myfil*.root
    hadd result.root file1.root @list.txt file2. root myfil*.root
    will merge file1. root, file2. root, all files in myfil*.root
    and all files in the indirect text file list.txt ("@" as the first
    character of the file indicates an indirect file. An indirect file
    is a text file containing a list of other files, including other
    indirect files, one line per file).

  If the sources and and target compression levels are identical (default),
  the program uses the TChain::Merge function with option "fast", ie
  the merge will be done without  unzipping or unstreaming the baskets
  (i.e. direct copy of the raw byte on disk). The "fast" mode is typically
  5 times faster than the mode unzipping and unstreaming the baskets.

  NOTE: By default histograms are added. However if histograms have their bit kIsAverage
        set, the contents are averaged instead of being summed. See TH1::Add.

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
           Toby Burnett implemented the possibility to use indirect files.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "THashList.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"
#include "TClass.h"
#include "TSystem.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;
Bool_t fastMethod;

int AddFile(TList* sourcelist, std::string entry, int newcomp) ;
void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

//___________________________________________________________________________
int main( int argc, char **argv )
{

   if ( argc < 3 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
      cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 [source2 source3 ...]" << endl;
      cout << "This program will add histograms from a list of root files and write them" << endl;
      cout << "to a target root file. The target file is newly created and must not " << endl;
      cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
      cout << "Supply at least two source files for this to make sense... ;-)" << endl;
      cout << "If the first argument is -T, Trees are not merged" <<endl;
      cout << "When -the -f option is specified, one can also specify the compression" <<endl;
      cout << "level of the target file. By default the compression level is 1, but" <<endl;
      cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
      cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
      cout << "if Target and source files have different compression levels"<<endl;
      cout << " a slower method is used"<<endl;
      return 1;
   }
   FileList = new TList();

   Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
   noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
   Int_t newcomp = 1;
   char ft[4];
   for (int j=0;j<=9;j++) {
      sprintf(ft,"-f%d",j);
      if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
         force = kTRUE;
         newcomp = j;
         break;
      }
   }

   gSystem->Load("libTreePlayer");

   int ffirst = 2;
   if (force) ffirst++;
   if (noTrees) ffirst++;

   cout << "Target file: " << argv[ffirst-1] << endl;

   Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
   if (!Target || Target->IsZombie()) {
      cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
      cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
      exit(1);
   }
   Target->SetCompressionLevel(newcomp);

   // by default hadd can merge Trees in a file that can go up to 100 Gbytes
   Long64_t maxsize = 100000000; //100GB
   maxsize *= 100;  //to bypass some compiler limitations with big constants
   TTree::SetMaxTreeSize(maxsize);

   fastMethod = kTRUE;
   for ( int i = ffirst; i < argc; i++ ) {
      if( AddFile(FileList, argv[i], newcomp) !=0 ) return 1;
   }
   if (!fastMethod) {
      cout <<"Sources and Target have different compression levels"<<endl;
      cout <<"Merging will be slower"<<endl;
   }

   MergeRootfile( Target, FileList,0 );

   //must delete Target to avoid a problem with dictionaries in~ TROOT
   delete Target;

   return 0;
}

//___________________________________________________________________________
int AddFile(TList* sourcelist, std::string entry, int newcomp)
{
   // add a new file to the list of files
   static int count(0);
   if( entry.empty() ) return 0;
   size_t j =entry.find_first_not_of(' ');
   if( j==std::string::npos ) return 0;
   entry = entry.substr(j);
   if( entry.substr(0,1)=="@"){
      std::ifstream indirect_file(entry.substr(1).c_str() );
      if( ! indirect_file.is_open() ) {
         std::cerr<< "Could not open indirect file " << entry.substr(1) << std::endl;
         return 1;
      }
      while( indirect_file ){
         std::string line;
         std::getline(indirect_file, line);
         if( AddFile(sourcelist, line, newcomp)!=0 )return 1;;
      }
      return 0;
   }
   cout << "Source file " << (++count) << ": " << entry << endl;

   TFile* source = TFile::Open( entry.c_str());
   if( source==0 ){
      return 1;
   }
   sourcelist->Add(source);
   if (newcomp != source->GetCompressionLevel())  fastMethod = kFALSE;
   return 0;
}

//___________________________________________________________________________
void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir )
{
   // Merge all objects in a directory
   cout << "Target path: " << target->GetPath() << endl;
   TString path( (char*)strstr( target->GetPath(), ":" ) );
   path.Remove( 0, 2 );

   TDirectory *first_source = (TDirectory*)sourcelist->First();
   Int_t nguess = sourcelist->GetSize()+1000;
   THashList allNames(nguess);
   ((THashList*)target->GetList())->Rehash(nguess);
   ((THashList*)target->GetListOfKeys())->Rehash(nguess);
   TList listH;
   while(first_source) {
      TDirectory *current_sourcedir = first_source->GetDirectory(path);
      if (!current_sourcedir) {
         first_source = (TDirectory*)sourcelist->After(first_source);
         continue;
      }

      // loop over all keys in this directory
      TChain *globChain = 0;
      TIter nextkey( current_sourcedir->GetListOfKeys() );
      TKey *key, *oldkey=0;
      //gain time, do not add the objects in the list in memory
      TH1::AddDirectory(kFALSE);

      while ( (key = (TKey*)nextkey())) {
         if (current_sourcedir == target) break;
         //keep only the highest cycle number for each key
         if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
         if (!strcmp(key->GetClassName(),"TProcessID")) {key->ReadObj(); continue;}
         if (allNames.FindObject(key->GetName())) continue;
         allNames.Add(new TObjString(key->GetName()));
         // read object from first source file
         //current_sourcedir->cd();
         TObject *obj = key->ReadObj();

         if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
            // descendant of TH1 -> merge it

            TH1 *h1 = (TH1*)obj;

            // loop over all source files and add the content of the
            // correspondant histogram to the one pointed to by "h1"
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               // make sure we are at the correct directory level by cd'ing to path
               TDirectory *ndir = nextsource->GetDirectory(path);
               if (ndir) {
                  ndir->cd();
                  TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
                  if (key2) {
                     TObject *hobj = key2->ReadObj();
                     hobj->ResetBit(kMustCleanup);
                     listH.Add(hobj);
                     h1->Merge(&listH);
                     listH.Delete();
                  }
               }
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         } else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

            // loop over all source files create a chain of Trees "globChain"
            if (!noTrees) {
               TString obj_name;
               if (path.Length()) {
                  obj_name = path + "/" + obj->GetName();
               } else {
                  obj_name = obj->GetName();
               }
               globChain = new TChain(obj_name);
               globChain->Add(first_source->GetName());
               TFile *nextsource = (TFile*)sourcelist->After( first_source );
               while ( nextsource ) {
                  //do not add to the list a file that does not contain this Tree
                  TFile *curf = TFile::Open(nextsource->GetName());
                  if (curf) {
                     Bool_t mustAdd = kFALSE;
                     if (curf->FindKey(obj_name)) {
                        mustAdd = kTRUE;
                     } else {
                        //we could be more clever here. No need to import the object
                        //we are missing a function in TDirectory
                        TObject *aobj = curf->Get(obj_name);
                        if (aobj) { mustAdd = kTRUE; delete aobj;}
                     }
                     if (mustAdd) {
                        globChain->Add(nextsource->GetName());
                     }
                  }
                  delete curf;
                  nextsource = (TFile*)sourcelist->After( nextsource );
               }
            }
         } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
            // it's a subdirectory

            cout << "Found subdirectory " << obj->GetName() << endl;
            // create a new subdir of same name and title in the target file
            target->cd();
            TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

            // newdir is now the starting point of another round of merging
            // newdir still knows its depth within the target file via
            // GetPath(), so we can still figure out where we are in the recursion
            MergeRootfile( newdir, sourcelist,1);

         } else {
            // object is of no type that we know or can handle
            cout << "Unknown object type, name: "
                 << obj->GetName() << " title: " << obj->GetTitle() << endl;
         }

         // now write the merged histogram (which is "in" obj) to the target file
         // note that this will just store obj in the current directory level,
         // which is not persistent until the complete directory itself is stored
         // by "target->Write()" below
         if ( obj ) {
            target->cd();

            //!!if the object is a tree, it is stored in globChain...
            if(obj->IsA()->InheritsFrom( "TDirectory" )) {
               //printf("cas d'une directory\n");
            } else if(obj->IsA()->InheritsFrom( "TTree" )) {
               if (!noTrees) {
                  globChain->ls();
                  if (fastMethod) globChain->Merge(target->GetFile(),0,"keep fast");
                  else            globChain->Merge(target->GetFile(),0,"keep");
                  delete globChain;
               }
            } else {
               obj->Write( key->GetName() );
            }
         }
         oldkey = key;
      } // while ( ( TKey *key = (TKey*)nextkey() ) )
      first_source = (TDirectory*)sourcelist->After(first_source);
   }
   // save modifications to target file
   target->SaveSelf(kTRUE);
   if (!isdir) sourcelist->Remove(sourcelist->First());
}
<commit_msg>When encountering objects that hadd does not know how to merge, it writes them directly to the output file with the option kSingleKey. Objects having the same name will be written with a new cycle for each instance if the list of input files. This implements the suggestion at: http://root.cern.ch/phpBB2/viewtopic.php?p=25141<commit_after>/*

  This program will add histograms (see note) and Trees from a list of root files and write them
  to a target root file. The target file is newly created and must not be
  identical to one of the source files.

  Syntax:

       hadd targetfile source1 source2 ...
    or
       hadd -f targetfile source1 source2 ...
         (targetfile is overwritten if it exists)

  When -the -f option is specified, one can also specify the compression
  level of the target file. By default the compression level is 1, but
  if "-f0" is specified, the target file will not be compressed.
  if "-f6" is specified, the compression level 6 will be used.

  For example assume 3 files f1, f2, f3 containing histograms hn and Trees Tn
    f1 with h1 h2 h3 T1
    f2 with h1 h4 T1 T2
    f3 with h5
   the result of
     hadd -f x.root f1.root f2.root f3.root
   will be a file x.root with h1 h2 h3 h4 h5 T1 T2
   where h1 will be the sum of the 2 histograms in f1 and f2
         T1 will be the merge of the Trees in f1 and f2

   The files may contain sub-directories.

  if the source files contains histograms and Trees, one can skip
  the Trees with
       hadd -T targetfile source1 source2 ...

  Wildcarding and indirect files are also supported
    hadd result.root  myfil*.root
   will merge all files in myfil*.root
    hadd result.root file1.root @list.txt file2. root myfil*.root
    will merge file1. root, file2. root, all files in myfil*.root
    and all files in the indirect text file list.txt ("@" as the first
    character of the file indicates an indirect file. An indirect file
    is a text file containing a list of other files, including other
    indirect files, one line per file).

  If the sources and and target compression levels are identical (default),
  the program uses the TChain::Merge function with option "fast", ie
  the merge will be done without  unzipping or unstreaming the baskets
  (i.e. direct copy of the raw byte on disk). The "fast" mode is typically
  5 times faster than the mode unzipping and unstreaming the baskets.

  NOTE: By default histograms are added. However if histograms have their bit kIsAverage
        set, the contents are averaged instead of being summed. See TH1::Add.

  Authors: Rene Brun, Dirk Geppert, Sven A. Schmidt, sven.schmidt@cern.ch
         : rewritten from scratch by Rene Brun (30 November 2005)
            to support files with nested directories.
           Toby Burnett implemented the possibility to use indirect files.
 */

#include "RConfig.h"
#include <string>
#include "TChain.h"
#include "TFile.h"
#include "THashList.h"
#include "TH1.h"
#include "TKey.h"
#include "TObjString.h"
#include "Riostream.h"
#include "TClass.h"
#include "TSystem.h"

TList *FileList;
TFile *Target, *Source;
Bool_t noTrees;
Bool_t fastMethod;

int AddFile(TList* sourcelist, std::string entry, int newcomp) ;
void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir );

//___________________________________________________________________________
int main( int argc, char **argv )
{

   if ( argc < 3 || "-h" == string(argv[1]) || "--help" == string(argv[1]) ) {
      cout << "Usage: " << argv[0] << " [-f] [-T] targetfile source1 [source2 source3 ...]" << endl;
      cout << "This program will add histograms from a list of root files and write them" << endl;
      cout << "to a target root file. The target file is newly created and must not " << endl;
      cout << "exist, or if -f (\"force\") is given, must not be one of the source files." << endl;
      cout << "Supply at least two source files for this to make sense... ;-)" << endl;
      cout << "If the first argument is -T, Trees are not merged" <<endl;
      cout << "When -the -f option is specified, one can also specify the compression" <<endl;
      cout << "level of the target file. By default the compression level is 1, but" <<endl;
      cout << "if \"-f0\" is specified, the target file will not be compressed." <<endl;
      cout << "if \"-f6\" is specified, the compression level 6 will be used." <<endl;
      cout << "if Target and source files have different compression levels"<<endl;
      cout << " a slower method is used"<<endl;
      return 1;
   }
   FileList = new TList();

   Bool_t force = (!strcmp(argv[1],"-f") || !strcmp(argv[2],"-f"));
   noTrees = (!strcmp(argv[1],"-T") || !strcmp(argv[2],"-T"));
   Int_t newcomp = 1;
   char ft[4];
   for (int j=0;j<=9;j++) {
      sprintf(ft,"-f%d",j);
      if (!strcmp(argv[1],ft) || !strcmp(argv[2],ft)) {
         force = kTRUE;
         newcomp = j;
         break;
      }
   }

   gSystem->Load("libTreePlayer");

   int ffirst = 2;
   if (force) ffirst++;
   if (noTrees) ffirst++;

   cout << "Target file: " << argv[ffirst-1] << endl;

   Target = TFile::Open( argv[ffirst-1], (force?"RECREATE":"CREATE") );
   if (!Target || Target->IsZombie()) {
      cerr << "Error opening target file (does " << argv[ffirst-1] << " exist?)." << endl;
      cerr << "Pass \"-f\" argument to force re-creation of output file." << endl;
      exit(1);
   }
   Target->SetCompressionLevel(newcomp);

   // by default hadd can merge Trees in a file that can go up to 100 Gbytes
   Long64_t maxsize = 100000000; //100GB
   maxsize *= 100;  //to bypass some compiler limitations with big constants
   TTree::SetMaxTreeSize(maxsize);

   fastMethod = kTRUE;
   for ( int i = ffirst; i < argc; i++ ) {
      if( AddFile(FileList, argv[i], newcomp) !=0 ) return 1;
   }
   if (!fastMethod) {
      cout <<"Sources and Target have different compression levels"<<endl;
      cout <<"Merging will be slower"<<endl;
   }

   MergeRootfile( Target, FileList,0 );

   //must delete Target to avoid a problem with dictionaries in~ TROOT
   delete Target;

   return 0;
}

//___________________________________________________________________________
int AddFile(TList* sourcelist, std::string entry, int newcomp)
{
   // add a new file to the list of files
   static int count(0);
   if( entry.empty() ) return 0;
   size_t j =entry.find_first_not_of(' ');
   if( j==std::string::npos ) return 0;
   entry = entry.substr(j);
   if( entry.substr(0,1)=="@"){
      std::ifstream indirect_file(entry.substr(1).c_str() );
      if( ! indirect_file.is_open() ) {
         std::cerr<< "Could not open indirect file " << entry.substr(1) << std::endl;
         return 1;
      }
      while( indirect_file ){
         std::string line;
         std::getline(indirect_file, line);
         if( AddFile(sourcelist, line, newcomp)!=0 )return 1;;
      }
      return 0;
   }
   cout << "Source file " << (++count) << ": " << entry << endl;

   TFile* source = TFile::Open( entry.c_str());
   if( source==0 ){
      return 1;
   }
   sourcelist->Add(source);
   if (newcomp != source->GetCompressionLevel())  fastMethod = kFALSE;
   return 0;
}

//___________________________________________________________________________
void MergeRootfile( TDirectory *target, TList *sourcelist, Int_t isdir )
{
   // Merge all objects in a directory
   cout << "Target path: " << target->GetPath() << endl;
   TString path( (char*)strstr( target->GetPath(), ":" ) );
   path.Remove( 0, 2 );

   TDirectory *first_source = (TDirectory*)sourcelist->First();
   Int_t nguess = sourcelist->GetSize()+1000;
   THashList allNames(nguess);
   ((THashList*)target->GetList())->Rehash(nguess);
   ((THashList*)target->GetListOfKeys())->Rehash(nguess);
   TList listH;
   while(first_source) {
      TDirectory *current_sourcedir = first_source->GetDirectory(path);
      if (!current_sourcedir) {
         first_source = (TDirectory*)sourcelist->After(first_source);
         continue;
      }

      // loop over all keys in this directory
      TChain *globChain = 0;
      TIter nextkey( current_sourcedir->GetListOfKeys() );
      TKey *key, *oldkey=0;
      //gain time, do not add the objects in the list in memory
      TH1::AddDirectory(kFALSE);

      while ( (key = (TKey*)nextkey())) {
         if (current_sourcedir == target) break;
         //keep only the highest cycle number for each key
         if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;
         if (!strcmp(key->GetClassName(),"TProcessID")) {key->ReadObj(); continue;}
         if (allNames.FindObject(key->GetName())) continue;
         allNames.Add(new TObjString(key->GetName()));
         // read object from first source file
         //current_sourcedir->cd();
         TObject *obj = key->ReadObj();

         if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
            // descendant of TH1 -> merge it

            TH1 *h1 = (TH1*)obj;

            // loop over all source files and add the content of the
            // correspondant histogram to the one pointed to by "h1"
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               // make sure we are at the correct directory level by cd'ing to path
               TDirectory *ndir = nextsource->GetDirectory(path);
               if (ndir) {
                  ndir->cd();
                  TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
                  if (key2) {
                     TObject *hobj = key2->ReadObj();
                     hobj->ResetBit(kMustCleanup);
                     listH.Add(hobj);
                     h1->Merge(&listH);
                     listH.Delete();
                  }
               }
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         } else if ( obj->IsA()->InheritsFrom( "TTree" ) ) {

            // loop over all source files create a chain of Trees "globChain"
            if (!noTrees) {
               TString obj_name;
               if (path.Length()) {
                  obj_name = path + "/" + obj->GetName();
               } else {
                  obj_name = obj->GetName();
               }
               globChain = new TChain(obj_name);
               globChain->Add(first_source->GetName());
               TFile *nextsource = (TFile*)sourcelist->After( first_source );
               while ( nextsource ) {
                  //do not add to the list a file that does not contain this Tree
                  TFile *curf = TFile::Open(nextsource->GetName());
                  if (curf) {
                     Bool_t mustAdd = kFALSE;
                     if (curf->FindKey(obj_name)) {
                        mustAdd = kTRUE;
                     } else {
                        //we could be more clever here. No need to import the object
                        //we are missing a function in TDirectory
                        TObject *aobj = curf->Get(obj_name);
                        if (aobj) { mustAdd = kTRUE; delete aobj;}
                     }
                     if (mustAdd) {
                        globChain->Add(nextsource->GetName());
                     }
                  }
                  delete curf;
                  nextsource = (TFile*)sourcelist->After( nextsource );
               }
            }
         } else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
            // it's a subdirectory

            cout << "Found subdirectory " << obj->GetName() << endl;
            // create a new subdir of same name and title in the target file
            target->cd();
            TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

            // newdir is now the starting point of another round of merging
            // newdir still knows its depth within the target file via
            // GetPath(), so we can still figure out where we are in the recursion
            MergeRootfile( newdir, sourcelist,1);

         } else {
            // object is of no type that we can merge
            cout << "Cannot merge object type, name: "
                 << obj->GetName() << " title: " << obj->GetTitle() << endl;

            // loop over all source files and write similar objects directly to the output file
            TFile *nextsource = (TFile*)sourcelist->After( first_source );
            while ( nextsource ) {
               // make sure we are at the correct directory level by cd'ing to path
               TDirectory *ndir = nextsource->GetDirectory(path);
               if (ndir) {
                  ndir->cd();
                  TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(key->GetName());
                  if (key2) {
                     TObject *nobj = key2->ReadObj();
                     nobj->ResetBit(kMustCleanup);
                     target->WriteTObject(nobj, key2->GetName(), "SingleKey" );
                     delete nobj;
                  }
               }
               nextsource = (TFile*)sourcelist->After( nextsource );
            }
         }

         // now write the merged histogram (which is "in" obj) to the target file
         // note that this will just store obj in the current directory level,
         // which is not persistent until the complete directory itself is stored
         // by "target->Write()" below
         if ( obj ) {
            target->cd();

            //!!if the object is a tree, it is stored in globChain...
            if(obj->IsA()->InheritsFrom( "TDirectory" )) {
               //printf("cas d'une directory\n");
            } else if(obj->IsA()->InheritsFrom( "TTree" )) {
               if (!noTrees) {
                  globChain->ls();
                  if (fastMethod) globChain->Merge(target->GetFile(),0,"keep fast");
                  else            globChain->Merge(target->GetFile(),0,"keep");
                  delete globChain;
               }
            } else {
               obj->Write( key->GetName(), TObject::kSingleKey );
            }
         }
         oldkey = key;
      } // while ( ( TKey *key = (TKey*)nextkey() ) )
      first_source = (TDirectory*)sourcelist->After(first_source);
   }
   // save modifications to target file
   target->SaveSelf(kTRUE);
   if (!isdir) sourcelist->Remove(sourcelist->First());
}
<|endoftext|>


<commit_before>// Copyright (C) 2017, 2018 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#include <iostream>
#include <string>
#include <utility>
#include <functional>

#include "loopp/ble/BLEScanner.hpp"
#include "loopp/core/MainLoop.hpp"
#include "loopp/core/Task.hpp"
#include "loopp/drivers/DriverRegistry.hpp"
#include "loopp/mqtt/MqttClient.hpp"
#include "loopp/net/Wifi.hpp"
#include "loopp/ota/OTA.hpp"
#include "loopp/utils/hexdump.hpp"
#include "loopp/utils/json.hpp"
#include "loopp/utils/memlog.hpp"

#include "string.h"

#include "esp_heap_caps.h"
#include "esp_log.h"
#include "nvs_flash.h"

// TODO: driver should be registered by the driver itself.
// However, the linker will eliminate unreferenced symbols from static libraries.
#include "loopp/drivers/BLEScannerDriver.hpp"
#include "loopp/drivers/GPIODriver.hpp"
LOOPP_REGISTER_DRIVER("ble-scanner", loopp::drivers::BLEScannerDriver);
LOOPP_REGISTER_DRIVER("gpio", loopp::drivers::GPIODriver);

static const char current_version[] = VERSION;

using json = nlohmann::json;

static const char tag[] = "BEACON-SCANNER";

#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
extern const uint8_t ca_start[] asm("_binary_CA_crt_start");
extern const uint8_t ca_end[] asm("_binary_CA_crt_end");
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
extern const uint8_t certificate_start[] asm("_binary_esp32_crt_start");
extern const uint8_t certificate_end[] asm("_binary_esp32_crt_end");
extern const uint8_t private_key_start[] asm("_binary_esp32_key_start");
extern const uint8_t private_key_end[] asm("_binary_esp32_key_end");
#endif
#endif

class Main
{
public:
  Main()
    : ble_scanner(loopp::ble::BLEScanner::instance())
    , wifi(loopp::net::Wifi::instance())
  {

    std::string mac = wifi.get_mac();
    topic_root = std::string(CONFIG_MQTT_TOPIC_PREFIX) + "/" + mac + "/";
    topic_command = topic_root + "command";
    topic_configuration = topic_root + "configuration";

    std::string client_id = std::string(CONFIG_MQTT_CLIENTID_PREFIX) + mac;

    loop = std::make_shared<loopp::core::MainLoop>();
    mqtt = std::make_shared<loopp::mqtt::MqttClient>(loop, client_id, CONFIG_MQTT_HOST, CONFIG_MQTT_PORT);
    task = std::make_shared<loopp::core::Task>("main_task", std::bind(&Main::main_task, this));
  }

  Main(const Main &other) = delete;
  Main(Main &&other) = delete;
  Main &operator=(const Main &other) = delete;
  Main &operator=(Main &&other) = delete;

private:
  void on_wifi_system_event(system_event_t event)
  {
    ESP_LOGI(tag, "-> System event %d", event.event_id);
  }

  void on_wifi_timeout()
  {
    ESP_LOGI(tag, "-> Wifi timer");
    wifi_timeout_timer = 0;
    if (!wifi.connected().get())
      {
        ESP_LOGI(tag, "-> Wifi failed to connect in time. Reset");
        wifi.reconnect();
        wifi_timeout_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
      }
  }

  void on_wifi_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> Wifi connected");
        loop->cancel_timer(wifi_timeout_timer);
        mqtt->set_username(CONFIG_MQTT_USER);
        mqtt->set_password(CONFIG_MQTT_PASSWORD);

#ifdef CONFIG_MQTT_TLS
#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
        mqtt->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
        mqtt->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
#endif
#endif
#endif
        mqtt->set_callback(loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_mqtt_data(topic, payload); }));
        mqtt->connected().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_mqtt_connected, this, std::placeholders::_1)));
        mqtt->connect();
      }
    else
      {
        ESP_LOGI(tag, "-> Wifi disconnected");
      }
  }

  void on_mqtt_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> MQTT connected");
        ESP_LOGI(tag, "-> Subscribing to configuration at %s", topic_configuration.c_str());
        mqtt->subscribe(topic_configuration);
        mqtt->add_filter(topic_configuration,
                         loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_provisioning(payload); }));
        ESP_LOGI(tag, "-> Subscribing to remote commands at %s", topic_command.c_str());
        mqtt->subscribe(topic_command);
        mqtt->add_filter(topic_command,
                         loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_remote_command(payload); }));

#ifdef CONFIG_DEFAULT_BLE_SCANNER
        std::string name = "ble-scanner";
        loopp::drivers::DriverContext context(loop, mqtt, topic_root);
        json config;
        std::shared_ptr<loopp::drivers::IDriver> driver = loopp::drivers::DriverRegistry::instance().create(name, context, config);
        if (driver)
          {
            ESP_LOGI(tag, "Adding default BLE scanner");
            drivers[name] = driver;
            driver->start();
          }
#endif
      }
    else
      {
        ESP_LOGI(tag, "-> MQTT disconnected");
      }
  }

  void on_mqtt_data(std::string topic, std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT %s -> %s (free %d)", topic.c_str(), payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
  }

  void on_firmware_provisioning(json top)
  {
    try
      {
        auto firmware = top.at("firmware");
        auto version = firmware.at("version").get<std::string>();
        auto url = firmware.at("url").get<std::string>();

        int timeout = 0;

        auto it = top.find("timeout");
        if (it != top.end())
          {
            timeout = *it;
          }

        ESP_LOGI(tag, "-> Version: %s (current %s)", version.c_str(), current_version);
        ESP_LOGI(tag, "-> URI    : %s", url.c_str());

        if (version != std::string(current_version))
          {
            firmware_update(url, timeout);
          }
      }
    catch (json::out_of_range &e)
      {
        ESP_LOGI(tag, "-> Invalid firmware specification: %s", e.what());
      }
  }

  void on_provisioning(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT provisioning: %s", payload.c_str());

    // TODO: Allow re-configuration. Not all driver can be properly stopped/restarted.

    auto top = json::parse(payload);

    ESP_LOGI(tag, "-> Name: %s", top["name"].get<std::string>().c_str());

    auto it = top.find("firmware");
    if (it != top.end())
      {
        on_firmware_provisioning(top);
      }

    it = top.find("devices");
    if (it != top.end())
      {
        for (auto driver : drivers)
          {
            ESP_LOGI(tag, "Stopping : %s", driver.first.c_str());
            driver.second->stop();
          }
        drivers.clear();

        for (auto device_config : top.at("devices"))
          {
            std::string name = device_config["name"].get<std::string>();
            std::string driver_name = device_config["driver"].get<std::string>();
            ESP_LOGI(tag, "-> Name  : %s", name.c_str());
            ESP_LOGI(tag, "-> Driver: %s", driver_name.c_str());

            loopp::drivers::DriverContext context(loop, mqtt, topic_root);
            std::shared_ptr<loopp::drivers::IDriver> driver = loopp::drivers::DriverRegistry::instance().create(driver_name, context, device_config);
            if (driver)
              {
                drivers[name] = driver;
                driver->start();
              }
            else
              {
                ESP_LOGE(tag, "No driver for %s", device_config["driver"].get<std::string>().c_str());
              }
          }
      }
  }

  void on_remote_command(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT remote command: %s", payload.c_str());

    auto top = json::parse(payload);

    try
      {
        auto cmd = top.at("cmd");
        ESP_LOGI(tag, "-> Command: %s", cmd.get<std::string>().c_str());

        if (cmd == "reboot")
          {
            ESP_LOGI(tag, "Restarting");
            esp_restart();
          }
        else if (cmd == "firmware-upgrade")
          {
            auto url = top.at("url").get<std::string>();
            int timeout = 0;

            auto it = top.find("timeout");
            if (it != top.end())
              {
                timeout = *it;
              }

            firmware_update(url, timeout);
          }
      }
    catch (json::out_of_range &e)
      {
        ESP_LOGI(tag, "-> Invalid command: %s", e.what());
      }
  }

  void firmware_update(std::string url, int timeout)
  {
    // 520K is insufficient to run two TLS connections, so close MQTT before retrieving new firmware.
    mqtt->disconnect();

    // Memory may be freed asynchronously, so delay firmware update until mainloop had a change to terminate the MQTT connection...
    loop->add_timer(std::chrono::milliseconds(1000), [this, url]() {
      std::shared_ptr<loopp::ota::OTA> ota = std::make_shared<loopp::ota::OTA>(loop);

#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
      ota->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
      ota->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
#endif
#endif
      ota->upgrade_async(url, std::chrono::seconds(60), loopp::core::bind_loop(loop, [this, ota](std::error_code ec) {
                           ESP_LOGI(tag, "-> OTA ready");
                           if (!ec)
                             {
                               ESP_LOGI(tag, "-> OTA commit");
                               ota->commit();
                             }
                           else
                             {
                               esp_restart();
                             }
                         }));
    });
  }

  void main_task()
  {
    loopp::utils::memlog("main_task");
    wifi.set_ssid(CONFIG_WIFI_SSID);
    wifi.set_passphase(CONFIG_WIFI_PASSWORD);
    wifi.set_host_name("scan");
    wifi.set_auto_connect(true);
    wifi.system_event_signal().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_wifi_system_event, this, std::placeholders::_1)));
    wifi.connected().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_wifi_connected, this, std::placeholders::_1)));
    wifi_timeout_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
    wifi.connect();

    ESP_LOGI(tag, "Main::main_task memory free %d", heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
    heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

    loopp::utils::memlog("running loop");
    loop->run();
  }

  loopp::ble::BLEScanner &ble_scanner;
  loopp::net::Wifi &wifi;
  std::shared_ptr<loopp::core::MainLoop> loop;
  std::shared_ptr<loopp::mqtt::MqttClient> mqtt;
  std::shared_ptr<loopp::core::Task> task;
  std::map<std::string, std::shared_ptr<loopp::drivers::IDriver>> drivers;
  loopp::core::MainLoop::timer_id wifi_timeout_timer = 0;
  std::string topic_root;
  std::string topic_command;
  std::string topic_configuration;
};

extern "C" void
app_main()
{
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
  ESP_ERROR_CHECK(ret);

  ESP_LOGI(tag, "Version: %s", current_version);
  ESP_LOGI(tag, "HEAP: startup");
  heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

  loopp::utils::memlog("app_main");
  new Main();

  while (1)
    {
      vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
<commit_msg>Reboot if WiFi fails to connect after 2 restart attempts<commit_after>// Copyright (C) 2017, 2018 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#include <iostream>
#include <string>
#include <utility>
#include <functional>

#include "loopp/ble/BLEScanner.hpp"
#include "loopp/core/MainLoop.hpp"
#include "loopp/core/Task.hpp"
#include "loopp/drivers/DriverRegistry.hpp"
#include "loopp/mqtt/MqttClient.hpp"
#include "loopp/net/Wifi.hpp"
#include "loopp/ota/OTA.hpp"
#include "loopp/utils/hexdump.hpp"
#include "loopp/utils/json.hpp"
#include "loopp/utils/memlog.hpp"

#include "string.h"

#include "esp_heap_caps.h"
#include "esp_log.h"
#include "nvs_flash.h"

// TODO: driver should be registered by the driver itself.
// However, the linker will eliminate unreferenced symbols from static libraries.
#include "loopp/drivers/BLEScannerDriver.hpp"
#include "loopp/drivers/GPIODriver.hpp"
LOOPP_REGISTER_DRIVER("ble-scanner", loopp::drivers::BLEScannerDriver);
LOOPP_REGISTER_DRIVER("gpio", loopp::drivers::GPIODriver);

static const char current_version[] = VERSION;

using json = nlohmann::json;

static const char tag[] = "BEACON-SCANNER";

#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
extern const uint8_t ca_start[] asm("_binary_CA_crt_start");
extern const uint8_t ca_end[] asm("_binary_CA_crt_end");
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
extern const uint8_t certificate_start[] asm("_binary_esp32_crt_start");
extern const uint8_t certificate_end[] asm("_binary_esp32_crt_end");
extern const uint8_t private_key_start[] asm("_binary_esp32_key_start");
extern const uint8_t private_key_end[] asm("_binary_esp32_key_end");
#endif
#endif

class Main
{
public:
  Main()
    : ble_scanner(loopp::ble::BLEScanner::instance())
    , wifi(loopp::net::Wifi::instance())
  {

    std::string mac = wifi.get_mac();
    topic_root = std::string(CONFIG_MQTT_TOPIC_PREFIX) + "/" + mac + "/";
    topic_command = topic_root + "command";
    topic_configuration = topic_root + "configuration";

    std::string client_id = std::string(CONFIG_MQTT_CLIENTID_PREFIX) + mac;

    loop = std::make_shared<loopp::core::MainLoop>();
    mqtt = std::make_shared<loopp::mqtt::MqttClient>(loop, client_id, CONFIG_MQTT_HOST, CONFIG_MQTT_PORT);
    task = std::make_shared<loopp::core::Task>("main_task", std::bind(&Main::main_task, this));
  }

  Main(const Main &other) = delete;
  Main(Main &&other) = delete;
  Main &operator=(const Main &other) = delete;
  Main &operator=(Main &&other) = delete;

private:
  void on_wifi_system_event(system_event_t event)
  {
    ESP_LOGI(tag, "-> System event %d", event.event_id);
  }

  void on_wifi_timeout()
  {
    ESP_LOGI(tag, "-> Wifi timer");
    wifi_timeout_timer = 0;
    if (!wifi.connected().get())
      {
        wifi_fail_count++;

        if (wifi_fail_count == 3)
          {
            ESP_LOGI(tag, "-> Wifi failed to connect in time. Reset");
            esp_restart();
          }

        ESP_LOGI(tag, "-> Wifi failed to connect in time. Retry");
        wifi.reconnect();
        wifi_timeout_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
      }
  }

  void on_wifi_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> Wifi connected");
        wifi_fail_count = 0;

        loop->cancel_timer(wifi_timeout_timer);
        mqtt->set_username(CONFIG_MQTT_USER);
        mqtt->set_password(CONFIG_MQTT_PASSWORD);

#ifdef CONFIG_MQTT_TLS
#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
        mqtt->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
        mqtt->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
#endif
#endif
#endif
        mqtt->set_callback(loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_mqtt_data(topic, payload); }));
        mqtt->connected().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_mqtt_connected, this, std::placeholders::_1)));
        mqtt->connect();
      }
    else
      {
        ESP_LOGI(tag, "-> Wifi disconnected");
      }
  }

  void on_mqtt_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> MQTT connected");
        ESP_LOGI(tag, "-> Subscribing to configuration at %s", topic_configuration.c_str());
        mqtt->subscribe(topic_configuration);
        mqtt->add_filter(topic_configuration,
                         loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_provisioning(payload); }));
        ESP_LOGI(tag, "-> Subscribing to remote commands at %s", topic_command.c_str());
        mqtt->subscribe(topic_command);
        mqtt->add_filter(topic_command,
                         loopp::core::bind_loop(loop, [this](std::string topic, std::string payload) { on_remote_command(payload); }));

#ifdef CONFIG_DEFAULT_BLE_SCANNER
        std::string name = "ble-scanner";
        loopp::drivers::DriverContext context(loop, mqtt, topic_root);
        json config;
        std::shared_ptr<loopp::drivers::IDriver> driver = loopp::drivers::DriverRegistry::instance().create(name, context, config);
        if (driver)
          {
            ESP_LOGI(tag, "Adding default BLE scanner");
            drivers[name] = driver;
            driver->start();
          }
#endif
      }
    else
      {
        ESP_LOGI(tag, "-> MQTT disconnected");
      }
  }

  void on_mqtt_data(std::string topic, std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT %s -> %s (free %d)", topic.c_str(), payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
  }

  void on_firmware_provisioning(json top)
  {
    try
      {
        auto firmware = top.at("firmware");
        auto version = firmware.at("version").get<std::string>();
        auto url = firmware.at("url").get<std::string>();

        int timeout = 0;

        auto it = top.find("timeout");
        if (it != top.end())
          {
            timeout = *it;
          }

        ESP_LOGI(tag, "-> Version: %s (current %s)", version.c_str(), current_version);
        ESP_LOGI(tag, "-> URI    : %s", url.c_str());

        if (version != std::string(current_version))
          {
            firmware_update(url, timeout);
          }
      }
    catch (json::out_of_range &e)
      {
        ESP_LOGI(tag, "-> Invalid firmware specification: %s", e.what());
      }
  }

  void on_provisioning(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT provisioning: %s", payload.c_str());

    // TODO: Allow re-configuration. Not all driver can be properly stopped/restarted.

    auto top = json::parse(payload);

    ESP_LOGI(tag, "-> Name: %s", top["name"].get<std::string>().c_str());

    auto it = top.find("firmware");
    if (it != top.end())
      {
        on_firmware_provisioning(top);
      }

    it = top.find("devices");
    if (it != top.end())
      {
        for (auto driver : drivers)
          {
            ESP_LOGI(tag, "Stopping : %s", driver.first.c_str());
            driver.second->stop();
          }
        drivers.clear();

        for (auto device_config : top.at("devices"))
          {
            std::string name = device_config["name"].get<std::string>();
            std::string driver_name = device_config["driver"].get<std::string>();
            ESP_LOGI(tag, "-> Name  : %s", name.c_str());
            ESP_LOGI(tag, "-> Driver: %s", driver_name.c_str());

            loopp::drivers::DriverContext context(loop, mqtt, topic_root);
            std::shared_ptr<loopp::drivers::IDriver> driver = loopp::drivers::DriverRegistry::instance().create(driver_name, context, device_config);
            if (driver)
              {
                drivers[name] = driver;
                driver->start();
              }
            else
              {
                ESP_LOGE(tag, "No driver for %s", device_config["driver"].get<std::string>().c_str());
              }
          }
      }
  }

  void on_remote_command(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT remote command: %s", payload.c_str());

    auto top = json::parse(payload);

    try
      {
        auto cmd = top.at("cmd");
        ESP_LOGI(tag, "-> Command: %s", cmd.get<std::string>().c_str());

        if (cmd == "reboot")
          {
            ESP_LOGI(tag, "Restarting");
            esp_restart();
          }
        else if (cmd == "firmware-upgrade")
          {
            auto url = top.at("url").get<std::string>();
            int timeout = 0;

            auto it = top.find("timeout");
            if (it != top.end())
              {
                timeout = *it;
              }

            firmware_update(url, timeout);
          }
      }
    catch (json::out_of_range &e)
      {
        ESP_LOGI(tag, "-> Invalid command: %s", e.what());
      }
  }

  void firmware_update(std::string url, int timeout)
  {
    // 520K is insufficient to run two TLS connections, so close MQTT before retrieving new firmware.
    mqtt->disconnect();

    // Memory may be freed asynchronously, so delay firmware update until mainloop had a change to terminate the MQTT connection...
    loop->add_timer(std::chrono::milliseconds(1000), [this, url]() {
      std::shared_ptr<loopp::ota::OTA> ota = std::make_shared<loopp::ota::OTA>(loop);

#ifdef CONFIG_EMBEDDED_CERTIFICATES
#ifdef CONFIG_CA_CERTIFICATE
      ota->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
#ifdef CONFIG_CLIENT_CERTIFICATES
      ota->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
#endif
#endif
      ota->upgrade_async(url, std::chrono::seconds(60), loopp::core::bind_loop(loop, [this, ota](std::error_code ec) {
                           ESP_LOGI(tag, "-> OTA ready");
                           if (!ec)
                             {
                               ESP_LOGI(tag, "-> OTA commit");
                               ota->commit();
                             }
                           else
                             {
                               esp_restart();
                             }
                         }));
    });
  }

  void main_task()
  {
    loopp::utils::memlog("main_task");
    wifi.set_ssid(CONFIG_WIFI_SSID);
    wifi.set_passphase(CONFIG_WIFI_PASSWORD);
    wifi.set_host_name("scan");
    wifi.set_auto_connect(true);
    wifi.system_event_signal().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_wifi_system_event, this, std::placeholders::_1)));
    wifi.connected().connect(loopp::core::bind_loop(loop, std::bind(&Main::on_wifi_connected, this, std::placeholders::_1)));
    wifi_timeout_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
    wifi.connect();

    ESP_LOGI(tag, "Main::main_task memory free %d", heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
    heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

    loopp::utils::memlog("running loop");
    loop->run();
  }

  loopp::ble::BLEScanner &ble_scanner;
  loopp::net::Wifi &wifi;
  std::shared_ptr<loopp::core::MainLoop> loop;
  std::shared_ptr<loopp::mqtt::MqttClient> mqtt;
  std::shared_ptr<loopp::core::Task> task;
  std::map<std::string, std::shared_ptr<loopp::drivers::IDriver>> drivers;
  loopp::core::MainLoop::timer_id wifi_timeout_timer = 0;
  int wifi_fail_count = 0;
  std::string topic_root;
  std::string topic_command;
  std::string topic_configuration;
};

extern "C" void
app_main()
{
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
  ESP_ERROR_CHECK(ret);

  ESP_LOGI(tag, "Version: %s", current_version);
  ESP_LOGI(tag, "HEAP: startup");
  heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

  loopp::utils::memlog("app_main");
  new Main();

  while (1)
    {
      vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: services.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-10 16:38:14 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _DBA_REGHELPER_HXX_
#include "dba_reghelper.hxx"
#endif

/********************************************************************************************/

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::registry;

//***************************************************************************************
//
// registry functions
extern "C" void SAL_CALL createRegistryInfo_ODatabaseContext();
//  extern "C" void SAL_CALL createRegistryInfo_ODocumentDefinition();
extern "C" void SAL_CALL createRegistryInfo_OCommandDefinition();
extern "C" void SAL_CALL createRegistryInfo_OComponentDefinition();
extern "C" void SAL_CALL createRegistryInfo_ORowSet();
extern "C" void SAL_CALL createRegistryInfo_ODatabaseDocument();
extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource();

//***************************************************************************************
//
// Die vorgeschriebene C-Api muss erfuellt werden!
// Sie besteht aus drei Funktionen, die von dem Modul exportiert werden muessen.
//
extern "C" void SAL_CALL createRegistryInfo_DBA()
{
    static sal_Bool bInit = sal_False;
    if (!bInit)
    {
        createRegistryInfo_ODatabaseContext();
        //  createRegistryInfo_ODocumentDefinition();
        createRegistryInfo_OCommandDefinition();
        createRegistryInfo_OComponentDefinition();
        createRegistryInfo_ORowSet();
        createRegistryInfo_ODatabaseDocument();
        createRegistryInfo_ODatabaseSource();
        bInit = sal_True;
    }
}

//---------------------------------------------------------------------------------------

extern "C" void SAL_CALL component_getImplementationEnvironment(
                const sal_Char  **ppEnvTypeName,
                uno_Environment **ppEnv
            )
{
    createRegistryInfo_DBA();
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//---------------------------------------------------------------------------------------
extern "C" sal_Bool SAL_CALL component_writeInfo(
                void* pServiceManager,
                void* pRegistryKey
            )
{
    if (pRegistryKey)
    try
    {
        return ::dbaccess::OModuleRegistration::writeComponentInfos(
            static_cast<XMultiServiceFactory*>(pServiceManager),
            static_cast<XRegistryKey*>(pRegistryKey));
    }
    catch (InvalidRegistryException& )
    {
        OSL_ENSURE(sal_False, "DBA::component_writeInfo : could not create a registry key ! ## InvalidRegistryException !");
    }

    return sal_False;
}

//---------------------------------------------------------------------------------------
extern "C" void* SAL_CALL component_getFactory(
                    const sal_Char* pImplementationName,
                    void* pServiceManager,
                    void* pRegistryKey)
{
    Reference< XInterface > xRet;
    if (pServiceManager && pImplementationName)
    {
        xRet = ::dbaccess::OModuleRegistration::getComponentFactory(
            ::rtl::OUString::createFromAscii(pImplementationName),
            static_cast< XMultiServiceFactory* >(pServiceManager));
    }

    if (xRet.is())
        xRet->acquire();
    return xRet.get();
};
<commit_msg>INTEGRATION: CWS ooo19126 (1.8.104); FILE MERGED 2005/09/05 17:32:37 rt 1.8.104.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: services.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 13:57:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _DBA_REGHELPER_HXX_
#include "dba_reghelper.hxx"
#endif

/********************************************************************************************/

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::registry;

//***************************************************************************************
//
// registry functions
extern "C" void SAL_CALL createRegistryInfo_ODatabaseContext();
//  extern "C" void SAL_CALL createRegistryInfo_ODocumentDefinition();
extern "C" void SAL_CALL createRegistryInfo_OCommandDefinition();
extern "C" void SAL_CALL createRegistryInfo_OComponentDefinition();
extern "C" void SAL_CALL createRegistryInfo_ORowSet();
extern "C" void SAL_CALL createRegistryInfo_ODatabaseDocument();
extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource();

//***************************************************************************************
//
// Die vorgeschriebene C-Api muss erfuellt werden!
// Sie besteht aus drei Funktionen, die von dem Modul exportiert werden muessen.
//
extern "C" void SAL_CALL createRegistryInfo_DBA()
{
    static sal_Bool bInit = sal_False;
    if (!bInit)
    {
        createRegistryInfo_ODatabaseContext();
        //  createRegistryInfo_ODocumentDefinition();
        createRegistryInfo_OCommandDefinition();
        createRegistryInfo_OComponentDefinition();
        createRegistryInfo_ORowSet();
        createRegistryInfo_ODatabaseDocument();
        createRegistryInfo_ODatabaseSource();
        bInit = sal_True;
    }
}

//---------------------------------------------------------------------------------------

extern "C" void SAL_CALL component_getImplementationEnvironment(
                const sal_Char  **ppEnvTypeName,
                uno_Environment **ppEnv
            )
{
    createRegistryInfo_DBA();
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//---------------------------------------------------------------------------------------
extern "C" sal_Bool SAL_CALL component_writeInfo(
                void* pServiceManager,
                void* pRegistryKey
            )
{
    if (pRegistryKey)
    try
    {
        return ::dbaccess::OModuleRegistration::writeComponentInfos(
            static_cast<XMultiServiceFactory*>(pServiceManager),
            static_cast<XRegistryKey*>(pRegistryKey));
    }
    catch (InvalidRegistryException& )
    {
        OSL_ENSURE(sal_False, "DBA::component_writeInfo : could not create a registry key ! ## InvalidRegistryException !");
    }

    return sal_False;
}

//---------------------------------------------------------------------------------------
extern "C" void* SAL_CALL component_getFactory(
                    const sal_Char* pImplementationName,
                    void* pServiceManager,
                    void* pRegistryKey)
{
    Reference< XInterface > xRet;
    if (pServiceManager && pImplementationName)
    {
        xRet = ::dbaccess::OModuleRegistration::getComponentFactory(
            ::rtl::OUString::createFromAscii(pImplementationName),
            static_cast< XMultiServiceFactory* >(pServiceManager));
    }

    if (xRet.is())
        xRet->acquire();
    return xRet.get();
};
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: WTypeSelect.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:43:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef DBAUI_WIZ_TYPESELECT_HXX
#define DBAUI_WIZ_TYPESELECT_HXX

#ifndef DBAUI_WIZ_TABBPAGE_HXX
#include "WTabPage.hxx"
#endif
#ifndef _SV_LSTBOX_HXX
#include <vcl/lstbox.hxx>
#endif
#ifndef _SV_FIELD_HXX
#include <vcl/field.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef DBAUI_FIELDDESCRIPTIONCONTROL_HXX
#include "FieldDescControl.hxx"
#endif
#ifndef DBAUI_TYPEINFO_HXX
#include "TypeInfo.hxx"
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif

class SvStream;
class SvParser;
namespace dbaui
{
    class OTableDesignHelpBar;
    // =============================================================================================
    // OWizTypeSelectControl
    // =============================================================================================
    class OWizTypeSelectControl : public OFieldDescControl
    {
    protected:
        virtual void        ActivateAggregate( EControlType eType );
        virtual void        DeactivateAggregate( EControlType eType );

        virtual void        CellModified(long nRow, sal_uInt16 nColId );
        virtual void        SetModified(sal_Bool bModified);

        virtual ::com::sun::star::lang::Locale  GetLocale() const;
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > GetFormatter() const;
        virtual TOTypeInfoSP        getTypeInfo(sal_Int32 _nPos);
        virtual const OTypeInfoMap* getTypeInfo() const;
        virtual sal_Bool            isAutoIncrementValueEnabled() const;
        virtual ::rtl::OUString     getAutoIncrementValue() const;

    public:
        OWizTypeSelectControl(Window* pParent, OTableDesignHelpBar* pHelpBar=NULL);
        OWizTypeSelectControl(Window* pParent, const ResId& rResId,OTableDesignHelpBar* pHelpBar=NULL);
        virtual ~OWizTypeSelectControl();

        virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData> getMetaData();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection> getConnection();
    };

    // ========================================================
    // Wizard Page: OWizTypeSelectList
    // definiert nur das ::com::sun::star::ucb::Command f"ur das Contextmenu
    // ========================================================
    class OWizTypeSelectList : public MultiListBox
    {
        sal_Bool                m_bPKey;
        sal_Bool                IsPrimaryKeyAllowed() const;
        void                    setPrimaryKey(  OFieldDescription* _pFieldDescr,
                                                sal_uInt16 _nPos,
                                                sal_Bool _bSet=sal_False);
    protected:
        virtual long            PreNotify( NotifyEvent& rNEvt );
    public:
        OWizTypeSelectList( Window* pParent, WinBits nStyle = WB_BORDER ) : MultiListBox(pParent,nStyle) {};
        OWizTypeSelectList( Window* pParent, const ResId& rResId ) : MultiListBox(pParent,rResId) {};
        void                    SetPKey(sal_Bool bPKey) { m_bPKey = bPKey; }
    };
    // ========================================================
    // Wizard Page: OWizTypeSelect
    // Dient als Basis Klasse fuer unterschiedliche Kopiereigenschaften
    // FillColumnList wird aufgerufen, wenn der Button AUTO ausgeloest wird.
    // ========================================================
    class OWizTypeSelect : public OWizardPage
    {
        friend class OWizTypeSelectControl;
        friend class OWizTypeSelectList;

        DECL_LINK( ColumnSelectHdl, MultiListBox* );
        DECL_LINK( ButtonClickHdl, Button * );

    protected:
        OWizTypeSelectList      m_lbColumnNames;
        FixedLine               m_flColumns;
        OWizTypeSelectControl   m_aTypeControl;
        FixedLine               m_flAutoType;
        FixedText               m_ftAuto;
        NumericField            m_etAuto;
        PushButton              m_pbAuto;

        Image                   m_imgPKey;
        SvStream*               m_pParserStream; // stream to read the tokens from or NULL
        ::rtl::OUString         m_sAutoIncrementValue;
        sal_Int32               m_nDisplayRow;
        sal_Bool                m_bAutoIncrementEnabled;
        sal_Bool                m_bDuplicateName;

        void                    fillColumnList(sal_uInt32 nRows);
        virtual SvParser*       createReader(sal_Int32 _nRows) = 0;

        void                    EnableAuto(sal_Bool bEnable);
    public:
        virtual void            Reset ( );
        virtual void            ActivatePage( );
        virtual void            Resize();
        virtual sal_Bool        LeavePage();
        virtual String          GetTitle() const;

        OWizTypeSelect(Window* pParent,SvStream*    _pStream = NULL);
        virtual ~OWizTypeSelect();

        inline void setDisplayRow(sal_Int32 _nRow) { m_nDisplayRow = _nRow - 1; }
        inline void setDuplicateName(sal_Bool _bDuplicateName) { m_bDuplicateName = _bDuplicateName; }
    };
}
#endif // DBAUI_WIZ_TYPESELECT_HXX

<commit_msg>INTEGRATION: CWS warnings01 (1.12.50); FILE MERGED 2006/03/24 15:36:18 fs 1.12.50.1: #i57457# warning-free code (unxlngi6/.pro + unxsoli4.pro)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: WTypeSelect.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 03:15:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef DBAUI_WIZ_TYPESELECT_HXX
#define DBAUI_WIZ_TYPESELECT_HXX

#ifndef DBAUI_WIZ_TABBPAGE_HXX
#include "WTabPage.hxx"
#endif
#ifndef _SV_LSTBOX_HXX
#include <vcl/lstbox.hxx>
#endif
#ifndef _SV_FIELD_HXX
#include <vcl/field.hxx>
#endif
#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef DBAUI_FIELDDESCRIPTIONCONTROL_HXX
#include "FieldDescControl.hxx"
#endif
#ifndef DBAUI_TYPEINFO_HXX
#include "TypeInfo.hxx"
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif

class SvStream;
class SvParser;
namespace dbaui
{
    class OTableDesignHelpBar;
    // =============================================================================================
    // OWizTypeSelectControl
    // =============================================================================================
    class OWizTypeSelectControl : public OFieldDescControl
    {
    protected:
        virtual void        ActivateAggregate( EControlType eType );
        virtual void        DeactivateAggregate( EControlType eType );

        virtual void        CellModified(long nRow, sal_uInt16 nColId );

        virtual ::com::sun::star::lang::Locale  GetLocale() const;
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > GetFormatter() const;
        virtual TOTypeInfoSP        getTypeInfo(sal_Int32 _nPos);
        virtual const OTypeInfoMap* getTypeInfo() const;
        virtual sal_Bool            isAutoIncrementValueEnabled() const;
        virtual ::rtl::OUString     getAutoIncrementValue() const;

    public:
        OWizTypeSelectControl(Window* pParent, OTableDesignHelpBar* pHelpBar=NULL);
        OWizTypeSelectControl(Window* pParent, const ResId& rResId,OTableDesignHelpBar* pHelpBar=NULL);
        virtual ~OWizTypeSelectControl();

        virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData> getMetaData();
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection> getConnection();
    };

    // ========================================================
    // Wizard Page: OWizTypeSelectList
    // definiert nur das ::com::sun::star::ucb::Command f"ur das Contextmenu
    // ========================================================
    class OWizTypeSelectList : public MultiListBox
    {
        sal_Bool                m_bPKey;
        sal_Bool                IsPrimaryKeyAllowed() const;
        void                    setPrimaryKey(  OFieldDescription* _pFieldDescr,
                                                sal_uInt16 _nPos,
                                                sal_Bool _bSet=sal_False);
    protected:
        virtual long            PreNotify( NotifyEvent& rNEvt );
    public:
        OWizTypeSelectList( Window* pParent, WinBits nStyle = WB_BORDER ) : MultiListBox(pParent,nStyle) {};
        OWizTypeSelectList( Window* pParent, const ResId& rResId ) : MultiListBox(pParent,rResId) {};
        void                    SetPKey(sal_Bool bPKey) { m_bPKey = bPKey; }
    };
    // ========================================================
    // Wizard Page: OWizTypeSelect
    // Dient als Basis Klasse fuer unterschiedliche Kopiereigenschaften
    // FillColumnList wird aufgerufen, wenn der Button AUTO ausgeloest wird.
    // ========================================================
    class OWizTypeSelect : public OWizardPage
    {
        friend class OWizTypeSelectControl;
        friend class OWizTypeSelectList;

        DECL_LINK( ColumnSelectHdl, MultiListBox* );
        DECL_LINK( ButtonClickHdl, Button * );

    protected:
        OWizTypeSelectList      m_lbColumnNames;
        FixedLine               m_flColumns;
        OWizTypeSelectControl   m_aTypeControl;
        FixedLine               m_flAutoType;
        FixedText               m_ftAuto;
        NumericField            m_etAuto;
        PushButton              m_pbAuto;

        Image                   m_imgPKey;
        SvStream*               m_pParserStream; // stream to read the tokens from or NULL
        ::rtl::OUString         m_sAutoIncrementValue;
        sal_Int32               m_nDisplayRow;
        sal_Bool                m_bAutoIncrementEnabled;
        sal_Bool                m_bDuplicateName;

        void                    fillColumnList(sal_uInt32 nRows);
        virtual SvParser*       createReader(sal_Int32 _nRows) = 0;

        void                    EnableAuto(sal_Bool bEnable);
    public:
        virtual void            Reset ( );
        virtual void            ActivatePage( );
        virtual void            Resize();
        virtual sal_Bool        LeavePage();
        virtual String          GetTitle() const;

        OWizTypeSelect(Window* pParent,SvStream*    _pStream = NULL);
        virtual ~OWizTypeSelect();

        inline void setDisplayRow(sal_Int32 _nRow) { m_nDisplayRow = _nRow - 1; }
        inline void setDuplicateName(sal_Bool _bDuplicateName) { m_bDuplicateName = _bDuplicateName; }
    };
}
#endif // DBAUI_WIZ_TYPESELECT_HXX

<|endoftext|>


<commit_before>#ifndef SLICE_HPP
#define SLICE_HPP

#include "iterator_range.hpp"
#include "wrap_iter.hpp"

#include <iterator>
#include <assert.h>

namespace iter {
    template <typename Container>
        auto slice(
                Container && container,
                typename std::iterator_traits<decltype(container.begin())>::difference_type begin,
                typename std::iterator_traits<decltype(container.begin())>::difference_type end,
                typename std::iterator_traits<decltype(container.begin())>::difference_type step = 1
                ) -> iterator_range<wrap_iter<decltype(container.begin())>>
        {
            //it seems like you can handle negative and positive ranges the same
            if (begin > end && step < 0) {
                typename std::iterator_traits<decltype(container.begin())>::difference_type new_end = end - ((end - begin) % step);
                return iterator_range<wrap_iter<decltype(container.begin())>>(
                        make_wrap_iter(container.begin()+begin,step),
                        make_wrap_iter(container.begin()+new_end,step));
            }
            else if (begin <= end && step > 0) {
                typename std::iterator_traits<decltype(container.begin())>::difference_type new_end = end - ((end - begin) % step);
                return iterator_range<wrap_iter<decltype(container.begin())>>(
                        make_wrap_iter(container.begin()+begin,step),
                        make_wrap_iter(container.begin()+new_end,step));
            }
            else {//return an empty range for invalid slice
                return iterator_range<wrap_iter<decltype(container.begin())>>(
                        make_wrap_iter(container.begin()+begin,step),
                        make_wrap_iter(container.begin()+begin,step));
            }

        }
    //only give the end as an arg and assume step  is 1 and begin is 0
    template <typename Container>
        auto slice(
                Container && container,
                typename std::iterator_traits<decltype(container.begin())>::difference_type end
                ) -> iterator_range<wrap_iter<decltype(container.begin())>>
        {
            return slice(std::forward<Container>(container),0,end);
        }

}

#endif //SLICE_HPP
<commit_msg>big fix on slice, uses std::begin and uses std::advance<commit_after>#ifndef SLICE_HPP
#define SLICE_HPP

#include "iterator_range.hpp"
#include "wrap_iter.hpp"

#include <iterator>
#include <assert.h>

namespace iter {
    template <typename Container>
        auto slice(
                Container && container,
                typename std::iterator_traits<decltype(std::begin(container))>::difference_type begin,
                typename std::iterator_traits<decltype(std::begin(container))>::difference_type end,
                typename std::iterator_traits<decltype(std::begin(container))>::difference_type step = 1
                ) -> iterator_range<wrap_iter<decltype(std::begin(container))>>
        {
            //it seems like you can handle negative and positive ranges the same
            //kept both checks to make checking for invalid slice more readable
            if (begin > end && step < 0) {
                typename std::iterator_traits<decltype(std::begin(container))>::difference_type new_end = end - ((end - begin) % step);
                auto begin_iter = std::begin(container);
                std::advance(begin_iter,begin);
                auto end_iter = std::begin(container);
                std::advance(end_iter,new_end);
                return iterator_range<wrap_iter<decltype(std::begin(container))>>(
                        make_wrap_iter(begin_iter,step),
                        make_wrap_iter(end_iter,step));
            }
            else if (begin <= end && step > 0) {
                typename std::iterator_traits<decltype(container.begin())>::difference_type new_end = end - ((end - begin) % step);
                auto begin_iter = std::begin(container);
                std::advance(begin_iter,begin);
                auto end_iter = std::begin(container);
                std::advance(end_iter,new_end);
                return iterator_range<wrap_iter<decltype(container.begin())>>(
                        make_wrap_iter(begin_iter,step),
                        make_wrap_iter(end_iter,step));
            }
            else {//return an empty range for invalid slice
                auto empty = std::begin(container);
                std::advance(empty,begin);
                return iterator_range<wrap_iter<decltype(container.begin())>>(
                        make_wrap_iter(empty,step),
                        make_wrap_iter(empty,step));
            }

        }
    //only give the end as an arg and assume step  is 1 and begin is 0
    template <typename Container>
        auto slice(
                Container && container,
                typename std::iterator_traits<decltype(std::begin(container))>::difference_type end
                ) -> iterator_range<wrap_iter<decltype(std::begin(container))>>
        {
            return slice(std::forward<Container>(container),0,end);
        }

}

#endif //SLICE_HPP
<|endoftext|>


<commit_before><commit_msg>Fix build failure with GCC on identifier reusing.<commit_after><|endoftext|>


<commit_before>// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The common functionality when building with or without snapshots.

#include "src/v8.h"

#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/full-codegen.h"
#include "src/snapshot/snapshot.h"

namespace v8 {
namespace internal {

#ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
  return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
         !Snapshot::ExtractContextData(snapshot_blob).is_empty();
}
#endif  // DEBUG

bool Snapshot::EmbedsScript(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
}

uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
  DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
  if (!isolate->snapshot_available()) {
    return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
  }
  uint32_t size;
  int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
  memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
  return size;
}

bool Snapshot::Initialize(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> startup_data = ExtractStartupData(blob);
  SnapshotData snapshot_data(startup_data);
  Deserializer deserializer(&snapshot_data);
  bool success = isolate->Init(&deserializer);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = startup_data.length();
    PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return success;
}

MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
    Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
    Handle<FixedArray>* outdated_contexts_out) {
  if (!isolate->snapshot_available()) return Handle<Context>();
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> context_data = ExtractContextData(blob);
  SnapshotData snapshot_data(context_data);
  Deserializer deserializer(&snapshot_data);

  MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
      isolate, global_proxy, outdated_contexts_out);
  Handle<Object> result;
  if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
  CHECK(result->IsContext());
  // If the snapshot does not contain a custom script, we need to update
  // the global object for exactly one context.
  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = context_data.length();
    PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return Handle<Context>::cast(result);
}

void CalculateFirstPageSizes(bool is_default_snapshot,
                             const SnapshotData& startup_snapshot,
                             const SnapshotData& context_snapshot,
                             uint32_t* sizes_out) {
  Vector<const SerializedData::Reservation> startup_reservations =
      startup_snapshot.Reservations();
  Vector<const SerializedData::Reservation> context_reservations =
      context_snapshot.Reservations();
  int startup_index = 0;
  int context_index = 0;

  if (FLAG_profile_deserialization) {
    int startup_total = 0;
    int context_total = 0;
    for (auto& reservation : startup_reservations) {
      startup_total += reservation.chunk_size();
    }
    for (auto& reservation : context_reservations) {
      context_total += reservation.chunk_size();
    }
    PrintF(
        "Deserialization will reserve:\n"
        "%10d bytes for startup\n"
        "%10d bytes per context\n",
        startup_total, context_total);
  }

  for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    bool single_chunk = true;
    while (!startup_reservations[startup_index].is_last()) {
      single_chunk = false;
      startup_index++;
    }
    while (!context_reservations[context_index].is_last()) {
      single_chunk = false;
      context_index++;
    }

    uint32_t required = kMaxUInt32;
    if (single_chunk) {
      // If both the startup snapshot data and the context snapshot data on
      // this space fit in a single page, then we consider limiting the size
      // of the first page. For this, we add the chunk sizes and some extra
      // allowance. This way we achieve a smaller startup memory footprint.
      required = (startup_reservations[startup_index].chunk_size() +
                  2 * context_reservations[context_index].chunk_size()) +
                 Page::kObjectStartOffset;
      // Add a small allowance to the code space for small scripts.
      if (space == CODE_SPACE) required += 32 * KB;
    } else {
      // We expect the vanilla snapshot to only require on page per space.
      DCHECK(!is_default_snapshot);
    }

    if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
      uint32_t max_size =
          MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
      sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size);
    } else {
      DCHECK(single_chunk);
    }
    startup_index++;
    context_index++;
  }

  DCHECK_EQ(startup_reservations.length(), startup_index);
  DCHECK_EQ(context_reservations.length(), context_index);
}

v8::StartupData Snapshot::CreateSnapshotBlob(
    const i::StartupSerializer& startup_ser,
    const i::PartialSerializer& context_ser, Snapshot::Metadata metadata) {
  SnapshotData startup_snapshot(startup_ser);
  SnapshotData context_snapshot(context_ser);
  Vector<const byte> startup_data = startup_snapshot.RawData();
  Vector<const byte> context_data = context_snapshot.RawData();

  uint32_t first_page_sizes[kNumPagedSpaces];

  CalculateFirstPageSizes(!metadata.embeds_script(), startup_snapshot,
                          context_snapshot, first_page_sizes);

  int startup_length = startup_data.length();
  int context_length = context_data.length();
  int context_offset = ContextOffset(startup_length);

  int length = context_offset + context_length;
  char* data = new char[length];

  memcpy(data + kMetadataOffset, &metadata.RawValue(), kInt32Size);
  memcpy(data + kFirstPageSizesOffset, first_page_sizes,
         kNumPagedSpaces * kInt32Size);
  memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size);
  memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
  memcpy(data + context_offset, context_data.begin(), context_length);
  v8::StartupData result = {data, length};

  if (FLAG_profile_deserialization) {
    PrintF(
        "Snapshot blob consists of:\n"
        "%10d bytes for startup\n"
        "%10d bytes for context\n",
        startup_length, context_length);
  }
  return result;
}

Snapshot::Metadata Snapshot::ExtractMetadata(const v8::StartupData* data) {
  uint32_t raw;
  memcpy(&raw, data->data + kMetadataOffset, kInt32Size);
  return Metadata(raw);
}

Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size);
  DCHECK_LT(startup_length, data->raw_size);
  const byte* startup_data =
      reinterpret_cast<const byte*>(data->data + kStartupDataOffset);
  return Vector<const byte>(startup_data, startup_length);
}

Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize);
  int context_offset = ContextOffset(startup_length);
  const byte* context_data =
      reinterpret_cast<const byte*>(data->data + context_offset);
  DCHECK_LT(context_offset, data->raw_size);
  int context_length = data->raw_size - context_offset;
  return Vector<const byte>(context_data, context_length);
}
} }  // namespace v8::internal
<commit_msg>Make mksnapshot stats unambiguous for easier parsing.<commit_after>// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The common functionality when building with or without snapshots.

#include "src/v8.h"

#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/full-codegen.h"
#include "src/snapshot/snapshot.h"

namespace v8 {
namespace internal {

#ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
  return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
         !Snapshot::ExtractContextData(snapshot_blob).is_empty();
}
#endif  // DEBUG

bool Snapshot::EmbedsScript(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
}

uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
  DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
  if (!isolate->snapshot_available()) {
    return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
  }
  uint32_t size;
  int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
  memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
  return size;
}

bool Snapshot::Initialize(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> startup_data = ExtractStartupData(blob);
  SnapshotData snapshot_data(startup_data);
  Deserializer deserializer(&snapshot_data);
  bool success = isolate->Init(&deserializer);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = startup_data.length();
    PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return success;
}

MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
    Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
    Handle<FixedArray>* outdated_contexts_out) {
  if (!isolate->snapshot_available()) return Handle<Context>();
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> context_data = ExtractContextData(blob);
  SnapshotData snapshot_data(context_data);
  Deserializer deserializer(&snapshot_data);

  MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
      isolate, global_proxy, outdated_contexts_out);
  Handle<Object> result;
  if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
  CHECK(result->IsContext());
  // If the snapshot does not contain a custom script, we need to update
  // the global object for exactly one context.
  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = context_data.length();
    PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return Handle<Context>::cast(result);
}

void CalculateFirstPageSizes(bool is_default_snapshot,
                             const SnapshotData& startup_snapshot,
                             const SnapshotData& context_snapshot,
                             uint32_t* sizes_out) {
  Vector<const SerializedData::Reservation> startup_reservations =
      startup_snapshot.Reservations();
  Vector<const SerializedData::Reservation> context_reservations =
      context_snapshot.Reservations();
  int startup_index = 0;
  int context_index = 0;

  if (FLAG_profile_deserialization) {
    int startup_total = 0;
    int context_total = 0;
    for (auto& reservation : startup_reservations) {
      startup_total += reservation.chunk_size();
    }
    for (auto& reservation : context_reservations) {
      context_total += reservation.chunk_size();
    }
    PrintF(
        "Deserialization will reserve:\n"
        "%10d bytes per isolate\n"
        "%10d bytes per context\n",
        startup_total, context_total);
  }

  for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    bool single_chunk = true;
    while (!startup_reservations[startup_index].is_last()) {
      single_chunk = false;
      startup_index++;
    }
    while (!context_reservations[context_index].is_last()) {
      single_chunk = false;
      context_index++;
    }

    uint32_t required = kMaxUInt32;
    if (single_chunk) {
      // If both the startup snapshot data and the context snapshot data on
      // this space fit in a single page, then we consider limiting the size
      // of the first page. For this, we add the chunk sizes and some extra
      // allowance. This way we achieve a smaller startup memory footprint.
      required = (startup_reservations[startup_index].chunk_size() +
                  2 * context_reservations[context_index].chunk_size()) +
                 Page::kObjectStartOffset;
      // Add a small allowance to the code space for small scripts.
      if (space == CODE_SPACE) required += 32 * KB;
    } else {
      // We expect the vanilla snapshot to only require on page per space.
      DCHECK(!is_default_snapshot);
    }

    if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
      uint32_t max_size =
          MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
      sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size);
    } else {
      DCHECK(single_chunk);
    }
    startup_index++;
    context_index++;
  }

  DCHECK_EQ(startup_reservations.length(), startup_index);
  DCHECK_EQ(context_reservations.length(), context_index);
}

v8::StartupData Snapshot::CreateSnapshotBlob(
    const i::StartupSerializer& startup_ser,
    const i::PartialSerializer& context_ser, Snapshot::Metadata metadata) {
  SnapshotData startup_snapshot(startup_ser);
  SnapshotData context_snapshot(context_ser);
  Vector<const byte> startup_data = startup_snapshot.RawData();
  Vector<const byte> context_data = context_snapshot.RawData();

  uint32_t first_page_sizes[kNumPagedSpaces];

  CalculateFirstPageSizes(!metadata.embeds_script(), startup_snapshot,
                          context_snapshot, first_page_sizes);

  int startup_length = startup_data.length();
  int context_length = context_data.length();
  int context_offset = ContextOffset(startup_length);

  int length = context_offset + context_length;
  char* data = new char[length];

  memcpy(data + kMetadataOffset, &metadata.RawValue(), kInt32Size);
  memcpy(data + kFirstPageSizesOffset, first_page_sizes,
         kNumPagedSpaces * kInt32Size);
  memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size);
  memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
  memcpy(data + context_offset, context_data.begin(), context_length);
  v8::StartupData result = {data, length};

  if (FLAG_profile_deserialization) {
    PrintF(
        "Snapshot blob consists of:\n"
        "%10d bytes for startup\n"
        "%10d bytes for context\n",
        startup_length, context_length);
  }
  return result;
}

Snapshot::Metadata Snapshot::ExtractMetadata(const v8::StartupData* data) {
  uint32_t raw;
  memcpy(&raw, data->data + kMetadataOffset, kInt32Size);
  return Metadata(raw);
}

Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size);
  DCHECK_LT(startup_length, data->raw_size);
  const byte* startup_data =
      reinterpret_cast<const byte*>(data->data + kStartupDataOffset);
  return Vector<const byte>(startup_data, startup_length);
}

Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize);
  int context_offset = ContextOffset(startup_length);
  const byte* context_data =
      reinterpret_cast<const byte*>(data->data + context_offset);
  DCHECK_LT(context_offset, data->raw_size);
  int context_length = data->raw_size - context_offset;
  return Vector<const byte>(context_data, context_length);
}
} }  // namespace v8::internal
<|endoftext|>