platform/codecs/XMLCodec.cpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
00018 //
00019 
00020 #include <libxml/tree.h>
00021 #include <libxml/xmlwriter.h>
00022 #include <libxml/xmlreader.h>
00023 #include <pion/platform/ConfigManager.hpp>
00024 #include <pion/platform/Event.hpp>
00025 #include <pion/platform/Vocabulary.hpp>
00026 #include "XMLCodec.hpp"
00027 
00028 using namespace pion::platform;
00029 
00030 
00031 namespace pion {        // begin namespace pion
00032 namespace plugins {     // begin namespace plugins
00033 
00034 
00035 // static members of XMLCodec
00036 const std::string           XMLCodec::CONTENT_TYPE = "text/xml";
00037 const std::string           XMLCodec::EVENT_TAG_ELEMENT_NAME = "EventTag";
00038 const std::string           XMLCodec::EVENT_CONTAINER_TAG_ELEMENT_NAME = "EventContainerTag";
00039 const std::string           XMLCodec::FIELD_ELEMENT_NAME = "Field";
00040 const std::string           XMLCodec::TERM_ATTRIBUTE_NAME = "term";
00041 const std::string           XMLCodec::DEFAULT_EVENT_TAG = "Event";
00042 const std::string           XMLCodec::DEFAULT_EVENT_CONTAINER_TAG = "Events";
00043 
00044 
00045 // XMLCodec member functions
00046 
00047 CodecPtr XMLCodec::clone(void) const
00048 {
00049     XMLCodec *new_codec(new XMLCodec());
00050     new_codec->copyCodec(*this);
00051     for (CurrentFormat::const_iterator i = m_format.begin(); i != m_format.end(); ++i) {
00052         new_codec->mapFieldToTerm((*i)->field_name, (*i)->term);
00053     }
00054     new_codec->m_XML_field_ptr_map = m_XML_field_ptr_map;
00055     new_codec->m_event_container_tag = m_event_container_tag;
00056     new_codec->m_event_tag = m_event_tag;
00057     new_codec->m_no_events_written = true;
00058     return CodecPtr(new_codec);
00059 }
00060 
00061 void XMLCodec::write(std::ostream& out, const Event& e)
00062 {
00063     if (m_no_events_written) {
00064         m_buf = xmlBufferCreate();
00065         if (m_buf == NULL)
00066             throw PionException("Error creating xmlBuffer");
00067 
00068         m_xml_writer = xmlNewTextWriterMemory(m_buf, 0 /* no compression */);
00069         if (m_xml_writer == NULL) 
00070             throw PionException("Error creating xmlTextWriter");
00071 
00072         // Initialize indentation.
00073         if (xmlTextWriterSetIndent(m_xml_writer, 1) < 0)
00074             throw PionException("xmlTextWriter failed to turn on indentation");
00075         if (xmlTextWriterSetIndentString(m_xml_writer, (xmlChar*)"\t") < 0)
00076             throw PionException("xmlTextWriter failed to set the indent string");
00077         
00078         // Write an XML header.
00079         if (xmlTextWriterStartDocument(m_xml_writer, NULL, "UTF-8", NULL) < 0)
00080             throw PionException("xmlTextWriter failed to write the start of the document");
00081 
00082         if (! m_event_container_tag.empty()) {
00083             // Start the root element, named "Events".
00084             if (xmlTextWriterStartElement(m_xml_writer, (xmlChar*)m_event_container_tag.c_str()) < 0)
00085                 throw PionException("xmlTextWriter failed to write a start-tag");
00086         }
00087         m_no_events_written = false;
00088     }
00089 
00090     if (xmlTextWriterStartElement(m_xml_writer, (xmlChar*)m_event_tag.c_str()) < 0)
00091         throw PionException("xmlTextWriter failed to write an Event start-tag");
00092 
00093     // Iterate through each field in the current format.
00094     CurrentFormat::const_iterator i;
00095     std::string value_str;
00096     const pion::platform::Event::BlobType* ss;
00097     for (i = m_format.begin(); i != m_format.end(); ++i) {
00098         // Get the range of values for the field Term.
00099         pion::platform::Vocabulary::TermRef term_ref = (*i)->term.term_ref;
00100         Event::ValuesRange range = e.equal_range(term_ref);
00101         xmlChar* field_name = (xmlChar*)(*i)->field_name.c_str();
00102 
00103         // Generate an XML element for each value.
00104         for (Event::ConstIterator i2 = range.first; i2 != range.second; ++i2) {
00105             int rc = 0;
00106             switch ((*i)->term.term_type) {
00107                 case pion::platform::Vocabulary::TYPE_NULL:
00108                 case pion::platform::Vocabulary::TYPE_OBJECT:
00109                     // TODO: should we output an empty element instead of nothing?
00110                     break;
00111                 case pion::platform::Vocabulary::TYPE_INT8:
00112                 case pion::platform::Vocabulary::TYPE_INT16:
00113                 case pion::platform::Vocabulary::TYPE_INT32:
00114                     rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%d", boost::get<boost::int32_t>(i2->value));
00115                     break;
00116                 case pion::platform::Vocabulary::TYPE_INT64:
00117                     value_str = boost::lexical_cast<std::string>(boost::get<boost::int64_t>(i2->value));
00118                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00119                     break;
00120                 case pion::platform::Vocabulary::TYPE_UINT8:
00121                 case pion::platform::Vocabulary::TYPE_UINT16:
00122                 case pion::platform::Vocabulary::TYPE_UINT32:
00123                     rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%d", boost::get<boost::uint32_t>(i2->value));
00124                     break;
00125                 case pion::platform::Vocabulary::TYPE_UINT64:
00126                     value_str = boost::lexical_cast<std::string>(boost::get<boost::uint64_t>(i2->value));
00127                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00128                     break;
00129                 case pion::platform::Vocabulary::TYPE_FLOAT:
00130                     rc = xmlTextWriterWriteFormatElement(m_xml_writer, field_name, "%g", boost::get<float>(i2->value));
00131                     break;
00132                 case pion::platform::Vocabulary::TYPE_DOUBLE:
00133                     // Using boost::lexical_cast<std::string> ensures precision appropriate to type double.
00134                     value_str = boost::lexical_cast<std::string>(boost::get<double>(i2->value));
00135                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00136                     break;
00137                 case pion::platform::Vocabulary::TYPE_LONG_DOUBLE:
00138                     // Using boost::lexical_cast<std::string> ensures precision appropriate to type long double.
00139                     value_str = boost::lexical_cast<std::string>(boost::get<long double>(i2->value));
00140                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00141                     break;
00142 
00143                 case pion::platform::Vocabulary::TYPE_SHORT_STRING:
00144                 case pion::platform::Vocabulary::TYPE_STRING:
00145                 case pion::platform::Vocabulary::TYPE_LONG_STRING:
00146                 case pion::platform::Vocabulary::TYPE_BLOB:
00147                 case pion::platform::Vocabulary::TYPE_ZBLOB:
00148                     ss = &boost::get<const pion::platform::Event::BlobType&>(i2->value);
00149                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)ss->get());
00150                     break;
00151                 case pion::platform::Vocabulary::TYPE_CHAR:
00152                     ss = &boost::get<const pion::platform::Event::BlobType&>(i2->value);
00153                     if (ss->size() <= (*i)->term.term_size) {
00154                         rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)ss->get());
00155                     } else {
00156                         std::string trunc_str(ss->get(), (*i)->term.term_size);
00157                         rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)trunc_str.c_str());
00158                     }
00159                     break;
00160 
00161                 case pion::platform::Vocabulary::TYPE_DATE_TIME:
00162                 case pion::platform::Vocabulary::TYPE_DATE:
00163                 case pion::platform::Vocabulary::TYPE_TIME:
00164                     (*i)->time_facet.toString(value_str, boost::get<const PionDateTime&>(i2->value));
00165                     rc = xmlTextWriterWriteElement(m_xml_writer, field_name, (xmlChar*)value_str.c_str());
00166                     break;
00167             }
00168             if (rc < 0)
00169                 throw PionException("xmlTextWriter failed to write a Term element");
00170         }
00171     }
00172 
00173     if (xmlTextWriterEndElement(m_xml_writer) < 0)
00174         throw PionException("xmlTextWriter failed to write an Event end-tag");
00175 
00176     if (xmlTextWriterFlush(m_xml_writer) < 0)
00177         throw PionException("Error flushing XML writer");
00178     out.write((char*)m_buf->content, m_buf->use);
00179 
00180     xmlBufferEmpty(m_buf);
00181 
00182     if (m_flush_after_write)
00183         out.flush();
00184 }
00185 
00186 void XMLCodec::finish(std::ostream& out)
00187 {
00188     if (m_no_events_written)
00189         return;
00190 
00191     // Write the 'Events' end-tag.
00192     if (xmlTextWriterEndDocument(m_xml_writer) < 0)
00193         throw PionException("xmlTextWriter failed to write end of document");
00194 
00195     // Send all remaining data to the output stream.
00196     if (xmlTextWriterFlush(m_xml_writer) < 0)
00197         throw PionException("Error flushing XML writer");
00198     out.write((char*)m_buf->content, m_buf->use);
00199 
00200     // We're done with the writer, so release it and the buffer it uses.
00201     xmlFreeTextWriter(m_xml_writer);
00202     m_xml_writer = NULL;
00203     xmlBufferFree(m_buf);
00204     m_buf = NULL;
00205 }
00206 
00207 int XMLCodec::xmlInputReadCallback(void* context, char* buffer, int len)
00208 {
00209     // Read up to len bytes into a buffer from the input stream.
00210     streambuf_type* buf_ptr = ((std::istream*)context)->rdbuf();
00211     char* p = buffer;
00212     std::streamsize num_bytes_read;
00213     for (num_bytes_read = 0; num_bytes_read < len; ++num_bytes_read) {
00214         *p = buf_ptr->sbumpc();
00215         if (traits_type::eq_int_type(*p, traits_type::eof()))
00216             break;
00217         ++p;
00218     }
00219 
00220     return num_bytes_read;
00221 }
00222 
00223 int XMLCodec::xmlInputCloseCallback(void* context)
00224 {
00225     return 0;
00226 }
00227 
00228 bool XMLCodec::read(std::istream& in, Event& e)
00229 {
00230     if (e.getType() != getEventType())
00231         throw WrongEventTypeException();
00232 
00233     e.clear();
00234     
00235     if (m_first_read_attempt) {
00236         // verify that field mappings are defined
00237         if (m_field_map.empty())
00238             throw PionException("Codec is not configured yet.");
00239 
00240         // initialize xml reader to use
00241         m_xml_reader = xmlReaderForIO(xmlInputReadCallback, xmlInputCloseCallback, (void*)(&in), NULL, NULL, XML_PARSE_NOBLANKS);
00242         if (!m_xml_reader)
00243             throw PionException("failed to create XML parser");
00244 
00245         if (! m_event_container_tag.empty()) {
00246             // parse the 'Events' start-tag
00247             while (1) {
00248                 int ret = xmlTextReaderRead(m_xml_reader);
00249                 if (ret == 0) {
00250                     return false;
00251                 } else if (ret < 0) {
00252                     throw PionException("XML parser error");
00253                 }
00254         
00255                 if (xmlTextReaderNodeType(m_xml_reader) == 1) {
00256                     const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00257                     if (name == NULL)
00258                         throw PionException("XML parser error");
00259                     if (strcmp((char*)name, m_event_container_tag.c_str()) == 0)
00260                         break;
00261                 }
00262             }
00263         }
00264 
00265         m_first_read_attempt = false;
00266     }
00267     
00268     // parse the input until the next 'Event' start-tag is found
00269     while (1) {
00270         int ret = xmlTextReaderRead(m_xml_reader);
00271         if (ret == 0) {
00272             // set eof bit (finished ok) if no outside container
00273             if (m_event_container_tag.empty())
00274                 in.setstate(std::ios::eofbit);
00275             return false;
00276         } else if (ret < 0) {
00277             throw PionException("XML parser error");
00278         }
00279         const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00280         if (xmlTextReaderNodeType(m_xml_reader) == 1) { // start xml element
00281             if (name == NULL)
00282                 throw PionException("XML parser error");
00283             if (strcmp((char*)name, m_event_tag.c_str()) == 0)
00284                 break;
00285         } else if (xmlTextReaderNodeType(m_xml_reader) == 15) { // end xml element
00286             if (name == NULL)
00287                 throw PionException("XML parser error");
00288             // check for </Event>
00289             if (strcmp((char*)name, m_event_tag.c_str()) == 0) {
00290                 return true;    // empty event !
00291             }
00292             // check for </Events>
00293             if (!m_event_container_tag.empty() && strcmp((char*)name, m_event_container_tag.c_str()) == 0) {
00294                 // Setting eofbit gives the caller a way to distinguish between the case where there is
00295                 // currently not enough data in the stream to parse an Event and the case where the
00296                 // Events end-tag has been reached.
00297                 in.setstate(std::ios::eofbit);
00298                 return false;
00299             }
00300         }
00301     }
00302 
00303     // parse the input until the 'Event' end-tag is found
00304     std::string open_element_name;
00305     while (1) {
00306         if (xmlTextReaderRead(m_xml_reader) != 1)
00307             throw PionException("XML parser error");
00308 
00309         // check for start or end XML element
00310         const xmlChar* name = xmlTextReaderConstName(m_xml_reader);
00311         if (xmlTextReaderNodeType(m_xml_reader) == 15) {        // end xml element
00312             if (name == NULL)
00313                 throw PionException("XML parser error");
00314             if (strcmp((char*)name, m_event_tag.c_str()) == 0)
00315                 break;  // found </Event> - done parsing current event
00316             if (!m_event_container_tag.empty() && strcmp((char*)name, m_event_container_tag.c_str()) == 0) {
00317                 // assume </Event> before </Events>
00318                 in.setstate(std::ios::eofbit);
00319                 return true;
00320             }
00321             if (strcmp((char*)name, open_element_name.c_str()) == 0)
00322                 open_element_name.clear();  // found closing node for ignored element
00323         } else if (xmlTextReaderNodeType(m_xml_reader) == 1) {  // start xml element
00324             // check for field element
00325             if (name == NULL)
00326                 throw PionException("XML parser error");
00327             if (! open_element_name.empty())
00328                 continue;   // skip contents if inside of an ignored element
00329             if (xmlTextReaderIsEmptyElement(m_xml_reader) == 1)
00330                 continue;   // no element contents to extract/assign and attributes not supported yet
00331             open_element_name = (char*)name;
00332 
00333             // get the Term corresponding to the tag
00334             XMLCodec::FieldMap::const_iterator i = m_field_map.find(open_element_name);
00335             if (i == m_field_map.end())
00336                 continue;   // ignore current element
00337             const pion::platform::Vocabulary::Term& term = i->second->term;
00338 
00339             // get the value of the Term from the contents of the element
00340             std::string value_str;
00341             bool found_end_of_field = false;
00342             while (!found_end_of_field) {
00343                 if (xmlTextReaderRead(m_xml_reader) != 1)
00344                     throw PionException("XML parser error");
00345                 switch (xmlTextReaderNodeType(m_xml_reader)) {
00346                 case 1: // start element
00347                     name = xmlTextReaderConstName(m_xml_reader);
00348                     if (name) {
00349                         value_str += '<';
00350                         value_str += (char*) name;
00351                         value_str += '>';
00352                     }
00353                     break;
00354                         
00355                 case 15:    // end element
00356                     name = xmlTextReaderConstName(m_xml_reader);
00357                     if (name) {
00358                         if (strcmp((char*)name, open_element_name.c_str()) == 0) {
00359                             // found end of data field
00360                             open_element_name.clear();
00361                             found_end_of_field = true;
00362                             break;
00363                         } else {
00364                             value_str += "</";
00365                             value_str += (char*) name;
00366                             value_str += '>';
00367                         }
00368                     }
00369                     break;
00370                     
00371                 case 3:     // text node
00372                 case 4:     // CDATA node
00373                     name = xmlTextReaderValue(m_xml_reader);
00374                     if (name) {
00375                         value_str += (char*) name;
00376                     }
00377                     break;
00378 
00379                 default:
00380                     break;
00381                 }
00382             }   // done getting field value
00383                     
00384             switch (term.term_type) {
00385                 case pion::platform::Vocabulary::TYPE_NULL:
00386                 case pion::platform::Vocabulary::TYPE_OBJECT:
00387                     // do nothing
00388                     break;
00389                 case pion::platform::Vocabulary::TYPE_INT8:
00390                 case pion::platform::Vocabulary::TYPE_INT16:
00391                 case pion::platform::Vocabulary::TYPE_INT32:
00392                     e.setInt(term.term_ref, boost::lexical_cast<boost::int32_t>(value_str));
00393                     break;
00394                 case pion::platform::Vocabulary::TYPE_INT64:
00395                     e.setBigInt(term.term_ref, boost::lexical_cast<boost::int64_t>(value_str));
00396                     break;
00397                 case pion::platform::Vocabulary::TYPE_UINT8:
00398                 case pion::platform::Vocabulary::TYPE_UINT16:
00399                 case pion::platform::Vocabulary::TYPE_UINT32:
00400                     e.setUInt(term.term_ref, boost::lexical_cast<boost::uint32_t>(value_str));
00401                     break;
00402                 case pion::platform::Vocabulary::TYPE_UINT64:
00403                     e.setUBigInt(term.term_ref, boost::lexical_cast<boost::uint64_t>(value_str));
00404                     break;
00405                 case pion::platform::Vocabulary::TYPE_FLOAT:
00406                     e.setFloat(term.term_ref, boost::lexical_cast<float>(value_str));
00407                     break;
00408                 case pion::platform::Vocabulary::TYPE_DOUBLE:
00409                     e.setDouble(term.term_ref, boost::lexical_cast<double>(value_str));
00410                     break;
00411                 case pion::platform::Vocabulary::TYPE_LONG_DOUBLE:
00412                     e.setLongDouble(term.term_ref, boost::lexical_cast<long double>(value_str));
00413                     break;
00414                 case pion::platform::Vocabulary::TYPE_SHORT_STRING:
00415                 case pion::platform::Vocabulary::TYPE_STRING:
00416                 case pion::platform::Vocabulary::TYPE_LONG_STRING:
00417                 case pion::platform::Vocabulary::TYPE_BLOB:
00418                 case pion::platform::Vocabulary::TYPE_ZBLOB:
00419                     e.setString(term.term_ref, value_str);
00420                     break;
00421                 case pion::platform::Vocabulary::TYPE_CHAR:
00422                     if (value_str.size() > term.term_size) {
00423                         e.setString(term.term_ref, std::string(value_str, 0, term.term_size));
00424                     } else {
00425                         e.setString(term.term_ref, value_str);
00426                     }
00427                     break;
00428                 case pion::platform::Vocabulary::TYPE_DATE_TIME:
00429                 case pion::platform::Vocabulary::TYPE_DATE:
00430                 case pion::platform::Vocabulary::TYPE_TIME:
00431                 {
00432                     PionDateTime dt;
00433                     m_XML_field_ptr_map[term.term_ref]->time_facet.fromString(value_str, dt);
00434                     e.setDateTime(term.term_ref, dt);
00435                     break;
00436                 }
00437             }
00438         }
00439     }
00440 
00441     return true;
00442 }
00443 
00444 void XMLCodec::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
00445 {
00446     // first set config options for the Codec base class
00447     reset();
00448     Codec::setConfig(v, config_ptr);
00449 
00450     // Read in the tags to use for Events and Event containers, or use the defaults if no tags are specified.
00451     if (! ConfigManager::getConfigOption(EVENT_TAG_ELEMENT_NAME, m_event_tag, config_ptr)) {
00452         m_event_tag = DEFAULT_EVENT_TAG;
00453     }
00454     if (! ConfigManager::getConfigOption(EVENT_CONTAINER_TAG_ELEMENT_NAME, m_event_container_tag, config_ptr)) {
00455         if (ConfigManager::findConfigNodeByName(EVENT_CONTAINER_TAG_ELEMENT_NAME, config_ptr)) {
00456             m_event_container_tag = "";
00457         } else {
00458             m_event_container_tag = DEFAULT_EVENT_CONTAINER_TAG;
00459         }
00460     }
00461 
00462     // next, map the fields to Terms
00463     xmlNodePtr codec_field_node = config_ptr;
00464     while ( (codec_field_node = ConfigManager::findConfigNodeByName(FIELD_ELEMENT_NAME, codec_field_node)) != NULL) {
00465         // parse new field mapping
00466 
00467         // start with the name of the field (element content)
00468         xmlChar *xml_char_ptr = xmlNodeGetContent(codec_field_node);
00469         if (xml_char_ptr == NULL || xml_char_ptr[0] == '\0') {
00470             if (xml_char_ptr != NULL)
00471                 xmlFree(xml_char_ptr);
00472             throw EmptyFieldException(getId());
00473         }
00474         const std::string field_name(reinterpret_cast<char*>(xml_char_ptr));
00475         xmlFree(xml_char_ptr);
00476 
00477         // next get the Term we want to map to
00478         xml_char_ptr = xmlGetProp(codec_field_node, reinterpret_cast<const xmlChar*>(TERM_ATTRIBUTE_NAME.c_str()));
00479         if (xml_char_ptr == NULL || xml_char_ptr[0] == '\0') {
00480             if (xml_char_ptr != NULL)
00481                 xmlFree(xml_char_ptr);
00482             throw EmptyTermException(getId());
00483         }
00484         const std::string term_id(reinterpret_cast<char*>(xml_char_ptr));
00485         xmlFree(xml_char_ptr);
00486 
00487         // make sure that the Term is valid
00488         const Vocabulary::TermRef term_ref = v.findTerm(term_id);
00489         if (term_ref == Vocabulary::UNDEFINED_TERM_REF)
00490             throw UnknownTermException(term_id);
00491 
00492         // add the field mapping
00493         mapFieldToTerm(field_name, v[term_ref]);
00494 
00495         // step to the next field mapping
00496         codec_field_node = codec_field_node->next;
00497     }
00498 
00499     m_XML_field_ptr_map.clear();
00500     for (FieldMap::const_iterator i = m_field_map.begin(); i != m_field_map.end(); ++i) {
00501         if (m_XML_field_ptr_map.find(i->second->term.term_ref) != m_XML_field_ptr_map.end())
00502             throw PionException("Duplicate Field Term");
00503         m_XML_field_ptr_map[i->second->term.term_ref] = i->second;
00504     }
00505 }
00506 
00507 void XMLCodec::updateVocabulary(const Vocabulary& v)
00508 {
00509     // First update anything in the Codec base class that might be needed.
00510     Codec::updateVocabulary(v);
00511 
00513     for (CurrentFormat::iterator i = m_format.begin(); i != m_format.end(); ++i) {
00514         // refresh term 
00515         v.refreshTerm((*i)->term);
00516 
00517         // For date/time types, update time_facet.
00518         switch ((*i)->term.term_type) {
00519             case pion::platform::Vocabulary::TYPE_DATE_TIME:
00520             case pion::platform::Vocabulary::TYPE_DATE:
00521             case pion::platform::Vocabulary::TYPE_TIME:
00522                 (*i)->time_facet.setFormat((*i)->term.term_format);
00523                 break;
00524             default:
00525                 break; // do nothing
00526         }
00527     }
00528 }
00529     
00530     
00531 }   // end namespace plugins
00532 }   // end namespace pion
00533 
00534 
00536 extern "C" PION_PLUGIN_API pion::platform::Codec *pion_create_XMLCodec(void) {
00537     return new pion::plugins::XMLCodec();
00538 }
00539 
00541 extern "C" PION_PLUGIN_API void pion_destroy_XMLCodec(pion::plugins::XMLCodec *codec_ptr) {
00542     delete codec_ptr;
00543 }

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7