vdr
1.7.27
|
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