1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-21 14:50:06 +02:00

Remove naked malloc (or similar) and free in: export

This commit is contained in:
Paul Licameli 2017-02-25 18:12:04 -05:00
parent 9314fe0cc0
commit 1614db9994
8 changed files with 131 additions and 149 deletions

View File

@ -240,7 +240,7 @@ wxWindow *ExportPlugin::OptionsCreate(wxWindow *parent, int WXUNUSED(format))
std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks, std::unique_ptr<Mixer> ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks,
const TimeTrack *timeTrack, const TimeTrack *timeTrack,
double startTime, double stopTime, double startTime, double stopTime,
unsigned numOutChannels, int outBufferSize, bool outInterleaved, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat, double outRate, sampleFormat outFormat,
bool highQuality, MixerSpec *mixerSpec) bool highQuality, MixerSpec *mixerSpec)
{ {

View File

@ -123,7 +123,7 @@ protected:
std::unique_ptr<Mixer> CreateMixer(const WaveTrackConstArray &inputTracks, std::unique_ptr<Mixer> CreateMixer(const WaveTrackConstArray &inputTracks,
const TimeTrack *timeTrack, const TimeTrack *timeTrack,
double startTime, double stopTime, double startTime, double stopTime,
unsigned numOutChannels, int outBufferSize, bool outInterleaved, unsigned numOutChannels, size_t outBufferSize, bool outInterleaved,
double outRate, sampleFormat outFormat, double outRate, sampleFormat outFormat,
bool highQuality = true, MixerSpec *mixerSpec = NULL); bool highQuality = true, MixerSpec *mixerSpec = NULL);

View File

@ -857,7 +857,7 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project,
if (!ret) if (!ret)
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
int pcmBufferSize = 1024; size_t pcmBufferSize = 1024;
const WaveTrackConstArray waveTracks = const WaveTrackConstArray waveTracks =
tracks->GetWaveTrackConstArray(selectionOnly, false); tracks->GetWaveTrackConstArray(selectionOnly, false);
auto mixer = CreateMixer(waveTracks, auto mixer = CreateMixer(waveTracks,

View File

@ -173,6 +173,14 @@ static struct
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
struct FLAC__StreamMetadataDeleter {
void operator () (FLAC__StreamMetadata *p) const
{ if (p) ::FLAC__metadata_object_delete(p); }
};
using FLAC__StreamMetadataHandle = std::unique_ptr<
FLAC__StreamMetadata, FLAC__StreamMetadataDeleter
>;
class ExportFLAC final : public ExportPlugin class ExportFLAC final : public ExportPlugin
{ {
public: public:
@ -196,7 +204,7 @@ private:
bool GetMetadata(AudacityProject *project, const Tags *tags); bool GetMetadata(AudacityProject *project, const Tags *tags);
FLAC__StreamMetadata *mMetadata; FLAC__StreamMetadataHandle mMetadata;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -248,7 +256,10 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
} }
if (mMetadata) { if (mMetadata) {
encoder.set_metadata(&mMetadata, 1); // set_metadata expects an array of pointers to metadata and a size.
// The size is 1.
FLAC__StreamMetadata *p = mMetadata.get();
encoder.set_metadata(&p, 1);
} }
sampleFormat format; sampleFormat format;
@ -299,9 +310,7 @@ ProgressResult ExportFLAC::Export(AudacityProject *project,
} }
#endif #endif
if (mMetadata) { mMetadata.reset();
::FLAC__metadata_object_delete(mMetadata);
}
const WaveTrackConstArray waveTracks = const WaveTrackConstArray waveTracks =
tracks->GetWaveTrackConstArray(selectionOnly, false); tracks->GetWaveTrackConstArray(selectionOnly, false);
@ -367,7 +376,7 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
if (tags == NULL) if (tags == NULL)
tags = project->GetTags(); tags = project->GetTags();
mMetadata = ::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); mMetadata.reset(::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT));
wxString n; wxString n;
for (const auto &pair : tags->GetRange()) { for (const auto &pair : tags->GetRange()) {
@ -378,7 +387,7 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
} }
FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8), FLAC::Metadata::VorbisComment::Entry entry(n.mb_str(wxConvUTF8),
v.mb_str(wxConvUTF8)); v.mb_str(wxConvUTF8));
::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata, ::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata.get(),
entry.get_entry(), entry.get_entry(),
true); true);
} }

