Formats::Chiptune::Container::Ptr Parse(const Binary::Container& data, Builder& target) { if (!FastCheck(data)) { return Formats::Chiptune::Container::Ptr(); } try { Binary::InputStream stream(data); stream.ReadField<SignatureType>(); target.SetTitle(DecodeString(stream.ReadCString(MAX_STRING_SIZE))); target.SetAuthor(DecodeString(stream.ReadCString(MAX_STRING_SIZE))); target.SetComment(DecodeString(stream.ReadCString(MAX_COMMENT_SIZE))); const std::size_t fixedOffset = stream.GetPosition(); std::size_t totalFrames = 0; for (;;) { const uint8_t val = stream.ReadField<uint8_t>(); if (val == FINISH) { break; } switch (val) { case BEGIN_FRAME: ++totalFrames; target.BeginFrames(1); break; case SKIP_FRAMES: { const uint_t frames = 3 + stream.ReadField<uint8_t>(); totalFrames += frames; target.BeginFrames(frames); } break; case SELECT_SECOND_CHIP: target.SelectChip(1); break; case SELECT_FIRST_CHIP: target.SelectChip(0); break; case LOOP_MARKER: target.SetLoop(); break; default: target.SetRegister(val, stream.ReadField<uint8_t>()); break; } } Require(totalFrames >= MIN_FRAMES); const std::size_t usedSize = stream.GetPosition(); const auto subData = stream.GetReadData(); return CreateCalculatingCrcContainer(subData, fixedOffset, usedSize - fixedOffset); } catch (const std::exception&) { return Formats::Chiptune::Container::Ptr(); } }
Formats::Chiptune::Container::Ptr Parse(const Binary::Container& rawData, Builder& target) { if (!FastCheck(rawData)) { return Formats::Chiptune::Container::Ptr(); } const Binary::TypedContainer& data(rawData); const Header& header = *data.GetField<Header>(0); //workaround for some emulators const std::size_t offset = (header.Version == INT_BEGIN) ? offsetof(Header, Version) : sizeof(header); std::size_t restSize = rawData.Size() - offset; const uint8_t* bdata = data.GetField<uint8_t>(offset); //detect as much chunks as possible, in despite of real format issues while (restSize) { const uint_t reg = *bdata; ++bdata; --restSize; if (INT_BEGIN == reg) { target.AddChunks(1); } else if (INT_SKIP == reg) { if (restSize < 1) { ++restSize;//put byte back break; } target.AddChunks(4 * *bdata); ++bdata; --restSize; } else if (MUS_END == reg) { break; } else if (reg <= 15) //register { if (restSize < 1) { ++restSize;//put byte back break; } target.SetRegister(reg, *bdata); ++bdata; --restSize; } else { ++restSize;//put byte back break; } } const std::size_t usedSize = rawData.Size() - restSize; const Binary::Container::Ptr subData = rawData.GetSubcontainer(0, usedSize); return CreateCalculatingCrcContainer(subData, offset, usedSize - offset); }