<commit_before>// @(#)root/base:$Name:  $:$Id: TStorage.cxx,v 1.9 2002/02/22 09:37:29 brun Exp $
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TMath.h"
#include "TString.h"
#include "TVirtualMutex.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#ifndef NOCINT
#define G__PVOID (-1)
#ifndef WIN32
extern long G__globalvarpointer;
#else
#include "G__ci.h"
#endif
#endif

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

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

static const char *spaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   memStatistics;
static Int_t    allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t    allocatedTotal, freedTotal;
static void   **traceArray = 0;
static Int_t    traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!memStatistics) return;

   if ((Int_t)size == memSize) {
      if (traceIndex == memIndex)
         Fatal("EnterStat", "trapped allocation %d", memIndex);

      if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);

      if (traceIndex >= traceCapacity) {
         traceCapacity = traceCapacity*2;
         traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
      }
      traceArray[traceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      allocated[kObjMaxSize-1]++;
   else
      allocated[size]++;
   allocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!memStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == memSize) {
      for (int i = 0; i < traceIndex; i++)
         if (traceArray[i] == vp) {
            traceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      freed[kObjMaxSize-1]++;
   else
      freed[size]++;
   freedTotal += size;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   R__LOCKGUARD(gCINTMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
      vp = ::operator new(size);
      if (vp == 0)
         Fatal(where, spaceErr);
      return vp;
   }

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   memmove(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   R__LOCKGUARD(gCINTMutex);

   if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
     vp = ::operator new(size);
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of chars. Size and oldsize are
   // in number of chars.

   R__LOCKGUARD(gCINTMutex);

   static const char *where = "TStorage::ReAllocChar";

   char *vp;
   if (ovp == 0) {
     vp = new char[size];
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new char[size];
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of integers. Size and oldsize are
   // number of integers (not number of bytes).

   R__LOCKGUARD(gCINTMutex);

   static const char *where = "TStorage::ReAllocInt";

   Int_t *vp;
   if (ovp == 0) {
     vp = new Int_t[size];
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new Int_t[size];
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize*sizeof(Int_t));
      memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
   } else
      memcpy(vp, ovp, size*sizeof(Int_t));
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   R__LOCKGUARD(gCINTMutex);

   ULong_t space;

#ifndef NOCINT
   // to handle new with placement called via CINT
#ifndef WIN32
   if (G__globalvarpointer != G__PVOID) {
      space = G__globalvarpointer;
      G__globalvarpointer = G__PVOID;
   } else
#else
   space = G__getgvp();
   if ((long)space != G__PVOID) {
      G__setgvp(G__PVOID);
   } else
#endif
#endif
   space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

   R__LOCKGUARD(gCINTMutex);

#ifndef NOCINT
   // to handle delete with placement called via CINT
#ifndef WIN32
   if ((long)vp == G__globalvarpointer && G__globalvarpointer != G__PVOID)
      return;
#else
   long gvp = G__getgvp();
   if ((long)vp == gvp && gvp != G__PVOID)
      return;
#endif
#endif
   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

   R__LOCKGUARD(gCINTMutex);

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!memStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (allocated[i] != freed[i])
      //if (allocated[i])
         Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
                allocated[i]-freed[i]);

   if (allocatedTotal != freedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", allocatedTotal, freedTotal,
              allocatedTotal-freedTotal);
   }

   if (memSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < traceIndex; i++)
         if (traceArray[i])
            Printf("block %d of size %d not freed", i, memSize);
   }
   Printf("================================================");
   Printf("");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   memSize       = size;
   memIndex      = ix;
   memStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   return fgFreeHook;
}

#endif
<commit_msg>in ReAlloc() use always operator new[] and operator delete[] since we will use ReAlloc() only to resize arrays. By Charles Lane.<commit_after>// @(#)root/base:$Name:  $:$Id: TStorage.cxx,v 1.10 2002/02/23 16:01:44 rdm Exp $
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TMath.h"
#include "TString.h"
#include "TVirtualMutex.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#ifndef NOCINT
#define G__PVOID (-1)
#ifndef WIN32
extern long G__globalvarpointer;
#else
#include "G__ci.h"
#endif
#endif

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

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

static const char *spaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   memStatistics;
static Int_t    allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t    allocatedTotal, freedTotal;
static void   **traceArray = 0;
static Int_t    traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!memStatistics) return;

   if ((Int_t)size == memSize) {
      if (traceIndex == memIndex)
         Fatal("EnterStat", "trapped allocation %d", memIndex);

      if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);

      if (traceIndex >= traceCapacity) {
         traceCapacity = traceCapacity*2;
         traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
      }
      traceArray[traceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      allocated[kObjMaxSize-1]++;
   else
      allocated[size]++;
   allocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!memStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == memSize) {
      for (int i = 0; i < traceIndex; i++)
         if (traceArray[i] == vp) {
            traceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      freed[kObjMaxSize-1]++;
   else
      freed[size]++;
   freedTotal += size;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   R__LOCKGUARD(gCINTMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
      vp = ::operator new[](size);
      if (vp == 0)
         Fatal(where, spaceErr);
      return vp;
   }

   vp = ::operator new[](size);
   if (vp == 0)
      Fatal(where, spaceErr);
   memmove(vp, ovp, size);
   ::operator delete[](ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   R__LOCKGUARD(gCINTMutex);

   if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
     vp = ::operator new[](size);
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = ::operator new[](size);
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   ::operator delete[](ovp);
   return vp;
}

//______________________________________________________________________________
char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of chars. Size and oldsize are
   // in number of chars.

   R__LOCKGUARD(gCINTMutex);

   static const char *where = "TStorage::ReAllocChar";

   char *vp;
   if (ovp == 0) {
     vp = new char[size];
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new char[size];
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of integers. Size and oldsize are
   // number of integers (not number of bytes).

   R__LOCKGUARD(gCINTMutex);

   static const char *where = "TStorage::ReAllocInt";

   Int_t *vp;
   if (ovp == 0) {
     vp = new Int_t[size];
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new Int_t[size];
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize*sizeof(Int_t));
      memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
   } else
      memcpy(vp, ovp, size*sizeof(Int_t));
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   R__LOCKGUARD(gCINTMutex);

   ULong_t space;

#ifndef NOCINT
   // to handle new with placement called via CINT
#ifndef WIN32
   if (G__globalvarpointer != G__PVOID) {
      space = G__globalvarpointer;
      G__globalvarpointer = G__PVOID;
   } else
#else
   space = G__getgvp();
   if ((long)space != G__PVOID) {
      G__setgvp(G__PVOID);
   } else
#endif
#endif
   space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

   R__LOCKGUARD(gCINTMutex);

#ifndef NOCINT
   // to handle delete with placement called via CINT
#ifndef WIN32
   if ((long)vp == G__globalvarpointer && G__globalvarpointer != G__PVOID)
      return;
#else
   long gvp = G__getgvp();
   if ((long)vp == gvp && gvp != G__PVOID)
      return;
#endif
#endif
   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

   R__LOCKGUARD(gCINTMutex);

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!memStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (allocated[i] != freed[i])
      //if (allocated[i])
         Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
                allocated[i]-freed[i]);

   if (allocatedTotal != freedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", allocatedTotal, freedTotal,
              allocatedTotal-freedTotal);
   }

   if (memSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < traceIndex; i++)
         if (traceArray[i])
            Printf("block %d of size %d not freed", i, memSize);
   }
   Printf("================================================");
   Printf("");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   memSize       = size;
   memIndex      = ix;
   memStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   return fgFreeHook;
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2019 The Open GEE Contributors
 *
 * 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 "AssetVersion.h"
#include "gee_version.h"
#include "StateUpdater.h"

#include <algorithm>
#include <assert.h>
#include <gtest/gtest.h>
#include <map>
#include <string>

using namespace std;

// All refs must end with "?version=X" or the calls to AssetVersionRef::Bind
// will try to load assets from disk. For simplicity, we force everything to
// be version 1. When you write additional tests you have to remember to call
// this function when working directly with the state updater.
const string SUFFIX = "?version=1";
AssetKey fix(AssetKey ref) {
  return ref.toString() + SUFFIX;
}

class MockVersion : public AssetVersionImpl {
  public:
    bool stateSet;
    vector<AssetKey> dependents;

    MockVersion() : stateSet(false) {
      type = AssetDefs::Imagery;
      state = AssetDefs::New;
    }
    MockVersion(const AssetKey & ref) : MockVersion() {
      name = fix(ref);
    }
    MockVersion(const MockVersion & that) : MockVersion() {
      name = that.name; // Don't add the suffix - the other MockVersion already did
    }
    void DependentChildren(vector<SharedString> & d) const {
      for(auto dependent : dependents) {
        d.push_back(dependent);
      }
    }
    bool NeedComputeState() const { return true; }
    AssetDefs::State CalcStateByInputsAndChildren(
        AssetDefs::State stateByInputs,
        AssetDefs::State stateByChildren,
        bool blockersAreOffline,
        uint32 numWaitingFor) const
    {
      return AssetDefs::New;
    }
    void SetMyStateOnly(AssetDefs::State newState, bool sendNotifications) {
      stateSet = true;
    }

    // Not used - only included to make MockVersion non-virtual
    string PluginName(void) const { return string(); }
    void GetOutputFilenames(vector<string> &) const {}
    string GetOutputFilename(uint) const { return string(); }
};

using VersionMap = map<AssetKey, shared_ptr<MockVersion>>;

