mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Implements write support for WOZ files.
This commit is contained in:
parent
4036c60b45
commit
523ca3264b
@ -10,6 +10,7 @@
|
||||
#define CRC_hpp
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace CRC {
|
||||
|
||||
@ -58,6 +59,19 @@ template <typename T, T reset_value, T xor_output, bool reflect_input, bool refl
|
||||
/// Sets the current value of the CRC.
|
||||
inline void set_value(T value) { value_ = value; }
|
||||
|
||||
/*!
|
||||
A compound for:
|
||||
|
||||
reset()
|
||||
[add all data from @c data]
|
||||
get_value()
|
||||
*/
|
||||
T compute_crc(const std::vector<uint8_t> &data) {
|
||||
reset();
|
||||
for(const auto &byte: data) add(byte);
|
||||
return get_value();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int multibyte_shift = (sizeof(T) * 8) - 8;
|
||||
T xor_table[256];
|
||||
|
@ -111,6 +111,7 @@ void AppleDSK::set_tracks(const std::map<Track::Address, std::shared_ptr<Track>>
|
||||
tracks_by_address[pair.first] = std::move(track_contents);
|
||||
}
|
||||
|
||||
// Grab the file lock and write out the new tracks.
|
||||
std::lock_guard<std::mutex> lock_guard(file_.get_file_access_mutex());
|
||||
for(const auto &pair: tracks_by_address) {
|
||||
file_.seek(file_offset(pair.first), SEEK_SET);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "WOZ.hpp"
|
||||
|
||||
#include "../../Track/PCMTrack.hpp"
|
||||
#include "../../../../NumberTheory/CRC.hpp"
|
||||
#include "../../Track/TrackSerialiser.hpp"
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
@ -22,15 +22,15 @@ WOZ::WOZ(const std::string &file_name) :
|
||||
};
|
||||
if(!file_.check_signature(signature, 8)) throw Error::InvalidFormat;
|
||||
|
||||
// Check the file's CRC32, instead of skipping it.
|
||||
// Get the file's CRC32.
|
||||
const uint32_t crc = file_.get32le();
|
||||
CRC::CRC32 crc_generator;
|
||||
while(true) {
|
||||
uint8_t next = file_.get8();
|
||||
if(file_.eof()) break;
|
||||
crc_generator.add(next);
|
||||
}
|
||||
if(crc != crc_generator.get_value()) {
|
||||
|
||||
// Get the collection of all data that contributes to the CRC.
|
||||
post_crc_contents_ = file_.read(static_cast<std::size_t>(file_.stats().st_size - 12));
|
||||
|
||||
// Test the CRC.
|
||||
const uint32_t computed_crc = crc_generator.compute_crc(post_crc_contents_);
|
||||
if(crc != computed_crc) {
|
||||
throw Error::InvalidFormat;
|
||||
}
|
||||
|
||||
@ -119,3 +119,36 @@ std::shared_ptr<Track> WOZ::get_track_at_position(Track::Address address) {
|
||||
|
||||
return std::shared_ptr<PCMTrack>(new PCMTrack(track_contents));
|
||||
}
|
||||
|
||||
void WOZ::set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) {
|
||||
for(const auto &pair: tracks) {
|
||||
// Decode the track and store, patching into the post_crc_contents_.
|
||||
auto segment = Storage::Disk::track_serialisation(*pair.second, Storage::Time(1, 50000));
|
||||
|
||||
auto offset = static_cast<std::size_t>(file_offset(pair.first) - 12);
|
||||
memcpy(&post_crc_contents_[offset - 12], segment.data.data(), segment.number_of_bits >> 3);
|
||||
|
||||
// Write number of bytes and number of bits.
|
||||
post_crc_contents_[offset + 6646] = static_cast<uint8_t>(segment.number_of_bits >> 3);
|
||||
post_crc_contents_[offset + 6647] = static_cast<uint8_t>(segment.number_of_bits >> 11);
|
||||
post_crc_contents_[offset + 6648] = static_cast<uint8_t>(segment.number_of_bits);
|
||||
post_crc_contents_[offset + 6649] = static_cast<uint8_t>(segment.number_of_bits >> 8);
|
||||
|
||||
// Set no splice information now provided, since it's been lost if ever it was known.
|
||||
post_crc_contents_[offset + 6650] = 0xff;
|
||||
post_crc_contents_[offset + 6651] = 0xff;
|
||||
}
|
||||
|
||||
// Calculate the new CRC.
|
||||
const uint32_t crc = crc_generator.compute_crc(post_crc_contents_);
|
||||
|
||||
// Grab the file lock, then write the CRC, then just dump the entire file buffer.
|
||||
std::lock_guard<std::mutex> lock_guard(file_.get_file_access_mutex());
|
||||
file_.seek(8, SEEK_SET);
|
||||
file_.put_le(crc);
|
||||
file_.write(post_crc_contents_);
|
||||
}
|
||||
|
||||
bool WOZ::get_is_read_only() {
|
||||
return file_.get_is_known_read_only();
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "../DiskImage.hpp"
|
||||
#include "../../../FileHolder.hpp"
|
||||
#include "../../../../NumberTheory/CRC.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -24,9 +25,12 @@ class WOZ: public DiskImage {
|
||||
public:
|
||||
WOZ(const std::string &file_name);
|
||||
|
||||
// Implemented to satisfy @c Disk.
|
||||
HeadPosition get_maximum_head_position() override;
|
||||
int get_head_count() override;
|
||||
std::shared_ptr<Track> get_track_at_position(Track::Address address) override;
|
||||
void set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) override;
|
||||
bool get_is_read_only() override;
|
||||
|
||||
private:
|
||||
Storage::FileHolder file_;
|
||||
@ -35,6 +39,9 @@ class WOZ: public DiskImage {
|
||||
uint8_t track_map_[160];
|
||||
long tracks_offset_ = -1;
|
||||
|
||||
std::vector<uint8_t> post_crc_contents_;
|
||||
CRC::CRC32 crc_generator;
|
||||
|
||||
/*!
|
||||
Gets the in-file offset of a track.
|
||||
|
||||
|
@ -52,6 +52,28 @@ class FileHolder final {
|
||||
*/
|
||||
uint32_t get32le();
|
||||
|
||||
/*!
|
||||
Writes @c value using successive @c put8s, in little endian order.
|
||||
*/
|
||||
template <typename T> void put_le(T value) {
|
||||
auto bytes = sizeof(T);
|
||||
while(bytes--) {
|
||||
put8(value&0xff);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes @c value using successive @c put8s, in big endian order.
|
||||
*/
|
||||
template <typename T> void put_be(T value) {
|
||||
auto shift = sizeof(T) * 8;
|
||||
while(shift) {
|
||||
shift -= 8;
|
||||
put8((value >> shift)&0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Performs @c get8 four times on @c file, casting each result to a @c uint32_t
|
||||
and returning the four assembled in big endian order.
|
||||
|
Loading…
Reference in New Issue
Block a user