<commit_before>#include "TMessage.h"
#include "TBenchmark.h"
#include "TSocket.h"
#include "TH2.h"
#include "TTree.h"
#include "TMemFile.h"
#include "TRandom.h"
#include "TError.h"
#include "TFileMerger.h"

#include "TServerSocket.h"
#include "TPad.h"
#include "TCanvas.h"
#include "TMonitor.h"

#include "TFileCacheWrite.h"
#include "TSystem.h"
#include "THashTable.h"

#include "TMath.h"
#include "TTimeStamp.h"

const int kIncremental = 0;
const int kReplaceImmediately = 1;
const int kReplaceWait = 2;

#include "TKey.h"
static Bool_t R__NeedInitialMerge(TDirectory *dir)
{

   if (dir==0) return kFALSE;

   TIter nextkey(dir->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *subdir = (TDirectory *)dir->GetList()->FindObject(key->GetName());
         if (!subdir) {
            subdir = (TDirectory *)key->ReadObj();
         }
         if (R__NeedInitialMerge(subdir)) {
            return kTRUE;
         }
      } else {
         if (0 != cl->GetResetAfterMerge()) {
            return kTRUE;
         }
      }
   }
   return kFALSE;
}

static void R__DeleteObject(TDirectory *dir, Bool_t withReset)
{
   if (dir==0) return;

   TIter nextkey(dir->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *subdir = (TDirectory *)dir->GetList()->FindObject(key->GetName());
         if (!subdir) {
            subdir = (TDirectory *)key->ReadObj();
         }
         R__DeleteObject(subdir,withReset);
      } else {
         Bool_t todelete = kFALSE;
         if (withReset) {
            todelete = (0 != cl->GetResetAfterMerge());
         } else {
            todelete = (0 ==  cl->GetResetAfterMerge());
         }
         if (todelete) {
            key->Delete();
            dir->GetListOfKeys()->Remove(key);
            delete key;
         }
      }
   }
}

static void R__MigrateKey(TDirectory *destination, TDirectory *source)
{
   if (destination==0 || source==0) return;

   TIter nextkey(source->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *source_subdir = (TDirectory *)source->GetList()->FindObject(key->GetName());
         if (!source_subdir) {
            source_subdir = (TDirectory *)key->ReadObj();
         }
         TDirectory *destination_subdir = destination->GetDirectory(key->GetName());
         if (!destination_subdir) {
            destination_subdir = destination->mkdir(key->GetName());
         }
         R__MigrateKey(destination,source);
      } else {
         TKey *oldkey = destination->GetKey(key->GetName());
         if (oldkey) {
            oldkey->Delete();
            delete oldkey;
         }
         TKey *newkey = new TKey(destination,*key,0 /* pidoffset */); // a priori the file are from the same client ..
         destination->GetFile()->SumBuffer(newkey->GetObjlen());
         newkey->WriteFile(0);
         if (destination->GetFile()->TestBit(TFile::kWriteError)) {
            return;
         }
      }
   }
   destination->SaveSelf();
}

struct ClientInfo
{
   TFile      *fFile;      // This object does *not* own the file, it will be own by the owner of the ClientInfo.
   TString    fLocalName;
   UInt_t     fContactsCount;
   TTimeStamp fLastContact;
   Double_t   fTimeSincePrevContact;

   ClientInfo() : fFile(0), fLocalName(), fContactsCount(0), fTimeSincePrevContact(0) {}
   ClientInfo(const char *filename, UInt_t clientId) : fFile(0), fContactsCount(0), fTimeSincePrevContact(0) {
      fLocalName.Form("%s-%d-%d",filename,clientId,gSystem->GetPid());
   }

   void Set(TFile *file)
   {
      // Register the new file as coming from this client.
      if (file != fFile) {
         // We need to keep any of the keys from the previous file that
         // are not in the new file.
         if (fFile) {
            R__MigrateKey(fFile,file);
            // delete the previous memory file (if any)
            delete file;
         } else {
            fFile = file;
         }
      }
      TTimeStamp now;
      fTimeSincePrevContact = now.AsDouble() - fLastContact.AsDouble();
      fLastContact = now;
      ++fContactsCount;
   }
};

struct ParallelFileMerger : public TObject
{
   typedef std::vector<ClientInfo> ClientColl_t;

   TString       fFilename;
   TBits         fClientsContact;       //
   UInt_t        fNClientsContact;      //
   ClientColl_t  fClients;
   TTimeStamp    fLastMerge;
   TFileMerger   fMerger;

   ParallelFileMerger(const char *filename, Bool_t writeCache = kFALSE) : fFilename(filename), fNClientsContact(0), fMerger(kFALSE,kTRUE)
   {
      // Default constructor.

      fMerger.SetPrintLevel(0);
      fMerger.OutputFile(filename,"RECREATE");
      if (writeCache) new TFileCacheWrite(fMerger.GetOutputFile(),32*1024*1024);
   }

   ~ParallelFileMerger()
   {
      // Destructor.

      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         fprintf(stderr,"Client %d reported %u times\n",f,fClients[f].fContactsCount);
      }
      for( ClientColl_t::iterator iter = fClients.begin();
          iter != fClients.end();
          ++iter)
      {
         delete iter->fFile;
      }
   }

   ULong_t  Hash() const
   {
      // Return hash value for this object.
      return fFilename.Hash();
   }

   const char *GetName() const
   {
      // Return the name of the object which is the name of the output file.
      return fFilename;
   }

   Bool_t InitialMerge(TFile *input)
   {
      // Initial merge of the input to copy the resetable object (TTree) into the output
      // and remove them from the input file.

      fMerger.AddFile(input);

      Bool_t result = fMerger.PartialMerge(TFileMerger::kIncremental | TFileMerger::kResetable);

      R__DeleteObject(input,kTRUE);
      return result;
   }

   Bool_t Merge()
   {
      // Merge the current inputs into the output file.

      R__DeleteObject(fMerger.GetOutputFile(),kFALSE); // Remove object that can *not* be incrementally merge and will *not* be reset by the client code.
      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         fMerger.AddFile(fClients[f].fFile);
      }
      Bool_t result = fMerger.PartialMerge(TFileMerger::kAllIncremental);

      // Remove any 'resetable' object (like TTree) from the input file so that they will not
      // be re-merged.  Keep only the object that always need to be re-merged (Histograms).
      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         if (fClients[f].fFile) {
            R__DeleteObject(fClients[f].fFile,kTRUE);
         } else {
            // We back up the file (probably due to memory constraint)
            TFile *file = TFile::Open(fClients[f].fLocalName,"UPDATE");
            R__DeleteObject(file,kTRUE); // Remove object that can be incrementally merge and will be reset by the client code.
            file->Write();
            delete file;
         }
      }
      fLastMerge = TTimeStamp();
      fNClientsContact = 0;
      fClientsContact.Clear();

      return result;
   }

   Bool_t NeedFinalMerge()
   {
      // Return true, if there is any data that has not been merged.

      return fClientsContact.CountBits() > 0;
   }

   Bool_t NeedMerge(Float_t clientThreshold)
   {
      // Return true, if enough client have reported

      if (fClients.size()==0) {
         return kFALSE;
      }

      // Calculate average and rms of the time between the last 2 contacts.
      Double_t sum = 0;
      Double_t sum2 = 0;
      for(unsigned int c = 0 ; c < fClients.size(); ++c) {
         sum += fClients[c].fTimeSincePrevContact;
         sum2 += fClients[c].fTimeSincePrevContact*fClients[c].fTimeSincePrevContact;
      }
      Double_t avg = sum / fClients.size();
      Double_t sigma = sum2 ? TMath::Sqrt( sum2 / fClients.size() - avg*avg) : 0;
      Double_t target = avg + 2*sigma;
      TTimeStamp now;
      if ( (now.AsDouble() - fLastMerge.AsDouble()) > target) {
//         Float_t cut = clientThreshold * fClients.size();
//         if (!(fClientsContact.CountBits() > cut )) {
//            for(unsigned int c = 0 ; c < fClients.size(); ++c) {
//               fprintf(stderr,"%d:%f ",c,fClients[c].fTimeSincePrevContact);
//            }
//            fprintf(stderr,"merge:%f avg:%f target:%f\n",(now.AsDouble() - fLastMerge.AsDouble()),avg,target);
//         }
         return kTRUE;
      }
      Float_t cut = clientThreshold * fClients.size();
      return fClientsContact.CountBits() > cut  || fNClientsContact > 2*cut;
   }

   void RegisterClient(UInt_t clientId, TFile *file)
   {
      // Register that a client has sent a file.

      ++fNClientsContact;
      fClientsContact.SetBitNumber(clientId);
      if (fClients.size() < clientId+1) {
         fClients.push_back( ClientInfo(fFilename,clientId) );
      }
      fClients[clientId].Set(file);
   }

   ClassDef(ParallelFileMerger,0);
};