class MockStorageManager : public StorageManagerInterface<AssetVersionImpl> {
  private:
    VersionMap versions;
    PointerType GetFromMap(const AssetKey & ref) {
      auto versionIter = versions.find(ref);
      if (versionIter != versions.end()) {
        auto version = dynamic_pointer_cast<AssetVersionImpl>(versionIter->second);
        assert(version);
        return version;
      }
      assert(false);
      return nullptr;
    }
  public:
    void AddVersion(const AssetKey & key, const MockVersion & v) {
      versions[key] = make_shared<MockVersion>(v);
    }
    virtual AssetHandle<const AssetVersionImpl> Get(const AssetKey &ref) {
      return AssetHandle<const AssetVersionImpl>(GetFromMap(ref), nullptr);
    }
    virtual AssetHandle<AssetVersionImpl> GetMutable(const AssetKey &ref) {
      return AssetHandle<AssetVersionImpl>(GetFromMap(ref), nullptr);
    }
};

class StateUpdaterTest : public testing::Test {
  protected:
   MockStorageManager sm;
   StateUpdater updater;
  public:
   StateUpdaterTest() : sm(), updater(&sm) {}
};

void SetVersions(MockStorageManager & sm, vector<MockVersion> versions) {
  for (auto & version: versions) {
    sm.AddVersion(version.name, version);
  }
}

// This is bad because technically the object could be deleted before you use
// it, but it works for unit tests.
AssetHandle<const MockVersion> GetVersion(MockStorageManager & sm, const AssetKey & key) {
  return sm.Get(fix(key));
}

void SetParentChild(MockStorageManager & sm, AssetKey parent, AssetKey child) {
  parent = fix(parent);
  child = fix(child);
  sm.GetMutable(parent)->children.push_back(child);
  sm.GetMutable(child)->parents.push_back(parent);
}

void SetListenerInput(MockStorageManager & sm, AssetKey listener, AssetKey input) {
  listener = fix(listener);
  input = fix(input);
  sm.GetMutable(listener)->inputs.push_back(input);
  sm.GetMutable(input)->listeners.push_back(listener);
}

void SetDependent(MockStorageManager & sm, AssetKey dependee, AssetKey dependent) {
  dependee = fix(dependee);
  dependent = fix(dependent);
  AssetHandle<MockVersion> dependeeHandle = sm.GetMutable(dependee);
  dependeeHandle->dependents.push_back(dependent);
}

void GetBigTree(MockStorageManager & sm) {
  SetVersions(sm,
              {
                MockVersion("gp"),
                MockVersion("p1"),
                MockVersion("p2"),
                MockVersion("gpi"),
                MockVersion("pi1"),
                MockVersion("c1"),
                MockVersion("c2"),
                MockVersion("c3"),
                MockVersion("c4"),
                MockVersion("ci1"),
                MockVersion("ci2"),
                MockVersion("ci3")
              });
  SetParentChild(sm, "gp", "p1");
  SetParentChild(sm, "gp", "p2");
  SetListenerInput(sm, "gp", "gpi");
  SetListenerInput(sm, "p1", "pi1");
  SetParentChild(sm, "p1", "c1");
  SetParentChild(sm, "p1", "c2");
  SetParentChild(sm, "p2", "c3");
  SetParentChild(sm, "p2", "c4");
  SetListenerInput(sm, "c2", "ci3");
  SetListenerInput(sm, "c4", "ci1");
  SetListenerInput(sm, "c4", "ci2");
  SetDependent(sm, "gp", "p1");
  SetDependent(sm, "gp", "c2");
  SetDependent(sm, "p1", "c1");
}

TEST_F(StateUpdaterTest, SetStateSingleVersion) {
  AssetKey ref1 = "test1";
  AssetKey ref2 = "test2";
  AssetKey ref3 = "test3";
  SetVersions(sm, {MockVersion(ref1), MockVersion(ref2), MockVersion(ref3)});
  updater.SetStateForRefAndDependents(fix(ref1), AssetDefs::Bad, [](AssetDefs::State) { return true; });
  ASSERT_TRUE(GetVersion(sm, ref1)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref2)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref3)->stateSet);
  updater.SetStateForRefAndDependents(fix(ref2), AssetDefs::Bad, [](AssetDefs::State) { return false; });
  ASSERT_FALSE(GetVersion(sm, ref2)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref3)->stateSet);
}

TEST_F(StateUpdaterTest, SetStateMultipleVersions) {
  GetBigTree(sm);
  updater.SetStateForRefAndDependents(fix("gp"), AssetDefs::Canceled, [](AssetDefs::State) {return true; });

  ASSERT_TRUE(GetVersion(sm, "gp")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "p1")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "c1")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "c2")->stateSet);

  ASSERT_FALSE(GetVersion(sm, "gpi")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "pi1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c3")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c4")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci2")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci3")->stateSet);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc,argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Check that assets aren't made mutable if it's unnecessary<commit_after>/*
 * Copyright 2019 The Open GEE Contributors
 *
 * 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 "AssetVersion.h"
#include "gee_version.h"
#include "StateUpdater.h"

#include <algorithm>
#include <assert.h>
#include <gtest/gtest.h>
#include <map>
#include <string>

using namespace std;

// All refs must end with "?version=X" or the calls to AssetVersionRef::Bind
// will try to load assets from disk. For simplicity, we force everything to
// be version 1. When you write additional tests you have to remember to call
// this function when working directly with the state updater.
const string SUFFIX = "?version=1";
AssetKey fix(AssetKey ref) {
  return ref.toString() + SUFFIX;
}

class MockVersion : public AssetVersionImpl {
  public:
    bool stateSet;
    bool loadedMutable;
    vector<AssetKey> dependents;

    MockVersion() : stateSet(false), loadedMutable(false) {
      type = AssetDefs::Imagery;
      state = AssetDefs::Blocked;
    }
    MockVersion(const AssetKey & ref) : MockVersion() {
      name = fix(ref);
    }
    MockVersion(const MockVersion & that) : MockVersion() {
      name = that.name; // Don't add the suffix - the other MockVersion already did
    }
    void DependentChildren(vector<SharedString> & d) const {
      for(auto dependent : dependents) {
        d.push_back(dependent);
      }
    }
    bool NeedComputeState() const { return true; }
    AssetDefs::State CalcStateByInputsAndChildren(
        AssetDefs::State stateByInputs,
        AssetDefs::State stateByChildren,
        bool blockersAreOffline,
        uint32 numWaitingFor) const
    {
      return AssetDefs::InProgress;
    }
    void SetMyStateOnly(AssetDefs::State newState, bool sendNotifications) {
      stateSet = true;
    }

    // Not used - only included to make MockVersion non-virtual
    string PluginName(void) const { return string(); }
    void GetOutputFilenames(vector<string> &) const {}
    string GetOutputFilename(uint) const { return string(); }
};

using VersionMap = map<AssetKey, shared_ptr<MockVersion>>;

class MockStorageManager : public StorageManagerInterface<AssetVersionImpl> {
  private:
    VersionMap versions;
    PointerType GetFromMap(const AssetKey & ref) {
      auto versionIter = versions.find(ref);
      if (versionIter != versions.end()) {
        auto version = dynamic_pointer_cast<AssetVersionImpl>(versionIter->second);
        assert(version);
        return version;
      }
      assert(false);
      return nullptr;
    }
  public:
    void AddVersion(const AssetKey & key, const MockVersion & v) {
      versions[key] = make_shared<MockVersion>(v);
    }
    virtual AssetHandle<const AssetVersionImpl> Get(const AssetKey &ref) {
      return AssetHandle<const AssetVersionImpl>(GetFromMap(ref), nullptr);
    }
    virtual AssetHandle<AssetVersionImpl> GetMutable(const AssetKey &ref) {
      auto handle = AssetHandle<AssetVersionImpl>(GetFromMap(ref), nullptr);
      dynamic_cast<MockVersion*>(handle.operator->())->loadedMutable = true;
      return handle;
    }
    void ResetLoadedMutable() {
      for (auto & v : versions) {
        v.second->loadedMutable = false;
      }
    }
};

class StateUpdaterTest : public testing::Test {
  protected:
   MockStorageManager sm;
   StateUpdater updater;
  public:
   StateUpdaterTest() : sm(), updater(&sm) {}
};

void SetVersions(MockStorageManager & sm, vector<MockVersion> versions) {
  for (auto & version: versions) {
    sm.AddVersion(version.name, version);
  }
}

// This is bad because technically the object could be deleted before you use
// it, but it works for unit tests.
AssetHandle<const MockVersion> GetVersion(MockStorageManager & sm, const AssetKey & key) {
  return sm.Get(fix(key));
}

void SetParentChild(MockStorageManager & sm, AssetKey parent, AssetKey child) {
  parent = fix(parent);
  child = fix(child);
  sm.GetMutable(parent)->children.push_back(child);
  sm.GetMutable(child)->parents.push_back(parent);
}

void SetListenerInput(MockStorageManager & sm, AssetKey listener, AssetKey input) {
  listener = fix(listener);
  input = fix(input);
  sm.GetMutable(listener)->inputs.push_back(input);
  sm.GetMutable(input)->listeners.push_back(listener);
}

void SetDependent(MockStorageManager & sm, AssetKey dependee, AssetKey dependent) {
  dependee = fix(dependee);
  dependent = fix(dependent);
  AssetHandle<MockVersion> dependeeHandle = sm.GetMutable(dependee);
  dependeeHandle->dependents.push_back(dependent);
}

