vdr  1.7.27
tools.h
Go to the documentation of this file.
00001 /*
00002  * tools.h: Various tools
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: tools.h 2.16 2012/02/29 10:41:00 kls Exp $
00008  */
00009 
00010 #ifndef __TOOLS_H
00011 #define __TOOLS_H
00012 
00013 #include <dirent.h>
00014 #include <errno.h>
00015 #include <fcntl.h>
00016 #include <float.h>
00017 #include <iconv.h>
00018 #include <math.h>
00019 #include <poll.h>
00020 #include <stdarg.h>
00021 #include <stddef.h>
00022 #include <stdint.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <syslog.h>
00027 #include <sys/stat.h>
00028 #include <sys/types.h>
00029 
00030 typedef unsigned char uchar;
00031 
00032 extern int SysLogLevel;
00033 
00034 #define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(LOG_ERR, a) : void() )
00035 #define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_ERR, a) : void() )
00036 #define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_ERR, a) : void() )
00037 
00038 #define LOG_ERROR         esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
00039 #define LOG_ERROR_STR(s)  esyslog("ERROR (%s,%d): %s: %m", __FILE__, __LINE__, s)
00040 
00041 #define SECSINDAY  86400
00042 
00043 #define KILOBYTE(n) ((n) * 1024)
00044 #define MEGABYTE(n) ((n) * 1024LL * 1024LL)
00045 
00046 #define MALLOC(type, size)  (type *)malloc(sizeof(type) * (size))
00047 
00048 template<class T> inline void DELETENULL(T *&p) { T *q = p; p = NULL; delete q; } 
00049 
00050 #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
00051 #define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
00052 
00053 #ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
00054 template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
00055 template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
00056 template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
00057 template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
00058 #endif
00059 
00060 template<class T> inline T constrain(T v, T l, T h) { return v < l ? l : v > h ? h : v; }
00061 
00062 void syslog_with_tid(int priority, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
00063 
00064 #define BCDCHARTOINT(x) (10 * ((x & 0xF0) >> 4) + (x & 0xF))
00065 int BCD2INT(int x);
00066 
00067 // Unfortunately there are no platform independent macros for unaligned
00068 // access, so we do it this way:
00069 
00070 template<class T> inline T get_unaligned(T *p)
00071 {
00072   struct s { T v; } __attribute__((packed));
00073   return ((s *)p)->v;
00074 }
00075 
00076 template<class T> inline void put_unaligned(unsigned int v, T* p)
00077 {
00078   struct s { T v; } __attribute__((packed));
00079   ((s *)p)->v = v;
00080 }
00081 
00082 // Comparing doubles for equality is unsafe, but unfortunately we can't
00083 // overwrite operator==(double, double), so this will have to do:
00084 
00085 inline bool DoubleEqual(double a, double b)
00086 {
00087   return fabs(a - b) <= DBL_EPSILON;
00088 }
00089 
00090 // When handling strings that might contain UTF-8 characters, it may be necessary
00091 // to process a "symbol" that consists of several actual character bytes. The
00092 // following functions allow transparently accessing a "char *" string without
00093 // having to worry about what character set is actually used.
00094 
00095 int Utf8CharLen(const char *s);
00098 uint Utf8CharGet(const char *s, int Length = 0);
00102 int Utf8CharSet(uint c, char *s = NULL);
00106 int Utf8SymChars(const char *s, int Symbols);
00109 int Utf8StrLen(const char *s);
00112 char *Utf8Strn0Cpy(char *Dest, const char *Src, int n);
00117 int Utf8ToArray(const char *s, uint *a, int Size);
00121 int Utf8FromArray(const uint *a, char *s, int Size, int Max = -1);
00127 
00128 // When allocating buffer space, make sure we reserve enough space to hold
00129 // a string in UTF-8 representation:
00130 
00131 #define Utf8BufSize(s) ((s) * 4)
00132 
00133 // The following macros automatically use the correct versions of the character
00134 // class functions:
00135 
00136 #define Utf8to(conv, c) (cCharSetConv::SystemCharacterTable() ? to##conv(c) : tow##conv(c))
00137 #define Utf8is(ccls, c) (cCharSetConv::SystemCharacterTable() ? is##ccls(c) : isw##ccls(c))
00138 
00139 class cCharSetConv {
00140 private:
00141   iconv_t cd;
00142   char *result;
00143   size_t length;
00144   static char *systemCharacterTable;
00145 public:
00146   cCharSetConv(const char *FromCode = NULL, const char *ToCode = NULL);
00151   ~cCharSetConv();
00152   const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
00162   static const char *SystemCharacterTable(void) { return systemCharacterTable; }
00163   static void SetSystemCharacterTable(const char *CharacterTable);
00164   };
00165 
00166 class cString {
00167 private:
00168   char *s;
00169 public:
00170   cString(const char *S = NULL, bool TakePointer = false);
00171   cString(const cString &String);
00172   virtual ~cString();
00173   operator const void * () const { return s; } // to catch cases where operator*() should be used
00174   operator const char * () const { return s; } // for use in (const char *) context
00175   const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
00176   cString &operator=(const cString &String);
00177   cString &operator=(const char *String);
00178   cString &Truncate(int Index); 
00179   static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
00180   static cString sprintf(const char *fmt, va_list &ap);
00181   };
00182 
00183 ssize_t safe_read(int filedes, void *buffer, size_t size);
00184 ssize_t safe_write(int filedes, const void *buffer, size_t size);
00185 void writechar(int filedes, char c);
00186 int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs = 0, int RetryMs = 0);
00190 char *strcpyrealloc(char *dest, const char *src);
00191 char *strn0cpy(char *dest, const char *src, size_t n);
00192 char *strreplace(char *s, char c1, char c2);
00193 char *strreplace(char *s, const char *s1, const char *s2); 
00194 inline char *skipspace(const char *s)
00195 {
00196   if ((uchar)*s > ' ') // most strings don't have any leading space, so handle this case as fast as possible
00197      return (char *)s;
00198   while (*s && (uchar)*s <= ' ') // avoiding isspace() here, because it is much slower
00199         s++;
00200   return (char *)s;
00201 }
00202 char *stripspace(char *s);
00203 char *compactspace(char *s);
00204 cString strescape(const char *s, const char *chars);
00205 bool startswith(const char *s, const char *p);
00206 bool endswith(const char *s, const char *p);
00207 bool isempty(const char *s);
00208 int numdigits(int n);
00209 bool isnumber(const char *s);
00210 int64_t StrToNum(const char *s);
00216 cString itoa(int n);
00217 cString AddDirectory(const char *DirName, const char *FileName);
00218 bool EntriesOnSameFileSystem(const char *File1, const char *File2);
00219 int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL);
00220 bool DirectoryOk(const char *DirName, bool LogErrors = false);
00221 bool MakeDirs(const char *FileName, bool IsDirectory = false);
00222 bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
00223 bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false);
00224 int DirSizeMB(const char *DirName); 
00225 char *ReadLink(const char *FileName); 
00226 bool SpinUpDisk(const char *FileName);
00227 void TouchFile(const char *FileName);
00228 time_t LastModifiedTime(const char *FileName);
00229 off_t FileSize(const char *FileName); 
00230 cString WeekDayName(int WeekDay);
00231 cString WeekDayName(time_t t);
00232 cString WeekDayNameFull(int WeekDay);
00233 cString WeekDayNameFull(time_t t);
00234 cString DayDateTime(time_t t = 0);
00235 cString TimeToString(time_t t);
00236 cString DateString(time_t t);
00237 cString TimeString(time_t t);
00238 uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100);
00247 
00248 class cBase64Encoder {
00249 private:
00250   const uchar *data;
00251   int length;
00252   int maxResult;
00253   int i;
00254   char *result;
00255   static const char *b64;
00256 public:
00257   cBase64Encoder(const uchar *Data, int Length, int MaxResult = 64);
00263   ~cBase64Encoder();
00264   const char *NextLine(void);
00270   };
00271 
00272 class cBitStream {
00273 private:
00274   const uint8_t *data;
00275   int length; // in bits
00276   int index; // in bits
00277 public:
00278   cBitStream(const uint8_t *Data, int Length) : data(Data), length(Length), index(0) {}
00279   ~cBitStream() {}
00280   int GetBit(void);
00281   uint32_t GetBits(int n);
00282   void ByteAlign(void);
00283   void WordAlign(void);
00284   bool SetLength(int Length);
00285   void SkipBits(int n) { index += n; }
00286   void SkipBit(void) { SkipBits(1); }
00287   bool IsEOF(void) const { return index >= length; }
00288   void Reset(void) { index = 0; }
00289   int Length(void) const { return length; }
00290   int Index(void) const { return (IsEOF() ? length : index); }
00291   const uint8_t *GetData(void) const { return (IsEOF() ? NULL : data + (index / 8)); }
00292   };
00293 
00294 class cTimeMs {
00295 private:
00296   uint64_t begin;
00297 public:
00298   cTimeMs(int Ms = 0);
00302   static uint64_t Now(void);
00303   void Set(int Ms = 0);
00304   bool TimedOut(void);
00305   uint64_t Elapsed(void);
00306   };
00307 
00308 class cReadLine {
00309 private:
00310   size_t size;
00311   char *buffer;
00312 public:
00313   cReadLine(void);
00314   ~cReadLine();
00315   char *Read(FILE *f);
00316   };
00317 
00318 class cPoller {
00319 private:
00320   enum { MaxPollFiles = 16 };
00321   pollfd pfd[MaxPollFiles];
00322   int numFileHandles;
00323 public:
00324   cPoller(int FileHandle = -1, bool Out = false);
00325   bool Add(int FileHandle, bool Out);
00326   bool Poll(int TimeoutMs = 0);
00327   };
00328 
00329 class cReadDir {
00330 private:
00331   DIR *directory;
00332   struct dirent *result;
00333   union { // according to "The GNU C Library Reference Manual"
00334     struct dirent d;
00335     char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
00336     } u;
00337 public:
00338   cReadDir(const char *Directory);
00339   ~cReadDir();
00340   bool Ok(void) { return directory != NULL; }
00341   struct dirent *Next(void);
00342   };
00343 
00344 class cFile {
00345 private:
00346   static bool files[];
00347   static int maxFiles;
00348   int f;
00349 public:
00350   cFile(void);
00351   ~cFile();
00352   operator int () { return f; }
00353   bool Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
00354   bool Open(int FileDes);
00355   void Close(void);
00356   bool IsOpen(void) { return f >= 0; }
00357   bool Ready(bool Wait = true);
00358   static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000);
00359   static bool FileReady(int FileDes, int TimeoutMs = 1000);
00360   static bool FileReadyForWriting(int FileDes, int TimeoutMs = 1000);
00361   };
00362 
00363 class cSafeFile {
00364 private:
00365   FILE *f;
00366   char *fileName;
00367   char *tempName;
00368 public:
00369   cSafeFile(const char *FileName);
00370   ~cSafeFile();
00371   operator FILE* () { return f; }
00372   bool Open(void);
00373   bool Close(void);
00374   };
00375 
00378 
00379 class cUnbufferedFile {
00380 private:
00381   int fd;
00382   off_t curpos;
00383   off_t cachedstart;
00384   off_t cachedend;
00385   off_t begin;
00386   off_t lastpos;
00387   off_t ahead;
00388   size_t readahead;
00389   size_t written;
00390   size_t totwritten;
00391   int FadviseDrop(off_t Offset, off_t Len);
00392 public:
00393   cUnbufferedFile(void);
00394   ~cUnbufferedFile();
00395   int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
00396   int Close(void);
00397   void SetReadAhead(size_t ra);
00398   off_t Seek(off_t Offset, int Whence);
00399   ssize_t Read(void *Data, size_t Size);
00400   ssize_t Write(const void *Data, size_t Size);
00401   static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
00402   };
00403 
00404 class cLockFile {
00405 private:
00406   char *fileName;
00407   int f;
00408 public:
00409   cLockFile(const char *Directory);
00410   ~cLockFile();
00411   bool Lock(int WaitSeconds = 0);
00412   void Unlock(void);
00413   };
00414 
00415 class cListObject {
00416 private:
00417   cListObject *prev, *next;
00418 public:
00419   cListObject(void);
00420   virtual ~cListObject();
00421   virtual int Compare(const cListObject &ListObject) const { return 0; }
00424   void Append(cListObject *Object);
00425   void Insert(cListObject *Object);
00426   void Unlink(void);
00427   int Index(void) const;
00428   cListObject *Prev(void) const { return prev; }
00429   cListObject *Next(void) const { return next; }
00430   };
00431 
00432 class cListBase {
00433 protected:
00434   cListObject *objects, *lastObject;
00435   cListBase(void);
00436   int count;
00437 public:
00438   virtual ~cListBase();
00439   void Add(cListObject *Object, cListObject *After = NULL);
00440   void Ins(cListObject *Object, cListObject *Before = NULL);
00441   void Del(cListObject *Object, bool DeleteObject = true);
00442   virtual void Move(int From, int To);
00443   void Move(cListObject *From, cListObject *To);
00444   virtual void Clear(void);
00445   cListObject *Get(int Index) const;
00446   int Count(void) const { return count; }
00447   void Sort(void);
00448   };
00449 
00450 template<class T> class cList : public cListBase {
00451 public:
00452   T *Get(int Index) const { return (T *)cListBase::Get(Index); }
00453   T *First(void) const { return (T *)objects; }
00454   T *Last(void) const { return (T *)lastObject; }
00455   T *Prev(const T *object) const { return (T *)object->cListObject::Prev(); } // need to call cListObject's members to
00456   T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists"
00457   };
00458 
00459 template<class T> class cVector {
00460 private:
00461   mutable int allocated;
00462   mutable int size;
00463   mutable T *data;
00464   cVector(const cVector &Vector) {} // don't copy...
00465   cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this!
00466   void Realloc(int Index) const
00467   {
00468     if (++Index > allocated) {
00469        data = (T *)realloc(data, Index * sizeof(T));
00470        if (!data) {
00471           esyslog("ERROR: out of memory - abort!");
00472           abort();
00473           }
00474        for (int i = allocated; i < Index; i++)
00475            data[i] = T(0);
00476        allocated = Index;
00477        }
00478   }
00479 public:
00480   cVector(int Allocated = 10)
00481   {
00482     allocated = 0;
00483     size = 0;
00484     data = NULL;
00485     Realloc(Allocated);
00486   }
00487   virtual ~cVector() { free(data); }
00488   T& At(int Index) const
00489   {
00490     Realloc(Index);
00491     if (Index >= size)
00492        size = Index + 1;
00493     return data[Index];
00494   }
00495   const T& operator[](int Index) const
00496   {
00497     return At(Index);
00498   }
00499   T& operator[](int Index)
00500   {
00501     return At(Index);
00502   }
00503   int Size(void) const { return size; }
00504   virtual void Insert(T Data, int Before = 0)
00505   {
00506     if (Before < size) {
00507        Realloc(size);
00508        memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T));
00509        size++;
00510        data[Before] = Data;
00511        }
00512     else
00513        Append(Data);
00514   }
00515   virtual void Append(T Data)
00516   {
00517     if (size >= allocated)
00518        Realloc(allocated * 4 / 2); // increase size by 50%
00519     data[size++] = Data;
00520   }
00521   virtual void Remove(int Index)
00522   {
00523     if (Index < size - 1)
00524        memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T));
00525     size--;
00526   }
00527   virtual void Clear(void)
00528   {
00529     size = 0;
00530   }
00531   void Sort(__compar_fn_t Compare)
00532   {
00533     qsort(data, size, sizeof(T), Compare);
00534   }
00535   };
00536 
00537 inline int CompareStrings(const void *a, const void *b)
00538 {
00539   return strcmp(*(const char **)a, *(const char **)b);
00540 }
00541 
00542 inline int CompareStringsIgnoreCase(const void *a, const void *b)
00543 {
00544   return strcasecmp(*(const char **)a, *(const char **)b);
00545 }
00546 
00547 class cStringList : public cVector<char *> {
00548 public:
00549   cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
00550   virtual ~cStringList();
00551   int Find(const char *s) const;
00552   void Sort(bool IgnoreCase = false)
00553   {
00554     if (IgnoreCase)
00555        cVector<char *>::Sort(CompareStringsIgnoreCase);
00556     else
00557        cVector<char *>::Sort(CompareStrings);
00558   }
00559   virtual void Clear(void);
00560   };
00561 
00562 class cFileNameList : public cStringList {
00563 public:
00564   cFileNameList(const char *Directory = NULL, bool DirsOnly = false);
00565   bool Load(const char *Directory, bool DirsOnly = false);
00566   };
00567 
00568 class cHashObject : public cListObject {
00569   friend class cHashBase;
00570 private:
00571   unsigned int id;
00572   cListObject *object;
00573 public:
00574   cHashObject(cListObject *Object, unsigned int Id) { object = Object; id = Id; }
00575   cListObject *Object(void) { return object; }
00576   };
00577 
00578 class cHashBase {
00579 private:
00580   cList<cHashObject> **hashTable;
00581   int size;
00582   unsigned int hashfn(unsigned int Id) const { return Id % size; }
00583 protected:
00584   cHashBase(int Size);
00585 public:
00586   virtual ~cHashBase();
00587   void Add(cListObject *Object, unsigned int Id);
00588   void Del(cListObject *Object, unsigned int Id);
00589   void Clear(void);
00590   cListObject *Get(unsigned int Id) const;
00591   cList<cHashObject> *GetList(unsigned int Id) const;
00592   };
00593 
00594 #define HASHSIZE 512
00595 
00596 template<class T> class cHash : public cHashBase {
00597 public:
00598   cHash(int Size = HASHSIZE) : cHashBase(Size) {}
00599   T *Get(unsigned int Id) const { return (T *)cHashBase::Get(Id); }
00600 };
00601 
00602 #endif //__TOOLS_H