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