void GetBigTree(MockStorageManager & sm) {
  SetVersions(sm,
              {
                MockVersion("gp"),
                MockVersion("p1"),
                MockVersion("p2"),
                MockVersion("gpi"),
                MockVersion("pi1"),
                MockVersion("c1"),
                MockVersion("c2"),
                MockVersion("c3"),
                MockVersion("c4"),
                MockVersion("ci1"),
                MockVersion("ci2"),
                MockVersion("ci3")
              });
  SetParentChild(sm, "gp", "p1");
  SetParentChild(sm, "gp", "p2");
  SetListenerInput(sm, "gp", "gpi");
  SetListenerInput(sm, "p1", "pi1");
  SetParentChild(sm, "p1", "c1");
  SetParentChild(sm, "p1", "c2");
  SetParentChild(sm, "p2", "c3");
  SetParentChild(sm, "p2", "c4");
  SetListenerInput(sm, "c2", "ci3");
  SetListenerInput(sm, "c4", "ci1");
  SetListenerInput(sm, "c4", "ci2");
  SetDependent(sm, "gp", "p1");
  SetDependent(sm, "gp", "c2");
  SetDependent(sm, "p1", "c1");
}

TEST_F(StateUpdaterTest, SetStateSingleVersion) {
  AssetKey ref1 = "test1";
  AssetKey ref2 = "test2";
  AssetKey ref3 = "test3";
  SetVersions(sm, {MockVersion(ref1), MockVersion(ref2), MockVersion(ref3)});
  updater.SetStateForRefAndDependents(fix(ref1), AssetDefs::Bad, [](AssetDefs::State) { return true; });
  ASSERT_TRUE(GetVersion(sm, ref1)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref2)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref3)->stateSet);
  updater.SetStateForRefAndDependents(fix(ref2), AssetDefs::Bad, [](AssetDefs::State) { return false; });
  ASSERT_FALSE(GetVersion(sm, ref2)->stateSet);
  ASSERT_FALSE(GetVersion(sm, ref3)->stateSet);
}

TEST_F(StateUpdaterTest, SetStateMultipleVersions) {
  GetBigTree(sm);
  updater.SetStateForRefAndDependents(fix("gp"), AssetDefs::Canceled, [](AssetDefs::State) {return true; });

  ASSERT_TRUE(GetVersion(sm, "gp")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "p1")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "c1")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "c2")->stateSet);

  ASSERT_FALSE(GetVersion(sm, "gpi")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "pi1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c3")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c4")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci2")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci3")->stateSet);
}

TEST_F(StateUpdaterTest, SetStateMultipleVersionsFromChild) {
  GetBigTree(sm);
  sm.ResetLoadedMutable();
  updater.SetStateForRefAndDependents(fix("p1"), AssetDefs::Canceled, [](AssetDefs::State) {return true; });

  ASSERT_TRUE(GetVersion(sm, "p1")->stateSet);
  ASSERT_TRUE(GetVersion(sm, "c1")->stateSet);

  ASSERT_FALSE(GetVersion(sm, "gp")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "gpi")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "pi1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c2")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c3")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "c4")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci1")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci2")->stateSet);
  ASSERT_FALSE(GetVersion(sm, "ci3")->stateSet);

  ASSERT_TRUE(GetVersion(sm, "p1")->loadedMutable);
  ASSERT_TRUE(GetVersion(sm, "c1")->loadedMutable);

  ASSERT_FALSE(GetVersion(sm, "gp")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "gpi")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "pi1")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "c2")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "c3")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "c4")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "ci1")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "ci2")->loadedMutable);
  ASSERT_FALSE(GetVersion(sm, "ci3")->loadedMutable);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc,argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before><commit_msg>fix for fdo#64078<commit_after><|endoftext|>


<commit_before>#ifndef __FASTX_PARSER__
#define __FASTX_PARSER__

#include "fcntl.h"
#include "unistd.h"
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>

extern "C" {
#include "kseq.h"
}

#include "concurrentqueue.h"

#ifndef __FASTX_PARSER_PRECXX14_MAKE_UNIQUE__
#define __FASTX_PARSER_PRECXX14_MAKE_UNIQUE__

#if __cplusplus >= 201402L
#include <memory>
using std::make_unique
#else

#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>

template <class T> struct _Unique_if {
  using _Single_object = std::unique_ptr<T>;
};

template <class T> struct _Unique_if<T[]> {
  using _Unknown_bound = std::unique_ptr<T[]>;
};

template <class T, size_t N> struct _Unique_if<T[N]> {
  using _Known_bound = void;
};

template <class T, class... Args>
typename _Unique_if<T>::_Single_object make_unique(Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <class T>
typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) {
  using U = typename std::remove_extent<T>::type;
  return std::unique_ptr<T>(new U[n]());
}

template <class T, class... Args>
typename _Unique_if<T>::_Known_bound make_unique(Args&&...) = delete;

#endif // C++11
#endif //__FASTX_PARSER_PRECXX14_MAKE_UNIQUE__

namespace fastx_parser {
struct ReadSeq {
    std::string seq;
    std::string name;
    ~ReadSeq() {}
};

struct ReadPair {
  ReadSeq first;
  ReadSeq second;
};

template <typename T> class ReadChunk {
public:
  ReadChunk(size_t want) : group_(want), want_(want), have_(want) {}
  inline void have(size_t num) { have_ = num; }
  inline size_t size() { return have_; }
  inline size_t want() const { return want_; }
  T& operator[](size_t i) { return group_[i]; }
  typename std::vector<T>::iterator begin() { return group_.begin(); }
  typename std::vector<T>::iterator end() { return group_.begin() + have_; }

private:
  std::vector<T> group_;
  size_t want_;
  size_t have_;
};

template <typename T> class ReadGroup {
public:
  ReadGroup(moodycamel::ProducerToken&& pt, moodycamel::ConsumerToken&& ct)
      : pt_(std::move(pt)), ct_(std::move(ct)) {}
  moodycamel::ConsumerToken& consumerToken() { return ct_; }
  moodycamel::ProducerToken& producerToken() { return pt_; }
  // get a reference to the chunk this ReadGroup owns
  std::unique_ptr<ReadChunk<T>>& chunkPtr() { return chunk_; }
  // get a *moveable* reference to the chunk this ReadGroup owns
  std::unique_ptr<ReadChunk<T>>&& takeChunkPtr() { return std::move(chunk_); }
  inline void have(size_t num) { chunk_->have(num); }
  inline size_t size() { return chunk_->size(); }
  inline size_t want() const { return chunk_->want(); }
  T& operator[](size_t i) { return (*chunk_)[i]; }
  typename std::vector<T>::iterator begin() { return chunk_->begin(); }
  typename std::vector<T>::iterator end() {
    return chunk_->begin() + chunk_->size();
  }
  void setChunkEmpty() { chunk_.release(); }
  bool empty() const { return chunk_.get() == nullptr; }

private:
  std::unique_ptr<ReadChunk<T>> chunk_{nullptr};
  moodycamel::ProducerToken pt_;
  moodycamel::ConsumerToken ct_;
};

template <typename T> class FastxParser {
public:
  FastxParser(std::vector<std::string> files, uint32_t numConsumers,
              uint32_t numParsers = 1, uint32_t chunkSize = 1000);

  FastxParser(std::vector<std::string> files, std::vector<std::string> files2,
              uint32_t numConsumers, uint32_t numParsers = 1,
              uint32_t chunkSize = 1000);

  ~FastxParser();
  bool start();
  bool stop();
  ReadGroup<T> getReadGroup();
  bool refill(ReadGroup<T>& rg);
  void finishedWithGroup(ReadGroup<T>& s);

private:
  moodycamel::ProducerToken getProducerToken_();
  moodycamel::ConsumerToken getConsumerToken_();

  std::vector<std::string> inputStreams_;
  std::vector<std::string> inputStreams2_;
  uint32_t numParsers_;
  std::atomic<uint32_t> numParsing_;

  // NOTE: Would like to use std::future<int> here instead, but that
  // solution doesn't seem to work.  It's unclear exactly why
  // see (https://twitter.com/nomad421/status/917748383321817088)
  std::vector<std::unique_ptr<std::thread>> parsingThreads_;

  // holds the results of the parsing threads, which is simply equal to
  // the return value of kseq_read() for the last call to that function.
  // A value < -1 signifies some sort of error.
  std::vector<int> threadResults_;

  size_t blockSize_;
  moodycamel::ConcurrentQueue<std::unique_ptr<ReadChunk<T>>> readQueue_,
      seqContainerQueue_;

  // holds the indices of files (file-pairs) to be processed
  moodycamel::ConcurrentQueue<uint32_t> workQueue_;

  std::vector<std::unique_ptr<moodycamel::ProducerToken>> produceReads_;
  std::vector<std::unique_ptr<moodycamel::ConsumerToken>> consumeContainers_;
  bool isActive_{false};
};
}
#endif // __FASTX_PARSER__
<commit_msg>Update FastxParser.hpp<commit_after>#ifndef __FASTX_PARSER__
#define __FASTX_PARSER__

#include "fcntl.h"
#include "unistd.h"
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>

extern "C" {
#include "kseq.h"
}

#include "concurrentqueue.h"

#ifndef __FASTX_PARSER_PRECXX14_MAKE_UNIQUE__
#define __FASTX_PARSER_PRECXX14_MAKE_UNIQUE__

#if __cplusplus >= 201402L
#include <memory>
using std::make_unique;
#else

#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>

template <class T> struct _Unique_if {
  using _Single_object = std::unique_ptr<T>;
};

