Skip to content

Commit

Permalink
all: Try to make mp3 tags reading crossplatform
Browse files Browse the repository at this point in the history
  • Loading branch information
dimhotepus committed May 23, 2024
1 parent 35aff8c commit ecd7eee
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 66 deletions.
2 changes: 1 addition & 1 deletion APETag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ CAPETag::CAPETag(CMPAStream* stream, bool is_appended, unsigned offset)
// get size
m_dwSize = stream->ReadLEValue(4, offset);

/*unsigned dwNumItems = */ stream->ReadLEValue(4U, offset);
m_dwNumItems = stream->ReadLEValue(4U, offset);

// only valid for version 2
const unsigned flag{stream->ReadLEValue(4U, offset)};
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ target_sources(mpaheaderinfo
"MPAHeader.cpp"
"MPAStream.cpp"
"MusicMatchTag.cpp"
"Platform.cpp"
"stdafx.cpp"
"Tag.cpp"
"Tags.cpp"
Expand All @@ -124,6 +125,7 @@ target_sources(mpaheaderinfo
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/MPAHeader.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/MPAStream.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/MusicMatchTag.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/Platform.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/Tag.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/Tags.h>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/VBRHeader.h>
Expand Down
22 changes: 22 additions & 0 deletions CMakeSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DMPA_BUILD_WITHOUT_ATL=True",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"variables": [
{
"name": "MPA_BUILD_WITHOUT_ATL",
"value": "true",
"type": "BOOL"
}
]
}
]
}
24 changes: 4 additions & 20 deletions MPAException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@

#include "stdafx.h"

#include "Platform.h"
#include "MPAException.h"

#include <Windows.h>

/// CMPAException: exception class
//////////////////////////////////////////////

