IBR-DTNSuite  0.8
ibrdtn/ibrdtn/api/PlainSerializer.cpp
Go to the documentation of this file.
00001 /*
00002  * PlainSerializer.cpp
00003  *
00004  *  Created on: 16.06.2011
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include "ibrdtn/api/PlainSerializer.h"
00010 #include "ibrdtn/utils/Utils.h"
00011 #include <ibrcommon/refcnt_ptr.h>
00012 #include <ibrcommon/data/Base64Stream.h>
00013 #include <ibrcommon/data/Base64Reader.h>
00014 #include <ibrcommon/Logger.h>
00015 #include <list>
00016 
00017 namespace dtn
00018 {
00019         namespace api
00020         {
00021                 PlainSerializer::PlainSerializer(std::ostream &stream, bool skip_payload)
00022                  : _stream(stream), _skip_payload(skip_payload)
00023                 {
00024                 }
00025 
00026                 PlainSerializer::~PlainSerializer()
00027                 {
00028                 }
00029 
00030                 dtn::data::Serializer& PlainSerializer::operator<<(const dtn::data::Bundle &obj)
00031                 {
00032                         // serialize the primary block
00033                         (*this) << (dtn::data::PrimaryBlock&)obj;
00034 
00035                         // serialize all secondary blocks
00036                         const std::list<const dtn::data::Block*> list = obj.getBlocks();
00037 
00038                         // block count
00039                         _stream << "Blocks: " << list.size() << std::endl;
00040 
00041                         for (std::list<const dtn::data::Block*>::const_iterator iter = list.begin(); iter != list.end(); iter++)
00042                         {
00043                                 const dtn::data::Block &b = (*(*iter));
00044                                 _stream << std::endl;
00045                                 (*this) << b;
00046                         }
00047 
00048                         _stream << std::endl;
00049 
00050                         return (*this);
00051                 }
00052 
00053                 dtn::data::Serializer& PlainSerializer::operator<<(const dtn::data::PrimaryBlock &obj)
00054                 {
00055                         _stream << "Processing flags: " << obj._procflags << std::endl;
00056                         _stream << "Timestamp: " << obj._timestamp << std::endl;
00057                         _stream << "Sequencenumber: " << obj._sequencenumber << std::endl;
00058                         _stream << "Source: " << obj._source.getString() << std::endl;
00059                         _stream << "Destination: " << obj._destination.getString() << std::endl;
00060                         _stream << "Reportto: " << obj._reportto.getString() << std::endl;
00061                         _stream << "Custodian: " << obj._custodian.getString() << std::endl;
00062                         _stream << "Lifetime: " << obj._lifetime << std::endl;
00063 
00064                         if (obj._procflags & dtn::data::PrimaryBlock::FRAGMENT)
00065                         {
00066                                 _stream << "Fragment offset: " << obj._fragmentoffset << std::endl;
00067                                 _stream << "Application data length: " << obj._appdatalength << std::endl;
00068                         }
00069 
00070                         return (*this);
00071                 }
00072 
00073                 dtn::data::Serializer& PlainSerializer::operator<<(const dtn::data::Block &obj)
00074                 {
00075                         _stream << "Block: " << (int)((unsigned char)obj.getType()) << std::endl;
00076 
00077                         std::stringstream flags;
00078 
00079                         if (obj.get(dtn::data::Block::LAST_BLOCK))
00080                         {
00081                                 flags << " LAST_BLOCK";
00082                         }
00083 
00084                         if (obj.get(dtn::data::Block::REPLICATE_IN_EVERY_FRAGMENT))
00085                         {
00086                                 flags << " REPLICATE_IN_EVERY_FRAGMENT";
00087                         }
00088 
00089                         if (obj.get(dtn::data::Block::TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED))
00090                         {
00091                                 flags << " TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED";
00092                         }
00093 
00094                         if (obj.get(dtn::data::Block::DELETE_BUNDLE_IF_NOT_PROCESSED))
00095                         {
00096                                 flags << " DELETE_BUNDLE_IF_NOT_PROCESSED";
00097                         }
00098 
00099                         if (obj.get(dtn::data::Block::DISCARD_IF_NOT_PROCESSED))
00100                         {
00101                                 flags << " DISCARD_IF_NOT_PROCESSED";
00102                         }
00103 
00104                         if (obj.get(dtn::data::Block::FORWARDED_WITHOUT_PROCESSED))
00105                         {
00106                                 flags << " FORWARDED_WITHOUT_PROCESSED";
00107                         }
00108 
00109                         if (flags.str().length() > 0)
00110                         {
00111                                 _stream << "Flags:" << flags.str() << std::endl;
00112                         }
00113 
00114                         if (obj.get(dtn::data::Block::BLOCK_CONTAINS_EIDS))
00115                         {
00116                                 std::list<dtn::data::EID> eid_list = obj.getEIDList();
00117 
00118                                 for (std::list<dtn::data::EID>::const_iterator iter = eid_list.begin(); iter != eid_list.end(); iter++)
00119                                 {
00120                                         _stream << "EID: " << (*iter).getString() << std::endl;
00121                                 }
00122                         }
00123 
00124                         _stream << "Length: " << obj.getLength() << std::endl;
00125 
00126 
00127                         if(!_skip_payload){
00128                                 try {
00129 
00130                                         _stream << std::endl;
00131 
00132                                         // put data here
00133                                         ibrcommon::Base64Stream b64(_stream, false, 80);
00134                                         size_t slength = 0;
00135                                         obj.serialize(b64, slength);
00136                                         b64 << std::flush;
00137                                 } catch (const std::exception &ex) {
00138                                         std::cerr << ex.what() << std::endl;
00139                                 }
00140 
00141                                 _stream << std::endl;
00142                         }
00143 
00144                         return (*this);
00145                 }
00146 
00147                 dtn::data::Serializer &PlainSerializer::serialize(ibrcommon::BLOB::iostream &obj, size_t limit){
00148                         size_t len = obj.size();
00149                         if(limit < len && limit > 0)
00150                         {
00151                                 len = limit;
00152                         }
00153 
00154                         _stream << "Length: " << len << std::endl;
00155                         _stream << std::endl;
00156 
00157                         ibrcommon::Base64Stream b64(_stream, false, 80);
00158                         ibrcommon::BLOB::copy(b64, *obj, len);
00159                         b64 << std::flush;
00160 
00161                         _stream << std::endl;
00162 
00163                         return *this;
00164                 }
00165 
00166                 size_t PlainSerializer::getLength(const dtn::data::Bundle &obj)
00167                 {
00168                         return 0;
00169                 }
00170 
00171                 size_t PlainSerializer::getLength(const dtn::data::PrimaryBlock &obj) const
00172                 {
00173                         return 0;
00174                 }
00175 
00176                 size_t PlainSerializer::getLength(const dtn::data::Block &obj) const
00177                 {
00178                         return 0;
00179                 }
00180 
00181                 PlainDeserializer::PlainDeserializer(std::istream &stream)
00182                  : _stream(stream)
00183                 {
00184                 }
00185 
00186                 PlainDeserializer::~PlainDeserializer()
00187                 {
00188                 }
00189 
00190                 dtn::data::Deserializer& PlainDeserializer::operator>>(dtn::data::Bundle &obj)
00191                 {
00192                         // clear all blocks
00193                         obj.clearBlocks();
00194 
00195                         // read the primary block
00196                         (*this) >> (dtn::data::PrimaryBlock&)obj;
00197 
00198                         // read until the last block
00199                         bool lastblock = false;
00200 
00201                         // read all BLOCKs
00202                         while (!_stream.eof() && !lastblock)
00203                         {
00204                                 try
00205                                 {
00206                                         dtn::data::Block& block = readBlock(BlockInserter(obj, BlockInserter::END), obj.get(dtn::data::Bundle::APPDATA_IS_ADMRECORD));
00207                                         lastblock = block.get(dtn::data::Block::LAST_BLOCK);
00208                                 }
00209                                 catch (const UnknownBlockException &ex)
00210                                 {
00211                                         IBRCOMMON_LOGGER_DEBUG(5) << "unknown administrative block in bundle " << obj.toString() << " has been removed" << IBRCOMMON_LOGGER_ENDL;
00212                                 }
00213                                 catch (const BlockNotProcessableException &ex)
00214                                 {
00215                                         IBRCOMMON_LOGGER_DEBUG(5) << "unprocessable block in bundle " << obj.toString() << " has been removed" << IBRCOMMON_LOGGER_ENDL;
00216                                 }
00217                         }
00218 
00219                         return (*this);
00220                 }
00221 
00222                 dtn::data::Deserializer& PlainDeserializer::operator>>(dtn::data::PrimaryBlock &obj)
00223                 {
00224                         std::string data;
00225 
00226                         // read until the first empty line appears
00227                         while (_stream.good())
00228                         {
00229                                 std::stringstream ss;
00230                                 getline(_stream, data);
00231 
00232                                 std::string::reverse_iterator iter = data.rbegin();
00233                                 if ( (*iter) == '\r' ) data = data.substr(0, data.length() - 1);
00234 
00235 //                              // strip off the last char
00236 //                              data.erase(data.size() - 1);
00237 
00238                                 // abort after the first empty line
00239                                 if (data.size() == 0) break;
00240 
00241                                 // split header value
00242                                 std::vector<std::string> values = dtn::utils::Utils::tokenize(":", data, 1);
00243 
00244                                 // if there are not enough parameter abort with an error
00245                                 if (values.size() < 1) throw ibrcommon::Exception("parsing error");
00246 
00247                                 // assign header value
00248                                 if (values[0] == "Processing flags")
00249                                 {
00250                                         ss.clear(); ss.str(values[1]);
00251                                         ss >> obj._procflags;
00252                                 }
00253                                 else if (values[0] == "Timestamp")
00254                                 {
00255                                         ss.clear(); ss.str(values[1]);
00256                                         ss >> obj._timestamp;
00257                                 }
00258                                 else if (values[0] == "Sequencenumber")
00259                                 {
00260                                         ss.clear(); ss.str(values[1]);
00261                                         ss >> obj._sequencenumber;
00262                                 }
00263                                 else if (values[0] == "Source")
00264                                 {
00265                                         obj._source = values[1];
00266                                 }
00267                                 else if (values[0] == "Destination")
00268                                 {
00269                                         obj._destination = values[1];
00270                                 }
00271                                 else if (values[0] == "Reportto")
00272                                 {
00273                                         obj._reportto = values[1];
00274                                 }
00275                                 else if (values[0] == "Custodian")
00276                                 {
00277                                         obj._custodian = values[1];
00278                                 }
00279                                 else if (values[0] == "Lifetime")
00280                                 {
00281                                         ss.clear(); ss.str(values[1]);
00282                                         ss >> obj._lifetime;
00283                                 }
00284                                 else if (values[0] == "Fragment offset")
00285                                 {
00286                                         ss.clear(); ss.str(values[1]);
00287                                         ss >> obj._fragmentoffset;
00288                                 }
00289                                 else if (values[0] == "Application data length")
00290                                 {
00291                                         ss.clear(); ss.str(values[1]);
00292                                         ss >> obj._appdatalength;
00293                                 }
00294                         }
00295 
00296                         return (*this);
00297                 }
00298 
00299                 dtn::data::Deserializer& PlainDeserializer::operator>>(dtn::data::Block &obj)
00300                 {
00301                         std::string data;
00302                         size_t blocksize = 0;
00303 
00304                         // read until the first empty line appears
00305                         while (_stream.good())
00306                         {
00307                                 getline(_stream, data);
00308 
00309                                 std::string::reverse_iterator iter = data.rbegin();
00310                                 if ( (*iter) == '\r' ) data = data.substr(0, data.length() - 1);
00311 
00312 //                              // strip off the last char
00313 //                              data.erase(data.size() - 1);
00314 
00315                                 // abort after the first empty line
00316                                 if (data.size() == 0) break;
00317 
00318                                 // split header value
00319                                 std::vector<std::string> values = dtn::utils::Utils::tokenize(":", data, 1);
00320 
00321                                 // skip invalid lines
00322                                 if(values.size() < 2)
00323                                         continue;
00324 
00325                                 // assign header value
00326                                 if (values[0] == "Flags")
00327                                 {
00328                                         std::vector<std::string> flags = dtn::utils::Utils::tokenize(" ", values[1]);
00329 
00330                                         for (std::vector<std::string>::const_iterator iter = flags.begin(); iter != flags.end(); iter++)
00331                                         {
00332                                                 const std::string &value = (*iter);
00333                                                 if (value == "LAST_BLOCK")
00334                                                 {
00335                                                         obj.set(dtn::data::Block::LAST_BLOCK, true);
00336                                                 }
00337                                                 else if (value == "FORWARDED_WITHOUT_PROCESSED")
00338                                                 {
00339                                                         obj.set(dtn::data::Block::FORWARDED_WITHOUT_PROCESSED, true);
00340                                                 }
00341                                                 else if (value == "DISCARD_IF_NOT_PROCESSED")
00342                                                 {
00343                                                         obj.set(dtn::data::Block::DISCARD_IF_NOT_PROCESSED, true);
00344                                                 }
00345                                                 else if (value == "DELETE_BUNDLE_IF_NOT_PROCESSED")
00346                                                 {
00347                                                         obj.set(dtn::data::Block::DELETE_BUNDLE_IF_NOT_PROCESSED, true);
00348                                                 }
00349                                                 else if (value == "TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED")
00350                                                 {
00351                                                         obj.set(dtn::data::Block::TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED, true);
00352                                                 }
00353                                                 else if (value == "REPLICATE_IN_EVERY_FRAGMENT")
00354                                                 {
00355                                                         obj.set(dtn::data::Block::REPLICATE_IN_EVERY_FRAGMENT, true);
00356                                                 }
00357                                         }
00358                                 }
00359                                 else if (values[0] == "EID")
00360                                 {
00361                                         obj.addEID(values[1]);
00362                                         obj.set(dtn::data::Block::BLOCK_CONTAINS_EIDS, true);
00363                                 }
00364                                 else if (values[0] == "Length")
00365                                 {
00366                                         std::stringstream ss; ss.str(values[1]);
00367                                         ss >> blocksize;
00368                                 }
00369                         }
00370 
00371                         // then read the payload
00372                         IBRCOMMON_LOGGER_DEBUG(20) << "API expecting payload size of " << blocksize << IBRCOMMON_LOGGER_ENDL;
00373                         ibrcommon::Base64Reader base64_decoder(_stream, blocksize);
00374                         obj.deserialize(base64_decoder, blocksize);
00375 
00376                         std::string buffer;
00377 
00378                         // read the appended newline character
00379                         getline(_stream, buffer);
00380                         std::string::reverse_iterator iter = buffer.rbegin();
00381                         if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00382                         if (buffer.size() != 0) throw dtn::InvalidDataException("last line not empty");
00383 
00384                         // read the final empty line
00385                         getline(_stream, buffer);
00386                         iter = buffer.rbegin();
00387                         if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00388                         if (buffer.size() != 0) throw dtn::InvalidDataException("last line not empty");
00389 
00390                         return (*this);
00391                 }
00392 
00393                 dtn::data::Deserializer& PlainDeserializer::operator>>(ibrcommon::BLOB::iostream &obj)
00394                 {
00395                         std::string data;
00396                         size_t blocksize = 0;
00397 
00398                         // read until the first empty line appears
00399                         while (_stream.good())
00400                         {
00401                                 getline(_stream, data);
00402 
00403                                 std::string::reverse_iterator iter = data.rbegin();
00404                                 if ( (*iter) == '\r' ) data = data.substr(0, data.length() - 1);
00405 
00406                                 // abort after the first empty line
00407                                 if (data.size() == 0) break;
00408 
00409                                 // split header value
00410                                 std::vector<std::string> values = dtn::utils::Utils::tokenize(":", data, 1);
00411 
00412                                 // skip invalid lines
00413                                 if(values.size() < 1)
00414                                         continue;
00415 
00416                                 // assign header value
00417                                 if (values[0] == "Length")
00418                                 {
00419                                         std::stringstream ss; ss.str(values[1]);
00420                                         ss >> blocksize;
00421                                 }
00422                         }
00423 
00424                         // then read the payload
00425                         ibrcommon::Base64Reader base64_decoder(_stream, blocksize);
00426                         ibrcommon::BLOB::copy(*obj, base64_decoder, blocksize);
00427                         //*obj.iostream() << base64_decoder.rdbuf() << std::flush;
00428 
00429                         std::string buffer;
00430 
00431                         // read the appended newline character
00432                         getline(_stream, buffer);
00433                         std::string::reverse_iterator iter = buffer.rbegin();
00434                         if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00435                         if (buffer.size() != 0) throw dtn::InvalidDataException("last line not empty");
00436 
00437                         // read the final empty line
00438                         getline(_stream, buffer);
00439                         iter = buffer.rbegin();
00440                         if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00441                         if (buffer.size() != 0) throw dtn::InvalidDataException("last line not empty");
00442 
00443                         return (*this);
00444                 }
00445 
00446                 dtn::data::Deserializer& PlainDeserializer::operator>>(std::ostream &stream)
00447                 {
00448                         ibrcommon::Base64Stream b64(stream, true);
00449                         std::string data;
00450 
00451                         while (b64.good())
00452                         {
00453                                 getline(_stream, data);
00454 
00455                                 std::string::reverse_iterator iter = data.rbegin();
00456                                 if ( (*iter) == '\r' ) data = data.substr(0, data.length() - 1);
00457 
00458 //                              // strip off the last char
00459 //                              data.erase(data.size() - 1);
00460 
00461                                 // abort after the first empty line
00462                                 if (data.size() == 0) break;
00463 
00464                                 // put the line into the stream decoder
00465                                 b64 << data;
00466                         }
00467 
00468                         b64 << std::flush;
00469 
00470                         return (*this);
00471                 }
00472 
00473                 dtn::data::Block& PlainDeserializer::readBlock(BlockInserter inserter, bool payload_is_adm)
00474                 {
00475                         std::string buffer;
00476                         int block_type;
00477 
00478                         // read the block type (first line)
00479                         getline(_stream, buffer);
00480 
00481                         std::string::reverse_iterator iter = buffer.rbegin();
00482                         if ( (*iter) == '\r' ) buffer = buffer.substr(0, buffer.length() - 1);
00483 
00484                         // abort if the line data is empty
00485                         if (buffer.size() == 0) throw dtn::InvalidDataException("block header is missing");
00486 
00487                         // split header value
00488                         std::vector<std::string> values = dtn::utils::Utils::tokenize(":", buffer, 1);
00489 
00490                         if (values[0] == "Block")
00491                         {
00492                                 std::stringstream ss; ss.str(values[1]);
00493                                 ss >> block_type;
00494                         }
00495                         else
00496                         {
00497                                 throw dtn::InvalidDataException("need block type as first header");
00498                         }
00499 
00500                         switch (block_type)
00501                         {
00502                                 case 0:
00503                                 {
00504                                         throw dtn::InvalidDataException("block type is zero");
00505                                         break;
00506                                 }
00507 
00508                                 case dtn::data::PayloadBlock::BLOCK_TYPE:
00509                                 {
00510                                         //if (payload_is_adm)
00511                                         if (payload_is_adm)
00512                                         {
00513                                                 // create a temporary block
00514                                                 dtn::data::ExtensionBlock block;
00515                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00516 
00517                                                 // read the block data
00518                                                 (*this) >> block;
00519 
00520                                                 // access the payload to get the first byte
00521                                                 char admfield;
00522                                                 ibrcommon::BLOB::Reference ref = block.getBLOB();
00523                                                 ref.iostream()->get(admfield);
00524 
00525                                                 // write the block into a temporary stream
00526                                                 stringstream ss;
00527                                                 PlainSerializer serializer(ss);
00528                                                 PlainDeserializer deserializer(ss);
00529 
00530                                                 serializer << block;
00531 
00532                                                 switch (admfield >> 4)
00533                                                 {
00534                                                         case 1:
00535                                                         {
00536                                                                 dtn::data::StatusReportBlock &block = inserter.insert<dtn::data::StatusReportBlock>();
00537                                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00538                                                                 deserializer >> block;
00539                                                                 //lastblock = block.get(dtn::data::Block::LAST_BLOCK);
00540                                                                 return block;
00541                                                         }
00542 
00543                                                         case 2:
00544                                                         {
00545                                                                 dtn::data::CustodySignalBlock &block = inserter.insert<dtn::data::CustodySignalBlock>();
00546                                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00547                                                                 deserializer >> block;
00548                                                                 //lastblock = block.get(dtn::data::Block::LAST_BLOCK);
00549                                                                 //break;
00550                                                                 return block;
00551                                                         }
00552 
00553                                                         default:
00554                                                         {
00555                                                                 // drop unknown administrative block
00556                                                                 throw UnknownBlockException("unknown administrative record");
00557                                                                 break;
00558                                                         }
00559                                                 }
00560 
00561                                         }
00562                                         else
00563                                         {
00564                                                 dtn::data::PayloadBlock &block = inserter.insert<dtn::data::PayloadBlock>();
00565                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00566                                                 (*this) >> block;
00567 
00568                                                 return block;
00569                                         }
00570                                 }
00571 
00572                                 default:
00573                                 {
00574                                         // get a extension block factory
00575                                         try {
00576                                                 dtn::data::ExtensionBlock::Factory &f = dtn::data::ExtensionBlock::Factory::get((char) block_type);
00577 
00578                                                 dtn::data::Block &block = inserter.insert(f);
00579                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00580                                                 (*this) >> block;
00581 
00582                                                 if (block.get(dtn::data::Block::DISCARD_IF_NOT_PROCESSED))
00583                                                 {
00584                                                         //IBRCOMMON_LOGGER_DEBUG(5) << "unprocessable block in bundle " << obj.toString() << " has been removed" << IBRCOMMON_LOGGER_ENDL;
00585 
00586                                                         throw BlockNotProcessableException();
00587                                                 }
00588                                                 return block;
00589                                         }
00590                                         catch (const BlockNotProcessableException &ex){
00591                                                 throw ex;
00592                                         }
00593                                         catch (const ibrcommon::Exception &ex)
00594                                         {
00595                                                 dtn::data::ExtensionBlock &block = inserter.insert<dtn::data::ExtensionBlock>();
00596                                                 block.set(dtn::data::Block::LAST_BLOCK, false);
00597                                                 (*this) >> block;
00598 
00599                                                 if (block.get(dtn::data::Block::DISCARD_IF_NOT_PROCESSED))
00600                                                 {
00601                                                         //IBRCOMMON_LOGGER_DEBUG(5) << "unprocessable block in bundle " << obj.toString() << " has been removed" << IBRCOMMON_LOGGER_ENDL;
00602 
00603                                                         throw BlockNotProcessableException();
00604                                                 }
00605                                                 return block;
00606                                         }
00607                                 }
00608                         }
00609                 }
00610 
00611                 PlainDeserializer::BlockInserter::BlockInserter(dtn::data::Bundle &bundle, POSITION alignment, int pos)
00612                         :       _bundle(&bundle), _alignment(alignment), _pos(pos)
00613                 {
00614                 }
00615 
00616                 dtn::data::Block &PlainDeserializer::BlockInserter::insert(dtn::data::ExtensionBlock::Factory &f)
00617                 {
00618                         switch (_alignment)
00619                         {
00620                         case FRONT:
00621                                 return _bundle->push_front(f);
00622                         case END:
00623                                 return _bundle->push_back(f);
00624                         default:
00625                                 if(_pos <= 0)
00626                                         return _bundle->push_front(f);
00627 
00628                                 try
00629                                 {
00630                                         dtn::data::Block &prev_block = _bundle->getBlock(_pos-1);
00631                                         return _bundle->insert(f, prev_block);
00632                                 }
00633                                 catch (const std::exception &ex)
00634                                 {
00635                                         return _bundle->push_back(f);
00636                                 }
00637                         }
00638                 }
00639 
00640                 PlainDeserializer::BlockInserter::POSITION PlainDeserializer::BlockInserter::getAlignment() const
00641                 {
00642                         return _alignment;
00643                 }
00644         }
00645 }