void parallelMergeServer(bool cache = false) {
   // This script shows how to make a simple iterative server that
   // can accept connections while handling currently open connections.
   // Compare this script to hserv.C that blocks on accept.
   // In this script a server socket is created and added to a monitor.
   // A monitor object is used to monitor connection requests on
   // the server socket. After accepting the connection
   // the new socket is added to the monitor and immediately ready
   // for use. Once two connections are accepted the server socket
   // is removed from the monitor and closed. The monitor continues
   // monitoring the sockets.
   //
   // To run this demo do the following:
   //   - Open three windows
   //   - Start ROOT in all three windows
   //   - Execute in the first window: .x hserv2.C
   //   - Execute in the second and third windows: .x hclient.C
   //Author: Fons Rademakers

   // Open a server socket looking for connections on a named service or
   // on a specified port.
   //TServerSocket *ss = new TServerSocket("rootserv", kTRUE);
   TServerSocket *ss = new TServerSocket(1095, kTRUE);
   if (!ss->IsValid()) {
      return;
   }

   TMonitor *mon = new TMonitor;

   mon->Add(ss);

   UInt_t clientCount = 0;

   THashTable mergers;

   enum StatusKind {
      kStartConnection = 0,
      kProtocol = 1,

      kProtocolVersion = 1
   };

   printf("fastMergeServerHist ready to accept connections\n");
   while (1) {
      TMessage *mess;
      TSocket  *s;

      // NOTE: this needs to be update to handle the case where the client
      // dies.
      s = mon->Select();

      if (s->IsA() == TServerSocket::Class()) {
         if (clientCount > 100) {
            printf("only accept 100 clients connections\n");
            mon->Remove(ss);
            ss->Close();
         } else {
            TSocket *client = ((TServerSocket *)s)->Accept();
            client->Send(clientCount, kStartConnection);
            client->Send(kProtocolVersion, kProtocol);
            ++clientCount;
            mon->Add(client);
            printf("Accept %d connections\n",clientCount);
         }
         continue;
      }

      s->Recv(mess);

      if (mess==0) {
         Error("fastMergeServer","The client did not send a message\n");
      } else if (mess->What() == kMESS_STRING) {
         char str[64];
         mess->ReadString(str, 64);
         printf("Client %d: %s\n", clientCount, str);
         mon->Remove(s);
         printf("Client %d: bytes recv = %d, bytes sent = %d\n", clientCount, s->GetBytesRecv(),
                s->GetBytesSent());
         s->Close();
         --clientCount;
         if (mon->GetActive() == 0 || clientCount == 0) {
            printf("No more active clients... stopping\n");
            break;
         }
      } else if (mess->What() == kMESS_ANY) {

         Long64_t length;
         TString filename;
         Int_t clientId;
         mess->ReadInt(clientId);
         mess->ReadTString(filename);
         mess->ReadLong64(length); // '*mess >> length;' is broken in CINT for Long64_t.

         // Info("fastMergeServerHist","Received input from client %d for %s",clientId,filename.Data());

         TMemFile *transient = new TMemFile(filename,mess->Buffer() + mess->Length(),length,"UPDATE"); // UPDATE because we need to remove the TTree after merging them.
         mess->SetBufferOffset(mess->Length()+length);

         const Float_t clientThreshold = 0.75; // control how often the histogram are merged.  Here as soon as half the clients have reported.

         ParallelFileMerger *info = (ParallelFileMerger*)mergers.FindObject(filename);
         if (!info) {
            info = new ParallelFileMerger(filename,cache);
            mergers.Add(info);
         }

         if (R__NeedInitialMerge(transient)) {
            info->InitialMerge(transient);
         }
         info->RegisterClient(clientId,transient);
         if (info->NeedMerge(clientThreshold)) {
            // Enough clients reported.
            Info("fastMergeServerHist","Merging input from %ld clients (%d)",info->fClients.size(),clientId);
            info->Merge();
         }
         transient = 0;
      } else if (mess->What() == kMESS_OBJECT) {
         printf("got object of class: %s\n", mess->GetClass()->GetName());
      } else {
         printf("*** Unexpected message ***\n");
      }

      delete mess;
   }

   TIter next(&mergers);
   ParallelFileMerger *info;
   while ( (info = (ParallelFileMerger*)next()) ) {
      if (info->NeedFinalMerge())
      {
         info->Merge();
      }
   }

   mergers.Delete();
   delete mon;
   delete ss;
}
<commit_msg>separate the clientCount from the clientIdx<commit_after>#include "TMessage.h"
#include "TBenchmark.h"
#include "TSocket.h"
#include "TH2.h"
#include "TTree.h"
#include "TMemFile.h"
#include "TRandom.h"
#include "TError.h"
#include "TFileMerger.h"

#include "TServerSocket.h"
#include "TPad.h"
#include "TCanvas.h"
#include "TMonitor.h"

#include "TFileCacheWrite.h"
#include "TSystem.h"
#include "THashTable.h"

#include "TMath.h"
#include "TTimeStamp.h"

const int kIncremental = 0;
const int kReplaceImmediately = 1;
const int kReplaceWait = 2;

#include "TKey.h"
static Bool_t R__NeedInitialMerge(TDirectory *dir)
{

   if (dir==0) return kFALSE;

   TIter nextkey(dir->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *subdir = (TDirectory *)dir->GetList()->FindObject(key->GetName());
         if (!subdir) {
            subdir = (TDirectory *)key->ReadObj();
         }
         if (R__NeedInitialMerge(subdir)) {
            return kTRUE;
         }
      } else {
         if (0 != cl->GetResetAfterMerge()) {
            return kTRUE;
         }
      }
   }
   return kFALSE;
}

static void R__DeleteObject(TDirectory *dir, Bool_t withReset)
{
   if (dir==0) return;

   TIter nextkey(dir->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *subdir = (TDirectory *)dir->GetList()->FindObject(key->GetName());
         if (!subdir) {
            subdir = (TDirectory *)key->ReadObj();
         }
         R__DeleteObject(subdir,withReset);
      } else {
         Bool_t todelete = kFALSE;
         if (withReset) {
            todelete = (0 != cl->GetResetAfterMerge());
         } else {
            todelete = (0 ==  cl->GetResetAfterMerge());
         }
         if (todelete) {
            key->Delete();
            dir->GetListOfKeys()->Remove(key);
            delete key;
         }
      }
   }
}

static void R__MigrateKey(TDirectory *destination, TDirectory *source)
{
   if (destination==0 || source==0) return;

   TIter nextkey(source->GetListOfKeys());
   TKey *key;
   while( (key = (TKey*)nextkey()) ) {
      TClass *cl = TClass::GetClass(key->GetClassName());
      if (cl->InheritsFrom(TDirectory::Class())) {
         TDirectory *source_subdir = (TDirectory *)source->GetList()->FindObject(key->GetName());
         if (!source_subdir) {
            source_subdir = (TDirectory *)key->ReadObj();
         }
         TDirectory *destination_subdir = destination->GetDirectory(key->GetName());
         if (!destination_subdir) {
            destination_subdir = destination->mkdir(key->GetName());
         }
         R__MigrateKey(destination,source);
      } else {
         TKey *oldkey = destination->GetKey(key->GetName());
         if (oldkey) {
            oldkey->Delete();
            delete oldkey;
         }
         TKey *newkey = new TKey(destination,*key,0 /* pidoffset */); // a priori the file are from the same client ..
         destination->GetFile()->SumBuffer(newkey->GetObjlen());
         newkey->WriteFile(0);
         if (destination->GetFile()->TestBit(TFile::kWriteError)) {
            return;
         }
      }
   }
   destination->SaveSelf();
}

struct ClientInfo
{
   TFile      *fFile;      // This object does *not* own the file, it will be own by the owner of the ClientInfo.
   TString    fLocalName;
   UInt_t     fContactsCount;
   TTimeStamp fLastContact;
   Double_t   fTimeSincePrevContact;

   ClientInfo() : fFile(0), fLocalName(), fContactsCount(0), fTimeSincePrevContact(0) {}
   ClientInfo(const char *filename, UInt_t clientId) : fFile(0), fContactsCount(0), fTimeSincePrevContact(0) {
      fLocalName.Form("%s-%d-%d",filename,clientId,gSystem->GetPid());
   }

   void Set(TFile *file)
   {
      // Register the new file as coming from this client.
      if (file != fFile) {
         // We need to keep any of the keys from the previous file that
         // are not in the new file.
         if (fFile) {
            R__MigrateKey(fFile,file);
            // delete the previous memory file (if any)
            delete file;
         } else {
            fFile = file;
         }
      }
      TTimeStamp now;
      fTimeSincePrevContact = now.AsDouble() - fLastContact.AsDouble();
      fLastContact = now;
      ++fContactsCount;
   }
};

struct ParallelFileMerger : public TObject
{
   typedef std::vector<ClientInfo> ClientColl_t;

   TString       fFilename;
   TBits         fClientsContact;       //
   UInt_t        fNClientsContact;      //
   ClientColl_t  fClients;
   TTimeStamp    fLastMerge;
   TFileMerger   fMerger;

   ParallelFileMerger(const char *filename, Bool_t writeCache = kFALSE) : fFilename(filename), fNClientsContact(0), fMerger(kFALSE,kTRUE)
   {
      // Default constructor.

      fMerger.SetPrintLevel(0);
      fMerger.OutputFile(filename,"RECREATE");
      if (writeCache) new TFileCacheWrite(fMerger.GetOutputFile(),32*1024*1024);
   }