template <class T> struct _Unique_if<T[]> {
  using _Unknown_bound = std::unique_ptr<T[]>;
};

template <class T, size_t N> struct _Unique_if<T[N]> {
  using _Known_bound = void;
};

template <class T, class... Args>
typename _Unique_if<T>::_Single_object make_unique(Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <class T>
typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) {
  using U = typename std::remove_extent<T>::type;
  return std::unique_ptr<T>(new U[n]());
}

template <class T, class... Args>
typename _Unique_if<T>::_Known_bound make_unique(Args&&...) = delete;

#endif // C++11
#endif //__FASTX_PARSER_PRECXX14_MAKE_UNIQUE__

namespace fastx_parser {
struct ReadSeq {
    std::string seq;
    std::string name;
    ~ReadSeq() {}
};

struct ReadPair {
  ReadSeq first;
  ReadSeq second;
};

template <typename T> class ReadChunk {
public:
  ReadChunk(size_t want) : group_(want), want_(want), have_(want) {}
  inline void have(size_t num) { have_ = num; }
  inline size_t size() { return have_; }
  inline size_t want() const { return want_; }
  T& operator[](size_t i) { return group_[i]; }
  typename std::vector<T>::iterator begin() { return group_.begin(); }
  typename std::vector<T>::iterator end() { return group_.begin() + have_; }

private:
  std::vector<T> group_;
  size_t want_;
  size_t have_;
};

template <typename T> class ReadGroup {
public:
  ReadGroup(moodycamel::ProducerToken&& pt, moodycamel::ConsumerToken&& ct)
      : pt_(std::move(pt)), ct_(std::move(ct)) {}
  moodycamel::ConsumerToken& consumerToken() { return ct_; }
  moodycamel::ProducerToken& producerToken() { return pt_; }
  // get a reference to the chunk this ReadGroup owns
  std::unique_ptr<ReadChunk<T>>& chunkPtr() { return chunk_; }
  // get a *moveable* reference to the chunk this ReadGroup owns
  std::unique_ptr<ReadChunk<T>>&& takeChunkPtr() { return std::move(chunk_); }
  inline void have(size_t num) { chunk_->have(num); }
  inline size_t size() { return chunk_->size(); }
  inline size_t want() const { return chunk_->want(); }
  T& operator[](size_t i) { return (*chunk_)[i]; }
  typename std::vector<T>::iterator begin() { return chunk_->begin(); }
  typename std::vector<T>::iterator end() {
    return chunk_->begin() + chunk_->size();
  }
  void setChunkEmpty() { chunk_.release(); }
  bool empty() const { return chunk_.get() == nullptr; }

private:
  std::unique_ptr<ReadChunk<T>> chunk_{nullptr};
  moodycamel::ProducerToken pt_;
  moodycamel::ConsumerToken ct_;
};

template <typename T> class FastxParser {
public:
  FastxParser(std::vector<std::string> files, uint32_t numConsumers,
              uint32_t numParsers = 1, uint32_t chunkSize = 1000);

  FastxParser(std::vector<std::string> files, std::vector<std::string> files2,
              uint32_t numConsumers, uint32_t numParsers = 1,
              uint32_t chunkSize = 1000);

  ~FastxParser();
  bool start();
  bool stop();
  ReadGroup<T> getReadGroup();
  bool refill(ReadGroup<T>& rg);
  void finishedWithGroup(ReadGroup<T>& s);

private:
  moodycamel::ProducerToken getProducerToken_();
  moodycamel::ConsumerToken getConsumerToken_();

  std::vector<std::string> inputStreams_;
  std::vector<std::string> inputStreams2_;
  uint32_t numParsers_;
  std::atomic<uint32_t> numParsing_;

  // NOTE: Would like to use std::future<int> here instead, but that
  // solution doesn't seem to work.  It's unclear exactly why
  // see (https://twitter.com/nomad421/status/917748383321817088)
  std::vector<std::unique_ptr<std::thread>> parsingThreads_;

  // holds the results of the parsing threads, which is simply equal to
  // the return value of kseq_read() for the last call to that function.
  // A value < -1 signifies some sort of error.
  std::vector<int> threadResults_;

  size_t blockSize_;
  moodycamel::ConcurrentQueue<std::unique_ptr<ReadChunk<T>>> readQueue_,
      seqContainerQueue_;

  // holds the indices of files (file-pairs) to be processed
  moodycamel::ConcurrentQueue<uint32_t> workQueue_;

  std::vector<std::unique_ptr<moodycamel::ProducerToken>> produceReads_;
  std::vector<std::unique_ptr<moodycamel::ConsumerToken>> consumeContainers_;
  bool isActive_{false};
};
}
#endif // __FASTX_PARSER__
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "imconversationmodel.h"
#include "callagent.h"
#include <TelepathyQt4/AvatarData>
#include <TelepathyQt4Yell/Models/ConversationItem>
#include "filetransferitem.h"

IMConversationModel::IMConversationModel(const Tp::AccountPtr &account,
    const Tp::ContactPtr &self,
    const Tp::ContactPtr &contact,
    const Tp::TextChannelPtr &channel,
    QObject *parent)
    : MergedModel(parent),
      mCallRunningItem(0)
{
    mLoggerConversationModel = new Tpl::LoggerConversationModel(account, contact, this);
    if (mLoggerConversationModel) {
        addModel(mLoggerConversationModel);
    }

    mSessionConversationModel = new Tpy::SessionConversationModel(self, channel, parent);
    if (mSessionConversationModel) {
        addModel(mSessionConversationModel);
    }

    QHash<int, QByteArray> roles = roleNames();
    roles[IncludeSearchRole] = "includeSearch";
    roles[StatusRole] = "status";
    roles[IncomingTransferRole] = "incomingTransfer";
    roles[FileNameRole] = "fileName";
    roles[FileSizeRole] = "fileSize";
    roles[TransferStateRole] = "transferState";
    roles[TransferStateReasonRole] = "transferStateReason";
    roles[PercentTransferredRole] = "percentTransferred";
    roles[BubbleColorRole] = "bubbleColor";
    setRoleNames(roles);

    mBubbleColor.clear();
    mBubbleColor.append("blue");
    mBubbleColor.append("green");
    mBubbleColor.append("orange");
    mBubbleColor.append("white");
}

IMConversationModel::~IMConversationModel()
{
}

QString IMConversationModel::searchString() const
{
    return mSearchString;
}

void IMConversationModel::onSearchByString(const QString &search)
{
    mSearchString = search;
    slotResetModel();
}

