diff options
-rw-r--r-- | src/adlmidi_load.cpp | 22 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 155 | ||||
-rw-r--r-- | src/file_reader.hpp | 259 |
3 files changed, 273 insertions, 163 deletions
diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp index 7f69e25..10bea21 100644 --- a/src/adlmidi_load.cpp +++ b/src/adlmidi_load.cpp @@ -60,14 +60,14 @@ uint64_t MIDIplay::ReadLEint(const void *buffer, size_t nbytes) bool MIDIplay::LoadBank(const std::string &filename) { - fileReader file; + FileAndMemReader file; file.openFile(filename.c_str()); return LoadBank(file); } bool MIDIplay::LoadBank(const void *data, size_t size) { - fileReader file; + FileAndMemReader file; file.openData(data, size); return LoadBank(file); } @@ -194,7 +194,7 @@ void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in) cvt_FMIns_to_generic(ins, in); } -bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) +bool MIDIplay::LoadBank(FileAndMemReader &fr) { int err = 0; WOPLFile *wopl = NULL; @@ -295,7 +295,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER bool MIDIplay::LoadMIDI(const std::string &filename) { - fileReader file; + FileAndMemReader file; file.openFile(filename.c_str()); if(!LoadMIDI(file)) return false; @@ -304,12 +304,12 @@ bool MIDIplay::LoadMIDI(const std::string &filename) bool MIDIplay::LoadMIDI(const void *data, size_t size) { - fileReader file; + FileAndMemReader file; file.openData(data, size); return LoadMIDI(file); } -bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr) +bool MIDIplay::LoadMIDI(FileAndMemReader &fr) { size_t fsize; ADL_UNUSED(fsize); @@ -406,7 +406,7 @@ riffskip: if(std::memcmp(HeaderBuf + 8, "XDIR", 4) != 0) { fr.close(); - errorStringOut = fr._fileName + ": Invalid format\n"; + errorStringOut = fr.fileName() + ": Invalid format\n"; return false; } @@ -570,7 +570,7 @@ riffskip: if(std::memcmp(HeaderBuf, "MThd\0\0\0\6", 8) != 0) { fr.close(); - errorStringOut = fr._fileName + ": Invalid format, Header signature is unknown!\n"; + errorStringOut = fr.fileName() + ": Invalid format, Header signature is unknown!\n"; return false; } @@ -667,7 +667,7 @@ riffskip: if(std::memcmp(HeaderBuf, "MTrk", 4) != 0) { fr.close(); - errorStringOut = fr._fileName + ": Invalid format, MTrk signature is not found!\n"; + errorStringOut = fr.fileName() + ": Invalid format, MTrk signature is not found!\n"; return false; } TrackLength = (size_t)ReadBEint(HeaderBuf + 4, 4); @@ -703,14 +703,14 @@ riffskip: if(totalGotten == 0) { - errorStringOut = fr._fileName + ": Empty track data"; + errorStringOut = fr.fileName() + ": Empty track data"; return false; } //Build new MIDI events table if(!buildTrackData()) { - errorStringOut = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString; + errorStringOut = fr.fileName() + ": MIDI data parsing error has occouped!\n" + errorString; return false; } diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index fda629d..13160b2 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -131,6 +131,7 @@ typedef int32_t ssize_t; #define INT32_MAX 0x7fffffff #endif +#include "file_reader.hpp" #include "fraction.hpp" #ifndef ADLMIDI_HW_OPL #include "chips/opl_chip_base.h" @@ -343,156 +344,6 @@ public: /**********************Internal structures and classes**********************/ - /** - * @brief A little class gives able to read filedata from disk and also from a memory segment - */ - class fileReader - { - public: - enum relTo - { - SET = 0, - CUR = 1, - END = 2 - }; - - fileReader() - { - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - ~fileReader() - { - close(); - } - - void openFile(const char *path) - { - #if !defined(_WIN32) || defined(__WATCOMC__) - fp = std::fopen(path, "rb"); - #else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH); - widePath[size] = '\0'; - fp = _wfopen(widePath, L"rb"); - #endif - _fileName = path; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - void openData(const void *mem, size_t lenght) - { - fp = NULL; - mp = mem; - mp_size = lenght; - mp_tell = 0; - } - - void seek(long pos, int rel_to) - { - if(fp) - std::fseek(fp, pos, rel_to); - else - { - switch(rel_to) - { - case SET: - mp_tell = static_cast<size_t>(pos); - break; - - case END: - mp_tell = mp_size - static_cast<size_t>(pos); - break; - - case CUR: - mp_tell = mp_tell + static_cast<size_t>(pos); - break; - } - - if(mp_tell > mp_size) - mp_tell = mp_size; - } - } - - inline void seeku(uint64_t pos, int rel_to) - { - seek(static_cast<long>(pos), rel_to); - } - - size_t read(void *buf, size_t num, size_t size) - { - if(fp) - return std::fread(buf, num, size, fp); - else - { - size_t pos = 0; - size_t maxSize = static_cast<size_t>(size * num); - - while((pos < maxSize) && (mp_tell < mp_size)) - { - reinterpret_cast<unsigned char *>(buf)[pos] = reinterpret_cast<unsigned const char *>(mp)[mp_tell]; - mp_tell++; - pos++; - } - - return pos; - } - } - - int getc() - { - if(fp) - return std::getc(fp); - else - { - if(mp_tell >= mp_size) return -1; - int x = reinterpret_cast<unsigned const char *>(mp)[mp_tell]; - mp_tell++; - return x; - } - } - - size_t tell() - { - if(fp) - return static_cast<size_t>(std::ftell(fp)); - else - return mp_tell; - } - - void close() - { - if(fp) std::fclose(fp); - - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - bool isValid() - { - return (fp) || (mp); - } - - bool eof() - { - if(fp) - return (std::feof(fp) != 0); - else - return mp_tell >= mp_size; - } - std::string _fileName; - std::FILE *fp; - const void *mp; - size_t mp_size; - size_t mp_tell; - }; - // Persistent settings for each MIDI channel struct MIDIchannel { @@ -1113,12 +964,12 @@ public: bool LoadBank(const std::string &filename); bool LoadBank(const void *data, size_t size); - bool LoadBank(fileReader &fr); + bool LoadBank(FileAndMemReader &fr); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER bool LoadMIDI(const std::string &filename); bool LoadMIDI(const void *data, size_t size); - bool LoadMIDI(fileReader &fr); + bool LoadMIDI(FileAndMemReader &fr); /** * @brief Periodic tick handler. diff --git a/src/file_reader.hpp b/src/file_reader.hpp new file mode 100644 index 0000000..ce4307b --- /dev/null +++ b/src/file_reader.hpp @@ -0,0 +1,259 @@ +/* + * FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block + * + * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru> + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <string> +#include <cstdio> +#ifdef _WIN32 +#include <windows.h> // MultiByteToWideChar +#endif + +/** + * @brief A little class gives able to read filedata from disk and also from a memory segment + */ +class FileAndMemReader +{ + //! Currently loaded filename (empty for a memory blocks) + std::string m_file_name; + //! File reader descriptor + std::FILE *m_fp; + + //! Memory pointer descriptor + const void *m_mp; + //! Size of memory block + size_t m_mp_size; + //! Cursor position in the memory block + size_t m_mp_tell; + +public: + /** + * @brief Relation direction + */ + enum relTo + { + //! At begin position + SET = 0, + //! At current position + CUR = 1, + //! At end position + END = 2 + }; + + /** + * @brief C.O.: It's a constructor! + */ + FileAndMemReader() : + m_fp(NULL), + m_mp(NULL), + m_mp_size(0), + m_mp_tell(0) + {} + + /** + * @brief C.O.: It's a destructor! + */ + ~FileAndMemReader() + { + close(); + } + + /** + * @brief Open file from a disk + * @param path Path to the file in UTF-8 (even on Windows!) + */ + void openFile(const char *path) + { + #if !defined(_WIN32) || defined(__WATCOMC__) + m_fp = std::fopen(path, "rb"); + #else + wchar_t widePath[MAX_PATH]; + int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH); + widePath[size] = '\0'; + fp = _wfopen(widePath, L"rb"); + #endif + m_file_name = path; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Open file from memory block + * @param mem Pointer to the memory block + * @param lenght Size of given block + */ + void openData(const void *mem, size_t lenght) + { + m_fp = NULL; + m_mp = mem; + m_mp_size = lenght; + m_mp_tell = 0; + } + + /** + * @brief Seek to given position + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + void seek(long pos, int rel_to) + { + if(m_fp)//If a file + { + std::fseek(m_fp, pos, rel_to); + } + else//If a memory block + { + switch(rel_to) + { + case SET: + m_mp_tell = static_cast<size_t>(pos); + break; + + case END: + m_mp_tell = m_mp_size - static_cast<size_t>(pos); + break; + + case CUR: + m_mp_tell = m_mp_tell + static_cast<size_t>(pos); + break; + } + + if(m_mp_tell > m_mp_size) + m_mp_tell = m_mp_size; + } + } + + /** + * @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported) + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + inline void seeku(uint64_t pos, int rel_to) + { + this->seek(static_cast<long>(pos), rel_to); + } + + /** + * @brief Read the buffer from a file + * @param buf Pointer to the destination memory block + * @param num Number of elements + * @param size Size of one element + * @return Size + */ + size_t read(void *buf, size_t num, size_t size) + { + if(m_fp) + return std::fread(buf, num, size, m_fp); + else + { + size_t pos = 0; + size_t maxSize = static_cast<size_t>(size * num); + + while((pos < maxSize) && (m_mp_tell < m_mp_size)) + { + reinterpret_cast<uint8_t *>(buf)[pos] = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell]; + m_mp_tell++; + pos++; + } + + return pos / num; + } + } + + /** + * @brief Get one byte and seek forward + * @return Readed byte or EOF (a.k.a. -1) + */ + int getc() + { + if(m_fp)//If a file + { + return std::getc(m_fp); + } + else //If a memory block + { + if(m_mp_tell >= m_mp_size) + return -1; + int x = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell]; + m_mp_tell++; + return x; + } + } + + /** + * @brief Returns current offset of cursor in a file + * @return Offset position + */ + size_t tell() + { + if(m_fp)//If a file + return static_cast<size_t>(std::ftell(m_fp)); + else//If a memory block + return m_mp_tell; + } + + /** + * @brief Close the file + */ + void close() + { + if(m_fp) + std::fclose(m_fp); + + m_fp = NULL; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Is file instance valid + * @return true if vaild + */ + bool isValid() + { + return (m_fp) || (m_mp); + } + + /** + * @brief Is End Of File? + * @return true if end of file was reached + */ + bool eof() + { + if(m_fp) + return (std::feof(m_fp) != 0); + else + return m_mp_tell >= m_mp_size; + } + + /** + * @brief Get a current file name + * @return File name of currently loaded file + */ + const std::string &fileName() + { + return m_file_name; + } + +}; |