endianness.cc
Go to the documentation of this file.
00001 #include "endianness.hh"
00002 #include <iostream>
00003 #include <boost/tuple/tuple.hpp>
00004 #include <boost/lexical_cast.hpp>
00005 
00006 namespace Typelib {
00007     size_t const CompileEndianSwapVisitor::FLAG_SKIP;
00008     size_t const CompileEndianSwapVisitor::FLAG_ARRAY;
00009     size_t const CompileEndianSwapVisitor::FLAG_END;
00010     size_t const CompileEndianSwapVisitor::FLAG_SWAP_4;
00011     size_t const CompileEndianSwapVisitor::FLAG_SWAP_8;
00012 
00013     size_t const CompileEndianSwapVisitor::SizeOfEnum;
00014 
00015     void CompileEndianSwapVisitor::skip(int skip_size)
00016     { 
00017         size_t size = m_compiled.size();
00018         if (m_compiled.size() > 1 && m_compiled[size - 2] == FLAG_SKIP)
00019             m_compiled[size - 1] += skip_size;
00020         else
00021         {
00022             m_compiled.push_back(FLAG_SKIP);
00023             m_compiled.push_back(skip_size);
00024         }
00025     }
00026 
00027     bool CompileEndianSwapVisitor::visit_ (Numeric const& type)
00028     {
00029         switch(type.getSize())
00030         {
00031         case 1:
00032             skip(1);
00033             return true;
00034         case 2:
00035             m_compiled.push_back(m_output_index + 1);
00036             m_compiled.push_back(m_output_index);
00037             return true;
00038 
00039         case 4:
00040             m_compiled.push_back(FLAG_SWAP_4);
00041             return true;
00042 
00043         case 8:
00044             m_compiled.push_back(FLAG_SWAP_8);
00045             return true;
00046 
00047         default:
00048             throw UnsupportedEndianSwap("objects of size " + boost::lexical_cast<std::string>(type.getSize()));
00049         }
00050     }
00051 
00052     bool CompileEndianSwapVisitor::visit_ (Enum const& type)
00053     {
00054         for (int i = SizeOfEnum - 1; i >= 0; --i)
00055             m_compiled.push_back(m_output_index + i);
00056         return true;
00057     }
00058 
00059     bool CompileEndianSwapVisitor::visit_ (OpaqueType const& type)
00060     { throw UnsupportedEndianSwap("opaque"); }
00061     bool CompileEndianSwapVisitor::visit_ (Pointer const& type)
00062     { throw UnsupportedEndianSwap("pointers"); }
00063     bool CompileEndianSwapVisitor::visit_ (Array const& type)
00064     {
00065         if (type.getIndirection().getCategory() == Type::Array)
00066         {
00067             size_t current_size = m_compiled.size();
00068             visit_(dynamic_cast<Array const&>(type.getIndirection()));
00069             m_compiled[current_size + 1] *= type.getDimension();
00070             return true;
00071         }
00072 
00073         m_compiled.push_back(FLAG_ARRAY);
00074         m_compiled.push_back(type.getDimension());
00075         m_compiled.push_back(type.getIndirection().getSize());
00076 
00077         size_t current_size = m_compiled.size();
00078         TypeVisitor::visit_(type);
00079 
00080         if (m_compiled.size() == current_size + 2 && m_compiled[current_size] == FLAG_SKIP)
00081         {
00082             m_compiled[current_size - 3] = FLAG_SKIP;
00083             m_compiled[current_size - 2] = m_compiled[current_size + 1] * type.getDimension();
00084             m_compiled.pop_back();
00085             m_compiled.pop_back();
00086             m_compiled.pop_back();
00087         }
00088         else
00089             m_compiled.push_back(FLAG_END);
00090 
00091         return true;
00092     }
00093 
00094     bool CompileEndianSwapVisitor::visit_ (Container const& type)
00095     { throw UnsupportedEndianSwap("containers"); }
00096 
00097     bool CompileEndianSwapVisitor::visit_ (Compound const& type)
00098     {
00099         size_t base_index = m_output_index;
00100 
00101         typedef Compound::FieldList Fields;
00102         Fields const& fields(type.getFields());
00103         Fields::const_iterator const end = fields.end();
00104 
00105         for (Fields::const_iterator it = fields.begin(); it != end; ++it)
00106         {
00107             size_t new_index = base_index + it->getOffset();
00108             if (new_index < m_output_index)
00109                 continue;
00110             else if (new_index > m_output_index)
00111                 skip(new_index - m_output_index);
00112 
00113             m_output_index = new_index;
00114             dispatch(it->getType());
00115             m_output_index = new_index + it->getType().getSize();
00116         }
00117         return true;
00118     }
00119 
00120     void CompileEndianSwapVisitor::apply(Type const& type)
00121     {
00122         m_output_index = 0;
00123         m_compiled.clear();
00124         TypeVisitor::apply(type);
00125     }
00126 
00127     std::pair<size_t, std::vector<size_t>::const_iterator> 
00128         CompileEndianSwapVisitor::swap(
00129             size_t output_offset, size_t input_offset,
00130             std::vector<size_t>::const_iterator it,
00131             std::vector<size_t>::const_iterator end,
00132             Value in, Value out)
00133     {
00134         uint8_t* input_buffer = reinterpret_cast<uint8_t*>(in.getData());
00135         uint8_t* output_buffer = reinterpret_cast<uint8_t*>(out.getData());
00136         while(it != end)
00137         {
00138             switch(*it)
00139             {
00140             case FLAG_SKIP:
00141                 {
00142                     size_t skip_size = *(++it);
00143                     for (size_t i = 0; i < skip_size; ++i)
00144                     {
00145                         output_buffer[output_offset] = input_buffer[output_offset];
00146                         output_offset++;
00147                     }
00148                 }
00149                 break;
00150             case FLAG_SWAP_4:
00151                 {
00152                     reinterpret_cast<uint32_t&>(output_buffer[output_offset]) = 
00153                         utilmm::endian::swap(reinterpret_cast<uint32_t const&>(input_buffer[output_offset]));
00154                     output_offset += 4;
00155                 }
00156                 break;
00157             case FLAG_SWAP_8:
00158                 {
00159                     reinterpret_cast<uint64_t&>(output_buffer[output_offset]) = 
00160                         utilmm::endian::swap(reinterpret_cast<uint64_t const&>(input_buffer[output_offset]));
00161                     output_offset += 8;
00162                 }
00163                 break;
00164             case FLAG_ARRAY:
00165                 {
00166                     size_t array_size = *(++it);
00167                     size_t element_size = *(++it);
00168 
00169                     // And swap as many elements as needed
00170                     ++it;
00171 
00172                     std::vector<size_t>::const_iterator array_end;
00173                     for (size_t i = 0; i < array_size; ++i)
00174                     {
00175                         boost::tie(output_offset, array_end) = 
00176                             swap(output_offset, input_offset + element_size * i, 
00177                                 it, end, in, out);
00178                     }
00179                     it = array_end;
00180                 }
00181                 break;
00182             case FLAG_END:
00183                 return make_pair(output_offset, it);
00184             default:
00185                 {
00186                     output_buffer[output_offset] = input_buffer[input_offset + *it];
00187                     ++output_offset;
00188                 }
00189                 break;
00190             }
00191 
00192             ++it;
00193         }
00194 
00195         return make_pair(output_offset, it);
00196     }
00197 
00198     void CompileEndianSwapVisitor::display()
00199     {
00200         std::string indent = "";
00201         std::vector<size_t>::const_iterator it, end;
00202         for (it = m_compiled.begin(); it != m_compiled.end(); ++it)
00203         {
00204             switch(*it)
00205             {
00206                 case FLAG_SKIP:
00207                     std::cout << std::endl << indent << "SKIP " << *(++it) << std::endl;
00208                     break;
00209                 case FLAG_ARRAY:
00210                     std::cout << std::endl << indent << "ARRAY " << *(++it) << " " << *(++it) << std::endl;
00211                     indent += "  ";
00212                     break;
00213                 case FLAG_END:
00214                     indent.resize(indent.length() - 2);
00215                     std::cout << std::endl << indent << "END" << std::endl;
00216                     break;
00217                 default:
00218                     std::cout << " " << *it;
00219             }
00220         }
00221     }
00222 }
00223 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41