/* Saves a corrupted rom to the given filename. It will automatically provide an extension if one is not given. @param filename - The file to save to. */ void PSPCorruption::save(std::string filename) { filename += ".iso"; if (boost::filesystem::exists(filename) && std::remove(filename.c_str()) != 0) { throw InvalidFileException("Could not delete already existing file: " + filename); } if (info->save_file() != "") { boost::filesystem::copy_file(this->m_temp_file, info->save_file()); } else { boost::filesystem::copy_file(this->m_temp_file, filename); } if (boost::filesystem::remove(this->m_temp_file) == false) { throw InvalidFileException("Could not remove temp file: " + this->m_temp_file); } this->m_saved = true; }
PSPCorruption::~PSPCorruption() { if (boost::filesystem::exists(this->m_temp_file)) { if (std::remove(this->m_temp_file.c_str()) != 0) { throw InvalidFileException("Could not delete temp file: " + this->m_temp_file); } } }
H5RandomReader::H5RandomReader(const std::string fileName, const std::string groupPath) throw (InvalidFileException) { try { file.openFile(fileName, H5F_ACC_RDONLY);} catch ( H5::FileIException ) { throw InvalidFileException("Cannot acces file");} try { group = file.openGroup(groupPath);} catch ( H5::GroupIException ) { file.close(); throw InvalidFileException("Cannot access group");} /* * extract timeline. This is also necessary to get the nbSteps. */ try { timeline = group.openDataSet("timeline"); nSteps = timeline.getSpace().getSimpleExtentNpoints();} catch ( H5::DataSetIException error ) { //error.printError(); group.close(); file.close(); throw InvalidFileException("Cannot access timeline dataset");} if (logging::info) std::cerr << "Opened group \"" << fileName << groupPath << "\" which has " << nSteps << " steps.\n"; /* * extract objects names in the xpGroup */ std::vector<std::string> names; H5Literate(group.getId(), H5_INDEX_NAME, H5_ITER_INC, NULL, iterInGroup, &names); /* * extract data from object in xpGroup * these data can be of 3 types: matrix, translate or wrench * each data are saved in related map */ for (unsigned int i=0; i<names.size(); i++){ //TODO: skip timeline H5::DataSet dSet = group.openDataSet(names[i]); if (H5Aexists(dSet.getId(), "ArborisViewerType")) { H5::Attribute att = dSet.openAttribute("ArborisViewerType"); std::string type; att.read(att.getDataType(), type); if (type == "matrix"){ H5::DataSpace dSpace = dSet.getSpace(); bool dimension_ok = false; if (dSpace.getSimpleExtentNdims()==3) { hsize_t dims[3]; dSpace.getSimpleExtentDims (dims); if (dims[0] == nSteps && dims[1] == 4 && dims[2] == 4) dimension_ok = true;} if (dimension_ok) matrices[names[i]] = dSet; else { if (logging::warning) std::cerr << "Skipping dataset \"" << names[i] << "\" which has wrong dimensions. I was expecting (" << nSteps << ",4,4).\n"; dSet.close();}} else if (type == "translate"){ H5::DataSpace dSpace = dSet.getSpace(); bool dimension_ok = false; if (dSpace.getSimpleExtentNdims()==2) { hsize_t dims[2]; dSpace.getSimpleExtentDims (dims); if (dims[0] == nSteps && dims[1] == 3) dimension_ok = true;} if (dimension_ok) translates[names[i]] = dSet; else { if (logging::warning) std::cerr << "Skipping dataset \"" << names[i] << "\" which has wrong dimensions. I was expecting (" << nSteps << ",3).\n"; dSet.close();}} else if (type == "wrench") { H5::DataSpace dSpace = dSet.getSpace(); bool dimension_ok = false; if (dSpace.getSimpleExtentNdims()==2) { hsize_t dims[2]; dSpace.getSimpleExtentDims (dims); if (dims[0] == nSteps && dims[1] == 6) dimension_ok = true;} if (dimension_ok) wrenches[names[i]] = dSet; else { if (logging::warning) std::cerr << "Skipping dataset \"" << names[i] << "\" which as wrong dimensions. I was expecting (" << nSteps << ",6).\n"; dSet.close();}} else { if (logging::warning) std::cerr << "Skipping dataset \"" << names[i] << "\" whose ArborisViewerType attribute as unknown value \"" << type << "\".\n"; dSet.close();} att.close(); } else { if (logging::info) std::cerr << "Skipping dataset \"" << names[i] << "\" which has no ArborisViewerType attribute.\n"; dSet.close(); } } };
/* Corrupt the loaded file with the parameters in the PSPCorruptionInfo class */ void PSPCorruption::corrupt() { if (info->step() > 0 && info->files().size() > 0) { // Copy file only if step is valid and there are files to corrupt. boost::filesystem::copy_file(this->m_original_file, this->m_temp_file, boost::filesystem::copy_option::overwrite_if_exists); } else { std::cout << "Not corrupting: " << info->step() << "\t" << info->files().size() << std::endl; return; // If no step or files to corrupt then return } // For counting amount of corruptions uint32_t corruptions = 0; // Random number distribution over the byte value range std::uniform_int_distribution<int> random(0x00, 0xFF); // Open file for read/write in binary mode std::fstream img(this->m_temp_file, std::ios::in | std::ios::out | std::ios::binary); // If image could not be read then throw an exception if (!img.good()) { throw InvalidFileException("Could not open temp file: " + this->m_temp_file); } for (auto& file : info->files()) { if (file == "") { continue; } // Read the file into wad Entry entry = (*this->rom)[file]; // Get the raw data of the entry std::vector<uint8_t> data; try { data = entry.get(img, false); } catch (...) { //std::cout << "Could not find file '" << file << "'" << std::endl; continue; } // If no data, then throw an exception if (data.empty()) { //std::cout << "No data found in file '" << file << "'" << std::endl; continue; } for (uint32_t i = info->start(); (i < data.size()) && (i < info->end()); i += info->step()) { if (info->type() == CorruptionType::Shift) { // If it's okay to put the other byte in this position then change it if (i + info->value() < data.size() && valid_byte(data[i + info->value()], i)) { corruptions++; data[i] = data[i + info->value()]; } } else if (info->type() == CorruptionType::Swap) { if (i + info->value() < data.size() && valid_byte(data[i + info->value()], i) && // If it's okay to put the other byte in this position valid_byte(data[i], i + info->value())) // And it's okay to put this byte in the other position { corruptions++; uint8_t temp = data[i + info->value()]; data[i] = temp; data[i + info->value()] = temp; } } else if (info->type() == CorruptionType::Add) { // If the new byte value is valid then do the corruption if (valid_byte(data[i] + info->value(), i)) { corruptions++; data[i] += info->value(); } } else if (info->type() == CorruptionType::Set) { // If the set value can be placed here then do it if (valid_byte(info->value(), i)) { corruptions++; data[i] = info->value(); } } else if (info->type() == CorruptionType::Random) { bool corrupted = false; // Try up to 100 times to corrupt for (uint32_t retry = 0; !corrupted && retry < 100; retry++) { uint8_t rand = random(this->random); if (valid_byte(rand, i)) { corruptions++; data[i] = rand; corrupted = true; } } } else if (info->type() == CorruptionType::RotateLeft) { uint8_t rotate = util::rol<uint8_t>(data[i], info->value()); if (valid_byte(rotate, i)) { data[i] = rotate; corruptions++; } } else if (info->type() == CorruptionType::RotateRight) { uint8_t rotate = util::ror<uint8_t>(data[i], info->value()); if (valid_byte(rotate, i)) { data[i] = rotate; corruptions++; } } else if (info->type() == CorruptionType::LogicalAnd) { if (valid_byte(data[i] & info->value(), i)) { data[i] &= info->value(); corruptions++; } } else if (info->type() == CorruptionType::LogicalOr) { if (valid_byte(data[i] | info->value(), i)) { data[i] |= info->value(); corruptions++; } } else if (info->type() == CorruptionType::LogicalXor) { if (valid_byte(data[i] ^ info->value(), i)) { data[i] ^= info->value(); corruptions++; } } else if (info->type() == CorruptionType::LogicalComplement) { if (valid_byte(~data[i], i)) { data[i] = ~data[i]; corruptions++; } } else { break; // No corruption selected, might as well quit. } } // Write the modified data back to the file entry.write(img, data, false); } // Close the file img.close(); // Tell the user how many bytes were corrupted std::cout << corruptions << " bytes corrupted." << std::endl; }