diff --git a/Source/ConfigVersion.cpp b/Source/ConfigVersion.cpp index b9b731e4..5d37b620 100644 --- a/Source/ConfigVersion.cpp +++ b/Source/ConfigVersion.cpp @@ -24,6 +24,7 @@ #include "FamiTrackerEnv.h" #include "FamiTrackerTypes.h" #include "Settings.h" +#include "ModuleException.h" namespace { diff --git a/Source/DocumentFile.cpp b/Source/DocumentFile.cpp index 0c949554..a3555425 100644 --- a/Source/DocumentFile.cpp +++ b/Source/DocumentFile.cpp @@ -219,13 +219,13 @@ void CDocumentFile::ValidateFile() // // // Older file version if (GetFileVersion() < COMPATIBLE_VER) - throw CModuleException::WithMessage("FamiTracker module version too old (0x%X), expected 0x%X or above", - GetFileVersion(), COMPATIBLE_VER); + throw CModuleException::WithMessage("FamiTracker module version too old (0x" + conv::from_int_hex(GetFileVersion()) + + "), expected 0x" + conv::from_int_hex(COMPATIBLE_VER) + " or above"); // // // File version is too new - if (GetFileVersion() > 0x450U /*FILE_VER*/) // // // 050B - throw CModuleException::WithMessage("FamiTracker module version too new (0x%X), expected 0x%X or below", - GetFileVersion(), FILE_VER); + if (GetFileVersion() > 0x450u /*FILE_VER*/) // // // 050B + throw CModuleException::WithMessage("FamiTracker module version too new (0x" + conv::from_int_hex(GetFileVersion()) + + "), expected 0x" + conv::from_int_hex(0x450u) + " or below"); m_bFileDone = false; m_bIncomplete = false; diff --git a/Source/FamiTrackerDoc.cpp b/Source/FamiTrackerDoc.cpp index bb2dee3b..fefda83c 100644 --- a/Source/FamiTrackerDoc.cpp +++ b/Source/FamiTrackerDoc.cpp @@ -26,6 +26,7 @@ #include "FamiTracker.h" #include "FamiTrackerViewMessage.h" // // // #include "ModuleException.h" // // // +#include "Settings.h" // // // #include "DocumentFile.h" #include "SoundGen.h" #include "MainFrm.h" // // // @@ -332,7 +333,7 @@ BOOL CFamiTrackerDoc::SaveDocument(LPCWSTR lpszPathName) const return FALSE; } - if (!CFamiTrackerDocIO {DocumentFile, (module_error_level_t)Env.GetSettings()->Version.iErrorLevel}.Save(*GetModule())) { // // // + if (!CFamiTrackerDocIO {DocumentFile, (module_error_level_t)theApp.GetSettings()->Version.iErrorLevel}.Save(*GetModule())) { // // // // The save process failed, delete temp file DocumentFile.Close(); DeleteFileW(TempFile); @@ -434,7 +435,7 @@ BOOL CFamiTrackerDoc::OpenDocument(LPCWSTR lpszPathName) m_bForceBackup = true; } else { - if (!CFamiTrackerDocIO {OpenFile, (module_error_level_t)Env.GetSettings()->Version.iErrorLevel}.Load(*GetModule())) { + if (!CFamiTrackerDocIO {OpenFile, (module_error_level_t)theApp.GetSettings()->Version.iErrorLevel}.Load(*GetModule())) { CStringA msg; msg.LoadStringW(IDS_FILE_LOAD_ERROR); OpenFile.RaiseModuleException((LPCSTR)msg); diff --git a/Source/FamiTrackerDocIO.cpp b/Source/FamiTrackerDocIO.cpp index d65a6d69..debead99 100644 --- a/Source/FamiTrackerDocIO.cpp +++ b/Source/FamiTrackerDocIO.cpp @@ -29,6 +29,7 @@ #include "SoundChipSet.h" #include "ChannelOrder.h" #include "str_conv/str_conv.hpp" +#include "NumConv.h" #include "FamiTrackerEnv.h" #include "SoundGen.h" @@ -395,7 +396,7 @@ void CFamiTrackerDocIO::LoadHeader(CFamiTrackerModule &modfile, int ver) { file_.GetBlockChar(), 0, MAX_EFFECT_COLUMNS - 1, "Effect column count") + 1); } catch (CModuleException e) { - e.AppendError("At channel %d", value_cast(i) + 1); + e.AppendError("At channel + " + conv::from_int(value_cast(i) + 1)); throw e; } }); @@ -419,13 +420,13 @@ void CFamiTrackerDocIO::LoadHeader(CFamiTrackerModule &modfile, int ver) { file_.GetBlockChar(), 0, MAX_EFFECT_COLUMNS - 1, "Effect column count") + 1); } catch (CModuleException e) { - e.AppendError("At song %d,", index + 1); + e.AppendError("At song " + conv::from_int(index + 1) + ','); throw e; } }); } catch (CModuleException e) { - e.AppendError("At channel %d,", value_cast(i) + 1); + e.AppendError("At channel " + conv::from_int(value_cast(i) + 1) + ','); throw e; } }); @@ -487,18 +488,17 @@ void CFamiTrackerDocIO::LoadInstruments(CFamiTrackerModule &modfile, int ver) { try { // Load the instrument AssertFileData(pInstrument.get() != nullptr, "Failed to create instrument"); - Env.GetInstrumentService()->GetInstrumentIO(Type).ReadFromModule(*pInstrument, file_); // // // + Env.GetInstrumentService()->GetInstrumentIO(Type, err_lv_)->ReadFromModule(*pInstrument, file_); // // // // Read name int size = AssertRange(file_.GetBlockInt(), 0, CInstrument::INST_NAME_MAX, "Instrument name length"); - char Name[CInstrument::INST_NAME_MAX + 1]; + char Name[CInstrument::INST_NAME_MAX + 1] = { }; file_.GetBlock(Name, size); - Name[size] = 0; pInstrument->SetName(Name); Manager.InsertInstrument(index, std::move(pInstrument)); // // // this registers the instrument content provider } catch (CModuleException e) { file_.SetDefaultFooter(e); - e.AppendError("At instrument %02X,", index); + e.AppendError("At instrument " + conv::from_int_hex(index, 2) + ','); Manager.RemoveInstrument(index); throw e; } @@ -531,20 +531,10 @@ void CFamiTrackerDocIO::SaveInstruments(const CFamiTrackerModule &modfile, int v return; // // // file_.WriteBlockInt(Count); - for (int i = 0; i < MAX_INSTRUMENTS; ++i) { - // Only write instrument if it's used - if (auto pInst = Manager.GetInstrument(i)) { - // Write index and type - file_.WriteBlockInt(i); - file_.WriteBlockChar(static_cast(pInst->GetType())); - - // Store the instrument - Env.GetInstrumentService()->GetInstrumentIO(pInst->GetType()).WriteToModule(*pInst, file_); // // // - - // Store the name - file_.WriteStringCounted(pInst->GetName()); // // // - } - } + // Only write instrument if it's used + for (int i = 0; i < MAX_INSTRUMENTS; ++i) + if (auto pInst = Manager.GetInstrument(i)) + Env.GetInstrumentService()->GetInstrumentIO(pInst->GetType(), err_lv_)->WriteToModule(*pInst, file_, i); // // // } void CFamiTrackerDocIO::LoadSequences(CFamiTrackerModule &modfile, int ver) { @@ -616,7 +606,7 @@ void CFamiTrackerDocIO::LoadSequences(CFamiTrackerModule &modfile, int ver) { pManager->GetCollection(Type)->SetSequence(Index, std::move(pSeq)); } catch (CModuleException e) { - e.AppendError("At 2A03 %s sequence %d,", CInstrument2A03::SEQUENCE_NAME[value_cast(Type)], Index); + e.AppendError("At 2A03 " + std::string {CInstrument2A03::SEQUENCE_NAME[value_cast(Type)]} + " sequence " + conv::from_int(Index) + ','); throw e; } } @@ -637,7 +627,7 @@ void CFamiTrackerDocIO::LoadSequences(CFamiTrackerModule &modfile, int ver) { } } catch (CModuleException e) { - e.AppendError("At 2A03 %s sequence %d,", CInstrument2A03::SEQUENCE_NAME[value_cast(j)], i); + e.AppendError("At 2A03 " + std::string {CInstrument2A03::SEQUENCE_NAME[value_cast(j)]} +" sequence " + conv::from_int(i) + ','); throw e; } }); @@ -652,7 +642,7 @@ void CFamiTrackerDocIO::LoadSequences(CFamiTrackerModule &modfile, int ver) { pSeq->SetSetting(static_cast(file_.GetBlockInt())); // // // } catch (CModuleException e) { - e.AppendError("At 2A03 %s sequence %d,", CInstrument2A03::SEQUENCE_NAME[value_cast(Types[i])], Indices[i]); + e.AppendError("At 2A03 " + std::string {CInstrument2A03::SEQUENCE_NAME[value_cast(Types[i])]} + " sequence " + conv::from_int(Indices[i]) + ','); throw e; } } @@ -816,7 +806,7 @@ void CFamiTrackerDocIO::LoadPatterns(CFamiTrackerModule &modfile, int ver) { file_.GetBlockChar(); // unused blank parameter } catch (CModuleException e) { - e.AppendError("At effect column fx%d,", n + 1); + e.AppendError("At effect column fx" + conv::from_int(n + 1) + ','); throw e; } @@ -908,12 +898,12 @@ void CFamiTrackerDocIO::LoadPatterns(CFamiTrackerModule &modfile, int ver) { pSong->SetPatternData(order.TranslateChannel(Channel), Pattern, Row, Note); // // // } catch (CModuleException e) { - e.AppendError("At row %02X,", Row); + e.AppendError("At row " + conv::from_int_hex(Row, 2) + ','); throw e; } } catch (CModuleException e) { - e.AppendError("At pattern %02X, channel %d, track %d,", Pattern, Channel, Track + 1); + e.AppendError("At pattern " + conv::from_int_hex(Pattern, 2) + ", channel " + conv::from_int(Channel) + ", track " + conv::from_int(Track + 1) + ','); throw e; } } @@ -987,7 +977,7 @@ void CFamiTrackerDocIO::LoadDSamples(CFamiTrackerModule &modfile, int ver) { manager.SetDSample(Index, std::make_unique(samples, Name)); // // // } catch (CModuleException e) { - e.AppendError("At DPCM sample %d,", Index); + e.AppendError("At DPCM sample " + conv::from_int(Index) + ','); throw e; } } @@ -1057,7 +1047,7 @@ void CFamiTrackerDocIO::LoadSequencesVRC6(CFamiTrackerModule &modfile, int ver) } } catch (CModuleException e) { - e.AppendError("At VRC6 %s sequence %d,", CInstrumentVRC6::SEQUENCE_NAME[value_cast(Type)], Index); + e.AppendError("At VRC6 " + std::string {CInstrumentVRC6::SEQUENCE_NAME[value_cast(Type)]} + " sequence " + conv::from_int(Index) + ','); throw e; } } @@ -1078,7 +1068,7 @@ void CFamiTrackerDocIO::LoadSequencesVRC6(CFamiTrackerModule &modfile, int ver) } } catch (CModuleException e) { - e.AppendError("At VRC6 %s sequence %d,", CInstrumentVRC6::SEQUENCE_NAME[value_cast(j)], i); + e.AppendError("At VRC6 " + std::string {CInstrumentVRC6::SEQUENCE_NAME[value_cast(j)]} + " sequence " + conv::from_int(i) + ','); throw e; } }); @@ -1092,7 +1082,7 @@ void CFamiTrackerDocIO::LoadSequencesVRC6(CFamiTrackerModule &modfile, int ver) pSeq->SetSetting(static_cast(file_.GetBlockInt())); // // // } catch (CModuleException e) { - e.AppendError("At VRC6 %s sequence %d,", CInstrumentVRC6::SEQUENCE_NAME[value_cast(Types[i])], Indices[i]); + e.AppendError("At VRC6 " + std::string {CInstrumentVRC6::SEQUENCE_NAME[value_cast(Types[i])]} + " sequence " + conv::from_int(Indices[i]) + ','); throw e; } } @@ -1151,7 +1141,7 @@ void CFamiTrackerDocIO::LoadSequencesN163(CFamiTrackerModule &modfile, int ver) } } catch (CModuleException e) { - e.AppendError("At N163 %s sequence %d,", CInstrumentN163::SEQUENCE_NAME[Type], Index); + e.AppendError("At N163 " + std::string {CInstrumentN163::SEQUENCE_NAME[Type]} + " sequence " + conv::from_int(Index) + ','); throw e; } } @@ -1209,7 +1199,7 @@ void CFamiTrackerDocIO::LoadSequencesS5B(CFamiTrackerModule &modfile, int ver) { } } catch (CModuleException e) { - e.AppendError("At 5B %s sequence %d,", CInstrumentS5B::SEQUENCE_NAME[Type], Index); + e.AppendError("At 5B " + std::string {CInstrumentS5B::SEQUENCE_NAME[Type]} + " sequence " + conv::from_int(Index) + ','); throw e; } } @@ -1271,7 +1261,7 @@ void CFamiTrackerDocIO::LoadDetuneTables(CFamiTrackerModule &modfile, int ver) { } } catch (CModuleException e) { - e.AppendError("At %s detune table,", conv::to_utf8(CDetuneDlg::CHIP_STR[Chip]).data()); + e.AppendError("At " + conv::to_utf8(CDetuneDlg::CHIP_STR[Chip]) + " detune table,"); throw e; } } @@ -1318,13 +1308,13 @@ void CFamiTrackerDocIO::LoadGrooves(CFamiTrackerModule &modfile, int ver) { static_cast(file_.GetBlockChar()), 1U, 0xFFU, "Groove item")); } catch (CModuleException e) { - e.AppendError("At position %i,", j); + e.AppendError("At position " + conv::from_int(j) + ','); throw e; } modfile.SetGroove(Index, std::move(pGroove)); } catch (CModuleException e) { - e.AppendError("At groove %i,", Index); + e.AppendError("At groove " + conv::from_int(Index) + ','); throw e; } } @@ -1343,7 +1333,7 @@ void CFamiTrackerDocIO::LoadGrooves(CFamiTrackerModule &modfile, int ver) { AssertRange(Speed, 1, MAX_TEMPO, "Track default speed"); } catch (CModuleException e) { - e.AppendError("At track %d,", i + 1); + e.AppendError("At track " + conv::from_int(i + 1) + ','); throw e; } } @@ -1424,7 +1414,7 @@ template T CFamiTrackerDocIO::AssertRange(T Value, U Min, V Max, const std::string &Desc) const { if (l <= err_lv_ && !(Value >= Min && Value <= Max)) { std::string msg = Desc + " out of range: expected [" - + std::to_string(Min) + "," + + std::to_string(Min) + ',' + std::to_string(Max) + "], got " + std::to_string(Value); auto e = CModuleException::WithMessage(msg); diff --git a/Source/FamiTrackerDocIO.h b/Source/FamiTrackerDocIO.h index 8d03b2d1..9c80d4e2 100644 --- a/Source/FamiTrackerDocIO.h +++ b/Source/FamiTrackerDocIO.h @@ -31,8 +31,6 @@ class CFamiTrackerModule; class CDocumentFile; -enum module_error_level_t : int; // Settings.h - class CFamiTrackerDocIO { public: CFamiTrackerDocIO(CDocumentFile &file, module_error_level_t err_lv); diff --git a/Source/InstrumentIO.cpp b/Source/InstrumentIO.cpp index eaa9ed5c..220e1374 100644 --- a/Source/InstrumentIO.cpp +++ b/Source/InstrumentIO.cpp @@ -26,6 +26,8 @@ #include "InstrumentFDS.h" #include "InstrumentN163.h" +#include "NumConv.h" + #include "InstrumentManagerInterface.h" #include "Sequence.h" #include "OldSequence.h" @@ -33,7 +35,6 @@ #include "DocumentFile.h" #include "SimpleFile.h" -#include "ModuleException.h" @@ -45,6 +46,21 @@ const std::string_view FTI_INST_VERSION = "2.4"; } // namespace +CInstrumentIO::CInstrumentIO(module_error_level_t err_lv) : err_lv_(err_lv) { +} + +void CInstrumentIO::WriteToModule(const CInstrument &inst, CDocumentFile &file, unsigned inst_index) const { + // Write index and type + file.WriteBlockInt(inst_index); + file.WriteBlockChar(static_cast(inst.GetType())); + + // Store the instrument + DoWriteToModule(inst, file); + + // Store the name + file.WriteStringCounted(inst.GetName()); // // // +} + void CInstrumentIO::WriteToFTI(const CInstrument &inst, CSimpleFile &file) const { // Write header file.WriteBytes(FTI_INST_HEADER); @@ -65,9 +81,21 @@ void CInstrumentIO::ReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ve DoReadFromFTI(inst, file, fti_ver); } +template +T CInstrumentIO::AssertRange(T Value, U Min, V Max, const std::string &Desc) const { + if (l <= err_lv_ && !(Value >= Min && Value <= Max)) { + std::string msg = Desc + " out of range: expected [" + + std::to_string(Min) + ',' + + std::to_string(Max) + "], got " + + std::to_string(Value); + throw CModuleException::WithMessage(msg); + } + return Value; +} + -void CInstrumentIONull::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentIONull::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { } void CInstrumentIONull::ReadFromModule(CInstrument &inst_, CDocumentFile &file) const { @@ -81,7 +109,7 @@ void CInstrumentIONull::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int -void CInstrumentIOSeq::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentIOSeq::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); int seqCount = inst.GetSeqCount(); @@ -96,13 +124,13 @@ void CInstrumentIOSeq::WriteToModule(const CInstrument &inst_, CDocumentFile &fi void CInstrumentIOSeq::ReadFromModule(CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); - CModuleException::AssertRangeFmt(file.GetBlockInt(), 0, (int)SEQ_COUNT, "Instrument sequence count"); // unused right now + AssertRange(file.GetBlockInt(), 0, (int)SEQ_COUNT, "Instrument sequence count"); // unused right now foreachSeq([&] (sequence_t i) { - inst.SetSeqEnable(i, 0 != CModuleException::AssertRangeFmt( + inst.SetSeqEnable(i, 0 != AssertRange( file.GetBlockChar(), 0, 1, "Instrument sequence enable flag")); int Index = static_cast(file.GetBlockChar()); - inst.SetSeqIndex(i, CModuleException::AssertRangeFmt(Index, 0, MAX_SEQUENCES - 1, "Instrument sequence index")); + inst.SetSeqIndex(i, AssertRange(Index, 0, MAX_SEQUENCES - 1, "Instrument sequence index")); }); } @@ -136,7 +164,7 @@ void CInstrumentIOSeq::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int // Sequences std::shared_ptr pSeq; - CModuleException::AssertRangeFmt(file.ReadInt8(), 0, (int)SEQ_COUNT, "Sequence count"); // unused right now + AssertRange(file.ReadInt8(), 0, (int)SEQ_COUNT, "Sequence count"); // unused right now // Loop through all instrument effects foreachSeq([&] (sequence_t i) { @@ -149,7 +177,7 @@ void CInstrumentIOSeq::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int inst.SetSeqEnable(i, true); // Read the sequence - int Count = CModuleException::AssertRangeFmt(file.ReadInt32(), 0, 0xFF, "Sequence item count"); + int Count = AssertRange(file.ReadInt32(), 0, 0xFF, "Sequence item count"); if (fti_ver < 20) { COldSequence OldSeq; @@ -163,10 +191,10 @@ void CInstrumentIOSeq::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int pSeq = std::make_shared(i); int Count2 = Count > MAX_SEQUENCE_ITEMS ? MAX_SEQUENCE_ITEMS : Count; pSeq->SetItemCount(Count2); - pSeq->SetLoopPoint(CModuleException::AssertRangeFmt( + pSeq->SetLoopPoint(AssertRange( static_cast(file.ReadInt32()), -1, Count2 - 1, "Sequence loop point")); if (fti_ver > 20) { - pSeq->SetReleasePoint(CModuleException::AssertRangeFmt( + pSeq->SetReleasePoint(AssertRange( static_cast(file.ReadInt32()), -1, Count2 - 1, "Sequence release point")); if (fti_ver >= 22) pSeq->SetSetting(static_cast(file.ReadInt32())); @@ -182,7 +210,7 @@ void CInstrumentIOSeq::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int inst.GetInstrumentManager()->SetSequence(inst.GetType(), i, inst.GetSeqIndex(i), pSeq); } catch (CModuleException e) { - e.AppendError("At %s sequence,", inst.GetSequenceName(value_cast(i))); + e.AppendError("At " + std::string {inst.GetSequenceName(value_cast(i))} + " sequence,"); throw e; } }); @@ -190,9 +218,9 @@ void CInstrumentIOSeq::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int -void CInstrumentIO2A03::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentIO2A03::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); - CInstrumentIOSeq::WriteToModule(inst_, file); + CInstrumentIOSeq::DoWriteToModule(inst_, file); int Version = 6; int Octaves = Version >= 2 ? OCTAVE_RANGE : 6; @@ -221,13 +249,13 @@ void CInstrumentIO2A03::ReadFromModule(CInstrument &inst_, CDocumentFile &file) const auto ReadAssignment = [&] (int MidiNote) { try { - int Index = CModuleException::AssertRangeFmt( + int Index = AssertRange( file.GetBlockChar(), 0, MAX_DSAMPLES, "DPCM sample assignment index"); if (Index > MAX_DSAMPLES) Index = 0; inst.SetSampleIndex(MidiNote, Index - 1); char Pitch = file.GetBlockChar(); - CModuleException::AssertRangeFmt(Pitch & 0x7F, 0, 0xF, "DPCM sample pitch"); + AssertRange(Pitch & 0x7F, 0, 0xF, "DPCM sample pitch"); inst.SetSamplePitch(MidiNote, Pitch & 0x8F); if (Version > 5) { char Value = file.GetBlockChar(); @@ -237,16 +265,18 @@ void CInstrumentIO2A03::ReadFromModule(CInstrument &inst_, CDocumentFile &file) } } catch (CModuleException e) { - e.AppendError("At note %i, octave %i,", value_cast(GET_NOTE(MidiNote)), GET_OCTAVE(MidiNote)); + auto n = value_cast(GET_NOTE(MidiNote)); + auto o = GET_OCTAVE(MidiNote); + e.AppendError("At note " + conv::from_int(n) + ", octave " + conv::from_int(o) + ','); throw e; } }; if (Version >= 7) { // // // 050B - const int Count = CModuleException::AssertRangeFmt( + const int Count = AssertRange( file.GetBlockInt(), 0, NOTE_COUNT, "DPCM sample assignment count"); for (int i = 0; i < Count; ++i) { - int Note = CModuleException::AssertRangeFmt( + int Note = AssertRange( file.GetBlockChar(), 0, NOTE_COUNT - 1, "DPCM sample assignment note index"); ReadAssignment(Note); } @@ -311,24 +341,26 @@ void CInstrumentIO2A03::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int char SampleNames[MAX_DSAMPLES][ft0cc::doc::dpcm_sample::max_name_length + 1]; unsigned int Count = file.ReadInt32(); - CModuleException::AssertRangeFmt(Count, 0U, static_cast(NOTE_COUNT), "DPCM assignment count"); + AssertRange(Count, 0U, static_cast(NOTE_COUNT), "DPCM assignment count"); // DPCM instruments for (unsigned int i = 0; i < Count; ++i) { unsigned char InstNote = file.ReadInt8(); try { - unsigned char Sample = CModuleException::AssertRangeFmt(file.ReadInt8(), 0, 0x7F, "DPCM sample assignment index"); + unsigned char Sample = AssertRange(file.ReadInt8(), 0, 0x7F, "DPCM sample assignment index"); if (Sample > MAX_DSAMPLES) Sample = 0; unsigned char Pitch = file.ReadInt8(); - CModuleException::AssertRangeFmt(Pitch & 0x7FU, 0U, 0xFU, "DPCM sample pitch"); + AssertRange(Pitch & 0x7FU, 0U, 0xFU, "DPCM sample pitch"); inst.SetSamplePitch(InstNote, Pitch); inst.SetSampleIndex(InstNote, Sample - 1); - inst.SetSampleDeltaValue(InstNote, CModuleException::AssertRangeFmt( + inst.SetSampleDeltaValue(InstNote, AssertRange( static_cast(fti_ver >= 24 ? file.ReadInt8() : -1), -1, 0x7F, "DPCM sample delta value")); } catch (CModuleException e) { - e.AppendError("At note %i, octave %i,", value_cast(GET_NOTE(InstNote)), GET_OCTAVE(InstNote)); + auto n = value_cast(GET_NOTE(InstNote)); + auto o = GET_OCTAVE(InstNote); + e.AppendError("At note " + conv::from_int(n) + ", octave " + conv::from_int(o) + ','); throw e; } } @@ -342,9 +374,9 @@ void CInstrumentIO2A03::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int unsigned int SampleCount = file.ReadInt32(); for (unsigned int i = 0; i < SampleCount; ++i) { - int Index = CModuleException::AssertRangeFmt( + int Index = AssertRange( file.ReadInt32(), 0, MAX_DSAMPLES - 1, "DPCM sample index"); - int Len = CModuleException::AssertRangeFmt( + int Len = AssertRange( file.ReadInt32(), 0, (int)ft0cc::doc::dpcm_sample::max_name_length, "DPCM sample name length"); file.ReadBytes(SampleNames[Index], Len); SampleNames[Index][Len] = '\0'; @@ -373,7 +405,7 @@ void CInstrumentIO2A03::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int // Load sample if (TotalSize + Size > MAX_SAMPLE_SPACE) - throw CModuleException::WithMessage("Insufficient DPCM sample space (maximum %d KB)", MAX_SAMPLE_SPACE / 1024); + throw CModuleException::WithMessage("Insufficient DPCM sample space (maximum " + conv::from_int(MAX_SAMPLE_SPACE / 1024) + " KB)"); int FreeSample = pManager->AddDSample(pSample); if (FreeSample == -1) throw CModuleException::WithMessage("Document has no free DPCM sample slot"); @@ -389,7 +421,7 @@ void CInstrumentIO2A03::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int -void CInstrumentIOVRC7::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentIOVRC7::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); file.WriteBlockInt(inst.GetPatch()); @@ -401,7 +433,7 @@ void CInstrumentIOVRC7::WriteToModule(const CInstrument &inst_, CDocumentFile &f void CInstrumentIOVRC7::ReadFromModule(CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); - inst.SetPatch(CModuleException::AssertRangeFmt(file.GetBlockInt(), 0, 0xF, "VRC7 patch number")); + inst.SetPatch(AssertRange(file.GetBlockInt(), 0, 0xF, "VRC7 patch number")); for (int i = 0; i < 8; ++i) inst.SetCustomReg(i, file.GetBlockChar()); @@ -427,7 +459,7 @@ void CInstrumentIOVRC7::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int -void CInstrumentIOFDS::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentIOFDS::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); // Write wave @@ -494,10 +526,10 @@ void CInstrumentIOFDS::ReadFromModule(CInstrument &inst_, CDocumentFile &file) c const auto LoadSequence = [&] (sequence_t SeqType) { int SeqCount = static_cast(file.GetBlockChar()); - unsigned int LoopPoint = CModuleException::AssertRangeFmt(file.GetBlockInt(), -1, SeqCount - 1, "Sequence loop point"); - unsigned int ReleasePoint = CModuleException::AssertRangeFmt(file.GetBlockInt(), -1, SeqCount - 1, "Sequence release point"); + unsigned int LoopPoint = AssertRange(file.GetBlockInt(), -1, SeqCount - 1, "Sequence loop point"); + unsigned int ReleasePoint = AssertRange(file.GetBlockInt(), -1, SeqCount - 1, "Sequence release point"); - // CModuleException::AssertRangeFmt(SeqCount, 0, MAX_SEQUENCE_ITEMS, "Sequence item count", "%i"); + // AssertRange(SeqCount, 0, MAX_SEQUENCE_ITEMS, "Sequence item count", "%i"); auto pSeq = std::make_shared(SeqType); pSeq->SetItemCount(SeqCount > MAX_SEQUENCE_ITEMS ? MAX_SEQUENCE_ITEMS : SeqCount); @@ -588,9 +620,9 @@ void CInstrumentIOFDS::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int // Sequences const auto LoadInstSequence = [&] (sequence_t SeqType) { - int SeqCount = CModuleException::AssertRangeFmt(file.ReadInt32(), 0, 0xFF, "Sequence item count"); - int Loop = CModuleException::AssertRangeFmt(static_cast(file.ReadInt32()), -1, SeqCount - 1, "Sequence loop point"); - int Release = CModuleException::AssertRangeFmt(static_cast(file.ReadInt32()), -1, SeqCount - 1, "Sequence release point"); + int SeqCount = AssertRange(file.ReadInt32(), 0, 0xFF, "Sequence item count"); + int Loop = AssertRange(static_cast(file.ReadInt32()), -1, SeqCount - 1, "Sequence loop point"); + int Release = AssertRange(static_cast(file.ReadInt32()), -1, SeqCount - 1, "Sequence release point"); auto pSeq = std::make_shared(SeqType); pSeq->SetItemCount(SeqCount > MAX_SEQUENCE_ITEMS ? MAX_SEQUENCE_ITEMS : SeqCount); @@ -618,9 +650,9 @@ void CInstrumentIOFDS::DoubleVolume(CSequence &seq) { -void CInstrumentION163::WriteToModule(const CInstrument &inst_, CDocumentFile &file) const { +void CInstrumentION163::DoWriteToModule(const CInstrument &inst_, CDocumentFile &file) const { auto &inst = dynamic_cast(inst_); - CInstrumentIOSeq::WriteToModule(inst_, file); + CInstrumentIOSeq::DoWriteToModule(inst_, file); // Store wave file.WriteBlockInt(inst.GetWaveSize()); @@ -637,21 +669,21 @@ void CInstrumentION163::ReadFromModule(CInstrument &inst_, CDocumentFile &file) auto &inst = dynamic_cast(inst_); CInstrumentIOSeq::ReadFromModule(inst_, file); - inst.SetWaveSize(CModuleException::AssertRangeFmt(file.GetBlockInt(), 4, CInstrumentN163::MAX_WAVE_SIZE, "N163 wave size")); - inst.SetWavePos(CModuleException::AssertRangeFmt(file.GetBlockInt(), 0, CInstrumentN163::MAX_WAVE_SIZE - 1, "N163 wave position")); - CModuleException::AssertRangeFmt(inst.GetWavePos(), 0, 0x7F, "N163 wave position"); + inst.SetWaveSize(AssertRange(file.GetBlockInt(), 4, CInstrumentN163::MAX_WAVE_SIZE, "N163 wave size")); + inst.SetWavePos(AssertRange(file.GetBlockInt(), 0, CInstrumentN163::MAX_WAVE_SIZE - 1, "N163 wave position")); + AssertRange(inst.GetWavePos(), 0, 0x7F, "N163 wave position"); if (file.GetBlockVersion() >= 8) { // // // 050B (void)(file.GetBlockInt() != 0); } - inst.SetWaveCount(CModuleException::AssertRangeFmt(file.GetBlockInt(), 1, CInstrumentN163::MAX_WAVE_COUNT, "N163 wave count")); - CModuleException::AssertRangeFmt(inst.GetWaveCount(), 1, 0x10, "N163 wave count"); + inst.SetWaveCount(AssertRange(file.GetBlockInt(), 1, CInstrumentN163::MAX_WAVE_COUNT, "N163 wave count")); + AssertRange(inst.GetWaveCount(), 1, 0x10, "N163 wave count"); for (int i = 0; i < inst.GetWaveCount(); ++i) { for (unsigned j = 0; j < inst.GetWaveSize(); ++j) try { - inst.SetSample(i, j, CModuleException::AssertRangeFmt(file.GetBlockChar(), 0, 15, "N163 wave sample")); + inst.SetSample(i, j, AssertRange(file.GetBlockChar(), 0, 15, "N163 wave sample")); } catch (CModuleException e) { - e.AppendError("At wave %i, sample %i,", i, j); + e.AppendError("At wave " + conv::from_int(i) + ", sample " + conv::from_int(j) + ','); throw e; } } @@ -680,13 +712,13 @@ void CInstrumentION163::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int CInstrumentIOSeq::DoReadFromFTI(inst_, file, fti_ver); // Read wave config - int WaveSize = CModuleException::AssertRangeFmt(static_cast(file.ReadInt32()), 4, CInstrumentN163::MAX_WAVE_SIZE, "N163 wave size"); - int WavePos = CModuleException::AssertRangeFmt(static_cast(file.ReadInt32()), 0, CInstrumentN163::MAX_WAVE_SIZE - 1, "N163 wave position"); + int WaveSize = AssertRange(static_cast(file.ReadInt32()), 4, CInstrumentN163::MAX_WAVE_SIZE, "N163 wave size"); + int WavePos = AssertRange(static_cast(file.ReadInt32()), 0, CInstrumentN163::MAX_WAVE_SIZE - 1, "N163 wave position"); if (fti_ver >= 25) { // // // 050B bool AutoWavePos = file.ReadInt32() != 0; (void)AutoWavePos; } - int WaveCount = CModuleException::AssertRangeFmt(static_cast(file.ReadInt32()), 1, CInstrumentN163::MAX_WAVE_COUNT, "N163 wave count"); + int WaveCount = AssertRange(static_cast(file.ReadInt32()), 1, CInstrumentN163::MAX_WAVE_COUNT, "N163 wave count"); inst.SetWaveSize(WaveSize); inst.SetWavePos(WavePos); @@ -694,10 +726,10 @@ void CInstrumentION163::DoReadFromFTI(CInstrument &inst_, CSimpleFile &file, int for (int i = 0; i < WaveCount; ++i) for (int j = 0; j < WaveSize; ++j) try { - inst.SetSample(i, j, CModuleException::AssertRangeFmt(file.ReadInt8(), 0, 15, "N163 wave sample")); + inst.SetSample(i, j, AssertRange(file.ReadInt8(), 0, 15, "N163 wave sample")); } catch (CModuleException e) { - e.AppendError("At wave %i, sample %i,", i, j); + e.AppendError("At wave " + conv::from_int(i) + ", sample " + conv::from_int(j) + ','); throw e; } } diff --git a/Source/InstrumentIO.h b/Source/InstrumentIO.h index ff0313b0..1876c3c9 100644 --- a/Source/InstrumentIO.h +++ b/Source/InstrumentIO.h @@ -23,50 +23,74 @@ #pragma once +#include "ModuleException.h" + class CDocumentFile; class CSimpleFile; class CInstrument; class CInstrumentIO { public: + explicit CInstrumentIO(module_error_level_t err_lv); virtual ~CInstrumentIO() noexcept = default; - virtual void WriteToModule(const CInstrument &inst, CDocumentFile &file) const = 0; + void WriteToModule(const CInstrument &inst, CDocumentFile &file, unsigned inst_index) const; virtual void ReadFromModule(CInstrument &inst, CDocumentFile &file) const = 0; void WriteToFTI(const CInstrument &inst, CSimpleFile &file) const; void ReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const; private: + virtual void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const = 0; virtual void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const = 0; virtual void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const = 0; + +protected: + template + T AssertRange(T Value, U Min, V Max, const std::string &Desc) const; + +private: + module_error_level_t err_lv_; }; class CInstrumentIONull final : public CInstrumentIO { - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; +public: + using CInstrumentIO::CInstrumentIO; + +private: + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; }; class CInstrumentIOSeq : public CInstrumentIO { +public: + using CInstrumentIO::CInstrumentIO; + protected: - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; }; class CInstrumentIO2A03 : public CInstrumentIOSeq { +public: + using CInstrumentIOSeq::CInstrumentIOSeq; + protected: - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; }; class CInstrumentIOVRC7 : public CInstrumentIO { +public: + using CInstrumentIO::CInstrumentIO; + protected: - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; @@ -75,8 +99,11 @@ class CInstrumentIOVRC7 : public CInstrumentIO { class CSequence; class CInstrumentIOFDS : public CInstrumentIO { +public: + using CInstrumentIO::CInstrumentIO; + protected: - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; @@ -85,8 +112,11 @@ class CInstrumentIOFDS : public CInstrumentIO { }; class CInstrumentION163 : public CInstrumentIOSeq { +public: + using CInstrumentIOSeq::CInstrumentIOSeq; + protected: - void WriteToModule(const CInstrument &inst, CDocumentFile &file) const override; + void DoWriteToModule(const CInstrument &inst, CDocumentFile &file) const override; void ReadFromModule(CInstrument &inst, CDocumentFile &file) const override; void DoWriteToFTI(const CInstrument &inst, CSimpleFile &file) const override; void DoReadFromFTI(CInstrument &inst, CSimpleFile &file, int fti_ver) const override; diff --git a/Source/InstrumentService.cpp b/Source/InstrumentService.cpp index b6425126..5987a552 100644 --- a/Source/InstrumentService.cpp +++ b/Source/InstrumentService.cpp @@ -22,14 +22,16 @@ #include "InstrumentService.h" #include "InstrumentTypeImpl.h" +#include "InstrumentIO.h" #include "Assertion.h" +#include "ModuleException.h" std::unique_ptr CInstrumentService::Make(inst_type_t index) const { return GetInstrumentType(index).MakeInstrument(); } -const CInstrumentIO &CInstrumentService::GetInstrumentIO(inst_type_t index) const { - return GetInstrumentType(index).GetInstrumentIO(); +std::unique_ptr CInstrumentService::GetInstrumentIO(inst_type_t index, module_error_level_t err_lv) const { + return GetInstrumentType(index).GetInstrumentIO(err_lv); } const CInstCompiler &CInstrumentService::GetChunkCompiler(inst_type_t index) const { diff --git a/Source/InstrumentService.h b/Source/InstrumentService.h index 58213517..92668c3f 100644 --- a/Source/InstrumentService.h +++ b/Source/InstrumentService.h @@ -31,11 +31,12 @@ class CInstrument; class CInstCompiler; class CInstrumentIO; enum inst_type_t : unsigned; +enum module_error_level_t : unsigned char; class CInstrumentService { public: std::unique_ptr Make(inst_type_t index) const; - const CInstrumentIO &GetInstrumentIO(inst_type_t index) const; + std::unique_ptr GetInstrumentIO(inst_type_t index, module_error_level_t err_lv) const; const CInstCompiler &GetChunkCompiler(inst_type_t index) const; void AddType(std::unique_ptr itype); diff --git a/Source/InstrumentType.h b/Source/InstrumentType.h index 1e84c9fb..97a5c480 100644 --- a/Source/InstrumentType.h +++ b/Source/InstrumentType.h @@ -29,12 +29,13 @@ class CInstrument; class CInstCompiler; class CInstrumentIO; enum inst_type_t : unsigned; +enum module_error_level_t : unsigned char; class CInstrumentType { public: virtual ~CInstrumentType() noexcept = default; virtual inst_type_t GetID() const = 0; virtual std::unique_ptr MakeInstrument() const = 0; - virtual const CInstrumentIO &GetInstrumentIO() const = 0; + virtual std::unique_ptr GetInstrumentIO(module_error_level_t err_lv) const = 0; virtual const CInstCompiler &GetChunkCompiler() const = 0; }; diff --git a/Source/InstrumentTypeImpl.cpp b/Source/InstrumentTypeImpl.cpp index c4adc8b7..15f74042 100644 --- a/Source/InstrumentTypeImpl.cpp +++ b/Source/InstrumentTypeImpl.cpp @@ -43,9 +43,8 @@ std::unique_ptr CInstrumentTypeImpl::MakeI } template -const CInstrumentIO &CInstrumentTypeImpl::GetInstrumentIO() const { - static IOT io_ = { }; - return io_; +std::unique_ptr CInstrumentTypeImpl::GetInstrumentIO(module_error_level_t err_lv) const { + return std::make_unique(err_lv); } template @@ -69,9 +68,8 @@ std::unique_ptr CInstrumentTypeNull::MakeInstrument() const { return nullptr; } -const CInstrumentIO &CInstrumentTypeNull::GetInstrumentIO() const { - static CInstrumentIONull io_ = { }; - return io_; +std::unique_ptr CInstrumentTypeNull::GetInstrumentIO(module_error_level_t err_lv) const { + return std::make_unique(err_lv); } const CInstCompiler &CInstrumentTypeNull::GetChunkCompiler() const { diff --git a/Source/InstrumentTypeImpl.h b/Source/InstrumentTypeImpl.h index d06ba396..ebd4a560 100644 --- a/Source/InstrumentTypeImpl.h +++ b/Source/InstrumentTypeImpl.h @@ -30,14 +30,14 @@ template class CInstrumentTypeImpl : public CInstrumentType { inst_type_t GetID() const override; std::unique_ptr MakeInstrument() const override; - const CInstrumentIO &GetInstrumentIO() const override; + std::unique_ptr GetInstrumentIO(module_error_level_t err_lv) const override; const CInstCompiler &GetChunkCompiler() const override; }; class CInstrumentTypeNull final : public CInstrumentType { inst_type_t GetID() const override; std::unique_ptr MakeInstrument() const override; - const CInstrumentIO &GetInstrumentIO() const override; + std::unique_ptr GetInstrumentIO(module_error_level_t err_lv) const override; const CInstCompiler &GetChunkCompiler() const override; }; diff --git a/Source/MainFrm.cpp b/Source/MainFrm.cpp index 1cca5d00..1ddc00d2 100644 --- a/Source/MainFrm.cpp +++ b/Source/MainFrm.cpp @@ -54,6 +54,7 @@ #include "FrameEditor.h" // // // #include "FamiTrackerModule.h" +#include "FamiTrackerEnv.h" #include "SongData.h" #include "SongView.h" #include "SongLengthScanner.h" @@ -1278,7 +1279,8 @@ bool CMainFrame::LoadInstrument(unsigned Index, const CStringW &filename) { // inst_type_t InstType = static_cast(file.ReadInt8()); if (auto pInstrument = pManager->CreateNew(InstType != INST_NONE ? InstType : INST_2A03)) { pInstrument->OnBlankInstrument(); - Env.GetInstrumentService()->GetInstrumentIO(InstType).ReadFromFTI(*pInstrument, file, iInstMaj * 10 + iInstMin); // // // + Env.GetInstrumentService()->GetInstrumentIO(InstType, (module_error_level_t)Env.GetSettings()->Version.iErrorLevel)-> + ReadFromFTI(*pInstrument, file, iInstMaj * 10 + iInstMin); // // // return pManager->InsertInstrument(Index, std::move(pInstrument)); } @@ -1365,7 +1367,8 @@ void CMainFrame::OnSaveInstrument() return; } - Env.GetInstrumentService()->GetInstrumentIO(pInst->GetType()).WriteToFTI(*pInst, file); // // // + Env.GetInstrumentService()->GetInstrumentIO(pInst->GetType(), + (module_error_level_t)Env.GetSettings()->Version.iErrorLevel)->WriteToFTI(*pInst, file); // // // if (m_pInstrumentFileTree) m_pInstrumentFileTree->Changed(); diff --git a/Source/ModuleException.cpp b/Source/ModuleException.cpp index 17204dc8..1768a9cc 100644 --- a/Source/ModuleException.cpp +++ b/Source/ModuleException.cpp @@ -22,12 +22,11 @@ #include "ModuleException.h" -std::string CModuleException::GetErrorString() const -{ +std::string CModuleException::GetErrorString() const { std::string out; for (const auto &x : m_strError) out += x + '\n'; - if (m_strFooter.size()) + if (!m_strFooter.empty()) out += m_strFooter; else out.pop_back(); @@ -35,7 +34,10 @@ std::string CModuleException::GetErrorString() const return out; } -void CModuleException::SetFooter(const std::string &footer) -{ - m_strFooter = footer; +void CModuleException::AppendError(std::string str) { + m_strError.push_back(std::move(str)); +} + +void CModuleException::SetFooter(std::string footer) { + m_strFooter = std::move(footer); } diff --git a/Source/ModuleException.h b/Source/ModuleException.h index 9e9aedd2..63e6ad75 100644 --- a/Source/ModuleException.h +++ b/Source/ModuleException.h @@ -27,8 +27,12 @@ #include #include -#include "FamiTrackerEnv.h" -#include "Settings.h" +enum module_error_level_t : unsigned char { // // // + MODULE_ERROR_NONE, /*!< No error checking at all (warning) */ + MODULE_ERROR_DEFAULT, /*!< Usual error checking */ + MODULE_ERROR_OFFICIAL, /*!< Special bounds checking according to the official build */ + MODULE_ERROR_STRICT, /*!< Extra validation for some values */ +}; /*! \brief An exception object raised while reading and writing FTM files. @@ -46,52 +50,20 @@ class CModuleException : public std::exception constructor. This exception object does not use std::exception::what. \return The error string. */ std::string GetErrorString() const; - /*! \brief Appends a formatted error string to the exception. - \param fmt The format specifier. - \param ... Extra arguments for the formatted string. */ - template - void AppendError(const std::string &fmt, T&&... args) - { - m_strError.emplace_back((LPCSTR)FormattedA(fmt.data(), std::forward(args)...)); - } + /*! \brief Appends an error string to the exception. + \param str The error message. */ + void AppendError(std::string str); /*! \brief Sets the footer string of the error message. \param footer The new footer string. */ - void SetFooter(const std::string &footer); + void SetFooter(std::string footer); public: - template - static CModuleException WithMessage(const std::string &fmt, T&&... args) { + static CModuleException WithMessage(std::string str) { CModuleException e; - e.AppendError(fmt, std::forward(args)...); + e.AppendError(std::move(str)); return e; } - /*! \brief Validates a numerical value so that it lies within the interval [Min, Max]. - \details This method may throw a CModuleException object and automatically supply a suitable - error message based on the value description. This method handles signed and unsigned types - properly. Errors may be ignored if the current module error level is low enough. - \param Value The value to check against. - \param Min The minimum value permitted, inclusive. - \param Max The maximum value permitted, inclusive. - \param Desc A description of the checked value. - \param fmt Print format specifier for the value type. - \return The value argument, if the method returns. - */ - template - static T AssertRangeFmt(T Value, U Min, V Max, const std::string &Desc) - { - if (l > Env.GetSettings()->Version.iErrorLevel) - return Value; - if (!(Value >= Min && Value <= Max)) { - std::string msg = Desc + " out of range: expected [" - + std::to_string(Min) + "," - + std::to_string(Max) + "], got " - + std::to_string(Value); - throw WithMessage(msg); - } - return Value; - } - private: std::vector m_strError; std::string m_strFooter; diff --git a/Source/Settings.cpp b/Source/Settings.cpp index 34658ae5..13b13210 100644 --- a/Source/Settings.cpp +++ b/Source/Settings.cpp @@ -30,6 +30,7 @@ #include "Settings.h" #include "FamiTracker.h" #include "ColorScheme.h" +#include "ModuleException.h" // // // // // // registry context diff --git a/Source/Settings.h b/Source/Settings.h index 797842bd..37654890 100644 --- a/Source/Settings.h +++ b/Source/Settings.h @@ -35,13 +35,6 @@ enum EDIT_STYLES { // // // renamed EDIT_STYLE_IT = 2, // IT }; -enum module_error_level_t { // // // - MODULE_ERROR_NONE, /*!< No error checking at all (warning) */ - MODULE_ERROR_DEFAULT, /*!< Usual error checking */ - MODULE_ERROR_OFFICIAL, /*!< Special bounds checking according to the official build */ - MODULE_ERROR_STRICT, /*!< Extra validation for some values */ -}; - enum WIN_STATES { STATE_NORMAL, STATE_MAXIMIZED,