QVariant IMConversationModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

    const FileTransferItem *item = qobject_cast<const FileTransferItem*>(
                MergedModel::data(index, Tpy::SessionConversationModel::ItemRole).value<QObject*>());
    const Tpy::ConversationItem *conversationItem = qobject_cast<const Tpy::ConversationItem*>(
                MergedModel::data(index, Tpy::SessionConversationModel::ItemRole).value<QObject*>());

    switch (role) {
    case Tpy::SessionConversationModel::TextRole: {
        QString text = MergedModel::data(index, role).toString();

        if (!mSearchString.isEmpty()) {
            text = text.replace(QString("<"), QString("<"));
            text = text.replace(QString(">"), QString(">"));
            text = text.replace(QChar('\n'), QString("
"));

            int index = text.indexOf(mSearchString, Qt::CaseInsensitive);
            QString prefix = text.left(index);
            QString middle = text.mid(index, mSearchString.length());
            QString suffix = text.mid(index + mSearchString.length());
            QString newText = QString(prefix + "" + middle + "" + suffix);
            newText = newText.replace(QString("&"), QString("&"));
            return QVariant(newText);
        } else {
            text = text.replace(QString("&"), QString("&"));
            text = text.replace(QString("<"), QString("<"));
            text = text.replace(QString(">"), QString(">"));
            text = text.replace(QChar('\n'), QString("
"));
            return text;
        }
    }
    case IncludeSearchRole: {
        if (!mSearchString.isEmpty()) {
            return QVariant(MergedModel::data(index, Qt::UserRole).toString().contains(mSearchString, Qt::CaseInsensitive));
        } else {
            return QVariant(true);
        }
    }
    case StatusRole: {
        if (conversationItem) {
            return conversationItem->contact()->presence().type();
        }

        return QVariant();
    }
    case BubbleColorRole: {
        if (item) {
            if(item->incomingTransfer()) {
                return contactColor(item->contact()->id());
            } else {
                return mBubbleColor[mBubbleColor.count()-1];
            }
        }
        else if (conversationItem) {
            if(conversationItem->type() == Tpy::ConversationItem::OUTGOING_MESSAGE) {
                return mBubbleColor[mBubbleColor.count()-1];
            } else {
                QString id = conversationItem->contact()->id();
                return contactColor(id);
            }
        }
        return mBubbleColor[mBubbleColor.count()-1];
    }
    // override the type role, so that we can return a custom type for file transfer items
    case Tpy::SessionConversationModel::TypeRole: {
        if (item) {
            return (item->incomingTransfer() ? "incoming_file_transfer" :
                                               "outgoing_file_transfer");
        }
        return MergedModel::data(index, role);
    }
    case IncomingTransferRole: {
        if (item) {
            return item->incomingTransfer();
        }
        return false;
    }
    case FileNameRole: {
        if (item) {
            return item->fileName();
        }
        return QVariant();
    }
    case FileSizeRole: {
        if (item) {
            return friendlyFileSize(item->fileSize());
        }
        return QVariant();
    }
    case TransferStateRole: {
        if (item) {
            return item->transferState();
        }
        return QVariant();
    }
    case TransferStateReasonRole: {
        if (item) {
            return item->transferStateReason();
        }
        return QVariant();
    }
    case PercentTransferredRole: {
        if (item) {
            return item->percentTransferred();
        }
        return QVariant();
    }
    default:
        return MergedModel::data(index, role);
    }
}

void IMConversationModel::slotResetModel()
{
    beginResetModel();
    endResetModel();
}

void IMConversationModel::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state)
{
    qDebug() << "IMConversationModel::onChatStateChanged state=" << state;

    // ignore events originating from self
    if (!mSessionConversationModel || contact == mSessionConversationModel->selfContact()) {
        return;
    }

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    // build the message
    QString message;
    bool running = true;

    mContactsTyping.removeOne(contact);
    switch(state) {
    case Tp::ChannelChatStateComposing: {
        mContactsTyping.append(contact);
        if (mContactsTyping.size() == 1) {
            message = tr("%1 is typing").arg(mContactsTyping.at(0)->alias());
        } else if (mContactsTyping.size() == 2) {
            message = tr("%1 and %2 are typing").arg(mContactsTyping.at(0)->alias()).arg(mContactsTyping.at(1)->alias());
        } else {
            message = tr("Lots of people are typing");
        }
        break;
    }
    case Tp::ChannelChatStateGone: {
        message = tr("%1 has left the conversation").arg(contact->alias());
        running = false;
        break;
    }
    case Tp::ChannelChatStatePaused: {
        message = tr("%1 has paused typing").arg(contact->alias());
        break;
    }
    case Tp::ChannelChatStateActive: {
        message = tr("%1 is now active").arg(contact->alias());
        break;
    }
    case Tp::ChannelChatStateInactive: {
        message = tr("%1 is now idle").arg(contact->alias());
        break;
    }
    default:
        break;
    }

    // if we have a previous running chat item from the contact, delete it
    foreach(Tpy::ConversationItem* item, mChatRunningItems) {
        if(item->contact() == contact) {
            qDebug("previous running item found, deleting");
            mChatRunningItems.removeOne(item);
            mSessionConversationModel->deleteItem(item);
            item = 0;
        }
    }

    // add the event message
    if (!message.isEmpty()) {
        Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
            QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
        // remember running messages
        if (running) {
            mChatRunningItems.append(item);
        }
        mSessionConversationModel->addItem(item);
    }
}

void IMConversationModel::onItemChanged()
{
    if (!mSessionConversationModel) {
        return;
    }

    Tpy::ConversationItem *item = qobject_cast<Tpy::ConversationItem*>(sender());
    if(!item) {
        return;
    }

    QModelIndex idx = mSessionConversationModel->index(item);
    if (idx.isValid()) {
        emit dataChanged(idx, idx);
    }

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(item->contact()->id())) {
        mContactsList.append(item->contact()->id());
    }
}

void IMConversationModel::notifyCallStatusChanged(Tp::ContactPtr contact, CallAgent::CallStatus oldCallStatus, CallAgent::CallStatus newCallStatus)
{
    qDebug() << "IMConversationModel::notifyCallStatusChanged: oldCallStatus=" << oldCallStatus << " newCallStatus=" << newCallStatus;

    if (!mLoggerConversationModel) {
        return;
    }

    // build the message
    QString message;
    bool running = true;

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    switch (newCallStatus) {
    case CallAgent::CallStatusNoCall:
        message = tr("Error in call with %1").arg(contact->alias());
        // check if previous was call
        if (oldCallStatus == CallAgent::CallStatusTalking ||
            oldCallStatus == CallAgent::CallStatusHeld ||
            oldCallStatus == CallAgent::CallStatusHangingUp) {
            message = tr("Call with %1 ended").arg(contact->alias());
        } else if (oldCallStatus == CallAgent::CallStatusIncomingCall) {
            message = tr("Missed call from %1").arg(contact->alias());
        }
        running = false;
        break;
    case CallAgent::CallStatusIncomingCall:
        message = tr("%1 is calling you").arg(contact->alias());
        break;
    case CallAgent::CallStatusConnecting:
        message = tr("Setting up call to %1").arg(contact->alias());
        break;
    case CallAgent::CallStatusRinging:
        message = tr("Calling %1").arg(contact->alias());
        break;
    case CallAgent::CallStatusTalking:
        message = tr("Call with %1 started").arg(contact->alias());
        break;
    case CallAgent::CallStatusHeld:
        message = tr("Call with %1 on hold").arg(contact->alias());
        break;
    case CallAgent::CallStatusHangingUp:
        break;
    }

    // if we have a previous running call item, delete it
    if (mCallRunningItem) {
        mLoggerConversationModel->deleteItem(mCallRunningItem);
        mCallRunningItem = 0;
    }

    // add the event message
    if (!message.isEmpty()) {
        Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
            QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
        // remember running messages
        if (running) {
            mCallRunningItem = item;
        }
        mLoggerConversationModel->addItem(item);
    }
}

void IMConversationModel::notifyCallError(Tp::ContactPtr contact, const QString & errorString)
{
    qDebug() << "IMConversationModel::notifyError: errorString=" << errorString;

    // build the message
    QString message;

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    message = tr("Error in call with %1").arg(contact->alias());

    Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
        QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
    mLoggerConversationModel->addItem(item);
}

void IMConversationModel::notifyFileTransfer(Tp::ContactPtr contact, FileTransferAgent *agent, Tp::FileTransferChannelPtr channel)
{
    FileTransferItem *item = new FileTransferItem(contact, agent, channel, this);
    connect(item, SIGNAL(itemChanged()), SLOT(onItemChanged()));

    if (mLoggerConversationModel) {
        mLoggerConversationModel->addItem(item);
    }
}

QString IMConversationModel::friendlyFileSize(qulonglong size)
{
    QString text;

    // size in bytes
    if (size < 1024) {
        text = tr("%1 bytes").arg(size);
    }
    // size in kbytes
    else if (size < 1048576) {
        text = tr("%1 KB").arg(size / 1024., 0, 'f', 2);
    }
    // size in mbytes
    else if (size < (1048576 * 1024)) {
        text = tr("%1 MB").arg(size / 1048576., 0, 'f', 2);
    }
    // size in gbytes
    else {
        text = tr("%1 GB").arg(size / (1048576. * 1024.), 0, 'f', 2);
    }

    return text;
}

QString IMConversationModel::contactColor(const QString &id) const
{
    // we want the modulo, to iterate among the available bubble colors
    // the last one, white, is reserved for the user
    int index = mContactsList.indexOf(id) % (mBubbleColor.count()-1);
    qDebug("bubble index: %d", index);
    if(index < 0 || index >= mBubbleColor.count()) {
        index = 0;
    }
    return mBubbleColor[index];
}

bool IMConversationModel::canFetchMoreBack() const
{
    if (mLoggerConversationModel) {
        return mLoggerConversationModel->canFetchMoreBack();
    }

    return false;
}

void IMConversationModel::fetchMoreBack()
{
    if (mLoggerConversationModel) {
        mLoggerConversationModel->fetchMoreBack();
    }
}

void IMConversationModel::sendMessage(const QString &text)
{
    if (mSessionConversationModel) {
        mSessionConversationModel->sendMessage(text);
    }
}

void IMConversationModel::disconnectChannelQueue()
{
    if (mSessionConversationModel) {
        mSessionConversationModel->disconnectChannelQueue();
    }
}

void IMConversationModel::connectChannelQueue()
{
    if (mSessionConversationModel) {
        mSessionConversationModel->connectChannelQueue();
    }
}
<commit_msg>Fix warning in QML for fileName<commit_after>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "imconversationmodel.h"
#include "callagent.h"
#include <TelepathyQt4/AvatarData>
#include <TelepathyQt4Yell/Models/ConversationItem>
#include "filetransferitem.h"

IMConversationModel::IMConversationModel(const Tp::AccountPtr &account,
    const Tp::ContactPtr &self,
    const Tp::ContactPtr &contact,
    const Tp::TextChannelPtr &channel,
    QObject *parent)
    : MergedModel(parent),
      mCallRunningItem(0)
{
    mLoggerConversationModel = new Tpl::LoggerConversationModel(account, contact, this);
    if (mLoggerConversationModel) {
        addModel(mLoggerConversationModel);
    }

    mSessionConversationModel = new Tpy::SessionConversationModel(self, channel, parent);
    if (mSessionConversationModel) {
        addModel(mSessionConversationModel);
    }

    QHash<int, QByteArray> roles = roleNames();
    roles[IncludeSearchRole] = "includeSearch";
    roles[StatusRole] = "status";
    roles[IncomingTransferRole] = "incomingTransfer";
    roles[FileNameRole] = "fileName";
    roles[FileSizeRole] = "fileSize";
    roles[TransferStateRole] = "transferState";
    roles[TransferStateReasonRole] = "transferStateReason";
    roles[PercentTransferredRole] = "percentTransferred";
    roles[BubbleColorRole] = "bubbleColor";
    setRoleNames(roles);

    mBubbleColor.clear();
    mBubbleColor.append("blue");
    mBubbleColor.append("green");
    mBubbleColor.append("orange");
    mBubbleColor.append("white");
}

IMConversationModel::~IMConversationModel()
{
}

QString IMConversationModel::searchString() const
{
    return mSearchString;
}

void IMConversationModel::onSearchByString(const QString &search)
{
    mSearchString = search;
    slotResetModel();
}

QVariant IMConversationModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

    const FileTransferItem *item = qobject_cast<const FileTransferItem*>(
                MergedModel::data(index, Tpy::SessionConversationModel::ItemRole).value<QObject*>());
    const Tpy::ConversationItem *conversationItem = qobject_cast<const Tpy::ConversationItem*>(
                MergedModel::data(index, Tpy::SessionConversationModel::ItemRole).value<QObject*>());

    switch (role) {
    case Tpy::SessionConversationModel::TextRole: {
        QString text = MergedModel::data(index, role).toString();

        if (!mSearchString.isEmpty()) {
            text = text.replace(QString("<"), QString("<"));
            text = text.replace(QString(">"), QString(">"));
            text = text.replace(QChar('\n'), QString("
"));

            int index = text.indexOf(mSearchString, Qt::CaseInsensitive);
            QString prefix = text.left(index);
            QString middle = text.mid(index, mSearchString.length());
            QString suffix = text.mid(index + mSearchString.length());
            QString newText = QString(prefix + "" + middle + "" + suffix);
            newText = newText.replace(QString("&"), QString("&"));
            return QVariant(newText);
        } else {
            text = text.replace(QString("&"), QString("&"));
            text = text.replace(QString("<"), QString("<"));
            text = text.replace(QString(">"), QString(">"));
            text = text.replace(QChar('\n'), QString("
"));
            return text;
        }
    }
    case IncludeSearchRole: {
        if (!mSearchString.isEmpty()) {
            return QVariant(MergedModel::data(index, Qt::UserRole).toString().contains(mSearchString, Qt::CaseInsensitive));
        } else {
            return QVariant(true);
        }
    }
    case StatusRole: {
        if (conversationItem) {
            return conversationItem->contact()->presence().type();
        }

        return QVariant();
    }
    case BubbleColorRole: {
        if (item) {
            if(item->incomingTransfer()) {
                return contactColor(item->contact()->id());
            } else {
                return mBubbleColor[mBubbleColor.count()-1];
            }
        }
        else if (conversationItem) {
            if(conversationItem->type() == Tpy::ConversationItem::OUTGOING_MESSAGE) {
                return mBubbleColor[mBubbleColor.count()-1];
            } else {
                QString id = conversationItem->contact()->id();
                return contactColor(id);
            }
        }
        return mBubbleColor[mBubbleColor.count()-1];
    }
    // override the type role, so that we can return a custom type for file transfer items
    case Tpy::SessionConversationModel::TypeRole: {
        if (item) {
            return (item->incomingTransfer() ? "incoming_file_transfer" :
                                               "outgoing_file_transfer");
        }
        return MergedModel::data(index, role);
    }
    case IncomingTransferRole: {
        if (item) {
            return item->incomingTransfer();
        }
        return false;
    }
    case FileNameRole: {
        if (item) {
            return item->fileName();
        }
        return QVariant("");
    }
    case FileSizeRole: {
        if (item) {
            return friendlyFileSize(item->fileSize());
        }
        return QVariant();
    }
    case TransferStateRole: {
        if (item) {
            return item->transferState();
        }
        return QVariant();
    }
    case TransferStateReasonRole: {
        if (item) {
            return item->transferStateReason();
        }
        return QVariant();
    }
    case PercentTransferredRole: {
        if (item) {
            return item->percentTransferred();
        }
        return QVariant();
    }
    default:
        return MergedModel::data(index, role);
    }
}

void IMConversationModel::slotResetModel()
{
    beginResetModel();
    endResetModel();
}

void IMConversationModel::onChatStateChanged(const Tp::ContactPtr &contact, Tp::ChannelChatState state)
{
    qDebug() << "IMConversationModel::onChatStateChanged state=" << state;

    // ignore events originating from self
    if (!mSessionConversationModel || contact == mSessionConversationModel->selfContact()) {
        return;
    }

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    // build the message
    QString message;
    bool running = true;

    mContactsTyping.removeOne(contact);
    switch(state) {
    case Tp::ChannelChatStateComposing: {
        mContactsTyping.append(contact);
        if (mContactsTyping.size() == 1) {
            message = tr("%1 is typing").arg(mContactsTyping.at(0)->alias());
        } else if (mContactsTyping.size() == 2) {
            message = tr("%1 and %2 are typing").arg(mContactsTyping.at(0)->alias()).arg(mContactsTyping.at(1)->alias());
        } else {
            message = tr("Lots of people are typing");
        }
        break;
    }
    case Tp::ChannelChatStateGone: {
        message = tr("%1 has left the conversation").arg(contact->alias());
        running = false;
        break;
    }
    case Tp::ChannelChatStatePaused: {
        message = tr("%1 has paused typing").arg(contact->alias());
        break;
    }
    case Tp::ChannelChatStateActive: {
        message = tr("%1 is now active").arg(contact->alias());
        break;
    }
    case Tp::ChannelChatStateInactive: {
        message = tr("%1 is now idle").arg(contact->alias());
        break;
    }
    default:
        break;
    }

    // if we have a previous running chat item from the contact, delete it
    foreach(Tpy::ConversationItem* item, mChatRunningItems) {
        if(item->contact() == contact) {
            qDebug("previous running item found, deleting");
            mChatRunningItems.removeOne(item);
            mSessionConversationModel->deleteItem(item);
            item = 0;
        }
    }

    // add the event message
    if (!message.isEmpty()) {
        Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
            QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
        // remember running messages
        if (running) {
            mChatRunningItems.append(item);
        }
        mSessionConversationModel->addItem(item);
    }
}

void IMConversationModel::onItemChanged()
{
    if (!mSessionConversationModel) {
        return;
    }

    Tpy::ConversationItem *item = qobject_cast<Tpy::ConversationItem*>(sender());
    if(!item) {
        return;
    }

    QModelIndex idx = mSessionConversationModel->index(item);
    if (idx.isValid()) {
        emit dataChanged(idx, idx);
    }

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(item->contact()->id())) {
        mContactsList.append(item->contact()->id());
    }
}

void IMConversationModel::notifyCallStatusChanged(Tp::ContactPtr contact, CallAgent::CallStatus oldCallStatus, CallAgent::CallStatus newCallStatus)
{
    qDebug() << "IMConversationModel::notifyCallStatusChanged: oldCallStatus=" << oldCallStatus << " newCallStatus=" << newCallStatus;

    if (!mLoggerConversationModel) {
        return;
    }

    // build the message
    QString message;
    bool running = true;

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    switch (newCallStatus) {
    case CallAgent::CallStatusNoCall:
        message = tr("Error in call with %1").arg(contact->alias());
        // check if previous was call
        if (oldCallStatus == CallAgent::CallStatusTalking ||
            oldCallStatus == CallAgent::CallStatusHeld ||
            oldCallStatus == CallAgent::CallStatusHangingUp) {
            message = tr("Call with %1 ended").arg(contact->alias());
        } else if (oldCallStatus == CallAgent::CallStatusIncomingCall) {
            message = tr("Missed call from %1").arg(contact->alias());
        }
        running = false;
        break;
    case CallAgent::CallStatusIncomingCall:
        message = tr("%1 is calling you").arg(contact->alias());
        break;
    case CallAgent::CallStatusConnecting:
        message = tr("Setting up call to %1").arg(contact->alias());
        break;
    case CallAgent::CallStatusRinging:
        message = tr("Calling %1").arg(contact->alias());
        break;
    case CallAgent::CallStatusTalking:
        message = tr("Call with %1 started").arg(contact->alias());
        break;
    case CallAgent::CallStatusHeld:
        message = tr("Call with %1 on hold").arg(contact->alias());
        break;
    case CallAgent::CallStatusHangingUp:
        break;
    }

    // if we have a previous running call item, delete it
    if (mCallRunningItem) {
        mLoggerConversationModel->deleteItem(mCallRunningItem);
        mCallRunningItem = 0;
    }

    // add the event message
    if (!message.isEmpty()) {
        Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
            QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
        // remember running messages
        if (running) {
            mCallRunningItem = item;
        }
        mLoggerConversationModel->addItem(item);
    }
}

void IMConversationModel::notifyCallError(Tp::ContactPtr contact, const QString & errorString)
{
    qDebug() << "IMConversationModel::notifyError: errorString=" << errorString;

    // build the message
    QString message;

    // if it is a new contact, add it to the list
    if(!mContactsList.contains(contact->id())) {
        mContactsList.append(contact->id());
    }

    message = tr("Error in call with %1").arg(contact->alias());

    Tpy::ConversationItem *item = new Tpy::ConversationItem(contact,
        QDateTime::currentDateTime(), message, Tpy::ConversationItem::EVENT, this);
    mLoggerConversationModel->addItem(item);
}

void IMConversationModel::notifyFileTransfer(Tp::ContactPtr contact, FileTransferAgent *agent, Tp::FileTransferChannelPtr channel)
{
    FileTransferItem *item = new FileTransferItem(contact, agent, channel, this);
    connect(item, SIGNAL(itemChanged()), SLOT(onItemChanged()));

    if (mLoggerConversationModel) {
        mLoggerConversationModel->addItem(item);
    }
}

QString IMConversationModel::friendlyFileSize(qulonglong size)
{
    QString text;

    // size in bytes
    if (size < 1024) {
        text = tr("%1 bytes").arg(size);
    }
    // size in kbytes
    else if (size < 1048576) {
        text = tr("%1 KB").arg(size / 1024., 0, 'f', 2);
    }
    // size in mbytes
    else if (size < (1048576 * 1024)) {
        text = tr("%1 MB").arg(size / 1048576., 0, 'f', 2);
    }
    // size in gbytes
    else {
        text = tr("%1 GB").arg(size / (1048576. * 1024.), 0, 'f', 2);
    }

    return text;
}

QString IMConversationModel::contactColor(const QString &id) const
{
    // we want the modulo, to iterate among the available bubble colors
    // the last one, white, is reserved for the user
    int index = mContactsList.indexOf(id) % (mBubbleColor.count()-1);
    qDebug("bubble index: %d", index);
    if(index < 0 || index >= mBubbleColor.count()) {
        index = 0;
    }
    return mBubbleColor[index];
}

bool IMConversationModel::canFetchMoreBack() const
{
    if (mLoggerConversationModel) {
        return mLoggerConversationModel->canFetchMoreBack();
    }

    return false;
}

void IMConversationModel::fetchMoreBack()
{
    if (mLoggerConversationModel) {
        mLoggerConversationModel->fetchMoreBack();
    }
}

void IMConversationModel::sendMessage(const QString &text)
{
    if (mSessionConversationModel) {
        mSessionConversationModel->sendMessage(text);
    }
}

void IMConversationModel::disconnectChannelQueue()
{
    if (mSessionConversationModel) {
        mSessionConversationModel->disconnectChannelQueue();
    }
}

void IMConversationModel::connectChannelQueue()
{
    if (mSessionConversationModel) {
        mSessionConversationModel->connectChannelQueue();
    }
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX700 グループ　PMGI 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/device.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  PMGI 定義
		@param[in]	base	ベース・アドレス
		@param[in]	per		ペリフェラル型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral per>
	struct pmgi_t {

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  PMGI コンフィギュレーションレジスタ (PMGCR)
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct pmgcr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B8,  6>  PSMCS;
			bit_rw_t <io_, bitpos::B15>     PSMDP;
			bits_rw_t<io_, bitpos::B16, 3>  PSMHT;
			bits_rw_t<io_, bitpos::B20, 3>  PSMCT;
		};
		static pmgcr_t<base + 0x00> PMGCR;

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  PHY ステーションマネジメントレジスタ (PSMR)
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct psmr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t <io_, bitpos::B0>      PSME;
			bit_rw_t <io_, bitpos::B1>      PSMAD;

			bits_rw_t<io_, bitpos::B3,  5>  PDA;
			bits_rw_t<io_, bitpos::B8,  5>  PRA;

			bits_rw_t<io_, bitpos::B16, 16> PRD;
		};
		static psmr_t<base + 0x04> PSMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return per; }
	};

	typedef etherc_t<0x000C5880, peripheral::PMGI0> PMGI0;
	typedef etherc_t<0x000C5890, peripheral::PMGI1> PMGI1;
}
<commit_msg>Update: cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX700 グループ　PMGI 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/device.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  PMGI 定義
		@param[in]	base	ベース・アドレス
		@param[in]	per		ペリフェラル型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral per>
	struct pmgi_t {

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  PMGI コンフィギュレーションレジスタ (PMGCR)
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct pmgcr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B8,  6>  PSMCS;
			bit_rw_t <io_, bitpos::B15>     PSMDP;
			bits_rw_t<io_, bitpos::B16, 3>  PSMHT;
			bits_rw_t<io_, bitpos::B20, 3>  PSMCT;
		};
		static pmgcr_t<base + 0x00> PMGCR;

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  PHY ステーションマネジメントレジスタ (PSMR)
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct psmr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t <io_, bitpos::B0>      PSME;
			bit_rw_t <io_, bitpos::B1>      PSMAD;

			bits_rw_t<io_, bitpos::B3,  5>  PDA;
			bits_rw_t<io_, bitpos::B8,  5>  PRA;

			bits_rw_t<io_, bitpos::B16, 16> PRD;
		};
		static psmr_t<base + 0x04> PSMR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ペリフェラル型を返す
			@return ペリフェラル型
		*/
		//-----------------------------------------------------------------//
		static peripheral get_peripheral() { return per; }
	};

	typedef pmgi_t<0x000C5880, peripheral::PMGI0> PMGI0;
	typedef pmgi_t<0x000C5890, peripheral::PMGI1> PMGI1;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include <wininet.h>
