From 33eadb554917fb1a459dbc3768b7a93102cd307b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 11 Jul 2017 22:41:10 -0400 Subject: [PATCH] Started taking further steps towards CSW support; reading the ZLib documentation is next. --- Storage/Tape/Formats/CSW.cpp | 60 ++++++++++++++++++++++++++++++++++++ Storage/Tape/Formats/CSW.hpp | 11 +++++++ Storage/Tape/Tape.hpp | 2 ++ 3 files changed, 73 insertions(+) diff --git a/Storage/Tape/Formats/CSW.cpp b/Storage/Tape/Formats/CSW.cpp index 957c8a448..9ce4b090f 100644 --- a/Storage/Tape/Formats/CSW.cpp +++ b/Storage/Tape/Formats/CSW.cpp @@ -12,8 +12,68 @@ using namespace Storage::Tape; CSW::CSW(const char *file_name) : Storage::FileHolder(file_name) { + if(file_stats_.st_size < 0x20) throw ErrorNotCSW; + + // Check signature. + char identifier[22]; + char signature[] = "Compressed Square Wave"; + fread(identifier, 1, 22, file_); + if(memcmp(identifier, signature, strlen(signature))) throw ErrorNotCSW; + + // Check terminating byte. + if(fgetc(file_) != 0x1a) throw ErrorNotCSW; + + // Get version file number. + uint8_t major_version = (uint8_t)fgetc(file_); + uint8_t minor_version = (uint8_t)fgetc(file_); + + // Reject if this is an unknown version. + if(major_version > 2 || !major_version || minor_version > 1) throw ErrorNotCSW; + + // The header now diverges based on version. + if(major_version == 1) { + pulse_.length.clock_rate = fgetc16le(); + + if(fgetc(file_) != 1) throw ErrorNotCSW; + compression_type_ = RLE; + + pulse_.type = (fgetc(file_) & 1) ? Pulse::High : Pulse::Low; + + fseek(file_, 0x20, SEEK_SET); + } else { + pulse_.length.clock_rate = fgetc32le(); + number_of_waves_ = fgetc32le(); + switch(fgetc(file_)) { + case 1: compression_type_ = RLE; break; + case 2: compression_type_ = ZRLE; break; + default: throw ErrorNotCSW; + } + + pulse_.type = (fgetc(file_) & 1) ? Pulse::High : Pulse::Low; + uint8_t extension_length = (uint8_t)fgetc(file_); + + if(file_stats_.st_size < 0x34 + extension_length) throw ErrorNotCSW; + fseek(file_, 0x34 + extension_length, SEEK_SET); + } + + if(compression_type_ == ZRLE) { + inflation_stream_.zalloc = Z_NULL; + inflation_stream_.zfree = Z_NULL; + inflation_stream_.opaque = Z_NULL; + inflation_stream_.avail_in = 0; + inflation_stream_.next_in = Z_NULL; + int result = inflateInit(&inflation_stream_); + if(result != Z_OK) throw ErrorNotCSW; + } } +CSW::~CSW() { + if(compression_type_ == ZRLE) { + inflateEnd(&inflation_stream_); + } +} + + bool CSW::is_at_end() { return true; } diff --git a/Storage/Tape/Formats/CSW.hpp b/Storage/Tape/Formats/CSW.hpp index ed98b3bed..4063e530b 100644 --- a/Storage/Tape/Formats/CSW.hpp +++ b/Storage/Tape/Formats/CSW.hpp @@ -12,6 +12,8 @@ #include "../Tape.hpp" #include "../../FileHolder.hpp" +#include + namespace Storage { namespace Tape { @@ -26,6 +28,7 @@ class CSW: public Tape, public Storage::FileHolder { @throws ErrorNotCSW if this file could not be opened and recognised as a valid CSW file. */ CSW(const char *file_name); + ~CSW(); enum { ErrorNotCSW @@ -37,6 +40,14 @@ class CSW: public Tape, public Storage::FileHolder { private: void virtual_reset(); Pulse virtual_get_next_pulse(); + + Pulse pulse_; + enum CompressionType { + RLE, + ZRLE + } compression_type_; + uint32_t number_of_waves_; + z_stream inflation_stream_; }; } diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 7ed5920da..483f8e551 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -58,6 +58,8 @@ class Tape { /// Advances or reverses the tape to the last time before or at @c time from which a pulse starts. virtual void seek(Time &time); + virtual ~Tape() {}; + private: Time current_time_, next_time_;