From d0c4fb0b420cbd21bb9330a475f7dce52602cf7e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 6 Sep 2025 17:46:16 -0500 Subject: [PATCH] IT import: comments, channel names and pat names the latter two are MPT extensions this may not work on songs with MIDI macro setup info --- src/engine/fileOps/it.cpp | 97 +++++++++++++++++++++++++++++++++++++++ src/engine/safeReader.cpp | 26 +++++++++++ src/engine/safeReader.h | 3 ++ 3 files changed, 126 insertions(+) diff --git a/src/engine/fileOps/it.cpp b/src/engine/fileOps/it.cpp index ba6b6d743..0975ed698 100644 --- a/src/engine/fileOps/it.cpp +++ b/src/engine/fileOps/it.cpp @@ -363,6 +363,103 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { patPtr[i]=reader.readI(); } + // skip edit history if present + if (special&2) { + logD("skipping edit history..."); + unsigned short editHistSize=reader.readS(); + if (editHistSize>0) { + if (!reader.seek(editHistSize*8,SEEK_CUR)) { + logV("what? I wasn't expecting that from you."); + } + } + } + + // read extension blocks, if any + logD("looking for extensions..."); + bool hasExtensions=true; + while (hasExtensions) { + char extType[4]; + unsigned int extSize=0; + memset(extType,0,4); + + reader.read(extType,4); + extSize=reader.readI(); + + if (memcmp(extType,"PNAM",4)==0) { + logV("found MPT extension: pattern names"); + // check whether this block is valid + if (extSize>patCount*32) { + logV("block may not be valid"); + break; + } + // read pattern names + logV("reading pattern names..."); + for (unsigned int i=0; i<(extSize>>5); i++) { + DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true); + p->name=reader.readStringLatin1(32); + } + } else if (memcmp(extType,"CNAM",4)==0) { + logV("found MPT extension: channel names"); + // check whether this block is valid + if (extSize>DIV_MAX_CHANS*20) { + logV("block may not be valid"); + break; + } + // read channel names + logV("reading channel names..."); + for (unsigned int i=0; i<(extSize>>5); i++) { + String chanName=reader.readStringLatin1(20); + for (DivSubSong* j: ds.subsong) { + j->chanName[i]=chanName; + } + } + } else if (memcmp(extType,"CHFX",4)==0) { + logV("found MPT extension: channel effects"); + // skip (stop if we cannot seek) + if (!reader.seek(extSize,SEEK_CUR)) { + break; + } + } else if ( + extType[0]=='F' && + (extType[1]=='X' || (extType[1]>='0' && extType[1]<='9')) && + (extType[2]>='0' && extType[2]<='9') && + (extType[3]>='0' && extType[3]<='9') + ) { // effect slot + logV("found MPT extension: effect slot"); + // skip (stop if we cannot seek) + if (!reader.seek(extSize,SEEK_CUR)) { + break; + } + } else { + logV("no further extensions found... %.2x%.2x%.2x%.2x",extType[0],extType[1],extType[2],extType[3]); + hasExtensions=false; + } + } + + // read song comment + logD("reading song comment..."); + if (reader.seek(commentPtr,SEEK_SET)) { + try { + String comment=reader.readStringLatin1Special(commentLen); + + ds.notes=""; + ds.notes.reserve(comment.size()); + + for (char& i: comment) { + if (i=='\r') { + ds.notes+='\n'; + } else { + ds.notes+=i; + } + } + } catch (EndOfFileException& e) { + logW("couldn't read song comment due to premature end of file."); + } + } else { + logW("couldn't seek to comment!"); + } + + // read instruments for (int i=0; i=0xa0) { + ret.push_back(0xc0|(c>>6)); + ret.push_back(0x80|(c&63)); + } + } else { + ret.push_back(c); + } } else { ret.push_back(c); } @@ -297,6 +306,15 @@ String SafeReader::readStringWithEncoding(DivStringEncoding encoding) { ret.push_back(c); } } + } else if (encoding==DIV_ENCODING_LATIN1_SPECIAL) { + if (c&0x80) { + if (c>=0xa0) { + ret.push_back(0xc0|(c>>6)); + ret.push_back(0x80|(c&63)); + } + } else { + ret.push_back(c); + } } else { ret.push_back(c); } @@ -320,6 +338,14 @@ String SafeReader::readStringLatin1(size_t stlen) { return readStringWithEncoding(DIV_ENCODING_LATIN1,stlen); } +String SafeReader::readStringLatin1Special() { + return readStringWithEncoding(DIV_ENCODING_LATIN1_SPECIAL); +} + +String SafeReader::readStringLatin1Special(size_t stlen) { + return readStringWithEncoding(DIV_ENCODING_LATIN1_SPECIAL,stlen); +} + String SafeReader::readStringLine() { String ret; unsigned char c; diff --git a/src/engine/safeReader.h b/src/engine/safeReader.h index 04385c3b6..a3b0579d8 100644 --- a/src/engine/safeReader.h +++ b/src/engine/safeReader.h @@ -33,6 +33,7 @@ enum DivStringEncoding { DIV_ENCODING_NONE=0, DIV_ENCODING_UTF8, DIV_ENCODING_LATIN1, + DIV_ENCODING_LATIN1_SPECIAL, DIV_ENCODING_SHIFT_JIS }; @@ -77,6 +78,8 @@ class SafeReader { String readString(size_t len); String readStringLatin1(); String readStringLatin1(size_t len); + String readStringLatin1Special(); + String readStringLatin1Special(size_t len); String readStringLine(); String readStringToken(unsigned char delim, bool stripContiguous); String readStringToken();