serialize.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
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   //ERR << "locale contains " << locales.size() << " translations" << endl;
00093   stringstream out;
00094   for ( set<Locale>::const_iterator it = locales.begin(); it != locales.end(); ++it)
00095   {
00096     //ERR << "serializing " << (*it).code() << endl;
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 ); //undefined
00107 
00108 template<>
00109 string toXML( const Edition &edition )
00110 {
00111   stringstream out;
00112   // sad the yum guys did not acll it edition
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   // why the YUM tag is freshen without s????
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   // is this shared? uh
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   // access implementation
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   //out << "  <license-to-confirm>" << xml_escape(obj->licenseToConfirm()) << "</license-to-confirm>" << endl;
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   // we assume we serialize on storeObject, set install time to NOW
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   // reuse Resolvable information serialize function
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   // reuse Resolvable information serialize function
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   // reuse Resolvable information serialize function
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   //out << "  <default>" << (obj->isDefault() ? "true" : "false" ) << "</default>" << endl;
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   // access implementation
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   // reuse Resolvable information serialize function
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 } // namespace storage
00461 } // namespace zypp

Generated on Tue Sep 25 19:23:09 2007 for libzypp by  doxygen 1.5.3