View File

@ -185,7 +185,7 @@ public:
private: private:
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags); int AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
#ifdef USE_LIBID3TAG #ifdef USE_LIBID3TAG
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name); void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
#endif #endif
@ -242,15 +242,15 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
} }
char *id3buffer = NULL; ArrayOf<char> id3buffer;
int id3len; int id3len;
bool endOfFile; bool endOfFile;
id3len = AddTags(project, &id3buffer, &endOfFile, metadata); id3len = AddTags(project, id3buffer, &endOfFile, metadata);
if (id3len && !endOfFile) if (id3len && !endOfFile)
outFile.Write(id3buffer, id3len); outFile.Write(id3buffer.get(), id3len);
// Values taken from the twolame simple encoder sample // Values taken from the twolame simple encoder sample
const int pcmBufferSize = 9216 / 2; // number of samples const size_t pcmBufferSize = 9216 / 2; // number of samples
const size_t mp2BufferSize = 16384u; // bytes const size_t mp2BufferSize = 16384u; // bytes
// We allocate a buffer which is twice as big as the // We allocate a buffer which is twice as big as the
@ -307,11 +307,7 @@ ProgressResult ExportMP2::Export(AudacityProject *project,
/* Write ID3 tag if it was supposed to be at the end of the file */ /* Write ID3 tag if it was supposed to be at the end of the file */
if (id3len && endOfFile) if (id3len && endOfFile)
outFile.Write(id3buffer, id3len); outFile.Write(id3buffer.get(), id3len);
if (id3buffer) {
free(id3buffer);
}
/* Close file */ /* Close file */
@ -326,11 +322,16 @@ wxWindow *ExportMP2::OptionsCreate(wxWindow *parent, int format)
return safenew ExportMP2Options(parent, format); return safenew ExportMP2Options(parent, format);
} }
struct id3_tag_deleter {
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
};
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
// returns buffer len; caller frees // returns buffer len; caller frees
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags) int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
{ {
#ifdef USE_LIBID3TAG #ifdef USE_LIBID3TAG
struct id3_tag *tp = id3_tag_new(); id3_tag_holder tp { id3_tag_new() };
for (const auto &pair : tags->GetRange()) { for (const auto &pair : tags->GetRange()) {
const auto &n = pair.first; const auto &n = pair.first;
@ -349,7 +350,7 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
else if (n.CmpNoCase(TAG_YEAR) == 0) { else if (n.CmpNoCase(TAG_YEAR) == 0) {
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR), // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
// so we add old one as well. // so we add old one as well.
AddFrame(tp, n, v, "TYER"); AddFrame(tp.get(), n, v, "TYER");
name = ID3_FRAME_YEAR; name = ID3_FRAME_YEAR;
} }
else if (n.CmpNoCase(TAG_GENRE) == 0) { else if (n.CmpNoCase(TAG_GENRE) == 0) {
@ -362,7 +363,7 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
name = ID3_FRAME_TRACK; name = ID3_FRAME_TRACK;
} }
AddFrame(tp, n, v, name); AddFrame(tp.get(), n, v, name);
} }
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
@ -378,11 +379,10 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool
id3_length_t len; id3_length_t len;
len = id3_tag_render(tp, 0); len = id3_tag_render(tp.get(), 0);
*buffer = (char *)malloc(len); buffer.reinit(len);
len = id3_tag_render(tp, (id3_byte_t *)*buffer); len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
id3_tag_delete(tp);
return len; return len;
#else //ifdef USE_LIBID3TAG #else //ifdef USE_LIBID3TAG
@ -402,8 +402,8 @@ void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1); id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
} }
id3_ucs4_t *ucs4 = MallocString<id3_ucs4_t> ucs4 {
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
if (strcmp(name, ID3_FRAME_COMMENT) == 0) { if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
// A hack to get around iTunes not recognizing the comment. The // A hack to get around iTunes not recognizing the comment. The
@ -413,22 +413,20 @@ void ExportMP2::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
// way of clearing the field, so do it directly. // way of clearing the field, so do it directly.
id3_field *f = id3_frame_field(frame, 1); id3_field *f = id3_frame_field(frame, 1);
memset(f->immediate.value, 0, sizeof(f->immediate.value)); memset(f->immediate.value, 0, sizeof(f->immediate.value));
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4); id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
} }
else if (strcmp(name, "TXXX") == 0) { else if (strcmp(name, "TXXX") == 0) {
id3_field_setstring(id3_frame_field(frame, 2), ucs4); id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
free(ucs4);
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)); ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
id3_field_setstring(id3_frame_field(frame, 1), ucs4); id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
} }
else { else {
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4); auto addr = ucs4.get();
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
} }
free(ucs4);
id3_tag_attachframe(tp, frame); id3_tag_attachframe(tp, frame);
} }
#endif #endif

