00001
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
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
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
00140 pkgCache::PkgFileIterator lastFile;
00141 FileFd file;
00142 size_t lastOffset;
00143
00144
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
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
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
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
00231
00232 size_t slack = vfi->Offset - lastOffset;
00233 if ( slack > 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
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