   ~ParallelFileMerger()
   {
      // Destructor.

      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         fprintf(stderr,"Client %d reported %u times\n",f,fClients[f].fContactsCount);
      }
      for( ClientColl_t::iterator iter = fClients.begin();
          iter != fClients.end();
          ++iter)
      {
         delete iter->fFile;
      }
   }

   ULong_t  Hash() const
   {
      // Return hash value for this object.
      return fFilename.Hash();
   }

   const char *GetName() const
   {
      // Return the name of the object which is the name of the output file.
      return fFilename;
   }

   Bool_t InitialMerge(TFile *input)
   {
      // Initial merge of the input to copy the resetable object (TTree) into the output
      // and remove them from the input file.

      fMerger.AddFile(input);

      Bool_t result = fMerger.PartialMerge(TFileMerger::kIncremental | TFileMerger::kResetable);

      R__DeleteObject(input,kTRUE);
      return result;
   }

   Bool_t Merge()
   {
      // Merge the current inputs into the output file.

      R__DeleteObject(fMerger.GetOutputFile(),kFALSE); // Remove object that can *not* be incrementally merge and will *not* be reset by the client code.
      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         fMerger.AddFile(fClients[f].fFile);
      }
      Bool_t result = fMerger.PartialMerge(TFileMerger::kAllIncremental);

      // Remove any 'resetable' object (like TTree) from the input file so that they will not
      // be re-merged.  Keep only the object that always need to be re-merged (Histograms).
      for(unsigned int f = 0 ; f < fClients.size(); ++f) {
         if (fClients[f].fFile) {
            R__DeleteObject(fClients[f].fFile,kTRUE);
         } else {
            // We back up the file (probably due to memory constraint)
            TFile *file = TFile::Open(fClients[f].fLocalName,"UPDATE");
            R__DeleteObject(file,kTRUE); // Remove object that can be incrementally merge and will be reset by the client code.
            file->Write();
            delete file;
         }
      }
      fLastMerge = TTimeStamp();
      fNClientsContact = 0;
      fClientsContact.Clear();

      return result;
   }

   Bool_t NeedFinalMerge()
   {
      // Return true, if there is any data that has not been merged.

      return fClientsContact.CountBits() > 0;
   }

   Bool_t NeedMerge(Float_t clientThreshold)
   {
      // Return true, if enough client have reported

      if (fClients.size()==0) {
         return kFALSE;
      }

      // Calculate average and rms of the time between the last 2 contacts.
      Double_t sum = 0;
      Double_t sum2 = 0;
      for(unsigned int c = 0 ; c < fClients.size(); ++c) {
         sum += fClients[c].fTimeSincePrevContact;
         sum2 += fClients[c].fTimeSincePrevContact*fClients[c].fTimeSincePrevContact;
      }
      Double_t avg = sum / fClients.size();
      Double_t sigma = sum2 ? TMath::Sqrt( sum2 / fClients.size() - avg*avg) : 0;
      Double_t target = avg + 2*sigma;
      TTimeStamp now;
      if ( (now.AsDouble() - fLastMerge.AsDouble()) > target) {
//         Float_t cut = clientThreshold * fClients.size();
//         if (!(fClientsContact.CountBits() > cut )) {
//            for(unsigned int c = 0 ; c < fClients.size(); ++c) {
//               fprintf(stderr,"%d:%f ",c,fClients[c].fTimeSincePrevContact);
//            }
//            fprintf(stderr,"merge:%f avg:%f target:%f\n",(now.AsDouble() - fLastMerge.AsDouble()),avg,target);
//         }
         return kTRUE;
      }
      Float_t cut = clientThreshold * fClients.size();
      return fClientsContact.CountBits() > cut  || fNClientsContact > 2*cut;
   }

   void RegisterClient(UInt_t clientId, TFile *file)
   {
      // Register that a client has sent a file.

      ++fNClientsContact;
      fClientsContact.SetBitNumber(clientId);
      if (fClients.size() < clientId+1) {
         fClients.push_back( ClientInfo(fFilename,clientId) );
      }
      fClients[clientId].Set(file);
   }

   ClassDef(ParallelFileMerger,0);
};

void parallelMergeServer(bool cache = false) {
   // This script shows how to make a simple iterative server that
   // can accept connections while handling currently open connections.
   // Compare this script to hserv.C that blocks on accept.
   // In this script a server socket is created and added to a monitor.
   // A monitor object is used to monitor connection requests on
   // the server socket. After accepting the connection
   // the new socket is added to the monitor and immediately ready
   // for use. Once two connections are accepted the server socket
   // is removed from the monitor and closed. The monitor continues
   // monitoring the sockets.
   //
   // To run this demo do the following:
   //   - Open three windows
   //   - Start ROOT in all three windows
   //   - Execute in the first window: .x hserv2.C
   //   - Execute in the second and third windows: .x hclient.C
   //Author: Fons Rademakers

   // Open a server socket looking for connections on a named service or
   // on a specified port.
   //TServerSocket *ss = new TServerSocket("rootserv", kTRUE);
   TServerSocket *ss = new TServerSocket(1095, kTRUE);
   if (!ss->IsValid()) {
      return;
   }

   TMonitor *mon = new TMonitor;

   mon->Add(ss);

   UInt_t clientCount = 0;
   UInt_t clientIndex = 0;

   THashTable mergers;

   enum StatusKind {
      kStartConnection = 0,
      kProtocol = 1,

      kProtocolVersion = 1
   };

   printf("fastMergeServerHist ready to accept connections\n");
   while (1) {
      TMessage *mess;
      TSocket  *s;

      // NOTE: this needs to be update to handle the case where the client
      // dies.
      s = mon->Select();

      if (s->IsA() == TServerSocket::Class()) {
         if (clientCount > 100) {
            printf("only accept 100 clients connections\n");
            mon->Remove(ss);
            ss->Close();
         } else {
            TSocket *client = ((TServerSocket *)s)->Accept();
            client->Send(clientIndex, kStartConnection);
            client->Send(kProtocolVersion, kProtocol);
            ++clientCount;
            ++clientIndex;
            mon->Add(client);
            printf("Accept %d connections\n",clientCount);
         }
         continue;
      }

      s->Recv(mess);

      if (mess==0) {
         Error("fastMergeServer","The client did not send a message\n");
      } else if (mess->What() == kMESS_STRING) {
         char str[64];
         mess->ReadString(str, 64);
         printf("Client %d: %s\n", clientCount, str);
         mon->Remove(s);
         printf("Client %d: bytes recv = %d, bytes sent = %d\n", clientCount, s->GetBytesRecv(),
                s->GetBytesSent());
         s->Close();
         --clientCount;
         if (mon->GetActive() == 0 || clientCount == 0) {
            printf("No more active clients... stopping\n");
            break;
         }
      } else if (mess->What() == kMESS_ANY) {

         Long64_t length;
         TString filename;
         Int_t clientId;
         mess->ReadInt(clientId);
         mess->ReadTString(filename);
         mess->ReadLong64(length); // '*mess >> length;' is broken in CINT for Long64_t.

         // Info("fastMergeServerHist","Received input from client %d for %s",clientId,filename.Data());

         TMemFile *transient = new TMemFile(filename,mess->Buffer() + mess->Length(),length,"UPDATE"); // UPDATE because we need to remove the TTree after merging them.
         mess->SetBufferOffset(mess->Length()+length);

         const Float_t clientThreshold = 0.75; // control how often the histogram are merged.  Here as soon as half the clients have reported.

         ParallelFileMerger *info = (ParallelFileMerger*)mergers.FindObject(filename);
         if (!info) {
            info = new ParallelFileMerger(filename,cache);
            mergers.Add(info);
         }

         if (R__NeedInitialMerge(transient)) {
            info->InitialMerge(transient);
         }
         info->RegisterClient(clientId,transient);
         if (info->NeedMerge(clientThreshold)) {
            // Enough clients reported.
            Info("fastMergeServerHist","Merging input from %ld clients (%d)",info->fClients.size(),clientId);
            info->Merge();
         }
         transient = 0;
      } else if (mess->What() == kMESS_OBJECT) {
         printf("got object of class: %s\n", mess->GetClass()->GetName());
      } else {
         printf("*** Unexpected message ***\n");
      }

      delete mess;
   }

   TIter next(&mergers);
   ParallelFileMerger *info;
   while ( (info = (ParallelFileMerger*)next()) ) {
      if (info->NeedFinalMerge())
      {
         info->Merge();
      }
   }

   mergers.Delete();
   delete mon;
   delete ss;
}
<|endoftext|>


<commit_before>#include "base64.hpp"

std::string base64_encode(const std::string &in)
{
    char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    std::string result;
    int len = (int)in.size();
    unsigned long value;

    for(int i=0; i<len;)
    {
	switch(len-i)
	{
	case 1:
	    // There's only one character left, so I have to pad with two '='
	    value = 0xff & in[i];
	    result += map[0x3f & (value >> 2)];
	    result += map[0x3f & (value << 4)];
	    result += "==";
	    i = len;
	    break;

	case 2:;
	    // There's only one character left, so I have to pad with one '='
	    value = ((0xff & in[i]) << 8) | (0xff & in[i+1]);
	    result += map[0x3f & (value >> 10)];
	    result += map[0x3f & (value >> 4)];
	    result += map[0x3f & (value << 2)];
	    result += "=";
	    i = len;
	    break;

	default:
	    // I encode three characters in four
	    value = ((0xff & in[i]) << 16) | ((0xff & in[i+1]) << 8) | (0xff & in[i+2]);
	    result += map[0x3f & (value >> 18)];
	    result += map[0x3f & (value >> 12)];
	    result += map[0x3f & (value >> 6)];
	    result += map[0x3f & (value >> 0)];
	    i += 3;
	    break;
	}
    }

    return result;
}

static short base64_char_decode_map(const char c)
{
    short result;

    if (isupper(c))
    {
	result = c - 'A';
    }
    else
    {
	if (islower(c))
	{
	    result = 26 + c - 'a';
	}
	else
	{
	    if (isdigit(c))
	    {
		result = 52 + c - '0';
	    }
	    else
	    {
		if ('+' == c)
		{
		    result = 62;
		}
		else
		{
		    if ('/' == c)
		    {
			result = 63;
		    }
		    else
		    {
			result = -1;
		    }
		}
	    }
	}
    }
    return result;
}

std::string base64_decode(const std::string &s)
{
    std::string result;
    unsigned long value;
    short m;
    int len, not_there, accumulated;
    len = s.size();
    not_there = 0;
    accumulated = 0;

    for (int i=0; i<len; ++i)
    {
	if ('=' != s[i])
	{
	    m= base64_char_decode_map(s[i]);
	    if (0 <= m)
	    {
		++accumulated;
		value = (value << 6) | m;
	    }
	}
	else
	{
	    m = 0;
	    ++accumulated;
	    ++not_there;
	    value = (value << 6) | m;
	}

	if (4 == accumulated)
	{
	    switch(not_there)
	    {
	    case 1:
		result += (unsigned char)(0xff & (value>>16));
		result += (unsigned char)(0xff & (value>>8));
		break;

	    case 2:
		result += (unsigned char)(0xff & (value>>16));
		break;

	    default:
		result += (unsigned char)(0xff & (value>>16));
		result += (unsigned char)(0xff & (value>>8));
		result += (unsigned char)(0xff & (value>>0));
		break;
	    }
	    accumulated = 0;
	    not_there = 0;
	}
    }
    return result;
}

#ifdef DEBUG_BASE64
#include <iostream>

int
main (int argc, char *argv[]) {
    CStdString s;
    s += '\0';
    s += "jguthrie";
    s += '\0';
    s += "test";
    CStdString e = base64_encode(s);
    std::cout << "Encoding the string gets \"" << e << "\"\n";

    std::cout << "Decoding \"" << e << "\"\n";
    s = base64_decode(e);
    for (unsigned i=0; i<s.size(); ++i) {
	printf("Character s[%d] = '%c' (0x%02x)\n", i, isprint(s[i]) ? s[i] : '.',
	       s[i]);
    }
}
#endif

#ifdef UTILITY
#include <iostream>

int
main(int argc, char **argv) {
    if (argc > 1) {
	CStdString s(argv[1]);
	CStdString e = base64_encode(s);
	std::cout << "Encoding the string \"" << s << "\" gives \"" << e << "\"\n";
	e = base64_decode(s);
	std::cout << "Decoding the string \"" << s << "\" gives \"" << e << "\"\n";
    }
    return 0;
}
#endif /* utility */
<commit_msg>Fix a warning in base64.cpp<commit_after>#include "base64.hpp"

std::string base64_encode(const std::string &in)
{
    const std::string map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    std::string result;
    int len = (int)in.size();
    unsigned long value;

    for(int i=0; i<len;)
    {
	switch(len-i)
	{
	case 1:
	    // There's only one character left, so I have to pad with two '='
	    value = 0xff & in[i];
	    result += map[0x3f & (value >> 2)];
	    result += map[0x3f & (value << 4)];
	    result += "==";
	    i = len;
	    break;

	case 2:;
	    // There's only one character left, so I have to pad with one '='
	    value = ((0xff & in[i]) << 8) | (0xff & in[i+1]);
	    result += map[0x3f & (value >> 10)];
	    result += map[0x3f & (value >> 4)];
	    result += map[0x3f & (value << 2)];
	    result += "=";
	    i = len;
	    break;

	default:
	    // I encode three characters in four
	    value = ((0xff & in[i]) << 16) | ((0xff & in[i+1]) << 8) | (0xff & in[i+2]);
	    result += map[0x3f & (value >> 18)];
	    result += map[0x3f & (value >> 12)];
	    result += map[0x3f & (value >> 6)];
	    result += map[0x3f & (value >> 0)];
	    i += 3;
	    break;
	}
    }

    return result;
}

static short base64_char_decode_map(const char c)
{
    short result;

    if (isupper(c))
    {
	result = c - 'A';
    }
    else
    {
	if (islower(c))
	{
	    result = 26 + c - 'a';
	}
	else
	{
	    if (isdigit(c))
	    {
		result = 52 + c - '0';
	    }
	    else
	    {
		if ('+' == c)
		{
		    result = 62;
		}
		else
		{
		    if ('/' == c)
		    {
			result = 63;
		    }
		    else
		    {
			result = -1;
		    }
		}
	    }
	}
    }
    return result;
}

std::string base64_decode(const std::string &s)
{
    std::string result;
    unsigned long value;
    short m;
    int len, not_there, accumulated;
    len = s.size();
    not_there = 0;
    accumulated = 0;

    for (int i=0; i<len; ++i)
    {
	if ('=' != s[i])
	{
	    m= base64_char_decode_map(s[i]);
	    if (0 <= m)
	    {
		++accumulated;
		value = (value << 6) | m;
	    }
	}
	else
	{
	    m = 0;
	    ++accumulated;
	    ++not_there;
	    value = (value << 6) | m;
	}

	if (4 == accumulated)
	{
	    switch(not_there)
	    {
	    case 1:
		result += (unsigned char)(0xff & (value>>16));
		result += (unsigned char)(0xff & (value>>8));
		break;

	    case 2:
		result += (unsigned char)(0xff & (value>>16));
		break;

	    default:
		result += (unsigned char)(0xff & (value>>16));
		result += (unsigned char)(0xff & (value>>8));
		result += (unsigned char)(0xff & (value>>0));
		break;
	    }
	    accumulated = 0;
	    not_there = 0;
	}
    }
    return result;
}

#ifdef DEBUG_BASE64
#include <iostream>

int
main (int argc, char *argv[]) {
    CStdString s;
    s += '\0';
    s += "jguthrie";
    s += '\0';
    s += "test";
    CStdString e = base64_encode(s);
    std::cout << "Encoding the string gets \"" << e << "\"\n";

    std::cout << "Decoding \"" << e << "\"\n";
    s = base64_decode(e);
    for (unsigned i=0; i<s.size(); ++i) {
	printf("Character s[%d] = '%c' (0x%02x)\n", i, isprint(s[i]) ? s[i] : '.',
	       s[i]);
    }
}
#endif

#ifdef UTILITY
#include <iostream>

int
main(int argc, char **argv) {
    if (argc > 1) {
	CStdString s(argv[1]);
	CStdString e = base64_encode(s);
	std::cout << "Encoding the string \"" << s << "\" gives \"" << e << "\"\n";
	e = base64_decode(s);
	std::cout << "Decoding the string \"" << s << "\" gives \"" << e << "\"\n";
    }
    return 0;
}
#endif /* utility */
<|endoftext|>


<commit_before><commit_msg>Bugfix: `load_DDS_texture`: Fix integer overflow of `bufsize`.<commit_after><|endoftext|>


<commit_before>#include "starlight_renderer.h"
#if defined(_WIN32) && defined(STARLIGHT_D3D10)
#include "starlight_d3d_shared.h"
#include "starlight_d3d10.h"
#include "starlight_renderer_windows.h"

#include <imgui.h>

#include "imgui_impl_dx10.h"

#include <d3d10_1.h>
#include <d3d10.h>
#include <d3dcompiler.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <tchar.h>

// Data
static ID3D10Device*            g_pd3dDevice = nullptr;
static IDXGISwapChain*          g_pSwapChain = nullptr;
static ID3D10RenderTargetView*  g_mainRenderTargetView = nullptr;

void CreateRenderTarget()
{
	DXGI_SWAP_CHAIN_DESC sd;
	g_pSwapChain->GetDesc(&sd);

	// Create the render target
	ID3D10Texture2D* pBackBuffer;
	D3D10_RENDER_TARGET_VIEW_DESC render_target_view_desc;
	ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
	render_target_view_desc.Format = sd.BufferDesc.Format;
	render_target_view_desc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
	g_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
	g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView);
	g_pd3dDevice->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
	pBackBuffer->Release();
}

void CleanupRenderTarget()
{
	if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; }
}

HRESULT CreateDeviceD3D(HWND hWnd)
{
	// Setup swap chain
	DXGI_SWAP_CHAIN_DESC sd;
	{
		ZeroMemory(&sd, sizeof(sd));
		sd.BufferCount = 2;
		sd.BufferDesc.Width = 0;
		sd.BufferDesc.Height = 0;
		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sd.BufferDesc.RefreshRate.Numerator = 60;
		sd.BufferDesc.RefreshRate.Denominator = 1;
		sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sd.OutputWindow = hWnd;
		sd.SampleDesc.Count = 1;
		sd.SampleDesc.Quality = 0;
		sd.Windowed = TRUE;
		sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	}

	UINT createDeviceFlags = 0;
	//createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
	if (D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice) != S_OK)
		return E_FAIL;

	// Setup rasterizer
	{
		D3D10_RASTERIZER_DESC RSDesc;
		memset(&RSDesc, 0, sizeof(D3D10_RASTERIZER_DESC));
		RSDesc.FillMode = D3D10_FILL_SOLID;
		RSDesc.CullMode = D3D10_CULL_NONE;
		RSDesc.FrontCounterClockwise = FALSE;
		RSDesc.DepthBias = 0;
		RSDesc.SlopeScaledDepthBias = 0.0f;
		RSDesc.DepthBiasClamp = 0;
		RSDesc.DepthClipEnable = TRUE;
		RSDesc.ScissorEnable = TRUE;
		RSDesc.AntialiasedLineEnable = FALSE;
		RSDesc.MultisampleEnable = (sd.SampleDesc.Count > 1) ? TRUE : FALSE;

		ID3D10RasterizerState* pRState = nullptr;
		g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState);
		g_pd3dDevice->RSSetState(pRState);
		pRState->Release();
	}

	CreateRenderTarget();

	return S_OK;
}

extern LRESULT ImGui_ImplDX10_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool renderer::D3D10::ImGuiHandleEvent(WindowEvent* e) {
	return (ImGui_ImplDX10_WndProcHandler(e->hWnd, e->msg, e->wParam, e->lParam) == 1);
}

void renderer::D3D10::Resize(int32_t width, int32_t height) {
	ImGui_ImplDX10_InvalidateDeviceObjects();
	CleanupRenderTarget();
	g_pSwapChain->ResizeBuffers(0, (UINT) width, (UINT) height, DXGI_FORMAT_UNKNOWN, 0);
	CreateRenderTarget();
	ImGui_ImplDX10_CreateDeviceObjects();
}

extern void ImGui_ImplDX10_NewFrame();
void renderer::D3D10::ImGuiNewFrame() {
	ImGui_ImplDX10_NewFrame();
}

void CleanupDeviceD3D() {
	CleanupRenderTarget();
	SafeRelease(g_pSwapChain);
	SafeRelease(g_pd3dDevice);
}

bool renderer::D3D10::Init(PlatformData* data)
{
	if (CreateDeviceD3D(data->hWnd) != S_OK) {
		CleanupDeviceD3D();
		return false;
	}

	ImGui_ImplDX10_Init(data->hWnd, g_pd3dDevice);

	return true;
}

void renderer::D3D10::Render() {
	// Clear
	ImVec4 clear_col = ImColor(114, 144, 154);
	g_pd3dDevice->ClearRenderTargetView(g_mainRenderTargetView, (float*) &clear_col);

	// TODO: Game rendering here

	ImGui::Render();

	// Present
	g_pSwapChain->Present(0, 0);
}