#include "IEBrowserEngine.h"
#include "common/RhoConf.h"
#include "MainWindow.h"

#if defined( OS_WINCE )
extern "C" bool CheckSymbolDevice();
#endif

#if defined(_WIN32_WCE)
#include <webvw.h>
#endif

CIEBrowserEngine::CIEBrowserEngine(HWND hParentWnd, HINSTANCE hInstance) :
    m_spIWebBrowser2(NULL)
{
#if defined(_WIN32_WCE)
    m_browser.Create(hParentWnd,
                     CWindow::rcDefault, // proper sizing is done in CMainWindow::OnSize
		    		 TEXT("Microsoft.PIEDocView"), // ProgID of the control
                     WS_CHILD, 0,
                     ID_BROWSER);

#else
	m_browser.Create(hParentWnd,
                     CWindow::rcDefault, // proper sizing is done in CMainWindow::OnSize
					 TEXT("Shell.Explorer"), // ProgID of the control
                     WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0,
                     ID_BROWSER);
#endif

    // cache IWebBrowser2 interface pointer
    HRESULT hr = m_browser.QueryControl(&m_spIWebBrowser2);
    m_spIWebBrowser2->put_AddressBar(VARIANT_FALSE);

    if ( !RHOCONF().getBool("wm_show_statusbar") )
        m_spIWebBrowser2->put_StatusBar(VARIANT_FALSE);

}

