Added a simple library for reading and writing LDBS files.

This commit is contained in:
David Given
2019-08-09 22:41:07 +02:00
parent 2f72c3f8f0
commit f9117b8d11
6 changed files with 217 additions and 10 deletions

View File

@@ -2,6 +2,7 @@
#include "bytes.h"
#include "fmt/format.h"
#include "common/crunch.h"
#include <fstream>
#include <zlib.h>
static std::shared_ptr<std::vector<uint8_t>> createVector(unsigned size)
@@ -280,6 +281,16 @@ Bytes Bytes::uncrunch() const
return output;
}
void Bytes::writeToFile(const std::string& filename) const
{
std::ofstream f(filename, std::ios::out | std::ios::binary);
if (!f.is_open())
Error() << fmt::format("cannot open output file '{}'", filename);
f.write((const char*) cbegin(), size());
f.close();
}
ByteReader Bytes::reader() const
{
return ByteReader(*this);

View File

@@ -56,6 +56,8 @@ public:
ByteReader reader() const;
ByteWriter writer();
void writeToFile(const std::string& filename) const;
private:
std::shared_ptr<std::vector<uint8_t>> _data;
unsigned _low;

81
lib/ldbs.cc Normal file
View File

@@ -0,0 +1,81 @@
#include "globals.h"
#include <string.h>
#include "bytes.h"
#include "ldbs.h"
#include "fmt/format.h"
LDBS::LDBS()
{}
uint32_t LDBS::put(const Bytes& data, uint32_t type)
{
uint32_t address = top;
Block& block = blocks[address];
block.type = type;
block.data = data;
top += data.size() + 20;
return address;
}
uint32_t LDBS::read(const Bytes& data)
{
ByteReader br(data);
br.seek(0);
if ((br.read_be32() != LDBS_FILE_MAGIC)
|| (br.read_be32() != LDBS_FILE_TYPE))
Error() << "not a valid LDBS file";
uint32_t address = br.read_le32();
br.skip(4);
uint32_t trackDirectory = br.read_le32();
while (address)
{
br.seek(address);
if (br.read_be32() != LDBS_BLOCK_MAGIC)
Error() << fmt::format("invalid block at address 0x{:x}", address);
Block& block = blocks[address];
block.type = br.read_be32();
uint32_t size = br.read_le32();
br.skip(4);
address = br.read_le32();
block.data.writer().append(br.read(size));
}
top = data.size();
return trackDirectory;
}
const Bytes LDBS::write(uint32_t trackDirectory)
{
Bytes data(top);
ByteWriter bw(data);
uint32_t previous = 0;
for (const auto& e : blocks)
{
bw.seek(e.first);
bw.write_be32(LDBS_BLOCK_MAGIC);
bw.write_be32(e.second.type);
bw.write_le32(e.second.data.size());
bw.write_le32(e.second.data.size());
bw.write_le32(previous);
bw.append(e.second.data);
previous = e.first;
}
bw.seek(0);
bw.write_be32(LDBS_FILE_MAGIC);
bw.write_be32(LDBS_FILE_TYPE);
bw.write_le32(previous);
bw.write_le32(0);
bw.write_le32(trackDirectory);
return data;
}

41
lib/ldbs.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef LDBS_H
#define LDBS_H
class Bytes;
/* A very simple interface to John Elliott's LDBS image format:
* http://www.seasip.info/Unix/LibDsk/ldbs.html
*/
#define LDBS_FILE_MAGIC 0x4C425301 /* "LBS\01" */
#define LDBS_FILE_TYPE 0x44534B02 /* "DSK\02" */
#define LDBS_BLOCK_MAGIC 0x4C444201 /* "LDB\01" */
#define LDBS_TRACK_BLOCK 0x44495201 /* "DIR\01" */
class LDBS
{
public:
LDBS();
public:
const Bytes& get(uint32_t address) const
{ return blocks.at(address).data; }
uint32_t put(const Bytes& data, uint32_t type);
public:
const Bytes write(uint32_t trackDirectory);
uint32_t read(const Bytes& bytes);
private:
struct Block
{
uint32_t type;
Bytes data;
};
std::map<uint32_t, Block> blocks;
unsigned top = 20;
};
#endif

View File

@@ -137,6 +137,10 @@ buildlibrary libfmt.a \
dep/fmt/posix.cc \
buildlibrary libbackend.a \
lib/imagereader/imagereader.cc \
lib/imagereader/imgimagereader.cc \
lib/imagewriter/imagewriter.cc \
lib/imagewriter/imgimagewriter.cc \
arch/aeslanier/decoder.cc \
arch/amiga/decoder.cc \
arch/apple2/decoder.cc \
@@ -168,13 +172,10 @@ buildlibrary libbackend.a \
lib/fluxsource/kryoflux.cc \
lib/fluxsource/sqlitefluxsource.cc \
lib/fluxsource/streamfluxsource.cc \
lib/imagereader/imagereader.cc \
lib/imagereader/imgimagereader.cc \
lib/imagewriter/imagewriter.cc \
lib/imagewriter/imgimagewriter.cc \
lib/globals.cc \
lib/hexdump.cc \
lib/image.cc \
lib/ldbs.cc \
lib/reader.cc \
lib/sector.cc \
lib/sectorset.cc \
@@ -227,12 +228,13 @@ buildsimpleprogram brother120tool \
libemu.a \
libfmt.a \
runtest bitaccumulator-test tests/bitaccumulator.cc
runtest bytes-test tests/bytes.cc
runtest compression-test tests/compression.cc
runtest crunch-test tests/crunch.cc
runtest dataspec-test tests/dataspec.cc
runtest flags-test tests/flags.cc
runtest fmmfm-test tests/fmmfm.cc
runtest bitaccumulator-test tests/bitaccumulator.cc
runtest kryoflux-test tests/kryoflux.cc
runtest compression-test tests/compression.cc
runtest bytes-test tests/bytes.cc
runtest crunch-test tests/crunch.cc
runtest fluxpattern-test tests/fluxpattern.cc
runtest fmmfm-test tests/fmmfm.cc
runtest kryoflux-test tests/kryoflux.cc
runtest ldbs-test tests/ldbs.cc

70
tests/ldbs.cc Normal file
View File

@@ -0,0 +1,70 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "globals.h"
#include "bytes.h"
#include "ldbs.h"
static Bytes testdata
{
'L', 'B', 'S', 0x01, 'D', 'S', 'K', 0x02,
0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x34, 0x12, 0x00, 0x00, 'L', 'D', 'B', 0x01,
0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 'L', 'D', 'B', 0x01, 0x00, 0x00, 0x00,
0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x14, 0x00, 0x00, 0x00, 0x02
};
static void assertBytes(const Bytes& want, const Bytes& got)
{
if (want != got)
{
std::cout << "Wanted bytes:" << std::endl;
hexdump(std::cout, want);
std::cout << std::endl << "Produced bytes:" << std::endl;
hexdump(std::cout, got);
abort();
}
}
static void test_getset()
{
LDBS ldbs;
uint32_t block1 = ldbs.put(Bytes { 1 }, 1);
uint32_t block2 = ldbs.put(Bytes { 2 }, 2);
assert(block1 != block2);
assert(ldbs.get(block1) == Bytes { 1 });
assert(ldbs.get(block2) == Bytes { 2 });
}
static void test_write()
{
LDBS ldbs;
uint32_t block1 = ldbs.put(Bytes { 1 }, 1);
uint32_t block2 = ldbs.put(Bytes { 2 }, 2);
Bytes data = ldbs.write(0x1234);
assertBytes(testdata, data);
}
static void test_read()
{
LDBS ldbs;
uint32_t trackDirectory = ldbs.read(testdata);
assert(trackDirectory == 0x1234);
assert(ldbs.get(0x14) == Bytes { 1 });
assert(ldbs.get(0x29) == Bytes { 2 });
}
int main(int argc, const char* argv[])
{
test_getset();
test_write();
test_read();
return 0;
}