vdr  1.7.31
tools.h
Go to the documentation of this file.
1 /*
2  * tools.h: Various tools
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: tools.h 2.22 2012/09/30 11:02:21 kls Exp $
8  */
9 
10 #ifndef __TOOLS_H
11 #define __TOOLS_H
12 
13 #include <dirent.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <float.h>
17 #include <iconv.h>
18 #include <math.h>
19 #include <poll.h>
20 #include <stdarg.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <syslog.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 
30 typedef unsigned char uchar;
31 
32 extern int SysLogLevel;
33 
34 #define esyslog(a...) void( (SysLogLevel > 0) ? syslog_with_tid(LOG_ERR, a) : void() )
35 #define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_ERR, a) : void() )
36 #define dsyslog(a...) void( (SysLogLevel > 2) ? syslog_with_tid(LOG_ERR, a) : void() )
37 
38 #define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
39 #define LOG_ERROR_STR(s) esyslog("ERROR (%s,%d): %s: %m", __FILE__, __LINE__, s)
40 
41 #define SECSINDAY 86400
42 
43 #define KILOBYTE(n) ((n) * 1024)
44 #define MEGABYTE(n) ((n) * 1024LL * 1024LL)
45 
46 #define MALLOC(type, size) (type *)malloc(sizeof(type) * (size))
47 
48 template<class T> inline void DELETENULL(T *&p) { T *q = p; p = NULL; delete q; }
49 
50 #define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
51 #define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
52 
53 #ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
54 template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
55 template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
56 template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
57 template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
58 #endif
59 
60 template<class T> inline T constrain(T v, T l, T h) { return v < l ? l : v > h ? h : v; }
61 
62 void syslog_with_tid(int priority, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
63 
64 #define BCDCHARTOINT(x) (10 * ((x & 0xF0) >> 4) + (x & 0xF))
65 int BCD2INT(int x);
66 
67 // Unfortunately there are no platform independent macros for unaligned
68 // access, so we do it this way:
69 
70 template<class T> inline T get_unaligned(T *p)
71 {
72  struct s { T v; } __attribute__((packed));
73  return ((s *)p)->v;
74 }
75 
76 template<class T> inline void put_unaligned(unsigned int v, T* p)
77 {
78  struct s { T v; } __attribute__((packed));
79  ((s *)p)->v = v;
80 }
81 
82 // Comparing doubles for equality is unsafe, but unfortunately we can't
83 // overwrite operator==(double, double), so this will have to do:
84 
85 inline bool DoubleEqual(double a, double b)
86 {
87  return fabs(a - b) <= DBL_EPSILON;
88 }
89 
90 // When handling strings that might contain UTF-8 characters, it may be necessary
91 // to process a "symbol" that consists of several actual character bytes. The
92 // following functions allow transparently accessing a "char *" string without
93 // having to worry about what character set is actually used.
94 
95 int Utf8CharLen(const char *s);
98 uint Utf8CharGet(const char *s, int Length = 0);
102 int Utf8CharSet(uint c, char *s = NULL);
106 int Utf8SymChars(const char *s, int Symbols);
109 int Utf8StrLen(const char *s);
112 char *Utf8Strn0Cpy(char *Dest, const char *Src, int n);
117 int Utf8ToArray(const char *s, uint *a, int Size);
121 int Utf8FromArray(const uint *a, char *s, int Size, int Max = -1);
127 
128 // When allocating buffer space, make sure we reserve enough space to hold
129 // a string in UTF-8 representation:
130 
131 #define Utf8BufSize(s) ((s) * 4)
132 
133 // The following macros automatically use the correct versions of the character
134 // class functions:
135 
136 #define Utf8to(conv, c) (cCharSetConv::SystemCharacterTable() ? to##conv(c) : tow##conv(c))
137 #define Utf8is(ccls, c) (cCharSetConv::SystemCharacterTable() ? is##ccls(c) : isw##ccls(c))
138 
139 class cCharSetConv {
140 private:
141  iconv_t cd;
142  char *result;
143  size_t length;
144  static char *systemCharacterTable;
145 public:
146  cCharSetConv(const char *FromCode = NULL, const char *ToCode = NULL);
151  ~cCharSetConv();
152  const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
162  static const char *SystemCharacterTable(void) { return systemCharacterTable; }
163  static void SetSystemCharacterTable(const char *CharacterTable);
164  };
165 
166 class cString {
167 private:
168  char *s;
169 public:
170  cString(const char *S = NULL, bool TakePointer = false);
171  cString(const cString &String);
172  virtual ~cString();
173  operator const void * () const { return s; } // to catch cases where operator*() should be used
174  operator const char * () const { return s; } // for use in (const char *) context
175  const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
176  cString &operator=(const cString &String);
177  cString &operator=(const char *String);
178  cString &Truncate(int Index);
179  static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
180  static cString vsprintf(const char *fmt, va_list &ap);
181  };
182 
183 ssize_t safe_read(int filedes, void *buffer, size_t size);
184 ssize_t safe_write(int filedes, const void *buffer, size_t size);
185 void writechar(int filedes, char c);
186 int WriteAllOrNothing(int fd, const uchar *Data, int Length, int TimeoutMs = 0, int RetryMs = 0);
190 char *strcpyrealloc(char *dest, const char *src);
191 char *strn0cpy(char *dest, const char *src, size_t n);
192 char *strreplace(char *s, char c1, char c2);
193 char *strreplace(char *s, const char *s1, const char *s2);
194 inline char *skipspace(const char *s)
195 {
196  if ((uchar)*s > ' ') // most strings don't have any leading space, so handle this case as fast as possible
197  return (char *)s;
198  while (*s && (uchar)*s <= ' ') // avoiding isspace() here, because it is much slower
199  s++;
200  return (char *)s;
201 }
202 char *stripspace(char *s);
203 char *compactspace(char *s);
204 cString strescape(const char *s, const char *chars);
205 bool startswith(const char *s, const char *p);
206 bool endswith(const char *s, const char *p);
207 bool isempty(const char *s);
208 int numdigits(int n);
209 bool isnumber(const char *s);
210 int64_t StrToNum(const char *s);
216 bool StrInArray(const char *a[], const char *s);
219 cString itoa(int n);
220 cString AddDirectory(const char *DirName, const char *FileName);
221 bool EntriesOnSameFileSystem(const char *File1, const char *File2);
222 int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL);
223 bool DirectoryOk(const char *DirName, bool LogErrors = false);
224 bool MakeDirs(const char *FileName, bool IsDirectory = false);
225 bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);
226 bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false, const char *IgnoreFiles[] = NULL);
232 int DirSizeMB(const char *DirName);
233 char *ReadLink(const char *FileName);
234 bool SpinUpDisk(const char *FileName);
235 void TouchFile(const char *FileName);
236 time_t LastModifiedTime(const char *FileName);
237 off_t FileSize(const char *FileName);
238 cString WeekDayName(int WeekDay);
241 cString WeekDayName(time_t t);
243 cString WeekDayNameFull(int WeekDay);
246 cString WeekDayNameFull(time_t t);
248 cString DayDateTime(time_t t = 0);
251 cString TimeToString(time_t t);
253 cString DateString(time_t t);
255 cString ShortDateString(time_t t);
257 cString TimeString(time_t t);
259 uchar *RgbToJpeg(uchar *Mem, int Width, int Height, int &Size, int Quality = 100);
268 
269 class cBase64Encoder {
270 private:
271  const uchar *data;
272  int length;
273  int maxResult;
274  int i;
275  char *result;
276  static const char *b64;
277 public:
278  cBase64Encoder(const uchar *Data, int Length, int MaxResult = 64);
284  ~cBase64Encoder();
285  const char *NextLine(void);
291  };
292 
293 class cBitStream {
294 private:
295  const uint8_t *data;
296  int length; // in bits
297  int index; // in bits
298 public:
299  cBitStream(const uint8_t *Data, int Length) : data(Data), length(Length), index(0) {}
301  int GetBit(void);
302  uint32_t GetBits(int n);
303  void ByteAlign(void);
304  void WordAlign(void);
305  bool SetLength(int Length);
306  void SkipBits(int n) { index += n; }
307  void SkipBit(void) { SkipBits(1); }
308  bool IsEOF(void) const { return index >= length; }
309  void Reset(void) { index = 0; }
310  int Length(void) const { return length; }
311  int Index(void) const { return (IsEOF() ? length : index); }
312  const uint8_t *GetData(void) const { return (IsEOF() ? NULL : data + (index / 8)); }
313  };
314 
315 class cTimeMs {
316 private:
317  uint64_t begin;
318 public:
319  cTimeMs(int Ms = 0);
323  static uint64_t Now(void);
324  void Set(int Ms = 0);
325  bool TimedOut(void);
326  uint64_t Elapsed(void);
327  };
328 
329 class cReadLine {
330 private:
331  size_t size;
332  char *buffer;
333 public:
334  cReadLine(void);
335  ~cReadLine();
336  char *Read(FILE *f);
337  };
338 
339 class cPoller {
340 private:
341  enum { MaxPollFiles = 16 };
342  pollfd pfd[MaxPollFiles];
343  int numFileHandles;
344 public:
345  cPoller(int FileHandle = -1, bool Out = false);
346  bool Add(int FileHandle, bool Out);
347  bool Poll(int TimeoutMs = 0);
348  };
349 
350 class cReadDir {
351 private:
352  DIR *directory;
353  struct dirent *result;
354  union { // according to "The GNU C Library Reference Manual"
355  struct dirent d;
356  char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
357  } u;
358 public:
359  cReadDir(const char *Directory);
360  ~cReadDir();
361  bool Ok(void) { return directory != NULL; }
362  struct dirent *Next(void);
363  };
364 
365 class cFile {
366 private:
367  static bool files[];
368  static int maxFiles;
369  int f;
370 public:
371  cFile(void);
372  ~cFile();
373  operator int () { return f; }
374  bool Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
375  bool Open(int FileDes);
376  void Close(void);
377  bool IsOpen(void) { return f >= 0; }
378  bool Ready(bool Wait = true);
379  static bool AnyFileReady(int FileDes = -1, int TimeoutMs = 1000);
380  static bool FileReady(int FileDes, int TimeoutMs = 1000);
381  static bool FileReadyForWriting(int FileDes, int TimeoutMs = 1000);
382  };
383 
384 class cSafeFile {
385 private:
386  FILE *f;
387  char *fileName;
388  char *tempName;
389 public:
390  cSafeFile(const char *FileName);
391  ~cSafeFile();
392  operator FILE* () { return f; }
393  bool Open(void);
394  bool Close(void);
395  };
396 
399 
400 class cUnbufferedFile {
401 private:
402  int fd;
403  off_t curpos;
404  off_t cachedstart;
405  off_t cachedend;
406  off_t begin;
407  off_t lastpos;
408  off_t ahead;
409  size_t readahead;
410  size_t written;
411  size_t totwritten;
412  int FadviseDrop(off_t Offset, off_t Len);
413 public:
414  cUnbufferedFile(void);
415  ~cUnbufferedFile();
416  int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
417  int Close(void);
418  void SetReadAhead(size_t ra);
419  off_t Seek(off_t Offset, int Whence);
420  ssize_t Read(void *Data, size_t Size);
421  ssize_t Write(const void *Data, size_t Size);
422  static cUnbufferedFile *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE);
423  };
424 
425 class cLockFile {
426 private:
427  char *fileName;
428  int f;
429 public:
430  cLockFile(const char *Directory);
431  ~cLockFile();
432  bool Lock(int WaitSeconds = 0);
433  void Unlock(void);
434  };
435 
436 class cListObject {
437 private:
438  cListObject *prev, *next;
439 public:
440  cListObject(void);
441  virtual ~cListObject();
442  virtual int Compare(const cListObject &ListObject) const { return 0; }
445  void Append(cListObject *Object);
446  void Insert(cListObject *Object);
447  void Unlink(void);
448  int Index(void) const;
449  cListObject *Prev(void) const { return prev; }
450  cListObject *Next(void) const { return next; }
451  };
452 
453 class cListBase {
454 protected:
455  cListObject *objects, *lastObject;
456  cListBase(void);
457  int count;
458 public:
459  virtual ~cListBase();
460  void Add(cListObject *Object, cListObject *After = NULL);
461  void Ins(cListObject *Object, cListObject *Before = NULL);
462  void Del(cListObject *Object, bool DeleteObject = true);
463  virtual void Move(int From, int To);
464  void Move(cListObject *From, cListObject *To);
465  virtual void Clear(void);
466  cListObject *Get(int Index) const;
467  int Count(void) const { return count; }
468  void Sort(void);
469  };
470 
471 template<class T> class cList : public cListBase {
472 public:
473  T *Get(int Index) const { return (T *)cListBase::Get(Index); }
474  T *First(void) const { return (T *)objects; }
475  T *Last(void) const { return (T *)lastObject; }
476  T *Prev(const T *object) const { return (T *)object->cListObject::Prev(); } // need to call cListObject's members to
477  T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists"
478  };
479 
480 template<class T> class cVector {
482 private:
483  mutable int allocated;
484  mutable int size;
485  mutable T *data;
486  cVector(const cVector &Vector) {} // don't copy...
487  cVector &operator=(const cVector &Vector) { return *this; } // ...or assign this!
488  void Realloc(int Index) const
489  {
490  if (++Index > allocated) {
491  data = (T *)realloc(data, Index * sizeof(T));
492  if (!data) {
493  esyslog("ERROR: out of memory - abort!");
494  abort();
495  }
496  for (int i = allocated; i < Index; i++)
497  data[i] = T(0);
498  allocated = Index;
499  }
500  }
501 public:
502  cVector(int Allocated = 10)
503  {
504  allocated = 0;
505  size = 0;
506  data = NULL;
507  Realloc(Allocated);
508  }
509  virtual ~cVector() { free(data); }
510  T& At(int Index) const
511  {
512  Realloc(Index);
513  if (Index >= size)
514  size = Index + 1;
515  return data[Index];
516  }
517  const T& operator[](int Index) const
518  {
519  return At(Index);
520  }
521  T& operator[](int Index)
522  {
523  return At(Index);
524  }
525  int Size(void) const { return size; }
526  virtual void Insert(T Data, int Before = 0)
527  {
528  if (Before < size) {
529  Realloc(size);
530  memmove(&data[Before + 1], &data[Before], (size - Before) * sizeof(T));
531  size++;
532  data[Before] = Data;
533  }
534  else
535  Append(Data);
536  }
537  virtual void Append(T Data)
538  {
539  if (size >= allocated)
540  Realloc(allocated * 3 / 2); // increase size by 50%
541  data[size++] = Data;
542  }
543  virtual void Remove(int Index)
544  {
545  if (Index < size - 1)
546  memmove(&data[Index], &data[Index + 1], (size - Index) * sizeof(T));
547  size--;
548  }
549  virtual void Clear(void)
550  {
551  for (int i = 0; i < size; i++)
552  data[i] = T(0);
553  size = 0;
554  }
555  void Sort(__compar_fn_t Compare)
556  {
557  qsort(data, size, sizeof(T), Compare);
558  }
559  };
560 
561 inline int CompareStrings(const void *a, const void *b)
562 {
563  return strcmp(*(const char **)a, *(const char **)b);
564 }
565 
566 inline int CompareStringsIgnoreCase(const void *a, const void *b)
567 {
568  return strcasecmp(*(const char **)a, *(const char **)b);
569 }
570 
571 class cStringList : public cVector<char *> {
572 public:
573  cStringList(int Allocated = 10): cVector<char *>(Allocated) {}
574  virtual ~cStringList();
575  int Find(const char *s) const;
576  void Sort(bool IgnoreCase = false)
577  {
578  if (IgnoreCase)
580  else
582  }
583  virtual void Clear(void);
584  };
585 
586 class cFileNameList : public cStringList {
587 public:
588  cFileNameList(const char *Directory = NULL, bool DirsOnly = false);
589  bool Load(const char *Directory, bool DirsOnly = false);
590  };
591 
592 class cHashObject : public cListObject {
593  friend class cHashBase;
594 private:
595  unsigned int id;
596  cListObject *object;
597 public:
598  cHashObject(cListObject *Object, unsigned int Id) { object = Object; id = Id; }
599  cListObject *Object(void) { return object; }
600  };
601 
602 class cHashBase {
603 private:
604  cList<cHashObject> **hashTable;
605  int size;
606  unsigned int hashfn(unsigned int Id) const { return Id % size; }
607 protected:
608  cHashBase(int Size);
609 public:
610  virtual ~cHashBase();
611  void Add(cListObject *Object, unsigned int Id);
612  void Del(cListObject *Object, unsigned int Id);
613  void Clear(void);
614  cListObject *Get(unsigned int Id) const;
615  cList<cHashObject> *GetList(unsigned int Id) const;
616  };
617 
618 #define HASHSIZE 512
619 
620 template<class T> class cHash : public cHashBase {
621 public:
622  cHash(int Size = HASHSIZE) : cHashBase(Size) {}
623  T *Get(unsigned int Id) const { return (T *)cHashBase::Get(Id); }
624 };
625 
626 #endif //__TOOLS_H