libept
|
00001 // -*- C++ -*- 00002 00003 #include <ept/core/apt/recordparser.h> 00004 00005 #ifndef EPT_APT_RECORD_H 00006 #define EPT_APT_RECORD_H 00007 00008 namespace ept { 00009 namespace core { 00010 namespace record { 00011 00012 struct Source; 00013 00014 struct InternalList { 00015 Source *m_source; 00016 size_t m_idx; 00017 00018 Internal head(); 00019 const Internal head() const; 00020 bool empty() const; 00021 00022 InternalList tail() const { 00023 InternalList t = *this; 00024 ++ t.m_idx; 00025 return t; 00026 } 00027 00028 InternalList( Source &s ) 00029 : m_source( &s ), m_idx( 0 ) 00030 {} 00031 }; 00032 00033 struct Setup { 00034 typedef ept::Token Token; 00035 typedef record::Internal Internal; 00036 typedef record::PropertyId PropertyId; 00037 typedef record::InternalList InternalList; 00038 }; 00039 00040 template<> struct PropertyType< InstalledSize > { typedef int T; }; 00041 template<> struct PropertyType< PackageSize > { typedef int T; }; 00042 00043 struct Parser: RecordParser 00044 { 00045 bool parseBool(bool& def, const std::string& str) const 00046 { 00047 // Believe it or not, this is what apt does to interpret bool fields 00048 if (str == "no" || str == "false" || str == "without" || 00049 str == "off" || str == "disable") 00050 return false; 00051 00052 if (str == "yes" || str == "true" || str == "with" || 00053 str == "on" || str == "enable") 00054 return true; 00055 00056 return def; 00057 } 00058 00059 public: 00060 Parser() : RecordParser() {} 00061 Parser(const std::string& str) : RecordParser(str) {} 00062 00063 template< PropertyId p > 00064 typename PropertyType< p >::T parse( typename PropertyType< p >::T def, 00065 std::string data ); 00066 00067 template< typename T > 00068 struct Default { 00069 static T def; 00070 }; 00071 00072 template< typename T > T parse( const T &def, 00073 const std::string &field ) const; 00074 00075 template< PropertyId p > 00076 typename PropertyType< p >::T get( 00077 const typename PropertyType< p >::T &def 00078 = Default< typename PropertyType< p >::T >::def ) const 00079 { 00080 return parse< typename PropertyType< p >::T >( def, 00081 lookup( fields[ p ] ) ); 00082 } 00083 00084 }; 00085 00086 template< typename T > T Parser::Default< T >::def = T(); 00087 00088 template<> inline std::string Parser::get< ShortDescription >( 00089 const std::string& def ) const 00090 { 00091 std::string str = lookup( fields[ Description ] ); 00092 if (str == std::string()) 00093 return def; 00094 size_t pos = str.find("\n"); 00095 if (pos == std::string::npos) 00096 return str; 00097 else 00098 return str.substr(0, pos); 00099 } 00100 00101 template<> inline std::string Parser::get< LongDescription >( 00102 const std::string& def ) const 00103 { 00104 std::string str = lookup( fields[ Description ] ); 00105 if (str == std::string()) 00106 return def; 00107 size_t pos = str.find("\n"); 00108 if (pos == std::string::npos) 00109 return str; 00110 else 00111 { 00112 // Trim trailing spaces 00113 for (++pos; pos < str.size() && isspace(str[pos]); ++pos) 00114 ; 00115 return str.substr(pos); 00116 } 00117 } 00118 00119 template<> inline std::string Parser::parse< std::string >( 00120 const std::string& def, const std::string& str) const 00121 { 00122 if (str == std::string()) 00123 return def; 00124 return str; 00125 } 00126 00127 template<> inline int Parser::parse< int >( 00128 const int& def, const std::string& str) const 00129 { 00130 if (str == string()) 00131 return def; 00132 return (size_t)strtoul(str.c_str(), NULL, 10); 00133 } 00134 00135 struct Source : core::Source< Source, Setup, PropertyType > 00136 { 00137 AptDatabase &m_db; 00138 00139 /* caching */ 00140 pkgCache::PkgFileIterator lastFile; 00141 FileFd file; 00142 size_t lastOffset; 00143 00144 /* in-order retrieval of records, for InternalList */ 00145 typedef vector< pkgCache::VerFile * > VfList; 00146 VfList m_vflist; 00147 00148 VfList &vfList() { 00149 if ( m_vflist.size() > 0 ) 00150 return m_vflist; 00151 00152 m_vflist.reserve(m_db.cache().HeaderP->PackageCount + 1); 00153 00154 // Populate the vector of versions to print 00155 for (pkgCache::PkgIterator pi = m_db.cache().PkgBegin(); !pi.end(); ++pi) 00156 { 00157 if (pi->VersionList == 0) 00158 continue; 00159 00160 for( pkgCache::VerIterator vi = pi.VersionList(); !vi.end(); ++vi ) { 00161 00162 // Choose a valid file that contains the record for this version 00163 pkgCache::VerFileIterator vfi = vi.FileList(); 00164 for ( ; !vfi.end(); ++vfi ) 00165 if ((vfi.File()->Flags & pkgCache::Flag::NotSource) == 0) 00166 break; 00167 00168 if ( !vfi.end() ) 00169 m_vflist.push_back( vfi ); 00170 } 00171 } 00172 00173 sort(m_vflist.begin(), m_vflist.end(), localityCompare); 00174 return m_vflist; 00175 } 00176 00177 Source( AptDatabase &db ) : m_db( db ) {} 00178 00179 InternalList listInternal() { 00180 return InternalList( *this ); 00181 } 00182 00183 Internal lookupToken( Token t ) { 00184 return m_db.lookupVersionFile( m_db.lookupVersion( t ) ); 00185 } 00186 00187 // Sort a version list by package file locality 00188 static bool localityCompare(const pkgCache::VerFile* a, 00189 const pkgCache::VerFile* b) 00190 { 00191 if (a == 0 && b == 0) 00192 return false; 00193 if (a == 0) 00194 return true; 00195 if (b == 0) 00196 return false; 00197 00198 if (a->File == b->File) 00199 return a->Offset < b->Offset; 00200 return a->File < b->File; 00201 } 00202 00203 void invalidate() { 00204 core::Source< Source, Setup, PropertyType >::invalidate(); 00205 lastFile = pkgCache::PkgFileIterator(); 00206 } 00207 00208 std::string getRecord( Internal vfi ) { 00209 if ( vfi.Cache() == 0 || vfi.end() ) 00210 return ""; 00211 00212 if ((lastFile.Cache() == 0) 00213 || vfi->File + m_db.cache().PkgFileP != lastFile) 00214 { 00215 lastFile = pkgCache::PkgFileIterator( 00216 m_db.cache(), vfi->File + m_db.cache().PkgFileP); 00217 if (!lastFile.IsOk()) 00218 throw wibble::exception::System( 00219 std::string("Reading the" 00220 " data record for a package from file ") 00221 + lastFile.FileName() ); 00222 if (file.IsOpen()) 00223 file.Close(); 00224 if (!file.Open(lastFile.FileName(), FileFd::ReadOnly)) 00225 throw wibble::exception::System( std::string("Opening file ") 00226 + lastFile.FileName() ); 00227 lastOffset = 0; 00228 } 00229 00230 // If we start near were we ended, avoid a seek 00231 // and enlarge the read a bit 00232 size_t slack = vfi->Offset - lastOffset; 00233 if ( slack > 128 ) // mornfall: was 8, making it 128 00234 { 00235 slack = 0; 00236 if ( !file.Seek( vfi->Offset ) ) 00237 throw wibble::exception::System( 00238 std::string("Cannot seek to package record in file ") 00239 + lastFile.FileName() ); 00240 } 00241 00242 char buffer[vfi->Size + slack + 1]; 00243 if (!file.Read(buffer, vfi->Size + slack)) 00244 throw wibble::exception::System( 00245 std::string("Cannot read package " 00246 "record in file ") + lastFile.FileName() ); 00247 00248 buffer[vfi->Size + slack] = '\0'; 00249 //cerr << "Data read (slack: " << slack << ")" << endl; 00250 00251 lastOffset = vfi->Offset + vfi->Size; 00252 00253 return string(buffer+slack); 00254 } 00255 00256 Token getToken( Internal i ) { 00257 Token t; 00258 t._id = getInternal< Name >( i ) + "_" + getInternal< Version >( i ); 00259 return t; 00260 } 00261 00262 template< PropertyId p > 00263 typename PropertyType< p >::T getInternal( Internal i ) { 00264 Parser rec( getRecord( i ) ); 00265 return rec.get< p >(); 00266 } 00267 }; 00268 00269 template<> inline std::string Source::getInternal< Record >( Internal i ) { 00270 assert( !i.end() ); 00271 return getRecord( i ); 00272 } 00273 00274 inline const Internal InternalList::head() const { 00275 return pkgCache::VerFileIterator( m_source->m_db.cache(), 00276 m_source->vfList()[ m_idx ] ); 00277 } 00278 00279 inline bool InternalList::empty() const { 00280 return m_idx == m_source->vfList().size(); 00281 } 00282 00283 00284 } 00285 } 00286 } 00287 00288 #endif