void renderer::D3D10::Destroy() {
	ImGui_ImplDX10_Shutdown();
	CleanupDeviceD3D();
}

void renderer::D3D10::Update() {
	// TODO
}

void renderer::D3D10::SetPlayerCameraViewMatrix(glm::mat4 matrix) {
	// TODO
}

void renderer::D3D10::SetProjectionMatrix(glm::mat4 matrix) {
	// TODO
}

int32_t renderer::D3D10::UploadMesh(Vertex* vertices, int32_t numVertices, int32_t* indices, int32_t numIndices) {
	// TOOD
	return -1;
}

#endif
<commit_msg>Fix DX10 resize crash<commit_after>#include "starlight_renderer.h"
#if defined(_WIN32) && defined(STARLIGHT_D3D10)
#include "starlight_d3d_shared.h"
#include "starlight_d3d10.h"
#include "starlight_renderer_windows.h"

#include <imgui.h>

#include "imgui_impl_dx10.h"

#include <d3d10_1.h>
#include <d3d10.h>
#include <d3dcompiler.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <tchar.h>

// Data
static ID3D10Device*            g_pd3dDevice = nullptr;
static IDXGISwapChain*          g_pSwapChain = nullptr;
static ID3D10RenderTargetView*  g_mainRenderTargetView = nullptr;

void CreateRenderTarget()
{
	DXGI_SWAP_CHAIN_DESC sd;
	g_pSwapChain->GetDesc(&sd);

	// Create the render target
	ID3D10Texture2D* pBackBuffer;
	D3D10_RENDER_TARGET_VIEW_DESC render_target_view_desc;
	ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
	render_target_view_desc.Format = sd.BufferDesc.Format;
	render_target_view_desc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
	g_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
	g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView);
	g_pd3dDevice->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
	pBackBuffer->Release();
}

void CleanupRenderTarget()
{
	if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; }
}

HRESULT CreateDeviceD3D(HWND hWnd)
{
	// Setup swap chain
	DXGI_SWAP_CHAIN_DESC sd;
	{
		ZeroMemory(&sd, sizeof(sd));
		sd.BufferCount = 2;
		sd.BufferDesc.Width = 0;
		sd.BufferDesc.Height = 0;
		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		sd.BufferDesc.RefreshRate.Numerator = 60;
		sd.BufferDesc.RefreshRate.Denominator = 1;
		sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sd.OutputWindow = hWnd;
		sd.SampleDesc.Count = 1;
		sd.SampleDesc.Quality = 0;
		sd.Windowed = TRUE;
		sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	}

	UINT createDeviceFlags = 0;
	//createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
	if (D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice) != S_OK)
		return E_FAIL;

	// Setup rasterizer
	{
		D3D10_RASTERIZER_DESC RSDesc;
		memset(&RSDesc, 0, sizeof(D3D10_RASTERIZER_DESC));
		RSDesc.FillMode = D3D10_FILL_SOLID;
		RSDesc.CullMode = D3D10_CULL_NONE;
		RSDesc.FrontCounterClockwise = FALSE;
		RSDesc.DepthBias = 0;
		RSDesc.SlopeScaledDepthBias = 0.0f;
		RSDesc.DepthBiasClamp = 0;
		RSDesc.DepthClipEnable = TRUE;
		RSDesc.ScissorEnable = TRUE;
		RSDesc.AntialiasedLineEnable = FALSE;
		RSDesc.MultisampleEnable = (sd.SampleDesc.Count > 1) ? TRUE : FALSE;

		ID3D10RasterizerState* pRState = nullptr;
		g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState);
		g_pd3dDevice->RSSetState(pRState);
		pRState->Release();
	}

	CreateRenderTarget();

	return S_OK;
}

extern LRESULT ImGui_ImplDX10_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool renderer::D3D10::ImGuiHandleEvent(WindowEvent* e) {
	return (ImGui_ImplDX10_WndProcHandler(e->hWnd, e->msg, e->wParam, e->lParam) == 1);
}

void renderer::D3D10::Resize(int32_t width, int32_t height) {
	CleanupRenderTarget();
	g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
	CreateRenderTarget();
}

extern void ImGui_ImplDX10_NewFrame();
void renderer::D3D10::ImGuiNewFrame() {
	ImGui_ImplDX10_NewFrame();
}

void CleanupDeviceD3D() {
	CleanupRenderTarget();
	SafeRelease(g_pSwapChain);
	SafeRelease(g_pd3dDevice);
}

bool renderer::D3D10::Init(PlatformData* data)
{
	if (CreateDeviceD3D(data->hWnd) != S_OK) {
		CleanupDeviceD3D();
		return false;
	}

	ImGui_ImplDX10_Init(data->hWnd, g_pd3dDevice);

	return true;
}

void renderer::D3D10::Render() {
	// Clear
	ImVec4 clear_col = ImColor(114, 144, 154);
	g_pd3dDevice->ClearRenderTargetView(g_mainRenderTargetView, (float*) &clear_col);

	// TODO: Game rendering here

	ImGui::Render();

	// Present
	g_pSwapChain->Present(0, 0);
}

void renderer::D3D10::Destroy() {
	ImGui_ImplDX10_Shutdown();
	CleanupDeviceD3D();
}

void renderer::D3D10::Update() {
	// TODO
}

void renderer::D3D10::SetPlayerCameraViewMatrix(glm::mat4 matrix) {
	// TODO
}

void renderer::D3D10::SetProjectionMatrix(glm::mat4 matrix) {
	// TODO
}

int32_t renderer::D3D10::UploadMesh(Vertex* vertices, int32_t numVertices, int32_t* indices, int32_t numIndices) {
	// TOOD
	return -1;
}

#endif
<|endoftext|>


<commit_before>#include <ros/ros.h>

#include <stdio.h>
#include <tf/transform_listener.h>
#include "std_msgs/String.h"
//#include <cob_object_detection_msg/Detection.msg>
//#include <cob_object_detection_msgs/DetectObjects.h>
#include "geometry_msgs/PoseStamped.h"
#include <cob_object_detection_msgs/DetectionArray.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/CameraInfo.h>
#include <visualization_msgs/Marker.h>
#include <visualization_msgs/MarkerArray.h>

//void Callback(const cob_object_detection_msgs::Detection::Detection_::_pose_type msg) //You cannot subscribe just to the pose, you subscribe to the whole message. Therefore, the types must match
void Callback(const cob_object_detection_msgs::DetectionArray &msg)                      //const because we are just reading it, & to pass by reference
{
    //int nvmark=0;                                 //Visible markers
    //ROS_INFO_STREAM("I heard " << msg); //"<<
    //ROS_INFO_STREAM("Message 1: " << msg.detections[0].label);
    //if (msg.detections.empty() != true) ROS_INFO_STREAM(msg.detections.size());
    //char buffer [50];
    if (msg.detections.empty() != true){
        for (int i=0; i <= msg.detections.size()-1; i++){  //msg.detections.size()
            try{
                //ROS_INFO_STREAM("Message 1: " << msg.detections[i]);                  //Displays the whole detection information
                switch (msg.detections[i].id){              //We do this so that we know that we can address the pose to the right marker. Will be replaced
                    case 0: {ROS_INFO("CF 0:"); break;};
                    case 1: {ROS_INFO("CF 1:"); break;};
                    case 2: {ROS_INFO("CF 2:"); break;};
                    case 3: {ROS_INFO("CF 3:"); break;};
                }

                ROS_INFO_STREAM(msg.detections[i].pose.pose);
            }
            catch(...){
                //ROS_INFO("Failed to send Marker [%s]", i); //sprintf(buffer, i)
            }
        }
    }
    //else  ROS_INFO("No Marker");

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

    /* **** Function to chop the Detection Array into several Detection, so that they can be treated and sent separately**** */

    /* **** Function to chop the Detection into the different datatypes and publish it **** */
    /*for (int i=1; i<=nvmark+1; i++)           //For all visible markers:
    {
        try{
            ROS_INFO("Marker [s%]", i);     //We could chop this marker
            //Here we should chop the data that interests us, taking just the geometry_msgs::PoseStamped and send it to the
        }
        catch(){
            ROS_INFO("Failed to send Marker [s%]", i);
        }
    }*/
}

int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle nh;

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */

  ros::Subscriber sub = nh.subscribe("/fiducials/fiducial_detection_array",1,Callback); //Basic subscriber. Just has the topic it is subscribed to, the callback function and how many messages it caches

  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  while(nh.ok()){
    ros::spinOnce();
  }

  return 0;
}
<commit_msg>Irrelevant comments and failed attempts erased, cleaner code<commit_after>#include <ros/ros.h>

#include <stdio.h>
#include <tf/transform_listener.h>
#include "std_msgs/String.h"
#include "geometry_msgs/PoseStamped.h"
#include <cob_object_detection_msgs/DetectionArray.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/CameraInfo.h>
#include <visualization_msgs/Marker.h>
#include <visualization_msgs/MarkerArray.h>

