00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <ctime>
00014 #include <fstream>
00015 #include <sstream>
00016 #include <streambuf>
00017
00018 #include <boost/logic/tribool.hpp>
00019
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/CapFactory.h"
00022 #include "zypp/Url.h"
00023
00024 #include "zypp/ResObject.h"
00025 #include "zypp/detail/ImplConnect.h"
00026 #include "zypp/detail/ResObjectImplIf.h"
00027 #include "zypp/detail/SelectionImplIf.h"
00028 #include "zypp/repo/ScriptProvider.h"
00029
00030 #include "serialize.h"
00031
00032 #include "xml_escape_parser.hpp"
00033
00034 using namespace std;
00036 namespace zypp
00037 {
00038 namespace storage
00039 {
00040
00041 static void copyFileToStream( const Pathname & file_r, std::ostream & out_r )
00042 {
00043 std::ifstream infile( file_r.c_str() );
00044 while (infile.good())
00045 {
00046 char c = (char)infile.get();
00047 if (! infile.eof())
00048 out_r << c;
00049 }
00050 infile.close();
00051 }
00052
00053 static string xml_escape( const string &text )
00054 {
00055 iobind::parser::xml_escape_parser parser;
00056 return parser.escape(text);
00057 }
00058
00059 static string xml_tag_enclose( const string &text, const string &tag, bool escape = false )
00060 {
00061 string result;
00062 result += "<" + tag + ">";
00063
00064 if ( escape)
00065 result += xml_escape(text);
00066 else
00067 result += text;
00068
00069 result += "</" + tag + ">";
00070 return result;
00071 }
00072
00073 static ostream & operator<<( ostream & str, const boost::tribool obj )
00074 {
00075 if (obj)
00076 return str << "true";
00077 else if (!obj)
00078 return str << "false";
00079 else
00080 return str << "indeterminate";
00081 }
00082
00089 static string translatedTextToXML(const TranslatedText &text, const string &tagname)
00090 {
00091 set<Locale> locales = text.locales();
00092
00093 stringstream out;
00094 for ( set<Locale>::const_iterator it = locales.begin(); it != locales.end(); ++it)
00095 {
00096
00097 if ( *it == Locale() )
00098 out << "<" << tagname << ">" << xml_escape(text.text(*it)) << "</" << tagname << ">" << endl;
00099 else
00100 out << "<" << tagname << " lang=\"" << (*it).code() << "\">" << xml_escape(text.text(*it)) << "</" << tagname << ">" << endl;
00101 }
00102 return out.str();
00103 }
00104
00105 template<class T>
00106 string toXML( const T &obj );
00107
00108 template<>
00109 string toXML( const Edition &edition )
00110 {
00111 stringstream out;
00112
00113 out << "<version ver=\"" << xml_escape(edition.version()) << "\" rel=\"" << xml_escape(edition.release()) << "\" epoch=\"" << edition.epoch() << "\" />";
00114 return out.str();
00115 }
00116
00117 template<>
00118 string toXML( const Arch &arch )
00119 {
00120 stringstream out;
00121 out << xml_tag_enclose(xml_escape(arch.asString()), "arch");
00122 return out.str();
00123 }
00124
00125 template<>
00126 string toXML( const Capability &cap )
00127 {
00128 stringstream out;
00129 CapFactory factory;
00130
00131 out << "<capability kind=\"" << cap.refers() << "\" >" << xml_escape(factory.encode(cap)) << "</capability>" << endl;
00132 return out.str();
00133 }
00134
00135 template<>
00136 string toXML( const CapSet &caps )
00137 {
00138 stringstream out;
00139 CapSet::iterator it = caps.begin();
00140 for ( ; it != caps.end(); ++it)
00141 {
00142 out << toXML((*it));
00143 }
00144 return out.str();
00145 }
00146
00147 template<>
00148 string toXML( const Dependencies &dep )
00149 {
00150 stringstream out;
00151 if ( dep[Dep::PROVIDES].size() > 0 )
00152 out << " " << xml_tag_enclose(toXML(dep[Dep::PROVIDES]), "provides") << endl;
00153 if ( dep[Dep::PREREQUIRES].size() > 0 )
00154 out << " " << xml_tag_enclose(toXML(dep[Dep::PREREQUIRES]), "prerequires") << endl;
00155 if ( dep[Dep::CONFLICTS].size() > 0 )
00156 out << " " << xml_tag_enclose(toXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
00157 if ( dep[Dep::OBSOLETES].size() > 0 )
00158 out << " " << xml_tag_enclose(toXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
00159
00160 if ( dep[Dep::FRESHENS].size() > 0 )
00161 out << " " << xml_tag_enclose(toXML(dep[Dep::FRESHENS]), "freshens") << endl;
00162 if ( dep[Dep::REQUIRES].size() > 0 )
00163 out << " " << xml_tag_enclose(toXML(dep[Dep::REQUIRES]), "requires") << endl;
00164 if ( dep[Dep::RECOMMENDS].size() > 0 )
00165 out << " " << xml_tag_enclose(toXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
00166 if ( dep[Dep::ENHANCES].size() > 0 )
00167 out << " " << xml_tag_enclose(toXML(dep[Dep::ENHANCES]), "enhances") << endl;
00168 if ( dep[Dep::SUPPLEMENTS].size() > 0 )
00169 out << " " << xml_tag_enclose(toXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
00170 if ( dep[Dep::SUGGESTS].size() > 0 )
00171 out << " " << xml_tag_enclose(toXML(dep[Dep::SUGGESTS]), "suggests") << endl;
00172 return out.str();
00173
00174 }
00175
00176 template<>
00177 string toXML( const Resolvable::constPtr &obj )
00178 {
00179 stringstream out;
00180
00181 out << " <name>" << xml_escape(obj->name()) << "</name>" << endl;
00182
00183 out << " " << toXML(obj->edition()) << endl;
00184 out << " " << toXML(obj->arch()) << endl;
00185 out << " " << toXML(obj->deps()) << endl;
00186 return out.str();
00187 }
00188
00189 template<>
00190 string toXML( const ResObject::constPtr &obj )
00191 {
00192 stringstream out;
00193
00194
00195 detail::ResImplTraits<ResObject::Impl>::constPtr pipp( detail::ImplConnect::resimpl( obj ) );
00196 out << translatedTextToXML(pipp->summary(), "summary");
00197 out << translatedTextToXML(pipp->description(), "description");
00198
00199 out << translatedTextToXML(pipp->insnotify(), "install-notify");
00200 out << translatedTextToXML(pipp->delnotify(), "delete-notify");
00201
00202 out << translatedTextToXML(pipp->licenseToConfirm(), "license-to-confirm");
00203 out << " <vendor>" << xml_escape(obj->vendor()) << "</vendor>" << endl;
00204 out << " <size>" << static_cast<ByteCount::SizeType>(obj->size()) << "</size>" << endl;
00205 out << " <archive-size>" << static_cast<ByteCount::SizeType>(obj->downloadSize()) << "</archive-size>" << endl;
00206 out << " <install-only>" << ( obj->installOnly() ? "true" : "false" ) << "</install-only>" << endl;
00207 out << " <build-time>" << obj->buildtime().asSeconds() << "</build-time>" << endl;
00208
00209 out << " <install-time>" << Date::now().asSeconds() << "</install-time>" << endl;
00210
00211 return out.str();
00212 }
00213
00214 template<>
00215 string toXML( const Package::constPtr &obj )
00216 {
00217 stringstream out;
00218 out << "<package>" << endl;
00219
00220 out << toXML(static_cast<Resolvable::constPtr>(obj));
00221 out << toXML(static_cast<ResObject::constPtr>(obj));
00222 out << "</package>" << endl;
00223 return out.str();
00224 }
00225
00226 template<>
00227 string toXML( const Script::constPtr &obj )
00228 {
00229 stringstream out;
00230 out << "<script>" << endl;
00231
00232 out << toXML(static_cast<Resolvable::constPtr>(obj));
00233 out << toXML(static_cast<ResObject::constPtr>(obj));
00234
00235 repo::RepoMediaAccess access;
00236 repo::ScriptProvider prov( access );
00237
00238 out << " <do>" << endl;
00239 out << " <![CDATA[" << endl;
00240 copyFileToStream( prov.provideDoScript( obj ), out );
00241 out << " ]]>" << endl;
00242 out << " </do>" << endl;
00243
00244 if ( obj->undoAvailable() )
00245 {
00246 out << " <undo>" << endl;
00247 out << " <![CDATA[" << endl;
00248 copyFileToStream( prov.provideUndoScript( obj ), out );
00249 out << " ]]>" << endl;
00250 out << " </undo>" << endl;
00251
00252 }
00253 out << "</script>" << endl;
00254 return out.str();
00255 }
00256
00257 template<>
00258 string toXML( const Message::constPtr &obj )
00259 {
00260 stringstream out;
00261 out << "<message>" << endl;
00262
00263 out << toXML(static_cast<Resolvable::constPtr>(obj));
00264 out << toXML(static_cast<ResObject::constPtr>(obj));
00265 out << " <text>" << xml_escape(obj->text().text()) << "</text>" << endl;
00266 out << "</message>" << endl;
00267 return out.str();
00268 }
00269
00270 template<>
00271 string toXML( const Language::constPtr &obj )
00272 {
00273 stringstream out;
00274 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00275 out << "<language version=\"" << SERIALIZER_VERSION << "\" xmlns=\"http://www.novell.com/metadata/zypp/xml-store\">" << endl;
00276 out << toXML(static_cast<Resolvable::constPtr>(obj)) << endl;
00277 out << toXML(static_cast<ResObject::constPtr>(obj));
00278 out << "</language>" << endl;
00279 return out.str();
00280 }
00281
00282
00283 template<>
00284 string toXML( const Selection::constPtr &obj )
00285 {
00286 stringstream out;
00287 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00288 out << "<pattern version=\"" << SERIALIZER_VERSION << "\" xmlns=\"http://www.novell.com/metadata/zypp/xml-store\">" << endl;
00289
00290 out << toXML(static_cast<Resolvable::constPtr>(obj)) << endl;
00291 out << toXML(static_cast<ResObject::constPtr>(obj));
00292
00293
00294 out << " <uservisible>" << (obj->visible() ? "true" : "false" ) << "</uservisible>" << endl;
00295 out << " <category>" << xml_escape(obj->category()) << "</category>" << endl;
00296 out << " <icon></icon>" << endl;
00297 out << "</pattern>" << endl;
00298 return out.str();
00299 }
00300
00301 template<>
00302 string toXML( const Atom::constPtr &obj )
00303 {
00304 stringstream out;
00305 out << "<atom>" << endl;
00306 out << toXML(static_cast<Resolvable::constPtr>(obj)) << endl;
00307 out << toXML(static_cast<ResObject::constPtr>(obj));
00308 out << "</atom>" << endl;
00309 return out.str();
00310 }
00311
00312 template<>
00313 string toXML( const Pattern::constPtr &obj )
00314 {
00315 stringstream out;
00316 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00317 out << "<pattern version=\"" << SERIALIZER_VERSION << "\" xmlns=\"http://www.novell.com/metadata/zypp/xml-store\">" << endl;
00318
00319 out << toXML(static_cast<Resolvable::constPtr>(obj)) << endl;
00320 out << toXML(static_cast<ResObject::constPtr>(obj));
00321
00322 out << " <default>" << (obj->isDefault() ? "true" : "false" ) << "</default>" << endl;
00323 out << " <uservisible>" << (obj->userVisible() ? "true" : "false" ) << "</uservisible>" << endl;
00324 out << " <category>" << xml_escape(obj->category()) << "</category>" << endl;
00325 out << " <icon>" << xml_escape(obj->icon().asString()) << "</icon>" << endl;
00326 out << " <script>" << xml_escape(obj->script().asString()) << "</script>" << endl;
00327 out << "</pattern>" << endl;
00328 return out.str();
00329 }
00330
00331 template<>
00332 string toXML( const Product::constPtr &obj )
00333 {
00334 stringstream out;
00335 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00336 out << "<product version=\"" << SERIALIZER_VERSION << "\" xmlns=\"http://www.novell.com/metadata/zypp/xml-store\" type=\"" << xml_escape(obj->type()) << "\">" << endl;
00337 out << toXML(static_cast<Resolvable::constPtr>(obj)) << endl;
00338 #warning "FIXME description and displayname of products"
00339
00340 out << toXML(static_cast<ResObject::constPtr>(obj));
00341
00342
00343 detail::ResImplTraits<Product::Impl>::constPtr pipp( detail::ImplConnect::resimpl( obj ) );
00344 out << translatedTextToXML(pipp->shortName(), "shortname");
00345
00346 out << " <distribution-name>" << xml_escape(obj->distributionName()) << "</distribution-name>" << endl;
00347 out << " <distribution-edition>" << xml_escape(obj->distributionEdition().asString()) << "</distribution-edition>" << endl;
00348 out << " <source>" << xml_escape(obj->repository().info().alias()) << "</source>" << endl;
00349 out << " <release-notes-url>" << xml_escape(obj->releaseNotesUrl().asString()) << "</release-notes-url>" << endl;
00350
00351 out << " <update-urls>" << endl;
00352 list<Url> updateUrls = obj->updateUrls();
00353 for ( list<Url>::const_iterator it = updateUrls.begin(); it != updateUrls.end(); ++it)
00354 {
00355 out << " <update-url>" << xml_escape(it->asString()) << "</update-url>" << endl;
00356 }
00357 out << " </update-urls>" << endl;
00358
00359 out << " <extra-urls>" << endl;
00360 list<Url> extraUrls = obj->extraUrls();
00361 for ( list<Url>::const_iterator it = extraUrls.begin(); it != extraUrls.end(); ++it)
00362 {
00363 out << " <extra-url>" << xml_escape(it->asString()) << "</extra-url>" << endl;
00364 }
00365 out << " </extra-urls>" << endl;
00366
00367 out << " <optional-urls>" << endl;
00368 list<Url> optionalUrls = obj->optionalUrls();
00369 for ( list<Url>::const_iterator it = optionalUrls.begin(); it != optionalUrls.end(); ++it)
00370 {
00371 out << " <optional-url>" << xml_escape(it->asString()) << "</optional-url>" << endl;
00372 }
00373 out << " </optional-urls>" << endl;
00374
00375 out << " <product-flags>" << endl;
00376 list<string> flags = obj->flags();
00377 for ( list<string>::const_iterator it = flags.begin(); it != flags.end(); ++it)
00378 {
00379 out << " <product-flag>" << xml_escape(*it) << "</product-flag>" << endl;
00380 }
00381 out << " </product-flags>" << endl;
00382
00383 out << "</product>" << endl;
00384
00385 return out.str();
00386 }
00387
00388
00389 string castedToXML( const Resolvable::constPtr &resolvable )
00390 {
00391 stringstream out;
00392 if ( isKind<Package>(resolvable) )
00393 out << toXML(asKind<const Package>(resolvable)) << endl;
00394 if ( isKind<Patch>(resolvable) )
00395 out << toXML(asKind<const Patch>(resolvable)) << endl;
00396 if ( isKind<Message>(resolvable) )
00397 out << toXML(asKind<const Message>(resolvable)) << endl;
00398 if ( isKind<Script>(resolvable) )
00399 out << toXML(asKind<const Script>(resolvable)) << endl;
00400 if ( isKind<Atom>(resolvable) )
00401 out << toXML(asKind<const Atom>(resolvable)) << endl;
00402 if ( isKind<Product>(resolvable) )
00403 out << toXML(asKind<const Product>(resolvable)) << endl;
00404 if ( isKind<Pattern>(resolvable) )
00405 out << toXML(asKind<const Pattern>(resolvable)) << endl;
00406 if ( isKind<Selection>(resolvable) )
00407 out << toXML(asKind<const Selection>(resolvable)) << endl;
00408 if ( isKind<Language>(resolvable) )
00409 out << toXML(asKind<const Language>(resolvable)) << endl;
00410 return out.str();
00411 }
00412
00413 string resolvableTypeToString( const Resolvable::constPtr &resolvable, bool plural )
00414 {
00415 return resolvableKindToString(resolvable->kind(), plural);
00416 }
00417
00418 string resolvableKindToString( const Resolvable::Kind &kind, bool plural)
00419 {
00420 string k = kind.asString();
00421 if (k.substr(k.size() - 2, 2) == "ch")
00422 return k + (plural?"es":"");
00423 else
00424 return k + (plural?"s":"");
00425 }
00426
00427 template<>
00428 string toXML( const Patch::constPtr &obj )
00429 {
00430 stringstream out;
00431 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00432 out << "<patch version=\"" << SERIALIZER_VERSION << "\" xmlns=\"http://www.novell.com/metadata/zypp/xml-store\">" << endl;
00433
00434
00435 out << toXML(static_cast<Resolvable::constPtr>(obj));
00436 out << toXML(static_cast<ResObject::constPtr>(obj));
00437
00438 out << "<id>" << xml_escape(obj->id()) << "</id>" << endl;
00439 out << "<timestamp>" << obj->timestamp().asSeconds() << "</timestamp>" << endl;
00440
00441 out << "<category>" << obj->category() << "</category>" << endl;
00442 out << "<affects-package-manager>" << ( obj->affects_pkg_manager() ? "true" : "false" ) << "</affects-package-manager>" << endl;
00443 out << "<reboot-needed>" << ( obj->reboot_needed() ? "true" : "false" ) << "</reboot-needed>" << endl;
00444
00445 Patch::AtomList at = obj->atoms();
00446 out << " <atoms>" << endl;
00447 for (Patch::AtomList::iterator it = at.begin(); it != at.end(); it++)
00448 {
00449 Resolvable::Ptr one_atom = *it;
00450 out << castedToXML(one_atom) << endl;
00451 }
00452 out << " </atoms>" << endl;
00453 out << "</patch>" << endl;
00454 return out.str();
00455 }
00456
00458 }
00461 }