📄 data.c
字号:
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <ctype.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/mman.h>#include <sys/stat.h>#include "data.h"#include "misc.h"#include "scsetup.h"#include "log-core.h"#include "i18n.h"#define KEY_FILE "SoftCam.Key"#define EXT_AU_INT (15*60*1000) // ms interval for external AU#define EXT_AU_MIN ( 2*60*1000) // ms min. interval for external AU// -- cFileMap -----------------------------------------------------------------cFileMap::cFileMap(const char *Filename, bool Rw){ filename=strdup(Filename); rw=Rw; fd=-1; count=len=0; addr=0; failed=false;}cFileMap::~cFileMap(){ Clean(); free(filename);}bool cFileMap::IsFileMap(const char *Name, bool Rw){ return (!strcmp(Name,filename) && (!Rw || rw));}void cFileMap::Clean(void){ if(addr) { munmap(addr,len); addr=0; len=0; } if(fd>=0) { close(fd); fd=-1; }}bool cFileMap::Map(void){ cMutexLock lock(this); if(addr) { count++; return true; } if(!failed) { struct stat64 ds; if(!stat64(filename,&ds)) { if(S_ISREG(ds.st_mode)) { fd=open(filename,rw ? O_RDWR : O_RDONLY); if(fd>=0) { unsigned char *map=(unsigned char *)mmap(0,ds.st_size,rw ? (PROT_READ|PROT_WRITE):(PROT_READ),MAP_SHARED,fd,0); if(map!=MAP_FAILED) { addr=map; len=ds.st_size; count=1; return true; } else PRINTF(L_GEN_ERROR,"mapping failed on %s: %s",filename,strerror(errno)); close(fd); fd=-1; } else PRINTF(L_GEN_ERROR,"error opening filemap %s: %s",filename,strerror(errno)); } else PRINTF(L_GEN_ERROR,"filemap %s is not a regular file",filename); } else PRINTF(L_GEN_ERROR,"can't stat filemap %s: %s",filename,strerror(errno)); failed=true; // don't try this one over and over again } return false;}bool cFileMap::Unmap(void){ cMutexLock lock(this); if(addr) { if(!(--count)) { Clean(); return true; } else Sync(); } return false;}void cFileMap::Sync(void){ cMutexLock lock(this); if(addr) msync(addr,len,MS_ASYNC);}// -- cFileMaps ----------------------------------------------------------------cFileMaps filemaps;cFileMaps::cFileMaps(void){ cfgDir=0;}cFileMaps::~cFileMaps(){ Clear(); free(cfgDir);}void cFileMaps::SetCfgDir(const char *CfgDir){ free(cfgDir); cfgDir=strdup(CfgDir);}cFileMap *cFileMaps::GetFileMap(const char *name, const char *domain, bool rw){ cMutexLock lock(this); char path[256]; snprintf(path,sizeof(path),"%s/%s/%s",cfgDir,domain,name); cFileMap *fm=First(); while(fm) { if(fm->IsFileMap(path,rw)) return fm; fm=Next(fm); } fm=new cFileMap(path,rw); Add(fm); return fm; }// -- cStructItem --------------------------------------------------------------cStructItem::cStructItem(void){ comment=0; deleted=special=false;}cStructItem::~cStructItem(){ free(comment);}void cStructItem::SetComment(const char *com){ free(comment); comment=com ? strdup(com):0;}bool cStructItem::Save(FILE *f){ fprintf(f,"%s%s\n",*ToString(false),comment?comment:""); return ferror(f)==0;}// -- cCommentItem -------------------------------------------------------------class cCommentItem : public cStructItem {public: cCommentItem(void); };cCommentItem::cCommentItem(void){ SetSpecial();}// -- cStructLoader ------------------------------------------------------------cStructLoader::cStructLoader(const char *Type, const char *Filename, int Flags):lock(true){ path=0; mtime=0; type=Type; filename=Filename; flags=Flags&SL_CUSTOMMASK; cStructLoaders::Register(this);}cStructLoader::~cStructLoader(){ free(path);}void cStructLoader::AddItem(cStructItem *n, const char *com, cStructItem *ref){ n->SetComment(com); ListLock(true); cStructItem *a=0; if(ref) { // insert before reference for(a=First(); a; a=Next(a)) if(Next(a)==ref) break; } if(!a) { // insert before first non-special for(a=First(); a;) { cStructItem *nn=Next(a); if(nn && !nn->Special()) break; a=nn; } } Add(n,a); Modified(); ListUnlock();}void cStructLoader::DelItem(cStructItem *d, bool keep){ if(d) { d->Delete(); if(keep) { cStructItem *n=new cCommentItem; n->SetComment(cString::sprintf(";%s%s",*d->ToString(false),d->Comment()?d->Comment():"")); ListLock(true); Add(n,d); ListUnlock(); } Modified(); }}cStructItem *cStructLoader::NextValid(cStructItem *it) const{ while(it && !it->Valid()) it=Next(it); return it;}void cStructLoader::SetCfgDir(const char *cfgdir){ free(path); path=strdup(AddDirectory(cfgdir,filename));}time_t cStructLoader::MTime(bool log){ struct stat64 st; if(stat64(path,&st)!=0) { if(log) { PRINTF(L_GEN_ERROR,"failed fstat %s: %s",path,strerror(errno)); PRINTF(L_GEN_WARN,"automatic reload of %s disabled",path); } st.st_mtime=0; } return st.st_mtime;}void cStructLoader::CheckAccess(void){ if(access(path,R_OK|W_OK)!=0) { if(errno!=EACCES) PRINTF(L_GEN_ERROR,"failed access %s: %s",path,strerror(errno)); PRINTF(L_GEN_WARN,"no write permission on %s. Changes will not be saved!",path); SL_SETFLAG(SL_NOACCESS); } else SL_CLRFLAG(SL_NOACCESS);}bool cStructLoader::CheckUnmodified(void){ time_t curr_mtime=MTime(false); if(mtime && mtime<curr_mtime && SL_TSTFLAG(SL_WATCH)) { PRINTF(L_CORE_LOAD,"abort save as file %s has been changed externaly",path); return false; } return true;}bool cStructLoader::CheckDoSave(void){ return !SL_TSTFLAG(SL_DISABLED) && SL_TSTFLAG(SL_READWRITE) && !SL_TSTFLAG(SL_NOACCESS) && SL_TSTFLAG(SL_LOADED) && IsModified() && CheckUnmodified();}void cStructLoader::LoadFinished(void){ SL_CLRFLAG(SL_SHUTUP); if(!SL_TSTFLAG(SL_LOADED)) PRINTF(L_CORE_LOAD,"loading %s terminated with error. Changes will not be saved!",path);}void cStructLoader::OpenFailed(void){ if(SL_TSTFLAG(SL_VERBOSE) && !SL_TSTFLAG(SL_SHUTUP)) { PRINTF(L_GEN_ERROR,"failed open %s: %s",path,strerror(errno)); SL_SETFLAG(SL_SHUTUP); } if(SL_TSTFLAG(SL_MISSINGOK)) SL_SETFLAG(SL_LOADED); else SL_CLRFLAG(SL_LOADED);}void cStructLoader::Load(bool reload){ if(SL_TSTFLAG(SL_DISABLED) || (reload && !SL_TSTFLAG(SL_WATCH))) return; FILE *f=fopen(path,"r"); if(f) { int curr_mtime=MTime(true); ListLock(true); bool doload=false; if(!reload) { Clear(); Modified(false); mtime=curr_mtime; doload=true; } else if(mtime<curr_mtime) { PRINTF(L_CORE_LOAD,"detected change of %s",path); if(IsModified()) PRINTF(L_CORE_LOAD,"discarding in-memory changes"); for(cStructItem *a=First(); a; a=Next(a)) DelItem(a); Modified(false); mtime=curr_mtime; doload=true; } if(doload) { SL_SETFLAG(SL_LOADED); PRINTF(L_GEN_INFO,"loading %s from %s",type,path); CheckAccess(); int lineNum=0, num=0; char buff[4096]; while(fgets(buff,sizeof(buff),f)) { lineNum++; if(!index(buff,'\n') && !feof(f)) { PRINTF(L_GEN_ERROR,"file %s readbuffer overflow line#%d",path,lineNum); SL_CLRFLAG(SL_LOADED); break; } strreplace(buff,'\n',0); strreplace(buff,'\r',0); // chomp bool hasContent=false; char *ls; for(ls=buff; *ls; ls++) { if(*ls==';' || *ls=='#') { // comment if(hasContent) while(ls>buff && ls[-1]<=' ') ls--; // search back to non-whitespace break; } if(*ls>' ') hasContent=true; // line contains something usefull } cStructItem *it=0; if(hasContent) { char save=*ls; *ls=0; it=ParseLine(skipspace(buff)); *ls=save; if(!it) { PRINTF(L_GEN_ERROR,"file %s has error in line #%d",path,lineNum); ls=buff; } else num++; } else ls=buff; if(!it) it=new cCommentItem; if(it) { it->SetComment(ls); Add(it); } else { PRINTF(L_GEN_ERROR,"out of memory loading file %s",path); SL_CLRFLAG(SL_LOADED); break; } } ListUnlock(); PRINTF(L_CORE_LOAD,"loaded %d %s from %s",num,type,path); PostLoad(); } else ListUnlock(); fclose(f); LoadFinished(); } else OpenFailed();}void cStructLoader::Purge(void){ if(!SL_TSTFLAG(SL_DISABLED) && !SL_TSTFLAG(SL_NOPURGE)) { ListLock(true); for(cStructItem *it=First(); it;) { cStructItem *n=Next(it); if(it->Deleted()) Del(it); it=n; } ListUnlock(); }}void cStructLoader::Save(void){ if(CheckDoSave()) { cSafeFile f(path); if(f.Open()) { ListLock(false); for(cStructItem *it=First(); it; it=Next(it)) if(!it->Deleted() && !it->Save(f)) break; f.Close(); mtime=MTime(true); Modified(false); ListUnlock(); PRINTF(L_CORE_LOAD,"saved %s to %s",type,path); } }}// -- cStructLoaderPlain -------------------------------------------------------cStructLoaderPlain::cStructLoaderPlain(const char *Type, const char *Filename, int Flags):cStructLoader(Type,Filename,Flags){}void cStructLoaderPlain::PreLoad(void){ ListLock(true); Clear(); Modified(false); ListUnlock();}void cStructLoaderPlain::Load(bool reload){ if(SL_TSTFLAG(SL_DISABLED) || reload) return; FILE *f=fopen(path,"r"); if(f) { PreLoad(); ListLock(true); SL_SETFLAG(SL_LOADED); PRINTF(L_GEN_INFO,"loading %s from %s",type,path); CheckAccess(); int lineNum=0; char buff[4096]; while(fgets(buff,sizeof(buff),f)) { lineNum++; if(!index(buff,'\n') && !feof(f)) { PRINTF(L_GEN_ERROR,"file %s readbuffer overflow line#%d",path,lineNum); SL_CLRFLAG(SL_LOADED); break; } strreplace(buff,'\n',0); strreplace(buff,'\r',0); // chomp bool hasContent=false; char *ls; for(ls=buff; *ls; ls++) { if(*ls==';' || *ls=='#') break; if(*ls>' ') hasContent=true; } if(hasContent) { *ls=0; if(!ParseLinePlain(skipspace(buff))) PRINTF(L_GEN_ERROR,"file %s has error in line #%d",path,lineNum); } } ListUnlock(); PostLoad(); fclose(f); LoadFinished(); } else OpenFailed();}void cStructLoaderPlain::PreSave(FILE *f){ fprintf(f,"## This is a generated file. DO NOT EDIT!!\n" "## This file will be OVERWRITTEN WITHOUT WARNING!!\n");}void cStructLoaderPlain::Save(void){ if(CheckDoSave()) { cSafeFile f(path); if(f.Open()) { ListLock(false); PreSave(f); for(cStructItem *it=First(); it; it=Next(it)) if(!it->Deleted() && !it->Save(f)) break; PostSave(f); f.Close(); Modified(false); ListUnlock(); PRINTF(L_CORE_LOAD,"saved %s to %s",type,path); } }}// -- cStructLoaders -----------------------------------------------------------#define RELOAD_TIMEOUT 20300 // ms#define PURGE_TIMEOUT 60700 // ms#define SAVE_TIMEOUT 5000 // ms
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -