From 1614db9994cf7e704cb776b6d273dbd2e76e7ad7 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 25 Feb 2017 18:12:04 -0500 Subject: [PATCH] Remove naked malloc (or similar) and free in: export --- src/export/Export.cpp | 2 +- src/export/Export.h | 2 +- src/export/ExportFFmpeg.cpp | 2 +- src/export/ExportFLAC.cpp | 23 ++++-- src/export/ExportMP2.cpp | 54 +++++++------- src/export/ExportMP3.cpp | 55 +++++++------- src/export/ExportOGG.cpp | 2 +- src/export/ExportPCM.cpp | 140 +++++++++++++++--------------------- 8 files changed, 131 insertions(+), 149 deletions(-) diff --git a/src/export/Export.cpp b/src/export/Export.cpp index 7d488a191..71598ad9f 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -240,7 +240,7 @@ wxWindow *ExportPlugin::OptionsCreate(wxWindow *parent, int WXUNUSED(format)) std::unique_ptr ExportPlugin::CreateMixer(const WaveTrackConstArray &inputTracks, const TimeTrack *timeTrack, double startTime, double stopTime, - unsigned numOutChannels, int outBufferSize, bool outInterleaved, + unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality, MixerSpec *mixerSpec) { diff --git a/src/export/Export.h b/src/export/Export.h index 3100d9ebe..c3ea5796f 100644 --- a/src/export/Export.h +++ b/src/export/Export.h @@ -123,7 +123,7 @@ protected: std::unique_ptr CreateMixer(const WaveTrackConstArray &inputTracks, const TimeTrack *timeTrack, double startTime, double stopTime, - unsigned numOutChannels, int outBufferSize, bool outInterleaved, + unsigned numOutChannels, size_t outBufferSize, bool outInterleaved, double outRate, sampleFormat outFormat, bool highQuality = true, MixerSpec *mixerSpec = NULL); diff --git a/src/export/ExportFFmpeg.cpp b/src/export/ExportFFmpeg.cpp index 148b69503..9ec87dd37 100644 --- a/src/export/ExportFFmpeg.cpp +++ b/src/export/ExportFFmpeg.cpp @@ -857,7 +857,7 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project, if (!ret) return ProgressResult::Cancelled; - int pcmBufferSize = 1024; + size_t pcmBufferSize = 1024; const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); auto mixer = CreateMixer(waveTracks, diff --git a/src/export/ExportFLAC.cpp b/src/export/ExportFLAC.cpp index f3ad2397f..2f427d92c 100644 --- a/src/export/ExportFLAC.cpp +++ b/src/export/ExportFLAC.cpp @@ -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 { public: @@ -196,7 +204,7 @@ private: bool GetMetadata(AudacityProject *project, const Tags *tags); - FLAC__StreamMetadata *mMetadata; + FLAC__StreamMetadataHandle mMetadata; }; //---------------------------------------------------------------------------- @@ -248,7 +256,10 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, } 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; @@ -299,9 +310,7 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, } #endif - if (mMetadata) { - ::FLAC__metadata_object_delete(mMetadata); - } + mMetadata.reset(); const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); @@ -367,7 +376,7 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags) if (tags == NULL) 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; 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), v.mb_str(wxConvUTF8)); - ::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata, + ::FLAC__metadata_object_vorbiscomment_append_comment(mMetadata.get(), entry.get_entry(), true); } diff --git a/src/export/ExportMP2.cpp b/src/export/ExportMP2.cpp index 0ab49220b..1de353290 100644 --- a/src/export/ExportMP2.cpp +++ b/src/export/ExportMP2.cpp @@ -185,7 +185,7 @@ public: private: - int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags); + int AddTags(AudacityProject *project, ArrayOf &buffer, bool *endOfFile, const Tags *tags); #ifdef USE_LIBID3TAG void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name); #endif @@ -242,15 +242,15 @@ ProgressResult ExportMP2::Export(AudacityProject *project, return ProgressResult::Cancelled; } - char *id3buffer = NULL; + ArrayOf id3buffer; int id3len; bool endOfFile; - id3len = AddTags(project, &id3buffer, &endOfFile, metadata); + id3len = AddTags(project, id3buffer, &endOfFile, metadata); if (id3len && !endOfFile) - outFile.Write(id3buffer, id3len); + outFile.Write(id3buffer.get(), id3len); // 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 // 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 */ if (id3len && endOfFile) - outFile.Write(id3buffer, id3len); - - if (id3buffer) { - free(id3buffer); - } + outFile.Write(id3buffer.get(), id3len); /* Close file */ @@ -326,11 +322,16 @@ wxWindow *ExportMP2::OptionsCreate(wxWindow *parent, int 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; + // 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 &buffer, bool *endOfFile, const Tags *tags) { #ifdef USE_LIBID3TAG - struct id3_tag *tp = id3_tag_new(); + id3_tag_holder tp { id3_tag_new() }; for (const auto &pair : tags->GetRange()) { 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) { // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR), // so we add old one as well. - AddFrame(tp, n, v, "TYER"); + AddFrame(tp.get(), n, v, "TYER"); name = ID3_FRAME_YEAR; } else if (n.CmpNoCase(TAG_GENRE) == 0) { @@ -362,7 +363,7 @@ int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool name = ID3_FRAME_TRACK; } - AddFrame(tp, n, v, name); + AddFrame(tp.get(), n, v, name); } 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; - len = id3_tag_render(tp, 0); - *buffer = (char *)malloc(len); - len = id3_tag_render(tp, (id3_byte_t *)*buffer); + len = id3_tag_render(tp.get(), 0); + buffer.reinit(len); + len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get()); - id3_tag_delete(tp); return len; #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_ucs4_t *ucs4 = - id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); + MallocString ucs4 { + id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) }; if (strcmp(name, ID3_FRAME_COMMENT) == 0) { // 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. id3_field *f = id3_frame_field(frame, 1); 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) { - id3_field_setstring(id3_frame_field(frame, 2), ucs4); - free(ucs4); + id3_field_setstring(id3_frame_field(frame, 2), ucs4.get()); - 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 { - 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); } #endif diff --git a/src/export/ExportMP3.cpp b/src/export/ExportMP3.cpp index a95d6f63e..a51047f44 100644 --- a/src/export/ExportMP3.cpp +++ b/src/export/ExportMP3.cpp @@ -1617,7 +1617,7 @@ private: int FindValue(CHOICES *choices, int cnt, int needle, int def); wxString FindName(CHOICES *choices, int cnt, int needle); 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 &buffer, bool *endOfFile, const Tags *tags); #ifdef USE_LIBID3TAG void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name); #endif @@ -1796,12 +1796,12 @@ ProgressResult ExportMP3::Export(AudacityProject *project, return ProgressResult::Cancelled; } - char *id3buffer = NULL; + ArrayOf id3buffer; int id3len; bool endOfFile; - id3len = AddTags(project, &id3buffer, &endOfFile, metadata); + id3len = AddTags(project, id3buffer, &endOfFile, metadata); if (id3len && !endOfFile) { - outFile.Write(id3buffer, id3len); + outFile.Write(id3buffer.get(), id3len); } 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 if (id3len && endOfFile) { - outFile.Write(id3buffer, id3len); - } - - if (id3buffer) { - free(id3buffer); + outFile.Write(id3buffer.get(), id3len); } // 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()); } +struct id3_tag_deleter { + void operator () (id3_tag *p) const { if (p) id3_tag_delete(p); } +}; +using id3_tag_holder = std::unique_ptr; + // 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 &buffer, bool *endOfFile, const Tags *tags) { #ifdef USE_LIBID3TAG - struct id3_tag *tp = id3_tag_new(); + id3_tag_holder tp { id3_tag_new() }; for (const auto &pair : tags->GetRange()) { 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) { // LLL: Some apps do not like the newer frame ID (ID3_FRAME_YEAR), // so we add old one as well. - AddFrame(tp, n, v, "TYER"); + AddFrame(tp.get(), n, v, "TYER"); name = ID3_FRAME_YEAR; } else if (n.CmpNoCase(TAG_GENRE) == 0) { @@ -2044,7 +2045,7 @@ int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool * name = ID3_FRAME_TRACK; } - AddFrame(tp, n, v, name); + AddFrame(tp.get(), n, v, name); } 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; - len = id3_tag_render(tp, 0); - *buffer = (char *)malloc(len); - len = id3_tag_render(tp, (id3_byte_t *)*buffer); - - id3_tag_delete(tp); + len = id3_tag_render(tp.get(), 0); + buffer.reinit(len); + len = id3_tag_render(tp.get(), (id3_byte_t *)buffer.get()); return len; #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_ucs4_t *ucs4 = - id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); + MallocString ucs4{ + id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) }; if (strcmp(name, ID3_FRAME_COMMENT) == 0) { // 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 // way of clearing the field, so do it directly. 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); memset(f2->immediate.value, 0, sizeof(f2->immediate.value)); id3_tag_attachframe(tp, frame2); // 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) { - id3_field_setstring(id3_frame_field(frame, 2), ucs4); - free(ucs4); + id3_field_setstring(id3_frame_field(frame, 2), ucs4.get()); - 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 { - 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); } #endif diff --git a/src/export/ExportOGG.cpp b/src/export/ExportOGG.cpp index f8859d02d..838b2486f 100644 --- a/src/export/ExportOGG.cpp +++ b/src/export/ExportOGG.cpp @@ -121,7 +121,7 @@ bool ExportOGGOptions::TransferDataFromWindow() // ExportOGG //---------------------------------------------------------------------------- -#define SAMPLES_PER_RUN 8192 +#define SAMPLES_PER_RUN 8192u class ExportOGG final : public ExportPlugin { diff --git a/src/export/ExportPCM.cpp b/src/export/ExportPCM.cpp index b650fba74..e9df03804 100644 --- a/src/export/ExportPCM.cpp +++ b/src/export/ExportPCM.cpp @@ -28,6 +28,7 @@ #include "../FileFormats.h" #include "../Internat.h" +#include "../MemoryX.h" #include "../Mix.h" #include "../Prefs.h" #include "../Project.h" @@ -328,7 +329,7 @@ public: private: - char *AdjustString(const wxString & wxStr, int sf_format); + ArrayOf AdjustString(const wxString & wxStr, 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); @@ -472,7 +473,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project, else format = int16Sample; - int maxBlockLen = 44100 * 5; + size_t maxBlockLen = 44100 * 5; const WaveTrackConstArray waveTracks = tracks->GetWaveTrackConstArray(selectionOnly, false); @@ -538,7 +539,7 @@ ProgressResult ExportPCM::Export(AudacityProject *project, return updateResult; } -char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format) +ArrayOf ExportPCM::AdjustString(const wxString & wxStr, int sf_format) { bool b_aiff = false; 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 size_t sz = wxStr.length(); if(sz == 0) - return NULL; - // Size for secure malloc in case of local wide char usage + return {}; + // Size for secure allocation in case of local wide char usage size_t sr = (sz+4) * 2; - char *pDest = (char *)malloc(sr); + ArrayOf pDest{ sr, true }; if (!pDest) - return NULL; - char *pSrc = (char *)malloc(sr); + return {}; + ArrayOf pSrc{ sr, true }; if (!pSrc) - { - free(pDest); - return NULL; - } - memset(pDest, 0, sr); - memset(pSrc, 0, sr); + return {}; 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()) - strncpy(pSrc, wxStr.mb_str(), sz); - else { - free(pDest); - free(pSrc); - return NULL; - } + strncpy(pSrc.get(), wxStr.mb_str(), sz); + else + return {}; - char *pD = pDest; - char *pS = pSrc; + char *pD = pDest.get(); + char *pS = pSrc.get(); unsigned char c; // 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'; - free(pSrc); - if(b_aiff) { - int len = (int)strlen(pDest); + int len = (int)strlen(pDest.get()); if((len % 2) != 0) { // 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) { 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) { - sf_set_string(sf, SF_STR_TITLE, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_TITLE, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_ALBUM, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_ALBUM, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_ARTIST, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_ARTIST, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_COMMENT, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_COMMENT, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_DATE, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_DATE, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_GENRE, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_GENRE, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_COPYRIGHT, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_SOFTWARE, ascii7Str.get()); } } 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) { - sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str); - free(ascii7Str); + sf_set_string(sf, SF_STR_TRACKNUMBER, ascii7Str.get()); } } 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; + void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format) { #ifdef USE_LIBID3TAG - struct id3_tag *tp = id3_tag_new(); + id3_tag_holder tp { id3_tag_new() }; for (const auto &pair : tags->GetRange()) { 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_ucs4_t *ucs4 = - id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)); + MallocString ucs4{ + id3_utf8_ucs4duplicate((id3_utf8_t *) (const char *) v.mb_str(wxConvUTF8)) }; if (strcmp(name, ID3_FRAME_COMMENT) == 0) { // 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. id3_field *f = id3_frame_field(frame, 1); 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) { - id3_field_setstring(id3_frame_field(frame, 2), ucs4); - free(ucs4); + id3_field_setstring(id3_frame_field(frame, 2), ucs4.get()); - 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 { - 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.get(), frame); } 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; - len = id3_tag_render(tp, 0); - if (len == 0) { - id3_tag_delete(tp); + len = id3_tag_render(tp.get(), 0); + if (len == 0) return; - } + if ((len % 2) != 0) len++; // Length must be even. - id3_byte_t *buffer = (id3_byte_t *)malloc(len); - if (buffer == NULL) { - id3_tag_delete(tp); + ArrayOf buffer { len, true }; + if (buffer == NULL) return; - } + // Zero all locations, for ending odd UTF16 content // correctly, i.e., two '\0's at the end. - memset(buffer, 0, len); - id3_tag_render(tp, buffer); - - id3_tag_delete(tp); + id3_tag_render(tp.get(), buffer.get()); wxFFile f(fName, wxT("r+b")); // 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(buffer, len); + f.Write(buffer.get(), len); sz = (wxUint32) f.Tell() - 8; 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(); } - - free(buffer); #endif return; }