// // ZX8081.cpp // Clock Signal // // Created by Thomas Harte on 08/06/2017. // Copyright © 2017 Thomas Harte. All rights reserved. // #include "ZX8081.hpp" using namespace Storage::Data::ZX8081; static uint16_t short_at(size_t address, const std::vector &data) { return (uint16_t)(data[address] | (data[address + 1] << 8)); } static std::shared_ptr ZX80FileFromData(const std::vector &data) { // Does this look like a ZX80 file? if(data.size() < 0x28) return nullptr; // uint16_t next_line_number = short_at(0x2, data); // uint16_t first_visible_line = short_at(0x13, data); uint16_t vars = short_at(0x8, data); uint16_t end_of_file = short_at(0xa, data); uint16_t display_address = short_at(0xc, data); // check that the end of file is contained within the supplied data if(end_of_file - 0x4000 > data.size()) return nullptr; // check for the proper ordering of buffers if(vars > end_of_file) return nullptr; if(end_of_file > display_address) return nullptr; // TODO: does it make sense to inspect the tokenised BASIC? // It starts at 0x4028 and proceeds as [16-bit line number] [tokens] [0x76], // but I'm as yet unable to find documentation of the tokens. // TODO: check that the line numbers declared above exist (?) std::shared_ptr file(new File); file->data = data; file->isZX81 = false; return file; } static std::shared_ptr ZX81FileFromData(const std::vector &data) { // Does this look like a ZX81 file? // Look for a file name. size_t data_pointer = 0; int c = 11; while(c--) { if(data[data_pointer] & 0x80) break; data_pointer++; } if(!c) return nullptr; data_pointer++; if(data.size() < data_pointer + 0x405e - 0x4009) return nullptr; // if(data[data_pointer]) return nullptr; uint16_t vars = short_at(data_pointer + 0x4010 - 0x4009, data); uint16_t end_of_file = short_at(data_pointer + 0x4014 - 0x4009, data); // uint16_t display_address = short_at(0x400c - 0x4009, data); // check that the end of file is contained within the supplied data if(data_pointer + end_of_file - 0x4009 > data.size()) return nullptr; // check for the proper ordering of buffers if(vars > end_of_file) return nullptr; // if(end_of_file > display_address) return nullptr; // TODO: does it make sense to inspect the tokenised BASIC? // It starts at 0x4028 and proceeds as [16-bit line number] [tokens] [0x76], // but I'm as yet unable to find documentation of the tokens. // TODO: check that the line numbers declared above exist (?) std::shared_ptr file(new File); file->data = data; file->isZX81 = true; return file; } std::shared_ptr Storage::Data::ZX8081::FileFromData(const std::vector &data) { std::shared_ptr result = ZX81FileFromData(data); if(result) return result; return ZX80FileFromData(data); } #pragma mark - String conversion std::wstring Storage::Data::ZX8081::StringFromData(const std::vector &data, bool is_zx81) { std::wstring string; wchar_t zx80_map[64] = { ' ', u'\u2598', u'\u259d', u'\u2580', u'\u2596', u'\u258c', u'\u259e', u'\u259b', u'\u2588', u'\u2584', u'\u2580', '"', u'£', '$', ':', '?', '(', ')', '>', '<', '=', '+', '-', '*', '/', ';', ',', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; // TODO: the block character conversions shown here are in the wrong order wchar_t zx81_map[64] = { ' ', u'\u2598', u'\u259d', u'\u2580', u'\u2596', u'\u258c', u'\u259e', u'\u259b', u'\u2588', u'\u2584', u'\u2580', '"', u'£', '$', ':', '?', '(', ')', '-', '+', '*', '/', '=', '>', '<', ';', ',', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; wchar_t *map = is_zx81 ? zx81_map : zx80_map; for(uint8_t byte : data) { string.push_back(map[byte & 0x3f]); } return string; } std::vector DataFromString(const std::wstring &string, bool is_zx81) { std::vector data; // TODO return data; }