void Callback(const cob_object_detection_msgs::DetectionArray &msg)                     //const because we are just reading it, & to pass by reference
{
    if (msg.detections.empty() != true){
        for (int i=0; i <= msg.detections.size()-1; i++){  //msg.detections.size()
            try{
                //ROS_INFO_STREAM("Message 1: " << msg.detections[i]);                  //Displays the whole detection information
                switch (msg.detections[i].id){                                          //We do this so that we know that we can address the pose to the right marker. Will be replaced
                    case 0: {ROS_INFO("CF 0:"); break;};
                    case 1: {ROS_INFO("CF 1:"); break;};
                    case 2: {ROS_INFO("CF 2:"); break;};
                    case 3: {ROS_INFO("CF 3:"); break;};
                default:{ROS_INFO("ID Fail"); break;};                                  //If an error occurs and the detections[i] is accessed erronially
                }

                ROS_INFO_STREAM(msg.detections[i].pose.pose);
            }
            catch(...){
                ROS_INFO("Failed to send Marker "); //sprintf(buffer, i));              //Need to find how to efficiently convert int to string without too much pain
            }
        }
    }
    //else  ROS_INFO("No Marker");
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe("/fiducials/fiducial_detection_array",1,Callback); //Basic subscriber. Just has the topic it is subscribed to, the callback function and how many messages it caches

  while(nh.ok()){
    ros::spinOnce();
  }

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Bugfix: `loaders::load_FBX_texture`: PNG loading loplaceholder code.<commit_after><|endoftext|>


<commit_before>#include "party.h"

std::shared_ptr<Party> cache_fetch_party(uint32_t charId) {
auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::Party partyTable{};
  Core::PartyMembers partyMembersTable{};

  auto res = conn(sqlpp::select(sqlpp::all_of(partyTable)).from(
    partyMembersTable.join(partyTable).on(partyMembersTable.id == partyTable.id))
                  .where(partyMembersTable.memberId == charId));

  if (res.empty()) {
    return {};
  }
  auto result = res.front();

  Party party;
  party.id = result.id;
  party.name = result.name;
  party.leader = result.leaderId;
  party.options = result.options;
  party.level = result.level;
  party.last_got_item_index = result.lastGotItemIndex;
  party.last_got_zuly_index = result.lastGotZulyIndex;
  party.last_got_etc_index = result.lastGotEtcIndex;

  // now we fetch all party members
  auto res2 = conn(sqlpp::select(partyMembersTable.memberId).from(partyMembersTable)
                   .where(partyMembersTable.id == party.id).order_by(partyMembersTable.rank.desc()));

  if (res.empty()) {
    return {};
  }

  for (auto& r : res2) {
    party.members.push_back(r.memberId);
  }

  return std::make_shared<Party>(party);
}

void cache_write_party(std::shared_ptr<Party> party) {
}

void cache_write_party_members(std::shared_ptr<Party> party) {
}

void cache_remove_party(std::shared_ptr<Party> party) {
}
<commit_msg>Update party.cpp<commit_after>#include "party.h"

std::shared_ptr<Party> cache_fetch_party(uint32_t charId) {
  auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::Party partyTable{};
  Core::PartyMembers partyMembersTable{};

  auto res = conn(sqlpp::select(sqlpp::all_of(partyTable)).from(
    partyMembersTable.join(partyTable).on(partyMembersTable.id == partyTable.id))
                  .where(partyMembersTable.memberId == charId));

  if (res.empty()) {
    return {};
  }
  auto result = res.front();

  Party party;
  party.id = result.id;
  party.name = result.name;
  party.leader = result.leaderId;
  party.options = result.options;
  party.level = result.level;
  party.last_got_item_index = result.lastGotItemIndex;
  party.last_got_zuly_index = result.lastGotZulyIndex;
  party.last_got_etc_index = result.lastGotEtcIndex;

  // now we fetch all party members
  auto res2 = conn(sqlpp::select(partyMembersTable.memberId).from(partyMembersTable)
                   .where(partyMembersTable.id == party.id).order_by(partyMembersTable.rank.desc()));

  if (res.empty()) {
    return {};
  }

  for (const auto& r : res2) {
    party.members.push_back(r.memberId);
  }

  return {party};
}

void cache_create_party(std::shared_ptr<Party> party) {
  if (!party) return;

  auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::Party partyTable{};

  conn(sqlpp::insert_into(partyTable)
       .set(partyTable.name = party->name)
       .set(partyTable.leaderId = party->leader)
       .set(partyTable.options = party->options)
       .set(partyTable.level = party->level)
       .set(partyTable.lastGotItemIndex = party->last_got_item_index)
       .set(partyTable.lastGotEtcIndex = party->last_got_etc_index)
       .set(partyTable.lastGotZulyIndex = party->last_got_zuly_index));
}

void cache_write_party(std::shared_ptr<Party> party) {
  if (!party) return;
  auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::Party partyTable{};

  conn(sqlpp::update(partyTable)
       .set(partyTable.name = party->name)
       .set(partyTable.leaderId = party->leader)
       .set(partyTable.options = party->options)
       .set(partyTable.level = party->level)
       .set(partyTable.lastGotItemIndex = party->last_got_item_index)
       .set(partyTable.lastGotEtcIndex = party->last_got_etc_index)
       .set(partyTable.lastGotZulyIndex = party->last_got_zuly_index)
       .where(partyTable.id == party->id));
}

void cache_write_party_members(std::shared_ptr<Party> party) {
  if (!party) return;
  auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::PartyMembers partyMembersTable{};

  conn(sqlpp::remove_from(partyMembersTable).where(partyMembersTable.id == party->id));
  auto insert = sqlpp::insert_into(partyMembersTable).columns(partyMembersTable.id, partyMembersTable.memberId);
  for (auto m : party-> members) {
    multi_insert.values.add(partyMembersTable.id = party->id, partyMembersTable.memberId = m);
  }
  conn(insert);
}

void cache_remove_party(std::shared_ptr<Party> party) {
  if (!party) return;
  auto conn = Core::connectionPool.getConnection<Core::Osirose>();
  Core::Party partyTable{};

  conn(sqlpp::remove_from(partyTable).where(partyTable.id == party->id));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperOutputImageParameter.h"
#include "otbClampImageFilter.h"
#include "otbImageIOFactory.h"
#include "itksys/SystemTools.hxx"

#ifdef OTB_USE_MPI

#include "otbMPIConfig.h"
#include "otbMPIVrtWriter.h"

#ifdef OTB_USE_SPTW
#include "otbSimpleParallelTiffWriter.h"
#endif

#endif

#define CAST_IMAGE_BASE( T, image_base )		\
  {							\
    T * img = dynamic_cast< T * >( image_base );	\
							\
    if( img )						\
      {							\
      SwitchInput< T >( img );				\
							\
      return;						\
      }							\
  }

namespace otb
{
namespace Wrapper
{

// Declare specialisation for UInt8RGBAImageType
template<>
void OutputImageParameter::SwitchInput(UInt8RGBAImageType * );

// Declare specialisation for UInt8RGBImageType
template <>
void OutputImageParameter::SwitchInput( UInt8RGBImageType * );

OutputImageParameter::OutputImageParameter()
  : m_PixelType(ImagePixelType_float),
    m_DefaultPixelType(ImagePixelType_float),
    m_RAMValue(0)
{
  SetName("Output Image");
  SetKey("out");
}

OutputImageParameter::~OutputImageParameter()
{
}

std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
{
  // TODO: Could be replaced by constant static string array e.g.:
  // return PIXEL_TYPE_NAME[ type ];

  std::string ret;
  switch(type)
    {
    case ImagePixelType_uint8:
      {
      ret = "uint8";
      break;
      }
    case ImagePixelType_int16:
      {
      ret = "int16";
      break;
      }
    case ImagePixelType_uint16:
      {
      ret = "uint16";
      break;
      }
    case ImagePixelType_int32:
      {
      ret = "int32";
      break;
      }
    case ImagePixelType_uint32:
      {
      ret = "uint32";
      break;
      }
    case ImagePixelType_float:
      {
      ret = "float";
      break;
      }
    case ImagePixelType_double:
      {
      ret = "double";
      break;
      }
    case ImagePixelType_cint16:
      {
      ret = "cint16";
      break;
      }
    case ImagePixelType_cint32:
      {
      ret = "cint32";
      break;
      }
    case ImagePixelType_cfloat:
      {
      ret = "cfloat";
      break;
      }
    case ImagePixelType_cdouble:
      {
      ret = "cdouble";
      break;
      }
    }
  return ret;
}

bool
OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePixelType &type)
{
  // TODO: Could be replaced std::find_if() in constant static string
  // array (see ::ConvertPixelTypeToString().

  if (value == "uint8")
    type = ImagePixelType_uint8;
  else if (value == "int16")
    type = ImagePixelType_int16;
  else if (value == "uint16")
    type = ImagePixelType_uint16;
  else if (value == "int32")
    type = ImagePixelType_int32;
  else if (value == "uint32")
    type = ImagePixelType_uint32;
  else if (value == "float")
    type = ImagePixelType_float;
  else if (value == "double")
    type = ImagePixelType_double;
  else if (value == "cint16")
    type = ImagePixelType_cint16;
  else if (value == "cint32")
    type = ImagePixelType_cint32;
  else if (value == "cfloat")
    type = ImagePixelType_cfloat;
  else if (value == "cdouble")
    type = ImagePixelType_cdouble;
  else
    return false;
  return true;
}

void
OutputImageParameter
::InitializeWriters()
{
  ImageBaseType * image = m_Image.GetPointer();

  CAST_IMAGE_BASE( UInt8VectorImageType, image );
  CAST_IMAGE_BASE( Int16VectorImageType, image );
  CAST_IMAGE_BASE( UInt16VectorImageType, image );
  CAST_IMAGE_BASE( Int32VectorImageType, image );
  CAST_IMAGE_BASE( UInt32VectorImageType, image );

  CAST_IMAGE_BASE( FloatVectorImageType, image );
  CAST_IMAGE_BASE( DoubleVectorImageType, image );

  CAST_IMAGE_BASE( ComplexInt16VectorImageType, image );
  CAST_IMAGE_BASE( ComplexInt32VectorImageType, image );
  CAST_IMAGE_BASE( ComplexFloatVectorImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleVectorImageType, image );

  CAST_IMAGE_BASE( UInt8ImageType, image );
  CAST_IMAGE_BASE( Int16ImageType, image );
  CAST_IMAGE_BASE( UInt16ImageType, image );
  CAST_IMAGE_BASE( Int32ImageType, image );
  CAST_IMAGE_BASE( UInt32ImageType, image );

  CAST_IMAGE_BASE( FloatImageType, image );
  CAST_IMAGE_BASE( DoubleImageType, image );

  CAST_IMAGE_BASE( ComplexInt16ImageType, image );
  CAST_IMAGE_BASE( ComplexInt32ImageType, image );
  CAST_IMAGE_BASE( ComplexFloatImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleImageType, image );

  CAST_IMAGE_BASE( UInt8RGBImageType, image );
  CAST_IMAGE_BASE( UInt8RGBAImageType, image );

  itkExceptionMacro( "Unknown image-base type." );
}

namespace details
{

template< typename TOutputImage,
	  typename TInputImage >
struct Clamp
{
  using InputClampImageFilter =
    ClampImageFilter< TInputImage, DoubleVectorImageType >;

  using OutputClampImageFilter =
    ClampImageFilter< DoubleVectorImageType , TOutputImage >;

  Clamp( TInputImage * in ) :
    icif( InputClampImageFilter::New() ),
    ocif( OutputClampImageFilter::New() ),
    out( ocif->GetOutput() )
  {
    assert( in );

    icif->SetInput( in );

    ocif->SetInput( icif->GetOutput() );
  }

  typename InputClampImageFilter::Pointer icif;
  typename OutputClampImageFilter::Pointer ocif;
  TOutputImage * out;
};

template< typename TOutputImage >
struct Clamp< TOutputImage,
	      DoubleVectorImageType >
{
  using OutputClampImageFilter =
    ClampImageFilter< DoubleVectorImageType , TOutputImage >;

  Clamp( DoubleVectorImageType * in ) :
    ocif( OutputClampImageFilter::New() ),
    out( ocif->GetOutput() )
  {
    assert( in );

    ocif->SetInput( in );
  }

  itk::ProcessObject::Pointer icif;
  typename OutputClampImageFilter::Pointer ocif;
  TOutputImage * out;
};

template<>
struct Clamp< DoubleVectorImageType,
	      DoubleVectorImageType >
{
  Clamp( DoubleVectorImageType * in ) :
    out( in )
  {
    assert( in );
  }

  itk::ProcessObject::Pointer icif;
  itk::ProcessObject::Pointer ocif;
  DoubleVectorImageType * out;
};

} // namespace details.

template< typename TOutputImage,
	  typename TInputImage >
void
OutputImageParameter
::ClampAndWriteVectorImage( TInputImage * in )
{
  assert( in );
  assert( !m_FileName.empty() );

  // Use metaprogramming to choose optimized pipeline.
  details::Clamp< TOutputImage, TInputImage > clamp( in );

#ifdef OTB_USE_MPI

  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();

  if( mpiConfig->GetNbProcs() > 1 )
    {
    std::string extension =
      itksys::SystemTools::GetFilenameExtension( m_FileName );

    if(extension == ".vrt")
      {
      // Use the MPIVrtWriter

      auto vrtWriter =
	otb::MPIVrtWriter< TOutputImage >::New();

      vrtWriter->SetInput( clamp.out );
      vrtWriter->SetFileName( m_FileName );
      vrtWriter->SetAvailableRAM( m_RAMValue);

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = clamp.icif;
      m_OutputCaster = clamp.ocif;

      m_Writer = vrtWriter;

      return;
      }

#ifdef OTB_USE_SPTW

    else if (extension == ".tif")
      {
      // Use simple parallel tiff writer

      auto sptWriter =
	otb::SimpleParallelTiffWriter< TOutputImage >::New();

      sptWriter->SetFileName( m_FileName );
      sptWriter->SetInput( clamp.out );
      sptWriter->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = clamp.icif;
      m_OutputCaster = clamp.ocif;

      m_Writer = sptWriter;

      return;
      }

#endif // OTB_USE_SPTW

    else
      {
      itkGenericExceptionMacro(
	"File format "
	<< extension
	<< " not supported for parallel writing with MPI. Supported formats are "
	   ".vrt and .tif. Extended filenames are not supported."
      );
      }
    }

#endif // OTB_USE_MPI

  //
  // Use default OTB writer.

  auto writer = otb::ImageFileWriter< TOutputImage >::New();

  writer->SetFileName( m_FileName );
  writer->SetInput( clamp.out );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  // Change internal state only when everything has been setup
  // without raising exception.

  m_InputCaster = clamp.icif;
  m_OutputCaster = clamp.ocif;

  m_Writer = writer;
}

template< typename TInputImage >
void
OutputImageParameter
::SwitchInput( TInputImage * image )
{
  assert( image );

  switch( m_PixelType )
    {
    case ImagePixelType_uint8:
      ClampAndWriteVectorImage< UInt8VectorImageType >( image );
      break;

    case ImagePixelType_int16:
      ClampAndWriteVectorImage< Int16VectorImageType >( image );
      break;

    case ImagePixelType_uint16:
      ClampAndWriteVectorImage< UInt16VectorImageType >( image );
      break;

    case ImagePixelType_int32:

      ClampAndWriteVectorImage< Int32VectorImageType >( image );
      break;

    case ImagePixelType_uint32:
      ClampAndWriteVectorImage< UInt32VectorImageType >( image );
      break;

    case ImagePixelType_float:
      ClampAndWriteVectorImage< FloatVectorImageType >( image );
      break;

    case ImagePixelType_double:
      ClampAndWriteVectorImage< DoubleVectorImageType >( image );
      break;

    case ImagePixelType_cint16:
      ClampAndWriteVectorImage < ComplexInt16VectorImageType >( image );
      break;

    case ImagePixelType_cint32:
      ClampAndWriteVectorImage < ComplexInt32VectorImageType >( image );
      break;

    case ImagePixelType_cfloat:
      ClampAndWriteVectorImage< ComplexFloatVectorImageType >( image );
    break;

    case ImagePixelType_cdouble:
      ClampAndWriteVectorImage < ComplexDoubleVectorImageType >( image );
    break;

    default:
      assert( false && "Unexpected image-type." );
      break;
    }
}

void
OutputImageParameter::Write()
{
  m_Writer->Update();

  // Clean internal filters
  m_InputCaster = nullptr;
  m_OutputCaster = nullptr;

  m_Writer = nullptr;
}

itk::ProcessObject*
OutputImageParameter::GetWriter()
{
  return m_Writer;
}

ImageBaseType*
OutputImageParameter::GetValue( )
{
  return m_Image;
}

void
OutputImageParameter::SetValue(ImageBaseType* image)
{
  m_Image = image;
  SetActive(true);
}

bool
OutputImageParameter
::HasValue() const
{
  return !m_FileName.empty();
}

std::string
OutputImageParameter::CheckFileName(bool fixMissingExtension)
{
  std::string ret("");
  // Check that there is an ImageIO capable of writing the file
  otb::ExtendedFilenameToWriterOptions::Pointer filenameHelper =
    otb::ExtendedFilenameToWriterOptions::New();
  filenameHelper->SetExtendedFileName(this->GetFileName());
  std::string simpleFilename = filenameHelper->GetSimpleFileName();
  // TODO : check if simpleFilename is empty

  otb::ImageIOBase::Pointer imageIO =
    otb::ImageIOFactory::CreateImageIO(simpleFilename.c_str(),
                                       otb::ImageIOFactory::WriteMode);
  if(imageIO.IsNull())
    {
    // check for missing extension
    std::string outExt = itksys::SystemTools::GetFilenameLastExtension(simpleFilename);
    if (outExt.empty())
      {
      if (fixMissingExtension)
        {
        // try with .tif
        std::string fullFileName(this->GetFileName());
        std::string extendedPart = fullFileName.substr(simpleFilename.size());
        this->SetFileName(simpleFilename+std::string(".tif")+extendedPart);
        ret += std::string("no extension detected, using TIF as default.");
        }
      else
        {
        // TODO : call exception here?
        }
      }
    else
      {
      // TODO : call exception here?
      }
    }
  return ret;
}

// Specialization for UInt8RGBAImageType

template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBAImageType * img )
{
  assert( img );

  if( m_PixelType != ImagePixelType_uint8 )
     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");

  auto writer =
    otb::ImageFileWriter< UInt8RGBAImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

// Specialization for UInt8RGBImageType
template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBImageType * img )
{
  if( m_PixelType != ImagePixelType_uint8 )
    itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");

  auto writer = otb::ImageFileWriter< UInt8RGBImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

void OutputImageParameter::SetFileName (const char* filename)
{
  this->SetFileName(std::string(filename));
}

void OutputImageParameter::SetFileName (const std::string& filename)
{
  m_FileName = filename;
  SetActive(true);
}

}
}
<commit_msg>ENH: 1649: Factorized otb::Wrapper::ClampAndWriteVectorImage<>().<commit_after>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperOutputImageParameter.h"

#include "otbClampImageFilter.h"
#include "otbImageIOFactory.h"
#include "otbWrapperCastImage.h"

#ifdef OTB_USE_MPI
#  include "otbMPIConfig.h"
#  include "otbMPIVrtWriter.h"
#  ifdef OTB_USE_SPTW
#    include "otbSimpleParallelTiffWriter.h"
#  endif
#endif

#include "itksys/SystemTools.hxx"

#define CAST_IMAGE_BASE( T, image_base )		\
  {							\
    T * img = dynamic_cast< T * >( image_base );	\
							\
    if( img )						\
      {							\
      SwitchInput< T >( img );				\
							\
      return;						\
      }							\
  }

namespace otb
{
namespace Wrapper
{

// Declare specialisation for UInt8RGBAImageType
template<>
void OutputImageParameter::SwitchInput(UInt8RGBAImageType * );

// Declare specialisation for UInt8RGBImageType
template <>
void OutputImageParameter::SwitchInput( UInt8RGBImageType * );

OutputImageParameter::OutputImageParameter()
  : m_PixelType(ImagePixelType_float),
    m_DefaultPixelType(ImagePixelType_float),
    m_RAMValue(0)
{
  SetName("Output Image");
  SetKey("out");
}

OutputImageParameter::~OutputImageParameter()
{
}

std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
{
  // TODO: Could be replaced by constant static string array e.g.:
  // return PIXEL_TYPE_NAME[ type ];

  std::string ret;
  switch(type)
    {
    case ImagePixelType_uint8:
      {
      ret = "uint8";
      break;
      }
    case ImagePixelType_int16:
      {
      ret = "int16";
      break;
      }
    case ImagePixelType_uint16:
      {
      ret = "uint16";
      break;
      }
    case ImagePixelType_int32:
      {
      ret = "int32";
      break;
      }
    case ImagePixelType_uint32:
      {
      ret = "uint32";
      break;
      }
    case ImagePixelType_float:
      {
      ret = "float";
      break;
      }
    case ImagePixelType_double:
      {
      ret = "double";
      break;
      }
    case ImagePixelType_cint16:
      {
      ret = "cint16";
      break;
      }
    case ImagePixelType_cint32:
      {
      ret = "cint32";
      break;
      }
    case ImagePixelType_cfloat:
      {
      ret = "cfloat";
      break;
      }
    case ImagePixelType_cdouble:
      {
      ret = "cdouble";
      break;
      }
    }
  return ret;
}

bool
OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePixelType &type)
{
  // TODO: Could be replaced std::find_if() in constant static string
  // array (see ::ConvertPixelTypeToString().

  if (value == "uint8")
    type = ImagePixelType_uint8;
  else if (value == "int16")
    type = ImagePixelType_int16;
  else if (value == "uint16")
    type = ImagePixelType_uint16;
  else if (value == "int32")
    type = ImagePixelType_int32;
  else if (value == "uint32")
    type = ImagePixelType_uint32;
  else if (value == "float")
    type = ImagePixelType_float;
  else if (value == "double")
    type = ImagePixelType_double;
  else if (value == "cint16")
    type = ImagePixelType_cint16;
  else if (value == "cint32")
    type = ImagePixelType_cint32;
  else if (value == "cfloat")
    type = ImagePixelType_cfloat;
  else if (value == "cdouble")
    type = ImagePixelType_cdouble;
  else
    return false;
  return true;
}

void
OutputImageParameter
::InitializeWriters()
{
  ImageBaseType * image = m_Image.GetPointer();

  CAST_IMAGE_BASE( UInt8VectorImageType, image );
  CAST_IMAGE_BASE( Int16VectorImageType, image );
  CAST_IMAGE_BASE( UInt16VectorImageType, image );
  CAST_IMAGE_BASE( Int32VectorImageType, image );
  CAST_IMAGE_BASE( UInt32VectorImageType, image );

  CAST_IMAGE_BASE( FloatVectorImageType, image );
  CAST_IMAGE_BASE( DoubleVectorImageType, image );

  CAST_IMAGE_BASE( ComplexInt16VectorImageType, image );
  CAST_IMAGE_BASE( ComplexInt32VectorImageType, image );
  CAST_IMAGE_BASE( ComplexFloatVectorImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleVectorImageType, image );

  CAST_IMAGE_BASE( UInt8ImageType, image );
  CAST_IMAGE_BASE( Int16ImageType, image );
  CAST_IMAGE_BASE( UInt16ImageType, image );
  CAST_IMAGE_BASE( Int32ImageType, image );
  CAST_IMAGE_BASE( UInt32ImageType, image );

  CAST_IMAGE_BASE( FloatImageType, image );
  CAST_IMAGE_BASE( DoubleImageType, image );

  CAST_IMAGE_BASE( ComplexInt16ImageType, image );
  CAST_IMAGE_BASE( ComplexInt32ImageType, image );
  CAST_IMAGE_BASE( ComplexFloatImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleImageType, image );

  CAST_IMAGE_BASE( UInt8RGBImageType, image );
  CAST_IMAGE_BASE( UInt8RGBAImageType, image );

  itkExceptionMacro( "Unknown image-base type." );
}

template< typename TOutputImage,
	  typename TInputImage >
void
OutputImageParameter
::ClampAndWriteVectorImage( TInputImage * in )
{
  assert( in );
  assert( !m_FileName.empty() );

  // Use metaprogramming to choose optimized pipeline.
  details::CastImage< TOutputImage, TInputImage > clamp( in );

#ifdef OTB_USE_MPI

  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();

  if( mpiConfig->GetNbProcs() > 1 )
    {
    std::string extension =
      itksys::SystemTools::GetFilenameExtension( m_FileName );

    if(extension == ".vrt")
      {
      // Use the MPIVrtWriter

      auto vrtWriter =
	otb::MPIVrtWriter< TOutputImage >::New();

      vrtWriter->SetInput( clamp.out );
      vrtWriter->SetFileName( m_FileName );
      vrtWriter->SetAvailableRAM( m_RAMValue);

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = clamp.icif;
      m_OutputCaster = clamp.ocif;

      m_Writer = vrtWriter;

      return;
      }

#ifdef OTB_USE_SPTW

    else if (extension == ".tif")
      {
      // Use simple parallel tiff writer

      auto sptWriter =
	otb::SimpleParallelTiffWriter< TOutputImage >::New();

      sptWriter->SetFileName( m_FileName );
      sptWriter->SetInput( clamp.out );
      sptWriter->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = clamp.icif;
      m_OutputCaster = clamp.ocif;

      m_Writer = sptWriter;

      return;
      }

#endif // OTB_USE_SPTW

    else
      {
      itkGenericExceptionMacro(
	"File format "
	<< extension
	<< " not supported for parallel writing with MPI. Supported formats are "
	   ".vrt and .tif. Extended filenames are not supported."
      );
      }
    }

#endif // OTB_USE_MPI

  //
  // Use default OTB writer.

  auto writer = otb::ImageFileWriter< TOutputImage >::New();

  writer->SetFileName( m_FileName );
  writer->SetInput( clamp.out );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  // Change internal state only when everything has been setup
  // without raising exception.

  m_InputCaster = clamp.icif;
  m_OutputCaster = clamp.ocif;

  m_Writer = writer;
}

template< typename TInputImage >
void
OutputImageParameter
::SwitchInput( TInputImage * image )
{
  assert( image );

  switch( m_PixelType )
    {
    case ImagePixelType_uint8:
      ClampAndWriteVectorImage< UInt8VectorImageType >( image );
      break;

    case ImagePixelType_int16:
      ClampAndWriteVectorImage< Int16VectorImageType >( image );
      break;

    case ImagePixelType_uint16:
      ClampAndWriteVectorImage< UInt16VectorImageType >( image );
      break;

    case ImagePixelType_int32:

      ClampAndWriteVectorImage< Int32VectorImageType >( image );
      break;

    case ImagePixelType_uint32:
      ClampAndWriteVectorImage< UInt32VectorImageType >( image );
      break;

    case ImagePixelType_float:
      ClampAndWriteVectorImage< FloatVectorImageType >( image );
      break;

    case ImagePixelType_double:
      ClampAndWriteVectorImage< DoubleVectorImageType >( image );
      break;

    case ImagePixelType_cint16:
      ClampAndWriteVectorImage < ComplexInt16VectorImageType >( image );
      break;

    case ImagePixelType_cint32:
      ClampAndWriteVectorImage < ComplexInt32VectorImageType >( image );
      break;

    case ImagePixelType_cfloat:
      ClampAndWriteVectorImage< ComplexFloatVectorImageType >( image );
    break;

    case ImagePixelType_cdouble:
      ClampAndWriteVectorImage < ComplexDoubleVectorImageType >( image );
    break;

    default:
      assert( false && "Unexpected image-type." );
      break;
    }
}

void
OutputImageParameter::Write()
{
  m_Writer->Update();

  // Clean internal filters
  m_InputCaster = nullptr;
  m_OutputCaster = nullptr;

  m_Writer = nullptr;
}

itk::ProcessObject*
OutputImageParameter::GetWriter()
{
  return m_Writer;
}

ImageBaseType*
OutputImageParameter::GetValue( )
{
  return m_Image;
}

void
OutputImageParameter::SetValue(ImageBaseType* image)
{
  m_Image = image;
  SetActive(true);
}

bool
OutputImageParameter
::HasValue() const
{
  return !m_FileName.empty();
}

std::string
OutputImageParameter::CheckFileName(bool fixMissingExtension)
{
  std::string ret("");
  // Check that there is an ImageIO capable of writing the file
  otb::ExtendedFilenameToWriterOptions::Pointer filenameHelper =
    otb::ExtendedFilenameToWriterOptions::New();
  filenameHelper->SetExtendedFileName(this->GetFileName());
  std::string simpleFilename = filenameHelper->GetSimpleFileName();
  // TODO : check if simpleFilename is empty

  otb::ImageIOBase::Pointer imageIO =
    otb::ImageIOFactory::CreateImageIO(simpleFilename.c_str(),
                                       otb::ImageIOFactory::WriteMode);
  if(imageIO.IsNull())
    {
    // check for missing extension
    std::string outExt = itksys::SystemTools::GetFilenameLastExtension(simpleFilename);
    if (outExt.empty())
      {
      if (fixMissingExtension)
        {
        // try with .tif
        std::string fullFileName(this->GetFileName());
        std::string extendedPart = fullFileName.substr(simpleFilename.size());
        this->SetFileName(simpleFilename+std::string(".tif")+extendedPart);
        ret += std::string("no extension detected, using TIF as default.");
        }
      else
        {
        // TODO : call exception here?
        }
      }
    else
      {
      // TODO : call exception here?
      }
    }
  return ret;
}

// Specialization for UInt8RGBAImageType

template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBAImageType * img )
{
  assert( img );

  if( m_PixelType != ImagePixelType_uint8 )
     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");

  auto writer =
    otb::ImageFileWriter< UInt8RGBAImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

// Specialization for UInt8RGBImageType
template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBImageType * img )
{
  if( m_PixelType != ImagePixelType_uint8 )
    itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");

  auto writer = otb::ImageFileWriter< UInt8RGBImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

void OutputImageParameter::SetFileName (const char* filename)
{
  this->SetFileName(std::string(filename));
}

void OutputImageParameter::SetFileName (const std::string& filename)
{
  m_FileName = filename;
  SetActive(true);
}

}
}
<|endoftext|>