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