From e3a718e45804255c0d75a5c3168330fd8a2378e6 Mon Sep 17 00:00:00 2001 From: Adrien Bertrand Date: Mon, 15 Jul 2024 20:21:29 +0200 Subject: [PATCH] TIVarFile: call getMinVersionFromData handler and add some tests. --- src/TIVarFile.cpp | 2 +- src/TypeHandlers/TH_Tokenized.cpp | 52 +++++++++++++++++++++++++++++-- tests.cpp | 51 ++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/TIVarFile.cpp b/src/TIVarFile.cpp index 6312603..a09bfdb 100644 --- a/src/TIVarFile.cpp +++ b/src/TIVarFile.cpp @@ -223,7 +223,7 @@ namespace tivars { entry.data_length2 = entry.data_length = (uint16_t) entry.data.size(); this->header.entries_len += sizeof(var_entry_t::data_length) + sizeof(var_entry_t::data_length2) + entry.meta_length + entry.data_length; - // todo: update entry version field + entry.version = (this->calcModel.getFlags() & TIFeatureFlags::hasFlash) ? std::get<2>(entry._type.getHandlers())(entry.data) : 0; } this->computedChecksum = this->computeChecksumFromInstanceData(); } diff --git a/src/TypeHandlers/TH_Tokenized.cpp b/src/TypeHandlers/TH_Tokenized.cpp index 7b3c433..69f795b 100644 --- a/src/TypeHandlers/TH_Tokenized.cpp +++ b/src/TypeHandlers/TH_Tokenized.cpp @@ -216,8 +216,56 @@ namespace tivars::TypeHandlers uint8_t TH_Tokenized::getMinVersionFromData(const data_t& data) { - (void)data; - return 0; + const size_t dataSize = data.size(); + if (dataSize < 2) + { + throw std::invalid_argument("Invalid data array. Needs to contain at least 2 bytes (size fields)"); + } + + bool usesRTC = false; + int maxBB = -1; + int maxEF = -1; + uint16_t offset = 2; + while (offset < dataSize) { + const uint8_t firstByte = data[offset++]; + if (is_in_vector(firstByteOfTwoByteTokens, firstByte)) { + if (offset >= dataSize) { + break; + } + uint8_t secondByte = data[offset++]; + if (firstByte == 0xBB) { + if (secondByte > maxBB) maxBB = secondByte; + } else if (firstByte == 0xEF) { + if (secondByte <= 0x10) usesRTC = true; + if (secondByte > maxEF) maxEF = secondByte; + } + } + } + uint8_t version = usesRTC ? 0x20 : 0x00; + if (maxBB > 0xF5 || maxEF > 0xA6) { + version = 0xFF; + } else if (maxEF > 0x98) { + version |= 0x0C; + } else if (maxEF > 0x75) { + version |= 0x0B; + } else if (maxEF > 0x40) { + version |= 0x0A; + } else if (maxEF > 0x3E) { + version |= 0x07; + } else if (maxEF > 0x16) { + version |= 0x06; + } else if (maxEF > 0x12) { + version |= 0x05; + } else if (maxEF > -1) { + version |= 0x04; + } else if (maxBB > 0xDA) { + version |= 0x03; + } else if (maxBB > 0xCE) { + version |= 0x02; + } else if (maxBB > 0x67) { + version |= 0x01; + } + return version; } std::string TH_Tokenized::reindentCodeString(const std::string& str_orig, const options_t& options) diff --git a/tests.cpp b/tests.cpp index ae73d33..b7b32f3 100644 --- a/tests.cpp +++ b/tests.cpp @@ -67,6 +67,57 @@ int main(int argc, char** argv) assert(trim(testPrgmStr1.getReadableContent({{"prettify", true}, {"reindent", true}})) == "\"42→Str1\nStr2\n123"); } + { + // See https://wikiti.brandonw.net/index.php?title=83Plus:OS:Variable_Versions + TIVarFile testPrgmStr1 = TIVarFile::createNew("Program", "asdf"); + const auto& ver = testPrgmStr1.getVarEntries()[0].version; + assert(ver == 0x00); + testPrgmStr1.setContentFromString("Disp 41+1"); + assert((ver & ~0x20) == 0x00); + testPrgmStr1.setContentFromString("Archive A"); + assert((ver & ~0x20) == 0x01); + testPrgmStr1.setContentFromString("GarbageCollect"); + assert((ver & ~0x20) == 0x01); + testPrgmStr1.setContentFromString("Disp 42%"); + assert((ver & ~0x20) == 0x02); + testPrgmStr1.setContentFromString("~A"); + assert((ver & ~0x20) == 0x02); + testPrgmStr1.setContentFromString("Disp \"…\""); + assert((ver & ~0x20) == 0x03); + testPrgmStr1.setContentFromString("Disp \"⌸\""); + assert((ver & ~0x20) == 0x03); + testPrgmStr1.setContentFromString("setDate(A,B,C)"); + assert((ver & ~0x20) == 0x04); + testPrgmStr1.setContentFromString("ExecLib \"A\""); + assert((ver & ~0x20) == 0x04); + testPrgmStr1.setContentFromString("Manual-Fit "); + assert((ver & ~0x20) == 0x05); + testPrgmStr1.setContentFromString("ZQuadrant1"); + assert((ver & ~0x20) == 0x06); + testPrgmStr1.setContentFromString("FRAC"); + assert((ver & ~0x20) == 0x06); + testPrgmStr1.setContentFromString("STATWIZARD ON"); + assert((ver & ~0x20) == 0x07); + testPrgmStr1.setContentFromString("STATWIZARD OFF"); + assert((ver & ~0x20) == 0x07); + testPrgmStr1.setContentFromString("BLUE"); + assert((ver & ~0x20) == 0x0A); + testPrgmStr1.setContentFromString("Dot-Thin"); + assert((ver & ~0x20) == 0x0A); + testPrgmStr1.setContentFromString("TraceStep"); + assert((ver & ~0x20) == 0x00); // 63** token ranges are not considered by a calculator when it generates the version. + testPrgmStr1.setContentFromString("Asm84CEPrgm:C9"); + assert((ver & ~0x20) == 0x0B); + testPrgmStr1.setContentFromString("Disp eval(Str1"); + assert((ver & ~0x20) == 0x0B); // 0Bh is used for all of TI-84 Plus CE OS 5.0 through 5.2, despite tokens being added between them. + testPrgmStr1.setContentFromString("Quartiles Setting…"); + assert((ver & ~0x20) == 0x0B); + testPrgmStr1.setContentFromString("Execute Program"); + assert((ver & ~0x20) == 0x0C); + testPrgmStr1.setContentFromString("piecewise("); + assert((ver & ~0x20) == 0x0C); + } + { assert(TH_Tokenized::oneTokenBytesToString(0x00) == ""); assert(TH_Tokenized::oneTokenBytesToString(0xBB) == "");