CIEBrowserEngine::~CIEBrowserEngine(void)
{
    //TODO: destroy browser
}

BOOL CIEBrowserEngine::Navigate(LPCTSTR szURL)
{
    BSTR bstrUrl = SysAllocString(szURL);
    BOOL bRes = m_spIWebBrowser2->Navigate(bstrUrl, NULL, &CComVariant(L"_self"), NULL, NULL) == S_OK;

    SysFreeString(bstrUrl);

    return bRes;
}

BOOL CIEBrowserEngine::ResizeOnTab(int iInstID,RECT rcNewSize)
{
    return m_browser.MoveWindow(&rcNewSize);
}

BOOL CIEBrowserEngine::BackOnTab(int iInstID,int iPagesBack /*= 1*/)
{
    return m_spIWebBrowser2->GoBack() == S_OK;
}

BOOL CIEBrowserEngine::ForwardOnTab(int iInstID)
{
    return m_spIWebBrowser2->GoForward() == S_OK;
}

BOOL CIEBrowserEngine::ReloadOnTab(bool bFromCache, UINT iTab)
{
    return m_spIWebBrowser2->Refresh() == S_OK;
}

BOOL CIEBrowserEngine::StopOnTab(UINT iTab)
{
    return FALSE;
}

BOOL CIEBrowserEngine::ZoomPageOnTab(float fZoom, UINT iTab)
{
    return FALSE;
}

BOOL CIEBrowserEngine::ZoomTextOnTab(int nZoom, UINT iTab)
{
    return FALSE;
}

int CIEBrowserEngine::GetTextZoomOnTab(UINT iTab)
{
    return 2; //Normal
}

BOOL CIEBrowserEngine::GetTitleOnTab(LPTSTR szURL, UINT iMaxLen, UINT iTab)
{
    return FALSE;
}

static void writeHtmlToTheDoc (
#if defined(_WIN32_WCE) && !defined( OS_PLATFORM_MOTCE )
					IPIEHTMLDocument2 *document
#else
					IHTMLDocument2 *document
#endif
					, LPCTSTR szHtml)
{
	HRESULT hresult = S_OK;
	VARIANT *param;
	SAFEARRAY *sfArray;
	//std::wstring html;
	BSTR bstr = SysAllocString(szHtml);

	// Creates a new one-dimensional array
	sfArray = SafeArrayCreateVector(VT_VARIANT, 0, 1);

	if (sfArray && document)
    {
	    hresult = SafeArrayAccessData(sfArray,(LPVOID*) & param);
	    param->vt = VT_BSTR;
	    param->bstrVal = bstr;
	    hresult = SafeArrayUnaccessData(sfArray);
	    hresult = document->write(sfArray);
    }

	SysFreeString(bstr);
	if (sfArray != NULL) {
		SafeArrayDestroy(sfArray);
	}
}

BOOL CIEBrowserEngine::NavigateToHtml(LPCTSTR szHtml)
{
	HRESULT hr;
	IDispatch* pHtmlDoc = NULL;

    // Retrieve the document object.
    hr = m_spIWebBrowser2->get_Document( &pHtmlDoc );
    if ( SUCCEEDED(hr) )
    {
#if defined(_WIN32_WCE)&& !defined( OS_PLATFORM_MOTCE )
		IPIEHTMLDocument2* pDoc;
		hr = pHtmlDoc->QueryInterface(__uuidof(IPIEHTMLDocument2),  (void**)&pDoc );
#else
		IHTMLDocument2* pDoc;
		hr = pHtmlDoc->QueryInterface(__uuidof(IHTMLDocument2),  (void**)&pDoc );
#endif
        if ( SUCCEEDED(hr) )
        {
			// Write to the document
			writeHtmlToTheDoc(pDoc, szHtml);
			pDoc->Release();
        }
    }

    return TRUE;
}

LRESULT CIEBrowserEngine::OnWebKitMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