Expand Down Expand Up @@ -77,12 +76,6 @@ LPCTSTR CMPAException::m_szErrors[static_cast<int>(

constexpr unsigned MAX_ERR_LENGTH{256};

void CMPAException::ShowError() {
LPCTSTR pErrorMsg = GetErrorDescription();
// show error message
::MessageBox(nullptr, pErrorMsg, _T("MPAFile Error"), MB_OK | MB_ICONERROR);
}

LPCTSTR CMPAException::GetErrorDescription() {
if (!m_szErrorMsg) {
m_szErrorMsg = new TCHAR[MAX_ERR_LENGTH];
Expand All @@ -105,18 +98,9 @@ LPCTSTR CMPAException::GetErrorDescription() {
m_szErrors[static_cast<int>(m_ErrorID)]);

if (m_bGetLastError) {
// get error message of last system error id
LPVOID buffer = nullptr;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&buffer, 0, nullptr)) {
_tcscat_s(m_szErrorMsg, MAX_ERR_LENGTH, _T("\n"));
_tcscat_s(m_szErrorMsg, MAX_ERR_LENGTH, (LPCTSTR)buffer);
LocalFree(buffer);
}
_tcscat_s(m_szErrorMsg, MAX_ERR_LENGTH, _T("\n"));
_tcscat_s(m_szErrorMsg, MAX_ERR_LENGTH,
std::system_category().message(GetLastSystemError()).c_str());
}

// make sure string is null-terminated
Expand Down
1 change: 0 additions & 1 deletion MPAException.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class CMPAException {

ErrorIDs GetErrorID() const { return m_ErrorID; };
LPCTSTR GetErrorDescription();
void ShowError();

private:
ErrorIDs m_ErrorID;
Expand Down
5 changes: 2 additions & 3 deletions MPAFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
#include "MpaFile.h"

#include "MPAException.h"

#include <Windows.h>
#include "Platform.h"

CMPAFile::CMPAFile(LPCTSTR file) {
m_pStream = new CMPAFileStream(file);
Expand Down Expand Up @@ -141,7 +140,7 @@ CMPAFrame* CMPAFile::GetFrame(CMPAFile::GetType Type, CMPAFrame* frame,
return GetFrame(GetType::Resync, frame, should_delete_old_frame, offset);
}

OutputDebugString(e.GetErrorDescription());
DumpSystemError(e.GetErrorDescription());
new_frame = nullptr;
}

Expand Down
75 changes: 50 additions & 25 deletions MPAFileStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,25 @@
#include "MPAException.h"
#include "MPAEndOfFileException.h"

#include <Windows.h>

// 1KB is initial buffersize
const unsigned CMPAFileStream::INIT_BUFFERSIZE = 1024U;

CMPAFileStream::CMPAFileStream(LPCTSTR file_name)
: CMPAStream(file_name), m_dwOffset(0) {
// open with CreateFile (no limitation of 128byte filename length, like in
// mmioOpen)
m_hFile = ::CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
m_hFile = fopen(file_name, "rb");

if (m_hFile == INVALID_HANDLE_VALUE) {
// throw error
if (!m_hFile) {
throw CMPAException{CMPAException::ErrorIDs::ErrOpenFile, file_name,
_T("CreateFile"),
true};
_T("CreateFile"), true};
}

m_bMustReleaseFile = true;
Init();
}

CMPAFileStream::CMPAFileStream(LPCTSTR file_name, HANDLE hFile)
CMPAFileStream::CMPAFileStream(LPCTSTR file_name, FILE* hFile)
: CMPAStream(file_name), m_hFile(hFile), m_dwOffset(0) {
m_bMustReleaseFile = false;
Init();
Expand All @@ -58,20 +53,19 @@ CMPAFileStream::~CMPAFileStream() {
delete[] m_pBuffer;

// close file
if (m_bMustReleaseFile) ::CloseHandle(m_hFile);
if (m_bMustReleaseFile) {
fclose(m_hFile);
m_hFile = nullptr;
}
}

// set file position
void CMPAFileStream::SetPosition(unsigned offset) const {
// convert from unsigned unsigned to signed 64bit long
const unsigned result =
::SetFilePointer(m_hFile, offset, nullptr, FILE_BEGIN);
const int result = fseek(m_hFile, offset, SEEK_SET);

if (result == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
// != NO_ERROR
// throw error
if (result != 0) {
throw CMPAException{CMPAException::ErrorIDs::ErrSetPosition, m_szFile,
_T("SetFilePointer"), true};
_T("fseek"), true};
}
}

Expand All @@ -94,11 +88,42 @@ unsigned char* CMPAFileStream::ReadBytes(unsigned size, unsigned& offset,
}

unsigned CMPAFileStream::GetSize() const {
unsigned size = ::GetFileSize(m_hFile, nullptr);
const long start_pos{ftell(m_hFile)};
if (start_pos == -1L) {
throw CMPAException{CMPAException::ErrorIDs::ErrReadFile, m_szFile,
_T("ftell"), true};
}

if (fseek(m_hFile, 0L, SEEK_END)) {
fseek(m_hFile, start_pos, SEEK_SET);
throw CMPAException{CMPAException::ErrorIDs::ErrReadFile, m_szFile,
_T("fseek"), true};
}

#ifdef _WIN32
// ftell and _ftelli64 return the current file position.
// The value returned by ftell and _ftelli64 may not reflect the physical byte
// offset for streams opened in text mode, because text mode causes carriage
// return-line feed translation.
const long size{ftell(m_hFile)};

if (size == INVALID_FILE_SIZE)
if (size == -1L) {
throw CMPAException{CMPAException::ErrorIDs::ErrReadFile, m_szFile,
_T("GetFileSize"), true};
_T("ftell"), true};
}
#else
// https://wiki.sei.cmu.edu/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
const long size{ftello(m_hFile)};

if (size == -1L) {
throw CMPAException{CMPAException::ErrorIDs::ErrReadFile, m_szFile,
_T("ftello"), true};
}
#endif


if (fseek(m_hFile, start_pos, SEEK_SET)) {
}

return size;
}
Expand Down Expand Up @@ -139,14 +164,14 @@ bool CMPAFileStream::FillBuffer(unsigned offset, unsigned size,
// read from file, return number of bytes read
unsigned CMPAFileStream::Read(void* data, unsigned offset,
unsigned size) const {
DWORD bytes_read = 0;

// set position first
SetPosition(offset);

if (!::ReadFile(m_hFile, data, size, &bytes_read, nullptr))
const size_t bytes_read = fread(data, 1, size, m_hFile);
if (ferror(m_hFile))
throw CMPAException{CMPAException::ErrorIDs::ErrReadFile, m_szFile,
_T("ReadFile"), true};
_T("fread"), true};

return bytes_read;
// Safe as size is unsigned.
return static_cast<unsigned>(bytes_read);
}
6 changes: 4 additions & 2 deletions MPAFileStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@
#ifndef MPA_HEADER_INFO_MPA_FILE_STREAM_H_
#define MPA_HEADER_INFO_MPA_FILE_STREAM_H_

#include <cstdio> // FILE

#include "MPAStream.h"

using HANDLE = void*;

class CMPAFileStream : public CMPAStream {
public:
explicit CMPAFileStream(LPCTSTR file_name);
CMPAFileStream(LPCTSTR file_name, HANDLE hFile);
CMPAFileStream(LPCTSTR file_name, FILE* hFile);

virtual ~CMPAFileStream();

private:
static const unsigned INIT_BUFFERSIZE;

HANDLE m_hFile;
FILE* m_hFile;
bool m_bMustReleaseFile;

// concerning read-buffer
Expand Down
5 changes: 2 additions & 3 deletions MPAFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
#include <cmath> // for ceil

#include "MPAEndOfFileException.h"

#include <Windows.h>
#include "Platform.h"

// number of bits that are used for CRC check in MPEG 1 Layer 2
// (this table is invalid for Joint Stereo/Intensity Stereo)
Expand Down Expand Up @@ -58,7 +57,7 @@ CMPAFrame::CMPAFrame(CMPAStream* stream, unsigned& offset,
} catch (CMPAEndOfFileException&) {
m_bIsLast = true;
} catch (CMPAException&) {
OutputDebugString(_T("Didn't find subsequent frame"));
DumpSystemError(_T("Didn't find subsequent frame"));
// if (e->GetErrorID() == CMPAException::NoFrameInTolerance
}
}
Expand Down
5 changes: 2 additions & 3 deletions MPAHeader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
#include "MPAException.h"
#include "MPAEndOfFileException.h"
#include "MPAStream.h"

#include <Windows.h>
#include "Platform.h"

// static variables
LPCTSTR CMPAHeader::m_szLayers[] = {_T("Layer I"), _T("Layer II"),
Expand Down Expand Up @@ -276,7 +275,7 @@ CMPAHeader::CMPAHeader(CMPAStream* stream, unsigned& offset,
errors is made upon the value of bExactOffset
*/
catch (const CMPAException&) {
OutputDebugString(_T("Exception at construction of MPAHeader."));
DumpSystemError(_T("Exception at construction of MPAHeader."));

if (is_exact_offset) throw;
}
Expand Down
3 changes: 2 additions & 1 deletion MPEGAudioInfoDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "MPEGAudioInfo.h"
#include "MPEGAudioInfoDlg.h"
#include "AboutDlg.h"
#include "Platform.h"
#include ".\mpegaudioinfodlg.h"


Expand Down Expand Up @@ -302,7 +303,7 @@ void CMPEGAudioInfoDlg::LoadMPEGFile(LPCTSTR szFile)
}
catch(CMPAException& Exc)
{
Exc.ShowError();
DumpSystemError(Exc.GetErrorDescription());
m_CtrlPrevFrame.EnableWindow(false);
m_CtrlNextFrame.EnableWindow(false);
m_CtrlFirstFrame.EnableWindow(false);
Expand Down
33 changes: 33 additions & 0 deletions Platform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Version 3, 29 June 2007
//
// Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
//
// Everyone is permitted to copy and distribute verbatim copies of this license
// document, but changing it is not allowed.
//
// This version of the GNU Lesser General Public License incorporates the terms
// and conditions of version 3 of the GNU General Public License, supplemented
// by the additional permissions listed below.

#include "stdafx.h"

#include "Platform.h"

#include <Windows.h>

int GetLastSystemError() {
#ifdef _WIN32
return ::GetLastError();
#else
return errno;
#endif
}

void DumpSystemError(const char* error) {
#ifdef _WIN32
::MessageBox(NULL, error, _T("MPAFile Error"),
MB_OK | MB_ICONERROR);
#else
fprintf(stderr, "mp3: %s\n", error);
#endif
}
19 changes: 19 additions & 0 deletions Platform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// GNU LESSER GENERAL PUBLIC LICENSE
// Version 3, 29 June 2007
//
// Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
//
// Everyone is permitted to copy and distribute verbatim copies of this license
// document, but changing it is not allowed.
//
// This version of the GNU Lesser General Public License incorporates the terms
// and conditions of version 3 of the GNU General Public License, supplemented
// by the additional permissions listed below.

#ifndef MPA_HEADER_INFO_PLATFORM_H_
#define MPA_HEADER_INFO_PLATFORM_H_

int GetLastSystemError();
void DumpSystemError(const char *error);

#endif // !MPA_HEADER_INFO_PLATFORM_H_
Loading

0 comments on commit ecd7eee

Please sign in to comment.