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
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