void CIEBrowserEngine::RunMessageLoop(CMainWindow& mainWnd)
{
#if defined( OS_WINCE )
	if(!CheckSymbolDevice()) return;
#endif

	MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if ( RHODESAPP().getExtManager().onWndMsg(msg) )
            continue;

        if (!mainWnd.TranslateAccelerator(&msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

bool CIEBrowserEngine::isExistJavascript(const wchar_t* szJSFunction, int index)
{
    return true;
}

void CIEBrowserEngine::executeJavascript(const wchar_t* szJSFunction, int index)
{
    StringW strUrlW;
    if(_memicmp(szJSFunction,L"JavaScript:",11*2) != 0)
        strUrlW = L"javascript:";

    strUrlW += szJSFunction;
    Navigate(strUrlW.c_str());
}

void CIEBrowserEngine::SetCookie(char* url, char* cookie)
{
	URL_COMPONENTSA uri;
	::memset(&uri, 0, sizeof(uri));
	uri.dwStructSize = sizeof(uri);
	uri.dwSchemeLength = 1;
	uri.dwHostNameLength = 1;
	uri.dwUrlPathLength = 1;
	if (!::InternetCrackUrlA(url, ::strlen(url), 0, &uri)) {
		RAWLOG_ERROR1("WebView.set_cookie: can not parse url: %s", url);
		return;
	}

	std::string nurl(uri.lpszScheme, uri.dwSchemeLength);
	nurl += "://";
	nurl += std::string(uri.lpszHostName, uri.dwHostNameLength);
	nurl += std::string(uri.lpszUrlPath, uri.dwUrlPathLength);

	for (const char *c = cookie;;) {
		const char *s = c;
		for (; *s != ';' && *s != '\0'; ++s);
		std::string c1(c, s - c);
		if (!::InternetSetCookieA(nurl.c_str(), NULL, c1.c_str()))
			RAWLOG_ERROR1("WebView.set_cookie: can not set cookie for url %s", nurl.c_str());
		if (*s == '\0')
			break;
		for (c = s + 1; *c == ' '; ++c);
	}
}
<commit_msg>added licence_rc checking<commit_after>#include "stdafx.h"
#include <wininet.h>
#include "IEBrowserEngine.h"
#include "common/RhoConf.h"
#include "MainWindow.h"

#if defined( OS_WINCE )
extern "C" bool CheckSymbolDevice();
#endif

#if defined(_WIN32_WCE)
#include <webvw.h>
#endif

CIEBrowserEngine::CIEBrowserEngine(HWND hParentWnd, HINSTANCE hInstance) :
    m_spIWebBrowser2(NULL)
{
#if defined(_WIN32_WCE)
    m_browser.Create(hParentWnd,
                     CWindow::rcDefault, // proper sizing is done in CMainWindow::OnSize
		    		 TEXT("Microsoft.PIEDocView"), // ProgID of the control
                     WS_CHILD, 0,
                     ID_BROWSER);

#else
	m_browser.Create(hParentWnd,
                     CWindow::rcDefault, // proper sizing is done in CMainWindow::OnSize
					 TEXT("Shell.Explorer"), // ProgID of the control
                     WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0,
                     ID_BROWSER);
#endif

    // cache IWebBrowser2 interface pointer
    HRESULT hr = m_browser.QueryControl(&m_spIWebBrowser2);
    m_spIWebBrowser2->put_AddressBar(VARIANT_FALSE);

    if ( !RHOCONF().getBool("wm_show_statusbar") )
        m_spIWebBrowser2->put_StatusBar(VARIANT_FALSE);

}

CIEBrowserEngine::~CIEBrowserEngine(void)
{
    //TODO: destroy browser
}

BOOL CIEBrowserEngine::Navigate(LPCTSTR szURL)
{
    BSTR bstrUrl = SysAllocString(szURL);
    BOOL bRes = m_spIWebBrowser2->Navigate(bstrUrl, NULL, &CComVariant(L"_self"), NULL, NULL) == S_OK;

    SysFreeString(bstrUrl);

    return bRes;
}

BOOL CIEBrowserEngine::ResizeOnTab(int iInstID,RECT rcNewSize)
{
    return m_browser.MoveWindow(&rcNewSize);
}

BOOL CIEBrowserEngine::BackOnTab(int iInstID,int iPagesBack /*= 1*/)
{
    return m_spIWebBrowser2->GoBack() == S_OK;
}

BOOL CIEBrowserEngine::ForwardOnTab(int iInstID)
{
    return m_spIWebBrowser2->GoForward() == S_OK;
}

BOOL CIEBrowserEngine::ReloadOnTab(bool bFromCache, UINT iTab)
{
    return m_spIWebBrowser2->Refresh() == S_OK;
}

BOOL CIEBrowserEngine::StopOnTab(UINT iTab)
{
    return FALSE;
}

BOOL CIEBrowserEngine::ZoomPageOnTab(float fZoom, UINT iTab)
{
    return FALSE;
}

BOOL CIEBrowserEngine::ZoomTextOnTab(int nZoom, UINT iTab)
{
    return FALSE;
}

int CIEBrowserEngine::GetTextZoomOnTab(UINT iTab)
{
    return 2; //Normal
}

BOOL CIEBrowserEngine::GetTitleOnTab(LPTSTR szURL, UINT iMaxLen, UINT iTab)
{
    return FALSE;
}

static void writeHtmlToTheDoc (
#if defined(_WIN32_WCE) && !defined( OS_PLATFORM_MOTCE )
					IPIEHTMLDocument2 *document
#else
					IHTMLDocument2 *document
#endif
					, LPCTSTR szHtml)
{
	HRESULT hresult = S_OK;
	VARIANT *param;
	SAFEARRAY *sfArray;
	//std::wstring html;
	BSTR bstr = SysAllocString(szHtml);

	// Creates a new one-dimensional array
	sfArray = SafeArrayCreateVector(VT_VARIANT, 0, 1);

	if (sfArray && document)
    {
	    hresult = SafeArrayAccessData(sfArray,(LPVOID*) & param);
	    param->vt = VT_BSTR;
	    param->bstrVal = bstr;
	    hresult = SafeArrayUnaccessData(sfArray);
	    hresult = document->write(sfArray);
    }

	SysFreeString(bstr);
	if (sfArray != NULL) {
		SafeArrayDestroy(sfArray);
	}
}

BOOL CIEBrowserEngine::NavigateToHtml(LPCTSTR szHtml)
{
	HRESULT hr;
	IDispatch* pHtmlDoc = NULL;

    // Retrieve the document object.
    hr = m_spIWebBrowser2->get_Document( &pHtmlDoc );
    if ( SUCCEEDED(hr) )
    {
#if defined(_WIN32_WCE)&& !defined( OS_PLATFORM_MOTCE )
		IPIEHTMLDocument2* pDoc;
		hr = pHtmlDoc->QueryInterface(__uuidof(IPIEHTMLDocument2),  (void**)&pDoc );
#else
		IHTMLDocument2* pDoc;
		hr = pHtmlDoc->QueryInterface(__uuidof(IHTMLDocument2),  (void**)&pDoc );
#endif
        if ( SUCCEEDED(hr) )
        {
			// Write to the document
			writeHtmlToTheDoc(pDoc, szHtml);
			pDoc->Release();
        }
    }

    return TRUE;
}

LRESULT CIEBrowserEngine::OnWebKitMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    bHandled = FALSE;
    return 0;
}

void CIEBrowserEngine::RunMessageLoop(CMainWindow& mainWnd)
{
	int res = CheckSymbolDevice();
	if(res == -1)
	{
		MessageBox(NULL, L"license_rc.dll is absent. Application will be closed"
						   , L"Rhodes", MB_SETFOREGROUND | MB_TOPMOST | MB_ICONSTOP | MB_OK);
		return;
	}
	else if(res == 0) return;

	MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if ( RHODESAPP().getExtManager().onWndMsg(msg) )
            continue;

        if (!mainWnd.TranslateAccelerator(&msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

bool CIEBrowserEngine::isExistJavascript(const wchar_t* szJSFunction, int index)
{
    return true;
}

void CIEBrowserEngine::executeJavascript(const wchar_t* szJSFunction, int index)
{
    StringW strUrlW;
    if(_memicmp(szJSFunction,L"JavaScript:",11*2) != 0)
        strUrlW = L"javascript:";

    strUrlW += szJSFunction;
    Navigate(strUrlW.c_str());
}

void CIEBrowserEngine::SetCookie(char* url, char* cookie)
{
	URL_COMPONENTSA uri;
	::memset(&uri, 0, sizeof(uri));
	uri.dwStructSize = sizeof(uri);
	uri.dwSchemeLength = 1;
	uri.dwHostNameLength = 1;
	uri.dwUrlPathLength = 1;
	if (!::InternetCrackUrlA(url, ::strlen(url), 0, &uri)) {
		RAWLOG_ERROR1("WebView.set_cookie: can not parse url: %s", url);
		return;
	}

	std::string nurl(uri.lpszScheme, uri.dwSchemeLength);
	nurl += "://";
	nurl += std::string(uri.lpszHostName, uri.dwHostNameLength);
	nurl += std::string(uri.lpszUrlPath, uri.dwUrlPathLength);

	for (const char *c = cookie;;) {
		const char *s = c;
		for (; *s != ';' && *s != '\0'; ++s);
		std::string c1(c, s - c);
		if (!::InternetSetCookieA(nurl.c_str(), NULL, c1.c_str()))
			RAWLOG_ERROR1("WebView.set_cookie: can not set cookie for url %s", nurl.c_str());
		if (*s == '\0')
			break;
		for (c = s + 1; *c == ' '; ++c);
	}
}
<|endoftext|>