View File

@ -1617,7 +1617,7 @@ private:
int FindValue(CHOICES *choices, int cnt, int needle, int def); int FindValue(CHOICES *choices, int cnt, int needle, int def);
wxString FindName(CHOICES *choices, int cnt, int needle); wxString FindName(CHOICES *choices, int cnt, int needle);
int AskResample(int bitrate, int rate, int lowrate, int highrate); int AskResample(int bitrate, int rate, int lowrate, int highrate);
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags); int AddTags(AudacityProject *project, ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags);
#ifdef USE_LIBID3TAG #ifdef USE_LIBID3TAG
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name); void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
#endif #endif
@ -1796,12 +1796,12 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
return ProgressResult::Cancelled; return ProgressResult::Cancelled;
} }
char *id3buffer = NULL; ArrayOf<char> id3buffer;
int id3len; int id3len;
bool endOfFile; bool endOfFile;
id3len = AddTags(project, &id3buffer, &endOfFile, metadata); id3len = AddTags(project, id3buffer, &endOfFile, metadata);
if (id3len && !endOfFile) { if (id3len && !endOfFile) {
outFile.Write(id3buffer, id3len); outFile.Write(id3buffer.get(), id3len);
} }
wxFileOffset pos = outFile.Tell(); wxFileOffset pos = outFile.Tell();
@ -1890,11 +1890,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
// Write ID3 tag if it was supposed to be at the end of the file // Write ID3 tag if it was supposed to be at the end of the file
if (id3len && endOfFile) { if (id3len && endOfFile) {
outFile.Write(id3buffer, id3len); outFile.Write(id3buffer.get(), id3len);
}
if (id3buffer) {
free(id3buffer);
} }
// Always write the info (Xing/Lame) tag. Until we stop supporting Lame // Always write the info (Xing/Lame) tag. Until we stop supporting Lame
@ -2008,11 +2004,16 @@ int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
return wxAtoi(choice->GetStringSelection()); return wxAtoi(choice->GetStringSelection());
} }
struct id3_tag_deleter {
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
};
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
// returns buffer len; caller frees // returns buffer len; caller frees
int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags) int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), ArrayOf<char> &buffer, bool *endOfFile, const Tags *tags)
{ {
#ifdef USE_LIBID3TAG #ifdef USE_LIBID3TAG
struct id3_tag *tp = id3_tag_new(); id3_tag_holder tp { id3_tag_new() };
for (const auto &pair : tags->GetRange()) { for (const auto &pair : tags->GetRange()) {
const auto &n = pair.first; const auto &n = pair.first;
@ -2031,7 +2032,7 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
else if (n.CmpNoCase(TAG_YEAR) == 0) { else if (n.CmpNoCase(TAG_YEAR) == 0) {
// LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR), // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR),
// so we add old one as well. // so we add old one as well.
AddFrame(tp, n, v, "TYER"); AddFrame(tp.get(), n, v, "TYER");
name = ID3_FRAME_YEAR; name = ID3_FRAME_YEAR;
} }
else if (n.CmpNoCase(TAG_GENRE) == 0) { else if (n.CmpNoCase(TAG_GENRE) == 0) {
@ -2044,7 +2045,7 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
name = ID3_FRAME_TRACK; name = ID3_FRAME_TRACK;
} }
AddFrame(tp, n, v, name); AddFrame(tp.get(), n, v, name);
} }
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
@ -2060,11 +2061,9 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *
id3_length_t len; id3_length_t len;
len = id3_tag_render(tp, 0); len = id3_tag_render(tp.get(), 0);
*buffer = (char *)malloc(len); buffer.reinit(len);
len = id3_tag_render(tp, (id3_byte_t *)*buffer); len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get());
id3_tag_delete(tp);
return len; return len;
#else //ifdef USE_LIBID3TAG #else //ifdef USE_LIBID3TAG
@ -2084,8 +2083,8 @@ void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1); id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
} }
id3_ucs4_t *ucs4 = MallocString<id3_ucs4_t> ucs4{
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
if (strcmp(name, ID3_FRAME_COMMENT) == 0) { if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
// A hack to get around iTunes not recognizing the comment. The // A hack to get around iTunes not recognizing the comment. The
@ -2094,27 +2093,25 @@ void ExportMP3::AddFrame(struct id3_tag *tp, const wxString & n, const wxString
// (which one???) or just clear it. Unfortunately, there's no supported // (which one???) or just clear it. Unfortunately, there's no supported
// way of clearing the field, so do it directly. // way of clearing the field, so do it directly.
struct id3_frame *frame2 = id3_frame_new(name); struct id3_frame *frame2 = id3_frame_new(name);
id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4); id3_field_setfullstring(id3_frame_field(frame2, 3), ucs4.get());
id3_field *f2 = id3_frame_field(frame2, 1); id3_field *f2 = id3_frame_field(frame2, 1);
memset(f2->immediate.value, 0, sizeof(f2->immediate.value)); memset(f2->immediate.value, 0, sizeof(f2->immediate.value));
id3_tag_attachframe(tp, frame2); id3_tag_attachframe(tp, frame2);
// Now install a second frame with the standard default language = "XXX" // Now install a second frame with the standard default language = "XXX"
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4); id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
} }
else if (strcmp(name, "TXXX") == 0) { else if (strcmp(name, "TXXX") == 0) {
id3_field_setstring(id3_frame_field(frame, 2), ucs4); id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
free(ucs4);
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)); ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
id3_field_setstring(id3_frame_field(frame, 1), ucs4); id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
} }
else { else {
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4); auto addr = ucs4.get();
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
} }
free(ucs4);
id3_tag_attachframe(tp, frame); id3_tag_attachframe(tp, frame);
} }
#endif #endif

View File

@ -121,7 +121,7 @@ bool ExportOGGOptions::TransferDataFromWindow()
// ExportOGG // ExportOGG
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#define SAMPLES_PER_RUN 8192 #define SAMPLES_PER_RUN 8192u
class ExportOGG final : public ExportPlugin class ExportOGG final : public ExportPlugin
{ {

View File

@ -28,6 +28,7 @@
#include "../FileFormats.h" #include "../FileFormats.h"
#include "../Internat.h" #include "../Internat.h"
#include "../MemoryX.h"
#include "../Mix.h" #include "../Mix.h"
#include "../Prefs.h" #include "../Prefs.h"
#include "../Project.h" #include "../Project.h"
@ -328,7 +329,7 @@ public:
private: private:
char *AdjustString(const wxString & wxStr, int sf_format); ArrayOf<char> AdjustString(const wxString & wxStr, int sf_format);
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format); bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format);
void AddID3Chunk(wxString fName, const Tags *tags, int sf_format); void AddID3Chunk(wxString fName, const Tags *tags, int sf_format);
@ -472,7 +473,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
else else
format = int16Sample; format = int16Sample;
int maxBlockLen = 44100 * 5; size_t maxBlockLen = 44100 * 5;
const WaveTrackConstArray waveTracks = const WaveTrackConstArray waveTracks =
tracks->GetWaveTrackConstArray(selectionOnly, false); tracks->GetWaveTrackConstArray(selectionOnly, false);
@ -538,7 +539,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project,
return updateResult; return updateResult;
} }
char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format) ArrayOf<char> ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
{ {
bool b_aiff = false; bool b_aiff = false;
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
@ -547,34 +548,26 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
// We must convert the string to 7 bit ASCII // We must convert the string to 7 bit ASCII
size_t sz = wxStr.length(); size_t sz = wxStr.length();
if(sz == 0) if(sz == 0)
return NULL; return {};
// Size for secure malloc in case of local wide char usage // Size for secure allocation in case of local wide char usage
size_t sr = (sz+4) * 2; size_t sr = (sz+4) * 2;
char *pDest = (char *)malloc(sr); ArrayOf<char> pDest{ sr, true };
if (!pDest) if (!pDest)
return NULL; return {};
char *pSrc = (char *)malloc(sr); ArrayOf<char> pSrc{ sr, true };
if (!pSrc) if (!pSrc)
{ return {};
free(pDest);
return NULL;
}
memset(pDest, 0, sr);
memset(pSrc, 0, sr);
if(wxStr.mb_str(wxConvISO8859_1)) if(wxStr.mb_str(wxConvISO8859_1))
strncpy(pSrc, wxStr.mb_str(wxConvISO8859_1), sz); strncpy(pSrc.get(), wxStr.mb_str(wxConvISO8859_1), sz);
else if(wxStr.mb_str()) else if(wxStr.mb_str())
strncpy(pSrc, wxStr.mb_str(), sz); strncpy(pSrc.get(), wxStr.mb_str(), sz);
else { else
free(pDest); return {};
free(pSrc);
return NULL;
}
char *pD = pDest; char *pD = pDest.get();
char *pS = pSrc; char *pS = pSrc.get();
unsigned char c; unsigned char c;
// ISO Latin to 7 bit ascii conversion table (best approximation) // ISO Latin to 7 bit ascii conversion table (best approximation)
@ -622,13 +615,11 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
} }
*pD = '\0'; *pD = '\0';
free(pSrc);
if(b_aiff) { if(b_aiff) {
int len = (int)strlen(pDest); int len = (int)strlen(pDest.get());
if((len % 2) != 0) { if((len % 2) != 0) {
// In case of an odd length string, add a space char // In case of an odd length string, add a space char
strcat(pDest, " "); strcat(pDest.get(), " ");
} }
} }
@ -638,84 +629,80 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format) bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
{ {
if (tags->HasTag(TAG_TITLE)) { if (tags->HasTag(TAG_TITLE)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_TITLE, ascii7Str); sf_set_string(sf, SF_STR_TITLE, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_ALBUM)) { if (tags->HasTag(TAG_ALBUM)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_ALBUM), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_ALBUM, ascii7Str); sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_ARTIST)) { if (tags->HasTag(TAG_ARTIST)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_ARTIST), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_ARTIST, ascii7Str); sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_COMMENTS)) { if (tags->HasTag(TAG_COMMENTS)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_COMMENTS), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_COMMENT, ascii7Str); sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_YEAR)) { if (tags->HasTag(TAG_YEAR)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_YEAR), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_DATE, ascii7Str); sf_set_string(sf, SF_STR_DATE, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_GENRE)) { if (tags->HasTag(TAG_GENRE)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_GENRE), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_GENRE, ascii7Str); sf_set_string(sf, SF_STR_GENRE, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_COPYRIGHT)) { if (tags->HasTag(TAG_COPYRIGHT)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_COPYRIGHT), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str); sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_SOFTWARE)) { if (tags->HasTag(TAG_SOFTWARE)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_SOFTWARE), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str); sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get());
free(ascii7Str);
} }
} }
if (tags->HasTag(TAG_TRACK)) { if (tags->HasTag(TAG_TRACK)) {
char * ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format); auto ascii7Str = AdjustString(tags->GetTag(TAG_TRACK), sf_format);
if (ascii7Str) { if (ascii7Str) {
sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str); sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get());
free(ascii7Str);
} }
} }
return true; return true;
} }
struct id3_tag_deleter {
void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); }
};
using id3_tag_holder = std::unique_ptr<id3_tag, id3_tag_deleter>;
void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
{ {
#ifdef USE_LIBID3TAG #ifdef USE_LIBID3TAG
struct id3_tag *tp = id3_tag_new(); id3_tag_holder tp { id3_tag_new() };
for (const auto &pair : tags->GetRange()) { for (const auto &pair : tags->GetRange()) {
const auto &n = pair.first; const auto &n = pair.first;
@ -756,8 +743,8 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1); id3_field_settextencoding(id3_frame_field(frame, 0), ID3_FIELD_TEXTENCODING_ISO_8859_1);
} }
id3_ucs4_t *ucs4 = MallocString<id3_ucs4_t> ucs4{
id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) };
if (strcmp(name, ID3_FRAME_COMMENT) == 0) { if (strcmp(name, ID3_FRAME_COMMENT) == 0) {
// A hack to get around iTunes not recognizing the comment. The // A hack to get around iTunes not recognizing the comment. The
@ -767,23 +754,21 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
// way of clearing the field, so do it directly. // way of clearing the field, so do it directly.
id3_field *f = id3_frame_field(frame, 1); id3_field *f = id3_frame_field(frame, 1);
memset(f->immediate.value, 0, sizeof(f->immediate.value)); memset(f->immediate.value, 0, sizeof(f->immediate.value));
id3_field_setfullstring(id3_frame_field(frame, 3), ucs4); id3_field_setfullstring(id3_frame_field(frame, 3), ucs4.get());
} }
else if (strcmp(name, "TXXX") == 0) { else if (strcmp(name, "TXXX") == 0) {
id3_field_setstring(id3_frame_field(frame, 2), ucs4); id3_field_setstring(id3_frame_field(frame, 2), ucs4.get());
free(ucs4);
ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)); ucs4.reset(id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) n.mb_str(wxConvUTF8)));
id3_field_setstring(id3_frame_field(frame, 1), ucs4); id3_field_setstring(id3_frame_field(frame, 1), ucs4.get());
} }
else { else {
id3_field_setstrings(id3_frame_field(frame, 1), 1, &ucs4); auto addr = ucs4.get();
id3_field_setstrings(id3_frame_field(frame, 1), 1, &addr);
} }
free(ucs4); id3_tag_attachframe(tp.get(), frame);
id3_tag_attachframe(tp, frame);
} }
tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression tp->options &= (~ID3_TAG_OPTION_COMPRESSION); // No compression
@ -797,24 +782,19 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
id3_length_t len; id3_length_t len;
len = id3_tag_render(tp, 0); len = id3_tag_render(tp.get(), 0);
if (len == 0) { if (len == 0)
id3_tag_delete(tp);
return; return;
}
if ((len % 2) != 0) len++; // Length must be even. if ((len % 2) != 0) len++; // Length must be even.
id3_byte_t *buffer = (id3_byte_t *)malloc(len); ArrayOf<id3_byte_t> buffer { len, true };
if (buffer == NULL) { if (buffer == NULL)
id3_tag_delete(tp);
return; return;
}
// Zero all locations, for ending odd UTF16 content // Zero all locations, for ending odd UTF16 content
// correctly, i.e., two '\0's at the end. // correctly, i.e., two '\0's at the end.
memset(buffer, 0, len);
id3_tag_render(tp, buffer); id3_tag_render(tp.get(), buffer.get());
id3_tag_delete(tp);
wxFFile f(fName, wxT("r+b")); wxFFile f(fName, wxT("r+b"));
// FIXME: TRAP_ERR wxFFILE ops in Export PCM ID3 could fail. // FIXME: TRAP_ERR wxFFILE ops in Export PCM ID3 could fail.
@ -831,7 +811,7 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
} }
f.Write(&sz, 4); f.Write(&sz, 4);
f.Write(buffer, len); f.Write(buffer.get(), len);
sz = (wxUint32) f.Tell() - 8; sz = (wxUint32) f.Tell() - 8;
if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF) if ((sf_format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AIFF)
@ -842,8 +822,6 @@ void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
f.Close(); f.Close();
} }
free(buffer);
#endif #endif
return; return;
} }